Processing Azure IoT Hub Events Using Azure Function


When an IoT Hub receives an event, it will store it in an Azure Event Hub partition to be processed. In this article, we will go through the process of creating an Azure Function and use it to pass the events to another Azure IoT device.

What we will need:

Creating an Azure Function with VS Code:

To develop Azure Function Apps in VS Code, we will first need to install the Azure Functions extension.

Azure Functions extension for VS Code

Press F1 to open the command palette, select Azure Functions: Create new project and follow the instructions. What we want to do is create a function that will get executed when an event occurs, in our case when a new event is added to the event hub.

Example of creating an Azure Function App using VS Code

We will also update the inputs to EventHubTrigger function, where:

  • MyHub
    • An app setting variable containing the event hub name
    • When developing locally, we can store this in “local.settings.json”
  • MyHubConnection
    • An app setting variable containing the connection string to the event hub
    • When developing locally, we can store this in “local.settings.json”

The event hub name and endpoint can be obtained from the IoT Hub built-in endpoints settings in Azure Portal.

At this point, we can run the Azure App in debug mode and watch the events being handled and printed in the console output.

IoT device agent sending events to IoT Hub and being processed by an Azure function

Putting the pieces together

Now let’s abstract the underlying infrastructure components away and focus on the things that matters. In our scenario, there are 3 things:

  • The Home Gateway
  • The Home Gateway Handler
  • The Home Gateway Client

The Home Gateway

The Home Gateway is a service (an Azure IoT device agent) that monitors and control some connected devices in the home. In a real world environment we would be deploying this service on any Azure IoT Hub capable device (supported platforms) but for the sake of demonstration, we will deploy the Home Gateway as a Windows service.

Every 3s (for demo only) we will simulate a doorbell event, it will send a MultiLinksMessage event to the IoT hub. The MultiLinksMessage event contains the following data:

  • Source (the event originator)
  • Destination (the event recipient)
  • MessageType (the type of event)
  • MessageData (the specific data associated with the event)
namespace HomeGateway
{
   public class Worker : BackgroundService
   {
      ...

      private async Task SendDoorbellTriggerMessageAsync()
      {
         _logger.LogInformation("Sending doorbell event");
         
         var doorbellTrigger = new DoorbellTrigger
         {
            TriggerTime = DateTimeOffset.Now
         };

         var messageData = JsonSerializer.Serialize(doorbellTrigger);

         var multilinksMessage = new MultiLinksMessage
         {
            Source = "HomeGateway",
            Destination = "HomeGatewayClient",
            MessageType = "DoorbellTrigger",
            MessageData = messageData
         };

         var jsonData = JsonSerializer.Serialize(multilinksMessage);

         var message = new Message(Encoding.ASCII.GetBytes(jsonData));
         message.ContentType = "MultiLinksMessage";

         try
         {
            await _client.SendEventAsync(message);
         }
         catch (Exception ex)
         {
            _logger.LogError(ex, "Fail to send message");
         }
      }
   }
}

In the code above, every 3s the SendDoorbellTriggerMessageAsync() method will get called. It will first log the event to a local file, then generate the data for the doorbell event and send it to the IoT hub.

The Home Gateway Handler

The Home Gateway Handler is the Azure Function we created earlier. It will process events the IoT hub receives.

namespace com.aniotodyssey
{
    public static class HomeGatewayHandler
    {
        private const string HubConnectionString = "iot-hub-connection-string";

        [FunctionName("HomeGatewayHandler")]
        public static async Task Run([EventHubTrigger("MyHub", Connection = "MyHubConnection")] EventData[] events, ILogger log)
        {
            var exceptions = new List<Exception>();
            ServiceClient client = ServiceClient.CreateFromConnectionString(HubConnectionString, Microsoft.Azure.Devices.TransportType.Amqp, null);

            foreach (EventData eventData in events)
            {
                try
                {
                    await CallDirectMethod(client, eventData);
                }
                ...
            }

            ...
        }

        private static async Task CallDirectMethod(ServiceClient client, EventData eventData)
        {
            var method = new CloudToDeviceMethod("ProcessMessage");

            var payload = Encoding.ASCII.GetString(eventData.Body.Array,
                                                   eventData.Body.Offset,
                                                   eventData.Body.Count);

            var multilinksMessage = JsonSerializer.Deserialize<MultiLinksMessage>(payload);
            method.SetPayloadJson(payload);

            var response = await client.InvokeDeviceMethodAsync(multilinksMessage.Destination, method);
        }
    }
}

In the code above, the CallDirectMethod() is called when the IoT hub receives an event. It will unpack the MultiLinksMessage payload to determine where the payload needs to go to and then invoke a direct method on the destination device (in this case the Home Gateway Client) and passing in the payload.

The Home Gateway Client

The Home Gateway Client is a service (an Azure IoT device agent) that can send commands to the Home Gateway or get notified of Home Gateway events. In a real world environment we would be deploying this service on any Azure IoT Hub capable device (supported platforms) but for the sake of demonstration, we will deploy the Home Gateway Client as a Windows service.

namespace HomeGatewayClient
{
   public class Worker : BackgroundService
   {
      ...

      private Task<MethodResponse> ProcessMessage(MethodRequest request, object context)
      {
         var multilinksMessage = JsonSerializer.Deserialize<MultiLinksMessage>(request.DataAsJson);

         if (multilinksMessage.MessageType == "DoorbellTrigger")
         {
            var doorbellTrigger = JsonSerializer.Deserialize<DoorbellTrigger>(multilinksMessage.MessageData);
            _logger.LogInformation($"{multilinksMessage.Source} Doorbell triggered at: {doorbellTrigger.TriggerTime}");
         }

         var responseData = Encoding.ASCII.GetBytes("\"response\": \"Message processed\"");
         return Task.FromResult(new MethodResponse(responseData, 200)); 
      }
   }
}

When the Home Gateway Handler receives an event, it will invoke ProcessMessage() method above. This method will unpack the payload provided by the Home Gateway Handler and checks the MessageType to make sure that it can handle the content, in this case if the type is “DoorbellTrigger” It will log the doorbell trigger time to a local file. After that it will respond to the Home Gateway Handler that everything is good.

To verify that things are working end to end we can inspect the logs in live view using the following Powershell commandlet:

Get-Content -Path C:\ProgramData\IoTApps\HomeGateway\activities_report.txt -Tail 10 -Wait
Get-Content -Path C:\ProgramData\IoTApps\HomeGatewayClient\activities_report.txt -Tail 10 -Wait
Live Home Gateway activity logs

Categories: .NET, Azure, Internet of things

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: