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:

    1. 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.

    2. On the left-side pane of your hub, select Shared access policies.

    3. From the top menu above the list of policies, select Add shared policy access policy.

    4. 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.

    5. Select your new policy from the list of policies.

    6. 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:

  1. Create a TwinCollection object for the reported property update
  2. Update one or more reported properties within the TwinCollection object
  3. 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:

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.

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:

  1. Use IotHubClientProtocol to choose a transport protocol. For example:

    IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
    
  2. 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);
    
  3. 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:

  1. Call getReportedProperties to fetch the twin reported properties into a TwinCollection object.

  2. Use put to update a reported property within the TwinCollection object. Call put for each reported property update.

  3. 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:

  1. Create a DeviceTwinClientOptions object. Set any options that are needed for your application. These options are passed to the DeviceTwin object.
  2. 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 the DeviceTwinClientOptions object.
  3. 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:

  1. 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);
    
  2. Use a HashSet object to add a group of twin tag pairs

  3. Use setTags to add a group of tag pairs from a tags object to a DeviceTwinDevice object

  4. Use 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:

  1. Use createSqlQuery to build the twins SQL query

  2. Use queryTwin to execute the query

  3. Use hasNextDeviceTwin to check if there's another device twin in the result set

  4. 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:

  1. Call create_from_connection_string to add the device connection string
  2. 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:

  1. Assign a reported property JSON patch to a variable.
  2. 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:

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.

  1. Call get_twin to get the current version of the device twin
  2. Use the Twin class to add tags and properties in JSON format.
  3. 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:

  1. Use a QuerySpecification object to define a SQL-like query request.

  2. 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 using Http, the Client 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:

  1. The minTemperature and maxTemperature properties are located under a property grouping named properties.desired.climate changes.

  2. A backend service application applies this patch to update minTemperature and maxTemperature desired properties:

    const twinPatch1 = {
    properties: {
       desired: {
        climate: { minTemperature: 68, maxTemperature: 76, },
        },
      },
     };
    
  3. 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.

  1. A backend application applies this desired property patch:

     const twinPatch2 = {
      properties: {
        desired: {
          climate: {
            hvac: {
              systemControl: { fanOn: true, },
            },
          },
        },
      },
    };
    
  2. 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:

  1. 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.
  1. 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.