Marcel
Marcel

Reputation: 15742

How to retrieve the latest message (event) from IoT Hub, by device, via HTTP

I have found many examples on how to retrieve data from a running IoT hub. However, in all of these, some variant of WebSockets is required.

I need a way to immediately get the latest message available from an IoT device.

Scenario

I am running a small weather station using 4 devices, which send their data to the IoT hub. As a display, I want to recycle a 1st generation iPad. It's browser does not support WebSockets, thus ruling out all the modern approaches.

I will update the values with polling, preferably using simple HTTP GET requests, every 15 minutes.

I have the above mentioned sample running (qrysweathertest.azurewebsites.net), but it uses web sockets, thus not working on a 1stGen iPad.

Upvotes: 0

Views: 1391

Answers (2)

Roman Kiss
Roman Kiss

Reputation: 8265

Another alternative for your hobby project can be considered to use a device twin tags property for storing the last telemetry data.

Basically, you can use the EventGridTrigger subscriber for storing the telemetry data to the device twin tags property in the push manner or using the pull manner for instance, the IoTHubTrigger function as a consumer of the iothub stream pipeline.

The following code snippet shows an example of the IoTHubTrigger function:

run.csx:

#r "Microsoft.Azure.EventHubs"
#r "Newtonsoft.Json"
#r "..\\bin\\Microsoft.Azure.Devices.dll"
#r "..\\bin\\Microsoft.Azure.Devices.Shared.dll"


using Microsoft.Azure.Devices;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.Azure.EventHubs;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text;

static RegistryManager registryManager = RegistryManager.CreateFromConnectionString(Environment.GetEnvironmentVariable("AzureIoTHubShariedAccessPolicy"));

public static async Task Run(EventData message, ILogger log)
{
    log.LogInformation($"\nSystemProperties:\n\t{string.Join(" | ", message.SystemProperties.Select(i => $"{i.Key}={i.Value}"))}");

    if (message.SystemProperties["iothub-message-source"]?.ToString() == "Telemetry")
    {    
        var connectionDeviceId = message.SystemProperties["iothub-connection-device-id"].ToString(); 
        var msg = Encoding.UTF8.GetString(message.Body.Array);
        
        log.LogInformation($"DeviceId = {connectionDeviceId}, Telemetry = {msg}");

        var twinPatch = JsonConvert.SerializeObject(new { tags = new { telemetry = new { lastUpdated = message.SystemProperties["iothub-enqueuedtime"], data = JObject.Parse(msg) }}});
        await registryManager.ReplaceTwinAsync(connectionDeviceId, twinPatch, "*");
    }
}

function.json:

{
  "bindings": [
    {
      "name": "message",
      "connection": "my_IOTHUB",
      "eventHubName": "my_IOTHUB_NAME",
      "consumerGroup": "function",
      "cardinality": "one",
      "direction": "in",
      "type": "eventHubTrigger"
    }
  ]
}

Once, the telemetry data are stored in the device twin tags property, we can use all iothub built-in features for querying and retrieving the device twins programmatically or using the azure portal.

The following example shows a query string to obtain the telemetry data from all devices:

SELECT devices.id, devices.tags.telemetry FROM devices WHERE is_defined(devices.tags.telemetry)

Using the REST Get Devices we can get the result of the query string, see the following example:

enter image description here

and using the REST Get Twin we can get the device twin for specific device, see the following example:

enter image description here

Notes:

  1. the REST request requires a sas token for Authorization header
  2. the above solution is not suitable for Basic Tier IoT Hub (doesn't have a device twin)
  3. usage of this solution is fine for a hobby project (Free and S1 pricing tiers), in the case of more hundreds devices with a frequently ingestion of the telemetry data, please refer to the IoT Hub quotas and throttling document about the throttles on the Queries and Twin updates.

Upvotes: 0

Matthijs van der Veer
Matthijs van der Veer

Reputation: 4095

This is not possible out of the box with IoT Hub. You will have to store the telemetry values to storage (a database for instance), and build a small API to retrieve the latest value. You could store and retrieve the values using Azure Functions, which would be a low-cost way to enable your scenario.

Alternatively, IoT Central does support retrieving the latest telemetry value through the inbuilt API. And possibly the dashboarding features of IoT Central can cover your entire scenario.

Upvotes: 1

Related Questions