[IoT] Limiting per device messaging & auto reset

In my aquarium monitor series I showed how to build an application to monitor a fish tank. The use of the Azure IoT components allow us to easily build these kinds of solutions based on generic components. It also allows us to scale, which makes it very suitable for scenarios with lots of devices or data.

Should you want to make your application multi-tenant, there’s no reason why you shouldn’t… or is there? What if you don’t have complete control over the clients and someone starts to send way more data then expected? Hmm… I considered this scenario because the code of my gateway is open source. Anyone can grab it and start up a gateway. With some small modifications, it’s very easy to increase the number of messages sent to the back-end. And although Azure scales well, it doesn’t do that for free so you might want to ensure that you’re not faced with a huge bill at the end of the month.

Control over devices

So what control over our IoT devices do we have?

  1. First of all, there needs to be a device provisioned in the IoT hub registry. Without a registered device and its key (secret), connecting will be impossible.
  2. Second, a device in the IoT hub registry can either be enabled or disabled. As you would expect, disabled devices are dead in the water; they cannot send or receive anything. Disabling a device can be done in the portal, or via code as illustrated below.

azure_device

The Enable and Disable buttons simply allow you to switch the state (be warned: there’s no “save” button so clicking is immediate!).

And in code:

var registry = RegistryManager.CreateFromConnectionString(iotHubConnectionString);

Device device = await registry.GetDeviceAsync("device-id");
device.Status = DeviceStatus.Disabled;
await registry.UpdateDeviceAsync(device);

Ok, so we have a way to “shut up” a device. But this should not be a manual action of course, we want to automate it!

 

Monitoring message count with Stream Analytics

To keep track of the number of incoming messages, Stream Analytics will be the most logical place as it provides the data and the tools to do so. In my case, I wanted to monitor the amount of messages per hour and cut off any device that produces too many. To do so, I used the following query:

WITH [MessageCounts]
AS (
    SELECT
        event.IoTHub.ConnectionDeviceId AS DeviceId,
        COUNT(*) AS MessageCount
    FROM
        [IoTHubStream] event
    GROUP BY
        event.IoTHub.ConnectionDeviceId,
        SlidingWindow(hour, 1)
)

/* Create throttle event requests for all device id's that have produced more then 80 messages
   in the window of the last 1 hour. Will be processed by an Azure Function
 */
SELECT     
    'DeviceThrottleRequest' AS ObjectType,  
    DeviceId,
    MessageCount
INTO [DeviceThrottleRequests]
FROM 
    [MessageCounts]
WHERE 
    MessageCount > 80

In the first section, a ASA query groups the messages per device id and counts the number of messages using a “SlidingWindow“. If you’re not familiar with the Window functions, check out the documentation here: https://azure.microsoft.com/en-us/documentation/articles/stream-analytics-window-functions/.

The second section compares the aggregated MessageCount with my hardcoded value of 80. Of course you could also put this number in a reference data file for some more flexibility. I chose 80 because each device should send 60 updates each hour (once every minute) and to have some headroom for commands and stuff. Of course this number will completely depend on your use case and the amount of money you’re willing to spend.

With this query running, items with an object type of ‘DeviceThrottleRequest’ will be sent to a event hub for further processing.

 

Azure function processing throttle requests

With the throttling requests now being put onto an event hub, we need to do something with those requests. In comes an Azure Function! I already had a function monitoring this event hub, so I only had to extend it with some logic to process this new type of event:

public static async Task DisableDevice(string input, TraceWriter log)
{
    log.Info("Received request to throttle device.");

    try {
        dynamic eventData = ((JArray)JsonConvert.DeserializeObject(input))[0];
        string deviceId = eventData.deviceid;

        string iotHubConnectionString = System.Configuration.ConfigurationManager.AppSettings["iotHub.ConnectionString"];
        var registry = RegistryManager.CreateFromConnectionString(iotHubConnectionString);

        log.Info($"Disabling device {deviceId} in IoT hub.");
        var device = await registry.GetDeviceAsync(deviceId);
        device.Status = DeviceStatus.Disabled;
        await registry.UpdateDeviceAsync(device);

        log.Info("Successfully disabled device.");       
    } 
    catch (Exception ex)
    {
        log.Error("Failure trying to disable a device: " + ex.ToString());
    }
}

Fairly straightforward, the event is picked up, the deviceId is extracted and we call the API to disable this device. The above is a snippet, the complete file can be found here. Also ensure that your function loads the Microsoft.Azure.Devices NuGet package.

As soon as your device is disabled in the registry, send and receive commands will start producing errors. So you’ll need to handle those gracefully if you don’t want your app to crash.

 

Resetting the device status

With the device disabled, your user will be left with a non functioning system. Although that was intended, you might want to consider some grace and re-enable the device again. I chose to do this daily, at 00:00 CET. A second Azure Function triggered by a timer will take care of this. The code is pretty much similar to what’s above:

using System;
using Microsoft.Azure.Devices;

public static async Task Run(TimerInfo myTimer, TraceWriter log)
{
    try {
        string iotHubConnectionString = System.Configuration.ConfigurationManager.AppSettings["iotHub.ConnectionString"];
        var registry = RegistryManager.CreateFromConnectionString(iotHubConnectionString);

        log.Info($"Getting the device registry list from IoT hub.");
        var devices = await registry.GetDevicesAsync(1000);

        foreach (var device in devices)
        {
            if (device.Status == DeviceStatus.Disabled)
            {
                device.Status = DeviceStatus.Enabled;
                await registry.UpdateDeviceAsync(device);
                log.Info($"Re-enabled device {device.Id}.");
            }
        }

        log.Info("Successfully re-enabled all devices.");       
    } 
    catch (Exception ex)
    {
        log.Error("Failure trying to disable a device: " + ex.ToString());
    }    
}

Get the list of devices, loop through it and re-enable all the devices that have a Status of Disabled. In your gateway app, write some code which retries connecting every 5 or 10 minutes and it should automatically come alive again.

 

Conclusion

By using the right bits of Azure, it’s pretty simple to limit the number of messages a single device is allowed to send. This can help manage your service and keep it alive for other users whilst also ensuring you’re not surprised by an enormous bill at the end of the month 🙂

 

 

, ,

Related posts

Long Term Support… or not?

In my aquarium monitor series I showed how to build an application to monitor a fish tank. The use of the Azure IoT components allow us to easily build these kinds of solutions based on generic components. It also allows us to scale, which makes it very suitable for scenarios with lots of devices or data.

Should you want to make your application multi-tenant, there's no reason why you shouldn't... or is there? What if you don't have complete control over the clients and someone starts to send way more data then expected? Hmm... 

[DevOps] Should you migrate onto YAML release pipelines?

In my aquarium monitor series I showed how to build an application to monitor a fish tank. The use of the Azure IoT components allow us to easily build these kinds of solutions based on generic components. It also allows us to scale, which makes it very suitable for scenarios with lots of devices or data.

Should you want to make your application multi-tenant, there's no reason why you shouldn't... or is there? What if you don't have complete control over the clients and someone starts to send way more data then expected? Hmm... 

Latest posts

Long Term Support… or not?

In my aquarium monitor series I showed how to build an application to monitor a fish tank. The use of the Azure IoT components allow us to easily build these kinds of solutions based on generic components. It also allows us to scale, which makes it very suitable for scenarios with lots of devices or data.

Should you want to make your application multi-tenant, there's no reason why you shouldn't... or is there? What if you don't have complete control over the clients and someone starts to send way more data then expected? Hmm... 

[DevOps] Should you migrate onto YAML release pipelines?

In my aquarium monitor series I showed how to build an application to monitor a fish tank. The use of the Azure IoT components allow us to easily build these kinds of solutions based on generic components. It also allows us to scale, which makes it very suitable for scenarios with lots of devices or data.

Should you want to make your application multi-tenant, there's no reason why you shouldn't... or is there? What if you don't have complete control over the clients and someone starts to send way more data then expected? Hmm... 

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *