Get started with device twins
Use the Azure IoT Hub device SDK and service SDK to develop applications that handle common device twin tasks. Device twins are JSON documents that store device state information including metadata, configurations, and conditions. IoT Hub persists a device twin for each device that connects to it.
You can use device twins to:
- Store device metadata from your solution back end
- Report current state information such as available capabilities and conditions, for example, the connectivity method used, from your device app
- Synchronize the state of long-running workflows, such as firmware and configuration updates, between a device app and a back-end app
- Query your device metadata, configuration, or state
For more information about device twins, including when to use device twins, see Understand and use device twins in IoT Hub.
Note
The features described in this article are available only in the standard tier of IoT Hub. For more information about the basic and standard/free IoT Hub tiers, see Choose the right IoT Hub tier for your solution.
This article shows you how to develop two types of applications:
- Device apps can handle requests to update desired properties and respond with changes to reported properties.
- Service apps can update device twin tags, set new desired properties, and query devices based on device twin values.
Note
This article is meant to complement Azure IoT SDKs samples that are referenced from within this article. You can use SDK tools to build both device and back-end applications.
Prerequisites
An IoT hub. Some SDK calls require the IoT Hub primary connection string, so make a note of the connection string.
A registered device. Some SDK calls require the device primary connection string, so make a note of the connection string.
IoT Hub service connection string
In this article, you create a back-end service that adds desired properties to a device twin and then queries the identity registry to find all devices with reported properties that have been updated accordingly. Your service needs the service connect permission to modify desired properties of a device twin, and it needs the registry read permission to query the identity registry. There is no default shared access policy that contains only these two permissions, so you need to create one.
To create a shared access policy that grants service connect and registry read permissions and get a connection string for this policy, follow these steps:
In the Azure portal, select Resource groups. Select the resource group where your hub is located, and then select your hub from the list of resources.
On the left-side pane of your hub, select Shared access policies.
From the top menu above the list of policies, select Add shared policy access policy.
In the Add shared access policy pane on the right, enter a descriptive name for your policy, such as "serviceAndRegistryRead". Under Permissions, select Registry Read and Service Connect, and then select Add.
Select your new policy from the list of policies.
Select the copy icon for the Primary connection string and save the value.
For more information about IoT Hub shared access policies and permissions, see Control access to IoT Hub with shared access signatures.
If your application uses the MQTT protocol, make sure that port 8883 is open in your firewall. The MQTT protocol communicates over port 8883. This port may be blocked in some corporate and educational network environments. For more information and ways to work around this issue, see Connecting to IoT Hub (MQTT).
Language SDK requirements:
- .NET SDK - Requires Visual Studio.
- Python SDK - Python version 3.7 or later is recommended. Make sure to use the 32-bit or 64-bit installation as required by your setup. When prompted during the installation, make sure to add Python to your platform-specific environment variable.
- Java - Requires Java SE Development Kit 8. Make sure you select Java 8 under Long-term support to navigate to downloads for JDK 8.
- Node.js - Requires Node.js version 10.0.x or later.
Overview
This article describes how to use the Azure IoT SDK for .NET to create device and backend service application code for device twins.
Create a device application
Device applications can read and write twin reported properties, and be notified of desired twin property changes that are set by a backend application or IoT Hub.
This section describes how to use device application code to:
- Retrieve a device twin and examine reported properties
- Update reported device twin properties
- Create a desired property update callback handler
Add device NuGet Package
Device client applications written in C# require the Microsoft.Azure.Devices.Client NuGet package.
Connect to a device
The DeviceClient class exposes all the methods required to interact with device twins from the device.
Connect to the device using the CreateFromConnectionString method along with device connection string and the connection transport protocol.
The CreateFromConnectionString
TransportType transport protocol parameter supports the following transport protocols:
Mqtt
Mqtt_WebSocket_Only
Mqtt_Tcp_Only
Amqp
Amqp_WebSocket_Only
Amqp_Tcp_Only
The Http1
protocol is not supported for device twin updates.
This example connects to a device using the Mqtt
transport protocol.
using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices.Shared;
using Newtonsoft.Json;
static string DeviceConnectionString = "{IoT hub device connection string}";
static _deviceClient = null;
_deviceClient = DeviceClient.CreateFromConnectionString(DeviceConnectionString,
TransportType.Mqtt);
Retrieve a device twin and examine properties
Call GetTwinAsync to retrieve the current device twin properties. There are many Twin object properties that you can use to access specific areas of the Twin
JSON data including Properties
, Status
, Tags
, and Version
.
This example retrieves device twin properties and prints the twin values in JSON format.
Console.WriteLine("Retrieving twin...");
Twin twin = await _deviceClient.GetTwinAsync();
Console.WriteLine("\tInitial twin value received:");
Console.WriteLine($"\t{twin.ToJson()}");
Update reported device twin properties
To update a twin reported property:
- Create a TwinCollection object for the reported property update
- Update one or more reported properties within the
TwinCollection
object - Use UpdateReportedPropertiesAsync to push reported property changes to the IoT hub service
For example:
try
{
Console.WriteLine("Sending sample start time as reported property");
TwinCollection reportedProperties = new TwinCollection();
reportedProperties["DateTimeLastAppLaunch"] = DateTime.UtcNow;
await _deviceClient.UpdateReportedPropertiesAsync(reportedProperties);
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine("Error in sample: {0}", ex.Message);
}
Create a desired property update callback handler
Create a desired property update callback handler that executes when a desired property is changed in the device twin by passing the callback handler method name to SetDesiredPropertyUpdateCallbackAsync.
For example, this call sets up the system to notify a method namedOnDesiredPropertyChangedAsync
whenever a desired property is changed.
await _deviceClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertyChangedAsync, null);
The twin properties are passed to the callback method as a TwinCollection and can be examined as KeyValuePair
structures.
This example receives the desired property updates as a TwinCollection
, then loops through and prints the KeyValuePair
collection updates. After looping through the KeyValuePair
collection, the code calls UpdateReportedPropertiesAsync
to update the DateTimeLastDesiredPropertyChangeReceived
reported property to keep the last updated time up to date.
private async Task OnDesiredPropertyChangedAsync(TwinCollection desiredProperties, object userContext)
{
var reportedProperties = new TwinCollection();
Console.WriteLine("\tDesired properties requested:");
Console.WriteLine($"\t{desiredProperties.ToJson()}");
// For the purpose of this sample, we'll blindly accept all twin property write requests.
foreach (KeyValuePair<string, object> desiredProperty in desiredProperties)
{
Console.WriteLine($"Setting {desiredProperty.Key} to {desiredProperty.Value}.");
reportedProperties[desiredProperty.Key] = desiredProperty.Value;
}
Console.WriteLine("\tAlso setting current time as reported property");
reportedProperties["DateTimeLastDesiredPropertyChangeReceived"] = DateTime.UtcNow;
await _deviceClient.UpdateReportedPropertiesAsync(reportedProperties);
}
SDK device sample
The Azure IoT SDK for .NET provides a working sample of a device app that handles device twin tasks. For more information, see TwinSample.
Create a backend application
A backend application:
- Connects to a device through IoT Hub
- Can read device reported and desired properties, write device desired properties, and run device queries
The RegistryManager class exposes all methods required to create a backend application to interact with device twins from the service.
This section describes how to create backend application code to:
- Read and update device twin fields
- Create a device twin query
Add service NuGet Package
Backend service applications require the Microsoft.Azure.Devices NuGet package.
Connect to IoT hub
Connect a backend application to a device using CreateFromConnectionString. As a parameter, supply the IoT Hub service connection string that you created in the prerequisites section.
using Microsoft.Azure.Devices;
static RegistryManager registryManager;
static string connectionString = "{IoT hub service connection string}";
registryManager = RegistryManager.CreateFromConnectionString(connectionString);
Read and update device twin fields
You can retrieve current device twin fields into a Twin object by calling GetTwinAsync.
The Twin
class includes properties that correspond to each section of a device twin. Use the Twin
class properties to view and update device twin fields. You can use the Twin
object properties to update multiple twin fields before writing the updates to the device using UpdateTwinAsync
.
After making twin field updates, call UpdateTwinAsync to write Twin
object field updates back to a device. Use try
and catch
logic coupled with an error handler to catch incorrectly formatted patch errors from UpdateTwinAsync
.
Read and update device twin tags
Use the device twin Tags property to read and write device tag information.
Update tags using a twin object
This example creates a location
tag patch, assigns it to the Twin
object using the Tags
property, and then applies the patch using UpdateTwinAsync
.
// Retrieve the device twin
var twin = await registryManager.GetTwinAsync("myDeviceId");
// Create the tag patch
var tagspatch =
@"{
tags: {
location: {
region: 'US',
plant: 'Redmond43'
}
}
}";
// Assign the patch to the Twin object
twin.Tags["location"] = tagspatch;
// Apply the patch to update the device twin tags section
try
{
await registryManager.UpdateTwinAsync(twin.DeviceId, patch, twin.ETag);
}
catch (Exception e)
{
console.WriteLine("Twin update failed.", e.Message);
}
Update tags using a JSON string
You can create and apply a JSON-formatted device twin information update patch. IoT Hub parses and applies the patch if it is correctly formatted.
This example calls GetTwinAsync
to retrieve the current device twin fields into a Twin
object, creates a JSON-formatted tag
patch with region and plant location information, then calls UpdateTwinAsync
to apply the patch to update the device twin. An error message is displayed if UpdateTwinAsync
failed.
// Retrieve the device twin
var twin = await registryManager.GetTwinAsync("myDeviceId");
// Create the JSON tags patch
var patch =
@"{
tags: {
location: {
region: 'US',
plant: 'Redmond43'
}
}
}";
// Apply the patch to update the device twin tags
try
{
await registryManager.UpdateTwinAsync(twin.DeviceId, patch, twin.ETag);
}
catch (Exception e)
{
console.WriteLine("Twin update failed.", e.Message);
}
View and update twin desired properties
Use the device twin TwinProperties.Desired property to read and write device desired property information. Update twin Desired
properties using a JSON-formatted patch.
This example calls GetTwinAsync
to retrieve the current device twin fields into a Twin
object, updates the twin speed
desired property, and then calls UpdateTwinAsync
to apply the Twin
object to update the device twin.
// Retrieve the device twin
var twin = await registryManager.GetTwinAsync("myDeviceId");
twin.Properties.Desired["speed"] = "type: '5G'";
await registryManager.UpdateTwinAsync(twin.DeviceId, twin, twin.ETag);
Other twin update methods
You can also apply twin updates using these SDK methods:
- Call ReplaceTwinAsync to replace the entire device twin.
- Call UpdateTwins2Async to update a list of twins previously created within the system.
Create a device twin query
This section demonstrates two device twin queries. Device twin queries are SQL-like queries that return a result set of device twins.
To create a device twin query, call CreateQuery to submit a twins SQL query and obtain an IQuery Interface. You can optionally call CreateQuery
with a second parameter to specify a maximum number of items per page.
Next call GetNextAsTwinAsync
or GetNextAsJsonAsync
method as many times as needed to retrieve all twin results.
- GetNextAsTwinAsync to retrieve the next paged result as Twin objects.
- GetNextAsJsonAsync to retrieve the next paged result as JSON strings.
The IQuery
interface includes a HasMoreResults boolean property that you can use to check if there are more twin results to fetch.
This example query selects only the device twins of devices located in the Redmond43 plant.
var query = registryManager.CreateQuery(
"SELECT * FROM devices WHERE tags.location.plant = 'Redmond43'", 100);
var twinsInRedmond43 = await query.GetNextAsTwinAsync();
Console.WriteLine("Devices in Redmond43: {0}",
string.Join(", ", twinsInRedmond43.Select(t => t.DeviceId)));
This example query refines the first query to select only the devices that are also connected through a cellular network.
query = registryManager.CreateQuery("SELECT * FROM devices WHERE tags.location.plant = 'Redmond43' AND properties.reported.connectivity.type = 'cellular'", 100);
var twinsInRedmond43UsingCellular = await query.GetNextAsTwinAsync();
Console.WriteLine("Devices in Redmond43 using cellular network: {0}",
string.Join(", ", twinsInRedmond43UsingCellular.Select(t => t.DeviceId)));
SDK service sample
The Azure IoT SDK for .NET provides a working sample of a service app that handles device twin tasks. For more information, see Registry Manager Sample.
Overview
This article describes how to use the Azure IoT SDK for Java to create device and backend service application code for device twins.
Create a device application
Device applications can read and write twin reported properties, and be notified of desired twin property changes that are set by a backend application or IoT Hub.
This section describes how to create device application code to:
- Retrieve and view a device twin
- Update reported device twin properties
- Subscribe to desired property changes
The DeviceClient class exposes all the methods you require to interact with device twins from the device.
Device import statements
Use the following device import statements to access the Azure IoT SDK for Java.
import com.microsoft.azure.sdk.iot.device.*;
import com.microsoft.azure.sdk.iot.device.DeviceTwin.*;
Connect to the device
To connect to a device:
Use IotHubClientProtocol to choose a transport protocol. For example:
IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
Use the
DeviceClient
constructor to add the device primary connection string and protocol.String connString = "{IoT hub device connection string}"; DeviceClient client = new DeviceClient(connString, protocol);
Use open to connect the device to IoT hub. If the client is already open, the method does nothing.
client.open(true);
Retrieve and view a device twin
After opening the client connection, call getTwin to retrieve the current twin properties into a Twin
object.
For example:
private static Twin twin;
System.out.println("Getting current twin");
twin = client.getTwin();
System.out.println("Received current twin:");
System.out.println(twin);
Update device twin reported properties
After retrieving the current twin, you can begin making reported property updates. You can also make reported property updates without getting the current twin as long as you have the correct reported properties version. If you send reported properties and receive a "precondition failed" error, then your reported properties version is out of date. In that case, get the latest version by calling getTwin
again.
To update reported properties:
Call getReportedProperties to fetch the twin reported properties into a TwinCollection object.
Use put to update a reported property within the
TwinCollection
object. Callput
for each reported property update.Use updateReportedProperties to apply the group of reported properties that were updated using the
put
method.
For example:
TwinCollection reportedProperties = twin.getReportedProperties();
int newTemperature = new Random().nextInt(80);
reportedProperties.put("HomeTemp(F)", newTemperature);
System.out.println("Updating reported property \"HomeTemp(F)\" to value " + newTemperature);
ReportedPropertiesUpdateResponse response = client.updateReportedProperties(reportedProperties);
System.out.println("Successfully set property \"HomeTemp(F)\" to value " + newTemperature);
Subscribe to desired property changes
Call subscribeToDesiredProperties to subscribe to desired property changes. This client receives a callback with a Twin
object each time a desired property is updated. That callback either contains the full desired properties set, or only the updated desired property depending on how the desired property was changed.
This example subscribes to desired property changes. Any desired property changes are passed to a handler named DesiredPropertiesUpdatedHandler
.
client.subscribeToDesiredProperties(new DesiredPropertiesUpdatedHandler(), null);
In this example, the DesiredPropertiesUpdatedHandler
desired property change callback handler calls getDesiredProperties to retrieve the property changes, then prints the updated twin properties.
private static class DesiredPropertiesUpdatedHandler implements DesiredPropertiesCallback
{
@Override
public void onDesiredPropertiesUpdated(Twin desiredPropertyUpdateTwin, Object context)
{
if (twin == null)
{
// No need to care about this update because these properties will be present in the twin retrieved by getTwin.
System.out.println("Received desired properties update before getting current twin. Ignoring this update.");
return;
}
// desiredPropertyUpdateTwin.getDesiredProperties() contains all the newly updated desired properties as well as the new version of the desired properties
twin.getDesiredProperties().putAll(desiredPropertyUpdateTwin.getDesiredProperties());
twin.getDesiredProperties().setVersion(desiredPropertyUpdateTwin.getDesiredProperties().getVersion());
System.out.println("Received desired property update. Current twin:");
System.out.println(twin);
}
}
SDK device sample
The Azure IoT SDK for Java includes a working sample to test the device app concepts described in this article. For more information, see Device Twin Sample.
Create a backend application
This section describes how to create a backend application that:
- Updates device twin tags
- Queries devices using filters on the tags and properties
The ServiceClient
DeviceTwin class contains methods that services can use to access device twins.
Service import statements
Use the following service import statements to access the Azure IoT SDK for Java.
import com.microsoft.azure.sdk.iot.service.devicetwin.*;
import com.microsoft.azure.sdk.iot.service.exceptions.IotHubException;
Connect to the IoT hub service client
To connect to IoT Hub to view and update device twin information:
- Create a DeviceTwinClientOptions object. Set any options that are needed for your application. These options are passed to the
DeviceTwin
object. - Use a DeviceTwin constructor to create the connection to IoT hub. The
DeviceTwin
object handles the communication with your IoT hub. As parameters, supply the IoT Hub service connection string that you created in the Prerequisites section and theDeviceTwinClientOptions
object. - The DeviceTwinDevice object represents the device twin with its properties and tags.
For example:
public static final String iotHubConnectionString = "{IoT hub service connection string}";
public static final String deviceId = "myDeviceId";
public static final String region = "US";
public static final String plant = "Redmond43";
// Get the DeviceTwin and DeviceTwinDevice objects
DeviceTwinClientOptions twinOptions = new DeviceTwinClientOptions();
DeviceTwin twinClient = new DeviceTwin(iotHubConnectionString,twinOptions);
DeviceTwinDevice device = new DeviceTwinDevice(deviceId);
Update device twin fields
To update device twin fields:
Use getTwin to retrieve the current device twin fields
This example retrieves and prints the device twin fields:
// Get the device twin from IoT Hub System.out.println("Device twin before update:"); twinClient.getTwin(device); System.out.println(device);
Use a
HashSet
object toadd
a group of twin tag pairsUse setTags to add a group of tag pairs from a
tags
object to aDeviceTwinDevice
objectUse updateTwin to update the twin in the IoT hub
This example updates the region and plant device twin tags for a device twin:
// Update device twin tags if they are different // from the existing values String currentTags = device.tagsToString(); if ((!currentTags.contains("region=" + region) && !currentTags.contains("plant=" + plant))) { // Create the tags and attach them to the DeviceTwinDevice object Set<Pair> tags = new HashSet<Pair>(); tags.add(new Pair("region", region)); tags.add(new Pair("plant", plant)); device.setTags(tags); // Update the device twin in IoT Hub System.out.println("Updating device twin"); twinClient.updateTwin(device); } // Retrieve and display the device twin with the tag values from IoT Hub System.out.println("Device twin after update:"); twinClient.getTwin(device); System.out.println(device);
Create a device twin query
This section demonstrates two device twin queries. Device twin queries are SQL-like queries that return a result set of device twins.
The Query class contains methods that can be used to create SQL-style queries to IoT Hub for twins, jobs, device jobs, or raw data.
To create a device query:
Use createSqlQuery to build the twins SQL query
Use queryTwin to execute the query
Use hasNextDeviceTwin to check if there's another device twin in the result set
Use getNextDeviceTwin to retrieve the next device twin from the result set
The following example queries return a maximum of 100 devices.
This example query selects only the device twins of devices located in the Redmond43 plant.
// Query the device twins in IoT Hub
System.out.println("Devices in Redmond:");
// Construct the query
SqlQuery sqlQuery = SqlQuery.createSqlQuery("*", SqlQuery.FromType.DEVICES, "tags.plant='Redmond43'", null);
// Run the query, returning a maximum of 100 devices
Query twinQuery = twinClient.queryTwin(sqlQuery.getQuery(), 100);
while (twinClient.hasNextDeviceTwin(twinQuery)) {
DeviceTwinDevice d = twinClient.getNextDeviceTwin(twinQuery);
System.out.println(d.getDeviceId());
}
This example query refines the first query to select only the devices that are also connected through a cellular network.
System.out.println("Devices in Redmond using a cellular network:");
// Construct the query
sqlQuery = SqlQuery.createSqlQuery("*", SqlQuery.FromType.DEVICES, "tags.plant='Redmond43' AND properties.reported.connectivityType = 'cellular'", null);
// Run the query, returning a maximum of 100 devices
twinQuery = twinClient.queryTwin(sqlQuery.getQuery(), 3);
while (twinClient.hasNextDeviceTwin(twinQuery)) {
DeviceTwinDevice d = twinClient.getNextDeviceTwin(twinQuery);
System.out.println(d.getDeviceId());
}
SDK service sample
The Azure IoT SDK for Java provides a working sample of a service app that handles device twin tasks. For more information, see Device Twin Sample.
Overview
This article describes how to use the Azure IoT SDK for Python to create device and backend service application code for device twins.
Create a device application
Device applications can read and write twin reported properties, and be notified of desired twin property changes that are set by a backend application or IoT Hub.
The IoTHubDeviceClient class contains methods that can be used to work with device twins.
This section describes how to create device application code that:
- Retrieves a device twin and examine reported properties
- Patch reported device twin properties
Connect to a device
This section shows how to connect an application to a device using a device primary key that includes a shared access key.
To connect an application to a device:
- Call create_from_connection_string to add the device connection string
- Call connect to connect the device client to an Azure IoT hub
# import the device client library
import asyncio
from azure.iot.device.aio import IoTHubDeviceClient
# substitute the device connection string in conn_str
# and add it to the IoTHubDeviceClient object
conn_str = "{IOT hub device connection string}"
device_client = IoTHubDeviceClient.create_from_connection_string(conn_str)
# connect the application to the device
await device_client.connect()
Retrieve a device twin and examine reported properties
You can retrieve and examine device twin information including tags and properties. The device twin information retrieved matches device twin JSON-formatted data that you can view for a device in the Azure portal.
Call get_twin to get the device twin from the Azure IoT Hub service. The twin information is placed into a variable that can be printed or examined.
This example retrieves the device twin and uses the print
command to view the device twin in JSON format.
# get the twin
twin = await device_client.get_twin()
print("Twin document:")
print("{}".format(twin))
Patch reported device twin properties
You can apply a patch to update device reported properties in JSON format.
To apply a patch to update reported properties:
- Assign a reported property JSON patch to a variable.
- Call patch_twin_reported_properties to apply the JSON patch to reported properties. This is a synchronous call, meaning that this function does not return until the patch is sent to the service and acknowledged.
If patch_twin_reported_properties
returns an error, this function raises the corresponding error.
# create the reported properties patch
reported_properties = {"temperature": random.randint(320, 800) / 10}
print("Setting reported temperature to {}".format(reported_properties["temperature"]))
# update the reported properties and wait for the result
await device_client.patch_twin_reported_properties(reported_properties)
You can also call these methods to update device twins:
- Call replace_twin to replace device twin tags and desired properties.
- Call update_twin to update device twin tags and desired properties.
Incoming desired properties patch handler
Call on_twin_desired_properties_patch_received to create a handler function or coroutine that is called when a twin desired properties patch is received. The handler takes one argument, which is the twin patch in the form of a JSON dictionary object.
This example sets up a desired properties patch handler named twin_patch_handler
.
For example:
try:
# Set handlers on the client
device_client.on_twin_desired_properties_patch_received = twin_patch_handler
except:
# Clean up in the event of failure
client.shutdown()
The twin_patch_handler
receives and prints JSON desired property updates.
# Define behavior for receiving twin desired property patches
def twin_patch_handler(twin_patch):
print("Twin patch received:")
print(twin_patch)
SDK device samples
The Azure IoT SDK for Python includes the following samples:
- get_twin - Connect to a device and retrieve twin information.
- update_twin_reported_properties - Update twin reported properties.
- receive_twin_desired_properties - Receive and update desired properties.
Create a backend application
A backend application connects to a device through IoT Hub and can read device reported and desired properties, write device desired properties, and run device queries.
This section describes how to create a backend application to:
- Update twin tags and desired properties
- Queries devices using filters on the tags and properties
The IoTHubRegistryManager class exposes all methods required to create a backend application to interact with device twins from the service.
Connect to IoT hub
Connect to IoT hub using from_connection_string. As a parameter, supply the IoT Hub service connection string that you created in the prerequisites section.
For example:
import sys
from time import sleep
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.models import Twin, TwinProperties, QuerySpecification, QueryResult
# Connect to IoT hub
IOTHUB_CONNECTION_STRING = "{IoT hub service connection string}"
iothub_registry_manager = IoTHubRegistryManager.from_connection_string(IOTHUB_CONNECTION_STRING)
Update twin tags and desired properties
You can update both device twin tags and desired properties from a backend application at the same time using update_twin.
- Call get_twin to get the current version of the device twin
- Use the Twin class to add tags and properties in JSON format.
- Call
update_twin
to apply the patch to the device twin. You can also use replace_twin to replace desired properties and tags for a device twin.
This example updates region
and plant
tag information, and sets a power_level
desired property to 1
.
new_tags = {
'location' : {
'region' : 'US',
'plant' : 'Redmond43'
}
}
DEVICE_ID = "[Device Id]"
twin = iothub_registry_manager.get_twin(DEVICE_ID)
twin_patch = Twin(tags=new_tags, properties= TwinProperties(desired={'power_level' : 1}))
twin = iothub_registry_manager.update_twin(DEVICE_ID, twin_patch, twin.etag)
Create a device twin query
You can query device twin information using device twin queries. Device twin queries are SQL-like queries that return a result set of device twins.
To use a device twin query:
Use a QuerySpecification object to define a SQL-like query request.
Use query_iot_hub to query an IoTHub and retrieve device twin information using the SQL-like query specification.
This example runs two queries. The first selects only the device twins of devices located in the Redmond43
plant, and the second refines the query to select only the devices that are also connected through a cellular network. Results are printed after each query.
query_spec = QuerySpecification(query="SELECT * FROM devices WHERE tags.location.plant = 'Redmond43'")
query_result = iothub_registry_manager.query_iot_hub(query_spec, None, 100)
print("Devices in Redmond43 plant: {}".format(', '.join([twin.device_id for twin in query_result.items])))
print()
query_spec = QuerySpecification(query="SELECT * FROM devices WHERE tags.location.plant = 'Redmond43' AND properties.reported.connectivity = 'cellular'")
query_result = iothub_registry_manager.query_iot_hub(query_spec, None, 100)
print("Devices in Redmond43 plant using cellular network: {}".format(', '.join([twin.device_id for twin in query_result.items])))
print()
SDK service sample
The Azure IoT SDK for Python provides a working sample of a service app that handles device twin tasks. For more information, see Registry Manager Query Sample.
Overview
This article describes how to use the Azure IoT SDK for Node.js to create device and backend service application code for device twins.
Create a device application
Device applications can read and write twin reported properties, and be notified of desired twin property changes that are set by a backend application or IoT Hub.
This section describes how to use the azure-iot-device package in the Azure IoT SDK for Node.js to create a device application to:
- Retrieve a device twin and examine reported properties
- Update reported device twin properties
- Receive notice of desired property changes
Install SDK packages
Run this command to install the azure-iot-device device SDK on your development machine:
npm install azure-iot-device --save
The azure-iot-device package contains objects that interface with IoT devices. The Twin class includes twin-specific objects. This section describes Client
class code that is used to read and write device twin data.
Choose a transport protocol
The Client
object supports these protocols:
Amqp
Http
- When usingHttp
, theClient
instance checks for messages from IoT Hub infrequently (a minimum of every 25 minutes).Mqtt
MqttWs
AmqpWs
Install needed transport protocols on your development machine.
For example, this command installs the Mqtt
protocol:
npm install azure-iot-device-mqtt --save
For more information about the differences between MQTT, AMQP, and HTTPS support, see Cloud-to-device communications guidance and Choose a communication protocol.
Create a client module
Create a Client
module using the installed package.
For example:
const Client = require('azure-iot-device').Client;
Create a protocol module
Create a Protocol
module using an installed transport package.
This example assigns the MQTT protocol:
const Protocol = require('azure-iot-device-mqtt').Mqtt;
Add the device connection string and transport protocol
Call fromConnectionString to supply device connection parameters:
- connStr - A connection string that encapsulates "device connect" permissions for an IoT hub. The connection string contains hostname, device ID & shared access key in this format: "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>".
- transportCtor - The transport protocol.
This example uses the Mqtt
transport protocol:
const deviceConnectionString = "{IoT hub device connection string}"
const Protocol = require('azure-iot-device-mqtt').Mqtt;
let client = Client.fromConnectionString(deviceConnectionString, Protocol);
Open the connection to IoT Hub
Use the open method to open a connection between an IoT device and IoT Hub.
Use .catch(err)
to catch an error and execute handler code.
For example:
client.open() //open the connection
.catch((err) => {
console.error('Could not connect: ' + err.message);
});
Retrieve a device twin and examine reported properties
Call getTwin to retrieve current device twin information into a Twin object.
For example:
client.getTwin(function(err, twin))
if (err)
console.error('could not get twin');
Update reported device twin properties
Use update to update device reported properties. Include a JSON-formatted patch as the first parameter and function execution status callback method as the second parameter to the method.
In this example, a JSON-formatted device twin patch is stored in the patch
variable. The patch contains a device twin connectivity
update value of cellular
. The patch and error handler are passed to the update
method. If there's an error, a console error message is displayed.
var patch = {
connectivity: {
type: 'cellular'
}
}
twin.properties.reported.update(patch, function(err)
{
if (err)
{
console.error('could not update twin');
}
else
{
console.log('twin state reported');
process.exit();
}
});
Receive notice of desired property changes
Create a desired property update event listener that executes when a desired property is changed in the device by passing the callback handler method name to twin.on.
The desired property event listener can take one of the following forms:
- Receive all patches with a single event handler
- Receive an event if anything changes under a properties grouping
- Receive an event for a single property change
Receive all patches with a single event handler
You can create a listener to receive any desired property change.
This example code outputs any properties that are received from the service.
twin.on('properties.desired', function (delta) {
console.log('new desired properties received:');
console.log(JSON.stringify(delta));
});
Receive an event if anything changes under a properties grouping
You can create a listener to receive an event if anything under a property grouping changes.
For example:
The
minTemperature
andmaxTemperature
properties are located under a property grouping namedproperties.desired.climate changes
.A backend service application applies this patch to update
minTemperature
andmaxTemperature
desired properties:const twinPatch1 = { properties: { desired: { climate: { minTemperature: 68, maxTemperature: 76, }, }, }, };
This code sets up a desired properties change event listener that triggers for any changes within the
properties.desired.climate
property grouping. If there's a desired property change within this group, min and max temperature change messages that are displayed to the console:twin.on('properties.desired.climate', function (delta) { if (delta.minTemperature || delta.maxTemperature) { console.log('updating desired temp:'); console.log('min temp = ' + twin.properties.desired.climate.minTemperature); console.log('max temp = ' + twin.properties.desired.climate.maxTemperature); } });
Receive an event for a single property change
You can set up a listener for a single property change. In this example, the code for this event is executed only if the fanOn
boolean value is part of the patch. The code outputs the new desired fanOn
state whenever the service updates it.
A backend application applies this desired property patch:
const twinPatch2 = { properties: { desired: { climate: { hvac: { systemControl: { fanOn: true, }, }, }, }, }, };
The listener triggers only when the
fanOn
property changes:twin.on('properties.desired.climate.hvac.systemControl', function (fanOn) { console.log('setting fan state to ' + fanOn); });
Device SDK samples
The Azure IoT SDK for Node.js contains two device twin samples:
Create a backend application
A backend application connects to a device through IoT Hub and can read device reported and desired properties, write device desired properties, and run device queries.
This section describes how to create a backend application that:
- Retrieves and updates a device twin
- Creates a device twin query
Install service SDK packages
Run this command to install azure-iothub on your development machine:
npm install azure-iothub --save
The Registry class exposes all methods required to interact with device twins from a backend application.
Connect to IoT hub
Use fromConnectionString to connect to IoT hub. As a parameter, supply the IoT hub service connection string that you created in the prerequisites section.
'use strict';
var iothub = require('azure-iothub');
var connectionString = '{Iot Hub service connection string}';
var registry = iothub.Registry.fromConnectionString(connectionString);
Retrieve and update a device twin
You can create a patch that contains tag and desired property updates for a device twin.
To update a device twin:
- Call getTwin to retrieve the device twin object.
- Format a patch that contains the device twin update. The patch is formatted in JSON as described in Twin class. A backend service patch can contain tag and desired property updates. For more patch format information, see Tags and properties format.
- Call update to update the device twin with the patch.
In this example, the device twin is retrieved for myDeviceId
, then a patch is applied to the twins that contains location
tag update of region: 'US', plant: 'Redmond43'
.
registry.getTwin('myDeviceId', function(err, twin){
if (err) {
console.error(err.constructor.name + ': ' + err.message);
} else {
var patch = {
tags: {
location: {
region: 'US',
plant: 'Redmond43'
}
}
};
twin.update(patch, function(err) {
if (err) {
console.error('Could not update twin: ' + err.constructor.name + ': ' + err.message);
} else {
console.log(twin.deviceId + ' twin updated successfully');
queryTwins();
}
});
}
});
Create a device twin query
You can create SQL-like device queries to gather information from device twins.
Use createQuery to create a query that can be run on an IoT hub instance to find information about devices or jobs.
createQuery
includes two parameters:
- sqlQuery - The query written as an SQL string.
- pageSize - The desired number of results per page (optional. default: 1000, max: 10000).
If the pageSize parameter is specified, the query object contains a hasMoreResults
boolean property that you can check and use the nextAsTwin
method to get the next twin results page as many times as needed to retrieve all results. A method called next
is available for results that are not device twins, for example, the results of aggregation queries.
This example query selects only the device twins of devices located in the Redmond43
plant.
var queryTwins = function() {
var query = registry.createQuery("SELECT * FROM devices WHERE tags.location.plant = 'Redmond43'", 100);
query.nextAsTwin(function(err, results) {
if (err) {
console.error('Failed to fetch the results: ' + err.message);
} else {
console.log("Devices in Redmond43: " + results.map(function(twin) {return twin.deviceId}).join(','));
}
});
This example query refines the first query to select only the devices that are also connected through cellular network.
query = registry.createQuery("SELECT * FROM devices WHERE tags.location.plant = 'Redmond43' AND properties.reported.connectivity.type = 'cellular'", 100);
query.nextAsTwin(function(err, results) {
if (err) {
console.error('Failed to fetch the results: ' + err.message);
} else {
console.log("Devices in Redmond43 using cellular network: " + results.map(function(twin) {return twin.deviceId}).join(','));
}
});
};
Service SDK sample
The Azure IoT SDK for Node.js provides a working sample of a service app that handles device twin tasks. For more information, see Device Twin Backend Service - This project is used to send device twin patch updates for a specific device.