{"id":2021,"date":"2016-10-18T13:07:43","date_gmt":"2016-10-18T12:07:43","guid":{"rendered":"http:\/\/blog.repsaj.nl\/?p=2021"},"modified":"2016-10-18T13:14:13","modified_gmt":"2016-10-18T12:14:13","slug":"iot-limiting-per-device-messaging-auto-reset","status":"publish","type":"post","link":"http:\/\/blog.repsaj.nl\/index.php\/2016\/10\/iot-limiting-per-device-messaging-auto-reset\/","title":{"rendered":"[IoT] Limiting per device messaging &#038; auto reset"},"content":{"rendered":"<p>In my <a href=\"http:\/\/blog.repsaj.nl\/index.php\/2016\/01\/iot-my-steps-to-an-aquarium-monitor\/\" target=\"_blank\">aquarium monitor series<\/a> I showed how to build an application to monitor a fish tank.\u00a0The use of the Azure IoT\u00a0components allow us to easily build these kinds of solutions based on <strong>generic components<\/strong>. It also allows us to <strong>scale,<\/strong> which makes it very suitable for scenarios with lots of devices or data.<\/p>\n<p>Should you want to make your application <strong>multi-tenant<\/strong>, there&#8217;s no reason why you shouldn&#8217;t&#8230; or is there? What if you don&#8217;t have complete control over the clients and someone starts to send way more data then expected? Hmm&#8230;\u00a0<!--more-->I considered this scenario because the code of my gateway is open source. Anyone can grab it and start up a gateway.\u00a0With some small modifications, it&#8217;s very easy to increase the number of messages sent to the back-end. And although Azure scales well, it doesn&#8217;t do that for free so you might want to ensure that you&#8217;re not faced with a huge bill at the end of the month.<\/p>\n<h2><\/h2>\n<h2>Control over devices<\/h2>\n<p>So what control over our IoT devices do we have?<\/p>\n<ol>\n<li>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.<\/li>\n<li>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.<\/li>\n<\/ol>\n<p><a href=\"http:\/\/blog.repsaj.nl\/index.php\/2016\/10\/iot-limiting-per-device-messaging-auto-reset\/azure_device\/\" rel=\"attachment wp-att-2022\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-2022\" src=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2016\/10\/azure_device.png\" alt=\"azure_device\" width=\"322\" height=\"482\" srcset=\"http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2016\/10\/azure_device.png 322w, http:\/\/blog.repsaj.nl\/wp-content\/uploads\/2016\/10\/azure_device-200x300.png 200w\" sizes=\"(max-width: 322px) 100vw, 322px\" \/><\/a><\/p>\n<p>The <strong>Enable<\/strong> and <strong>Disable<\/strong> buttons simply allow you to switch the state (be warned: there&#8217;s no &#8220;save&#8221; button so clicking is immediate!).<\/p>\n<p>And in code:<\/p>\n<pre class=\"lang:c# decode:true\">var registry = RegistryManager.CreateFromConnectionString(iotHubConnectionString);\r\n\r\nDevice device = await registry.GetDeviceAsync(\"device-id\");\r\ndevice.Status = DeviceStatus.Disabled;\r\nawait registry.UpdateDeviceAsync(device);<\/pre>\n<p>Ok, so we have a way to &#8220;shut up&#8221; a device. But this should not be a manual action of course, we want to automate it!<\/p>\n<p>&nbsp;<\/p>\n<h2>Monitoring message count with Stream Analytics<\/h2>\n<p>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:<\/p>\n<pre class=\"lang:default decode:true \">WITH [MessageCounts]\r\nAS (\r\n    SELECT\r\n        event.IoTHub.ConnectionDeviceId AS DeviceId,\r\n        COUNT(*) AS MessageCount\r\n    FROM\r\n        [IoTHubStream] event\r\n    GROUP BY\r\n        event.IoTHub.ConnectionDeviceId,\r\n        SlidingWindow(hour, 1)\r\n)\r\n\r\n\/* Create throttle event requests for all device id's that have produced more then 80 messages\r\n   in the window of the last 1 hour. Will be processed by an Azure Function\r\n *\/\r\nSELECT     \r\n    'DeviceThrottleRequest' AS ObjectType,  \r\n    DeviceId,\r\n    MessageCount\r\nINTO [DeviceThrottleRequests]\r\nFROM \r\n    [MessageCounts]\r\nWHERE \r\n    MessageCount &gt; 80<\/pre>\n<p>In the first section, a ASA query groups the messages per device id and counts the number of messages using a &#8220;<strong>SlidingWindow<\/strong>&#8220;. If you&#8217;re not familiar with the Window functions, check out the documentation here:\u00a0<a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/stream-analytics-window-functions\/\" target=\"_blank\">https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/stream-analytics-window-functions\/<\/a>.<\/p>\n<p>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&#8217;re willing to spend.<\/p>\n<p>With this query running, items with an object type of &#8216;DeviceThrottleRequest&#8217; will be sent to a event hub for further processing.<\/p>\n<p>&nbsp;<\/p>\n<h2>Azure function processing throttle requests<\/h2>\n<p>With the throttling requests now being put onto an event hub, we need to do something with those requests. In comes an <strong>Azure Function<\/strong>! 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:<\/p>\n<pre class=\"lang:default decode:true\">public static async Task DisableDevice(string input, TraceWriter log)\r\n{\r\n    log.Info(\"Received request to throttle device.\");\r\n\r\n    try {\r\n        dynamic eventData = ((JArray)JsonConvert.DeserializeObject(input))[0];\r\n        string deviceId = eventData.deviceid;\r\n\r\n        string iotHubConnectionString = System.Configuration.ConfigurationManager.AppSettings[\"iotHub.ConnectionString\"];\r\n        var registry = RegistryManager.CreateFromConnectionString(iotHubConnectionString);\r\n\r\n        log.Info($\"Disabling device {deviceId} in IoT hub.\");\r\n        var device = await registry.GetDeviceAsync(deviceId);\r\n        device.Status = DeviceStatus.Disabled;\r\n        await registry.UpdateDeviceAsync(device);\r\n\r\n        log.Info(\"Successfully disabled device.\");       \r\n    } \r\n    catch (Exception ex)\r\n    {\r\n        log.Error(\"Failure trying to disable a device: \" + ex.ToString());\r\n    }\r\n}<\/pre>\n<p>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 <a href=\"https:\/\/github.com\/jsiegmund\/submerged\/tree\/functions\/submerged-function-deviceInfo\" target=\"_blank\">here<\/a>. Also ensure that your function loads the <strong>Microsoft.Azure.Devices<\/strong> NuGet package.<\/p>\n<p>As soon as your device is disabled in the registry, send and receive commands will start producing errors. So you&#8217;ll need to handle those gracefully if you don&#8217;t want your app to crash.<\/p>\n<p>&nbsp;<\/p>\n<h2>Resetting the device status<\/h2>\n<p>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&#8217;s above:<\/p>\n<pre class=\"lang:default decode:true \">using System;\r\nusing Microsoft.Azure.Devices;\r\n\r\npublic static async Task Run(TimerInfo myTimer, TraceWriter log)\r\n{\r\n    try {\r\n        string iotHubConnectionString = System.Configuration.ConfigurationManager.AppSettings[\"iotHub.ConnectionString\"];\r\n        var registry = RegistryManager.CreateFromConnectionString(iotHubConnectionString);\r\n\r\n        log.Info($\"Getting the device registry list from IoT hub.\");\r\n        var devices = await registry.GetDevicesAsync(1000);\r\n\r\n        foreach (var device in devices)\r\n        {\r\n            if (device.Status == DeviceStatus.Disabled)\r\n            {\r\n                device.Status = DeviceStatus.Enabled;\r\n                await registry.UpdateDeviceAsync(device);\r\n                log.Info($\"Re-enabled device {device.Id}.\");\r\n            }\r\n        }\r\n\r\n        log.Info(\"Successfully re-enabled all devices.\");       \r\n    } \r\n    catch (Exception ex)\r\n    {\r\n        log.Error(\"Failure trying to disable a device: \" + ex.ToString());\r\n    }    \r\n}<\/pre>\n<p>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.<\/p>\n<p>&nbsp;<\/p>\n<h2>Conclusion<\/h2>\n<p>By using the right bits of Azure, it&#8217;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&#8217;re not surprised by an enormous bill at the end of the month \ud83d\ude42<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my aquarium monitor series I showed how to build an application to monitor a fish tank.\u00a0The use of the Azure IoT\u00a0components 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<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[34],"tags":[78,168,150],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3KFR1-wB","_links":{"self":[{"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/posts\/2021"}],"collection":[{"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/comments?post=2021"}],"version-history":[{"count":0,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/posts\/2021\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/media?parent=2021"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/categories?post=2021"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.repsaj.nl\/index.php\/wp-json\/wp\/v2\/tags?post=2021"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}