Bi-Directional Communication via IoTHub/Xamarin App/ESP8266

994 Views Asked by At

Working on a new product at work that will be using an ESP8266, Xamarin app, and the Azure IoTHub to enable bidirectional communication for customer's devices.

We've got C2D (Cloud 2 Device) and D2C (Device 2 Cloud) communication working properly on both the app and the ESP, but we are not finding any information on setting up the IoTHub to interpret incoming Telemetry messages, process their respective "To:" field and put them back in to the C2D topic, which should allow our target device to receive it.

What we have tried:

  1. Logic Apps. Were able to trigger on incoming messages to the queue, but not sure what HTTP request to do in order to forward it back in to the C2D event hub.
  2. We have successfully been able to forward each message in to a queue, but the PCL library for Xamarin is not capable of connecting to Azure Service Bus Queues (bummer).

I found a reference for an intern at Microsoft developing direct device to device communication for a garage door opener, but the library she is using is only available for UWP apps, which isn't all that convenient, when we really want to target iOS, Android and UWP (reason for choosing Xamarin in the first place).

https://blogs.windows.com/buildingapps/2016/09/08/device-to-device-communication-with-azure-iot-hub/#ykPJrVE734GpSEzV.97

Has anyone been able to trigger C2D conditional events using the Azure portal?

1

There are 1 best solutions below

0
On BEST ANSWER

Through some conversations with Microsoft Azure team, we determined that a webjob combined with a route to a queue was the best solution for us.

All messages are routed to the queue and as they arrive in the queue, the webjob processes the message and sends the message on using a ServiceBus Messaging object to send the cloud to device response message.

Here's the code for anyone who wants to use it.

As long as the original sender of the message specifies the "To" property in the brokered message, it will be delivered to that device in the registry. You will need the Service Bus and Azure.Messaging NuGet packages in order to use this. This code will copy the entire message and send the whole thing to the desired registry device.

private const string queueName = "<queue_name>";
    private const string IoTHubConnectionString = "HostName=<your_host>;SharedAccessKeyName=<your_service_user>;SharedAccessKey=<your sas>";
    // This function will get triggered/executed when a new message is written 
    // on an Azure Queue called <queue_name>.
    public static void ReceiveQueueMessages(
        [ServiceBusTrigger(queueName)] BrokeredMessage message,
        TextWriter log)
    {
        if (message.To == null)
        {
            //message = null
            return;
        }
        else
        {
            //Retrieve the message body regardless of the content as a stream
            Stream stream = message.GetBody<Stream>();
            StreamReader reader;

            if (stream != null)
                reader = new StreamReader(stream);
            else
                reader = null;

            string s;
            Message serviceMessage;

            if ( reader != null )
            {
                s = reader.ReadToEnd();
                serviceMessage = new Microsoft.Azure.Devices.Message(Encoding.ASCII.GetBytes(s));
            }
            else
            {
                serviceMessage = new Microsoft.Azure.Devices.Message();
            }

            foreach (KeyValuePair<string, object> property in message.Properties)
            {
                serviceMessage.Properties.Add(property.Key, property.Value.ToString());
            }
            SendToIoTHub(message.To.ToString(), serviceMessage);
        }
    }

    static async void SendToIoTHub(string target, Microsoft.Azure.Devices.Message message)
    {
        // Write it back out to the target device

        ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(IoTHubConnectionString);

        var serviceMessage = message;
        serviceMessage.Ack = DeliveryAcknowledgement.Full;
        serviceMessage.MessageId = Guid.NewGuid().ToString();

        try
        {
            await serviceClient.SendAsync(target, serviceMessage);
        }
        catch
        {
            await serviceClient.CloseAsync();
            return;
        }

        await serviceClient.CloseAsync();
    }