Azure IoT Hub allows us to communicate with billions of devices in an easy and secure manner. Built on proven Azure technologies like Service Bus and Event Hubs, IoT Hub helps us to authenticate, administrate and communicate with our devices running on various platforms and using diverse protocols.
In a series of blog posts, we will see how we can leverage the power of Azure IoT Hub in this ever-growing world called the Internet of Things. It will become clear how we can send our data into Azure, process it and visualize our data, as well as how we can communicate back to our devices securely. And of course, we will learn all about how we can administer all these devices remotely, and monitor them proactively to ensure maximum continuity. In this first blog post in my IoT Hub series, we will see how we can do the administration of our devices.
Scenario
For this blog post series, we will be using a scenario where we manage engines on ships. Each ship can have multiple engines from various manufacturers, sending out readings like temperature, RPM, warnings, etc. We will want to capture all this data, to make sure our engines are running optimally, and we get an early warning in case of upcoming maintenance or repairs. As these ships will often be hard to reach, being able to administrate them remotely can save a lot of time and effort, allowing our engineers to plan their activities as efficient as possible.
Setting up IoT Hub
To start, open the Azure Portal, go to the IoT Hub blade, and add a new IoT Hub.
Set the options for your IoT Hub. You can have one free IoT Hub per subscription, which is ideal for testing and demo purposes, but do keep in mind you won’t be able to switch between the free and paid version.
Click Create to start deploying your IoT Hub to your subscription.
Administration Application
Now that we have created our IoT Hub, we will need to manage our devices. This can be done partly from the portal, but we will opt to create an application for this instead, which will be used by our backend team to manage our devices. We will create a simple Windows Forms application for this.
Register Device
Create a simple application as the following, which will allow us to register a new engine. Later on, we will expand on this application.
Now that we have our basic application layout setup, we will add the actual interaction with IoT Hub. For this we will need to add the Microsoft.Azure.Devices NuGet package to our solution. This package will allow us to communicate with IoT Hub and manage our devices.
To connect to our IoT Hub, we will need to get the connection string from the Azure portal.
private readonly RegistryManager registry = RegistryManager.CreateFromConnectionString("HostName=youriothubname.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=yoursharedaccesskey");
We will now use this connection string to create a RegistryManager with which we can manage our devices in IoT Hub.
And to actually register a new device, we will add the following EventHandler to our Register button.
private async void ButtonRegister_Click(object sender, System.EventArgs e) { await registry.AddDeviceAsync(new Device(comboBoxSerialNumber.Text)); }
Set Device Tags
This will create a device twin in our IoT Hub, a virtual representation of our device. Now the beauty of these device twins is that we can add custom tags to them, which we can then use to query on our devices. For example, on a single ship, you can have multiple engines of different manufacturers, e.g. the main engine of MAK, two generators of Caterpillar, and a pump engine of ABC. Using device twins, we could send a message to all engines made by Caterpillar, or to all generators. Let’s expand our application to set these tags as well. To do this, change the form of our application as follows.
Adjust the EventHandler for our Register button to include these tags on our device twin. This is done by applying a patch on the device twin with the properties we want to set.
private async void ButtonRegister_Click(object sender, System.EventArgs e) { var deviceTwin = await registry.GetTwinAsync(comboBoxSerialNumber.Text); if (deviceTwin == null) { await registry.AddDeviceAsync(new Device(comboBoxSerialNumber.Text)); deviceTwin = await registry.GetTwinAsync(comboBoxSerialNumber.Text); } var patch = new { tags = new { engineType = comboBoxEngineType.Text, manufacturer = textBoxManufacturer.Text } }; await registry.UpdateTwinAsync(comboBoxSerialNumber.Text, JsonConvert.SerializeObject(patch), deviceTwin.ETag); }
Set Desired Properties
Another great thing about IoT Hub’s device twins is that we can remotely configure devices by using Reported properties and Desired properties. Reported properties are properties which are set by the device and reported back to IoT Hub, where desired properties are properties set in IoT Hub (by our backend, in this case, the Engine Management application), and will be propagated to our devices. By using desired properties, we can update settings on our device, even when the device is not currently online. When the device comes online, it will retrieve the desired properties, and update its settings accordingly. We can then be notified on our device of these changes, and execute code accordingly. We will once again start by updating our application’s form, this time to allow us to set the temperature at which the device will create an alert.
We will expand the patch in our EventHandler for the Register button to include a maximum temperature in the desired property.
Get Registered Devices
Now that we can register our device, including setting the tags and properties, let’s see how we can retrieve registered devices from our IoT Hub. For each registered device, we will also want to know the key to be used when connecting our device to IoT Hub, and if the device is currently online, so firstly let’s adjust the application’s form to the following.
To easily work with the retrieved devices, we will create an object on which we can project them.
internal class Engine { internal string SerialNumber { get; set; } internal string Manufacturer { get; set; } internal string EngineType { get; set; } internal string MaximumTemperature { get; set; } internal string DeviceKey { get; set; } internal bool IsOnline { get; set; } public override string ToString() { return SerialNumber; } }
Add a method to query our IoT Hub for all devices. Make sure to call this method from the constructor, as well as after adding/updating a device using the Register button.
private async void GetRegisteredEngines() { comboBoxSerialNumber.Items.Clear(); var registeredEngines = await registry.GetDevicesAsync(500); foreach(var engine in registeredEngines) { var deviceTwin = await registry.GetTwinAsync(engine.Id); var tags = deviceTwin.Tags; va0072 desiredProperties = deviceTwin.Properties.Desired; comboBoxSerialNumber.Items.Add(new Engine { SerialNumber = engine.Id, Manufacturer = tags["manufacturer"], EngineType = tags["engineType"], MaximumTemperature = desiredProperties["temperatureConfig"]["maximumTemperature"], DeviceKey = engine.Authentication.SymmetricKey.PrimaryKey, IsOnline = engine.ConnectionState == DeviceConnectionState.Connected }); } }
Unregister Device
Now that we can create, update and retrieve our devices, we should also be able to delete them from our IoT Hub registry. This can be needed when a device is being decommissioned, or because the device is compromised. Let’s update the application form to make this possible.
Next, we will add the following EventHandler to the Unregister button.
private async void ButtonUnregister_Click(object sender, EventArgs e) { await registry.RemoveDeviceAsync(comboBoxSerialNumber.Text); GetRegisteredEngines(); }
Simulated Device
For this series of blog posts, we will use a simulated device. This will be a console app, which represents one of the engines on a ship. Start by creating a console application.
To communicate with IoT Hub, we will need to install the Microsoft.Azure.Devices.Client NuGet package.
In our console application, we will create a DeviceClient which will be used to communicate with IoT Hub. The DeviceID is the serial number of the engine, and the device key we can get in the administration application after registering the engine in IoT Hub.
private static DeviceClient client = DeviceClient.Create("youriothubname.azure-devices.net", new DeviceAuthenticationWithRegistrySymmetricKey("yourdeviceid", "yourdevicekey"), TransportType.Mqtt);
Get Desired Properties
On startup of the application, we will retrieve the maximum temperature for our device from the desired properties.
private static async void GetMaximumTemperature() { var deviceTwin = await client.GetTwinAsync(); MaximumTemperature = deviceTwin.Properties.Desired["temperatureConfig"]["maximumTemperature"]; }
Handle Updated Desired Properties
As the maximum temperature can be changed from the administration application while the device is running, we should also implement a listener for changes on the desired properties. To do this, add the following code to the Main method.
client.SetDesiredPropertyUpdateCallback(DesiredPropertyUpdated, null);
private static Task DesiredPropertyUpdated(TwinCollection desiredProperties, object userContext) { MaximumTemperature = desiredProperties["temperatureConfig"]["maximumTemperature"]; return null; }
Conclusion
In this post, we have created an application we can use to administer our devices in IoT Hub and update the settings of the device. Our simulated device uses the settings we have set, and updates it’s configuration when they get changed.