Introduction
In IoT solutions, devices are often deployed in large numbers and operate remotely. Managing their configuration and tracking their state without direct access becomes a critical requirement. This is where device twins in Azure IoT Hub come into play. A device twin acts as a cloud-based representation of a physical device, allowing you to configure and monitor it in real time. In this article, we’ll explore how device twins work, understand desired and reported properties, and implement them using Azure CLI and .NET.
Prerequisites
Before getting started, ensure you have:
Device Twin
A device twin is a JSON document stored in the cloud that represents the state and configuration of a device.
It contains:
This allows you to interact with devices even when they are offline and synchronize state when they reconnect.
Understanding Desired and Reported Properties
Device twins are built around two important concepts:
Desired Properties
Desired properties are defined in the cloud and represent how the device is expected to behave.
They are used to:
Example
{
"telemetryInterval": 10
}
Reported Properties
Reported properties are sent by the device and reflect its current state.
They are used to:
Example
{
"status": "active",
"telemetryInterval": 10
}
Updating Desired Properties using Azure CLI
We can update device configuration directly from the cloud using Azure CLI:
az iot hub device-twin update \
--hub-name MyIoTHubDemo \
--device-id mydevice001 \
--set properties.desired.telemetryInterval=10
Output
{
"properties": {
"desired": {
"telemetryInterval": 10
}
}
}
This sets the expected behavior for the device.
Working with Device Twins in .NET
The following example demonstrates how a device interacts with its twin:
using System;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices.Shared;
class Program
{
private static string connectionString = "<DEVICE_CONNECTION_STRING>";
private static DeviceClient deviceClient;
static async Task Main(string[] args)
{
deviceClient = DeviceClient.CreateFromConnectionString(connectionString, TransportType.Mqtt);
await deviceClient.OpenAsync();
Console.WriteLine("Device connected.");
// Read desired properties
var twin = await deviceClient.GetTwinAsync();
int interval = twin.Properties.Desired.Contains("telemetryInterval")
? twin.Properties.Desired["telemetryInterval"]
: 5;
Console.WriteLine($"Initial telemetry interval: {interval}");
// Send reported properties
var reported = new TwinCollection();
reported["status"] = "active";
reported["telemetryInterval"] = interval;
await deviceClient.UpdateReportedPropertiesAsync(reported);
Console.WriteLine("Reported properties sent.");
// Listen for updates
await deviceClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredChanged, null);
Console.WriteLine("Waiting for updates...");
await Task.Delay(-1);
}
private static async Task OnDesiredChanged(TwinCollection desiredProperties, object userContext)
{
if (desiredProperties.Contains("telemetryInterval"))
{
int newInterval = desiredProperties["telemetryInterval"];
Console.WriteLine($"New interval received: {newInterval}");
var reported = new TwinCollection();
reported["telemetryInterval"] = newInterval;
reported["ack"] = "updated";
await deviceClient.UpdateReportedPropertiesAsync(reported);
Console.WriteLine("Reported properties updated.");
}
}
}
Output
Device connected.
Initial telemetry interval: 10
Reported properties sent.
Waiting for updates...
New interval received: 20
Reported properties updated.
Conclusion
Device twins provide a powerful way to manage IoT devices remotely and efficiently. Desired properties allow you to control device behavior from the cloud, while reported properties give you real-time visibility into device state. Using both effectively helps you build scalable and maintainable IoT solutions.