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.

  • 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

Important

This article includes steps to connect a device using a shared access signature, also called symmetric key authentication. This authentication method is convenient for testing and evaluation, but authenticating a device using X.509 certificates is a more secure approach. To learn more, see Security best practices > Connection security.

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 and can read device reported and desired properties, write device desired properties, and run device queries.

This section describes how to create backend application code to:

  • Read and update device twin fields
  • Create a device twin query

The RegistryManager class exposes all methods required to create a backend application to interact with device twins from the service.

Add service NuGet Package

Backend service applications require the Microsoft.Azure.Devices NuGet package.

Connect to IoT hub

You can connect a backend service to IoT Hub using the following methods:

  • Shared access policy
  • Microsoft Entra

Important

This article includes steps to connect to a service using a shared access signature. This authentication method is convenient for testing and evaluation, but authenticating to a service with Microsoft Entra ID or managed identities is a more secure approach. To learn more, see Security best practices > Cloud security.

Connect using a shared access policy

Connect a backend application to a device using CreateFromConnectionString. Your application needs the service connect permission to modify desired properties of a device twin, and it needs 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 if a one does not already exist. Supply this shared access policy connection string as a parameter to fromConnectionString. For more information about shared access policies, see Control access to IoT Hub with shared access signatures.

using Microsoft.Azure.Devices;
static RegistryManager registryManager;
static string connectionString = "{Shared access policy connection string}";
registryManager = RegistryManager.CreateFromConnectionString(connectionString);

Connect using Microsoft Entra

A backend app that uses Microsoft Entra must successfully authenticate and obtain a security token credential before connecting to IoT Hub. This token is passed to a IoT Hub connection method. For general information about setting up and using Microsoft Entra for IoT Hub, see Control access to IoT Hub by using Microsoft Entra ID.

Configure Microsoft Entra app

You must set up a Microsoft Entra app that is configured for your preferred authentication credential. The app contains parameters such as client secret that are used by the backend application to authenticate. The available app authentication configurations are:

  • Client secret
  • Certificate
  • Federated identity credential

Microsoft Entra apps may require specific role permissions depending on operations being performed. For example, IoT Hub Twin Contributor is required to enable read and write access to a IoT Hub device and module twins. For more information, see Manage access to IoT Hub by using Azure RBAC role assignment.

For more information about setting up a Microsoft Entra app, see Quickstart: Register an application with the Microsoft identity platform.

Authenticate using DefaultAzureCredential

The easiest way to use Microsoft Entra to authenticate a backend application is to use DefaultAzureCredential, but it's recommended to use a different method in a production environment including a specific TokenCredential or pared-down ChainedTokenCredential. For simplicity, this section describes authentication using DefaultAzureCredential and Client secret. For more information about the pros and cons of using DefaultAzureCredential, see Usage guidance for DefaultAzureCredential.

DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based on the environment it's executing in. It attempts to use multiple credential types in an order until it finds a working credential.

Microsoft Entra requires these NuGet packages and corresponding using statements:

  • Azure.Core
  • Azure.Identity
using Azure.Core;
using Azure.Identity;

In this example, Microsoft Entra app registration client secret, client ID, and tenant ID are added to environment variables. These environment variables are used by DefaultAzureCredential to authenticate the application. The result of a successful Microsoft Entra authentication is a security token credential that is passed to an IoT Hub connection method.

string clientSecretValue = "xxxxxxxxxxxxxxx";
string clientID = "xxxxxxxxxxxxxx";
string tenantID = "xxxxxxxxxxxxx";

Environment.SetEnvironmentVariable("AZURE_CLIENT_SECRET", clientSecretValue);
Environment.SetEnvironmentVariable("AZURE_CLIENT_ID", clientID);
Environment.SetEnvironmentVariable("AZURE_TENANT_ID", tenantID);

TokenCredential tokenCredential = new DefaultAzureCredential();

The resulting TokenCredential can then be passed to a connect to IoT Hub method for any SDK client that accepts Microsoft Entra credentials:

In this example, the TokenCredential is passed to ServiceClient.Create to create a ServiceClient connection object.

string hostname = "xxxxxxxxxx.azure-devices.net";
using var serviceClient = ServiceClient.Create(hostname, tokenCredential, TransportType.Amqp);

In this example, the TokenCredential is passed to RegistryManager.Create to create a RegistryManager object.

string hostname = "xxxxxxxxxx.azure-devices.net";
registryManager = RegistryManager.Create(hostname, tokenCredential);
Code sample

For a working sample of Microsoft Entra service authentication, see Role based authentication sample.

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.

Important

This article includes steps to connect a device using a shared access signature, also called symmetric key authentication. This authentication method is convenient for testing and evaluation, but authenticating a device using X.509 certificates is a more secure approach. To learn more, see Security best practices > Connection security.

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

You can connect a backend service to IoT Hub using the following methods:

  • Shared access policy
  • Microsoft Entra

Important

This article includes steps to connect to a service using a shared access signature. This authentication method is convenient for testing and evaluation, but authenticating to a service with Microsoft Entra ID or managed identities is a more secure approach. To learn more, see Security best practices > Cloud security.

Connect using a shared access policy

Use a DeviceTwin constructor to create the connection to IoT hub. The DeviceTwin object handles the communication with your IoT hub.

Your application needs the service connect permission to modify desired properties of a device twin, and it needs 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 if a one does not already exist. Supply this shared access policy connection string as a parameter to fromConnectionString. For more information about shared access policies, see Control access to IoT Hub with shared access signatures.

The DeviceTwinDevice object represents the device twin with its properties and tags.

For example:

public static final String iotHubConnectionString = "{Shared access policy 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
DeviceTwin twinClient = new DeviceTwin(iotHubConnectionString);
DeviceTwinDevice device = new DeviceTwinDevice(deviceId);

Connect using Microsoft Entra

A backend app that uses Microsoft Entra must successfully authenticate and obtain a security token credential before connecting to IoT Hub. This token is passed to a IoT Hub connection method. For general information about setting up and using Microsoft Entra for IoT Hub, see Control access to IoT Hub by using Microsoft Entra ID.

For an overview of Java SDK authentication, see Azure authentication with Java and Azure Identity.

For simplicity, this section focuses on describing authentication using client secret.

Configure Microsoft Entra app

You must set up a Microsoft Entra app that is configured for your preferred authentication credential. The app contains parameters such as client secret that are used by the backend application to authenticate. The available app authentication configurations are:

  • Client secret
  • Certificate
  • Federated identity credential

Microsoft Entra apps may require specific role permissions depending on operations being performed. For example, IoT Hub Twin Contributor is required to enable read and write access to a IoT Hub device and module twins. For more information, see Manage access to IoT Hub by using Azure RBAC role assignment.

For more information about setting up a Microsoft Entra app, see Quickstart: Register an application with the Microsoft identity platform.

Authenticate using DefaultAzureCredential

The easiest way to use Microsoft Entra to authenticate a backend application is to use DefaultAzureCredential, but it's recommended to use a different method in a production environment including a specific TokenCredential or pared-down ChainedTokenCredential. For more information about the pros and cons of using DefaultAzureCredential, see Credential chains in the Azure Identity client library for Java.

DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based on the environment it's executing in. It attempts to use multiple credential types in an order until it finds a working credential.

You can authenticate Microsoft Entra app credentials using DefaultAzureCredentialBuilder. Save connection parameters such as client secret tenantID, clientID, and client secret values as environmental variables. Once the TokenCredential is created, pass it to ServiceClient or other builder as the 'credential' parameter.

In this example, DefaultAzureCredentialBuilder attempts to authenticate a connection from the list described in DefaultAzureCredential. The result of a successful Microsoft Entra authentication is a security token credential that is passed to a constructor such as ServiceClient.

TokenCredential defaultAzureCredential = new DefaultAzureCredentialBuilder().build();
Authenticate using ClientSecretCredentialBuilder

You can use ClientSecretCredentialBuilder to create a credential using client secret information. If successful, this method returns a TokenCredential that can be passed to ServiceClient or other builder as the 'credential' parameter.

In this example, Microsoft Entra app registration client secret, client ID, and tenant ID values have been added to environment variables. These environment variables are used by ClientSecretCredentialBuilder to build the credential.

string clientSecretValue = System.getenv("AZURE_CLIENT_SECRET");
string clientID = System.getenv("AZURE_CLIENT_ID");
string tenantID = System.getenv("AZURE_TENANT_ID");

TokenCredential credential =
     new ClientSecretCredentialBuilder()
          .tenantId(tenantID)
          .clientId(clientID)
          .clientSecret(clientSecretValue)
          .build();
Other authentication classes

The Java SDK also includes these classes that authenticate a backend app with Microsoft Entra:

Code samples

For working samples of Microsoft Entra service authentication, see Role based authentication sample.

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

Important

This article includes steps to connect a device using a shared access signature, also called symmetric key authentication. This authentication method is convenient for testing and evaluation, but authenticating a device using X.509 certificates is a more secure approach. To learn more, see Security best practices > Connection security.

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

You can connect a backend service to IoT Hub using the following methods:

  • Shared access policy
  • Microsoft Entra

Important

This article includes steps to connect to a service using a shared access signature. This authentication method is convenient for testing and evaluation, but authenticating to a service with Microsoft Entra ID or managed identities is a more secure approach. To learn more, see Security best practices > Cloud security.

Connect using a shared access policy

Connect to IoT hub using from_connection_string. Your application needs the service connect permission to modify desired properties of a device twin, and it needs 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 if a one does not already exist. Supply this shared access policy connection string as a parameter to fromConnectionString. For more information about shared access policies, see Control access to IoT Hub with shared access signatures.

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)

Connect using Microsoft Entra

A backend app that uses Microsoft Entra must successfully authenticate and obtain a security token credential before connecting to IoT Hub. This token is passed to a IoT Hub connection method. For general information about setting up and using Microsoft Entra for IoT Hub, see Control access to IoT Hub by using Microsoft Entra ID.

For an overview of Python SDK authentication, see Authenticate Python apps to Azure services by using the Azure SDK for Python

Configure Microsoft Entra app

You must set up a Microsoft Entra app that is configured for your preferred authentication credential. The app contains parameters such as client secret that are used by the backend application to authenticate. The available app authentication configurations are:

  • Client secret
  • Certificate
  • Federated identity credential

Microsoft Entra apps may require specific role permissions depending on operations being performed. For example, IoT Hub Twin Contributor is required to enable read and write access to a IoT Hub device and module twins. For more information, see Manage access to IoT Hub by using Azure RBAC role assignment.

For more information about setting up a Microsoft Entra app, see Quickstart: Register an application with the Microsoft identity platform.

Authenticate using DefaultAzureCredential

The easiest way to use Microsoft Entra to authenticate a backend application is to use DefaultAzureCredential, but it's recommended to use a different method in a production environment including a specific TokenCredential or pared-down ChainedTokenCredential. For simplicity, this section describes authentication using DefaultAzureCredential and Client secret. For more information about the pros and cons of using DefaultAzureCredential, see Credential chains in the Azure Identity client library for Python.

DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based on the environment it's executing in. It attempts to use multiple credential types in an order until it finds a working credential.

Microsoft Entra requires this import package and corresponding import statement:

pip install azure-identity
from azure.identity import DefaultAzureCredential

In this example, Microsoft Entra app registration client secret, client ID, and tenant ID have been added to environment variables. These environment variables are used by DefaultAzureCredential to authenticate the application. The result of a successful Microsoft Entra authentication is a security token credential that is passed to an IoT Hub connection method.

from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()

The resulting AccessToken can then be passed to from_token_credential to connect to IoT Hub for any SDK client that accepts Microsoft Entra credentials:

from_token_credential requires two parameters:

  • The Azure service URL - The Azure service URL should be in the format {Your Entra domain URL}.azure-devices.net without a https:// prefix. For example, MyAzureDomain.azure-devices.net.
  • The Azure credential token

In this example, the Azure credential is obtained using DefaultAzureCredential. The Azure service URL and credential are then supplied to IoTHubRegistryManager.from_token_credential to create the connection to IoT Hub.

import sys
import os

from azure.identity import DefaultAzureCredential
from azure.iot.hub import IoTHubRegistryManager

# Define the client secret values
clientSecretValue = 'xxxxxxxxxxxxxxx'
clientID = 'xxxxxxxxxxxxxx'
tenantID = 'xxxxxxxxxxxxx'

# Set environment variables
os.environ['AZURE_CLIENT_SECRET'] = clientSecretValue
os.environ['AZURE_CLIENT_ID'] = clientID
os.environ['AZURE_TENANT_ID'] = tenantID

# Acquire a credential object
credential = DefaultAzureCredential()

# Use Entra to authorize IoT Hub service
print("Connecting to IoTHubRegistryManager...")
iothub_registry_manager = IoTHubRegistryManager.from_token_credential(
url="MyAzureDomain.azure-devices.net",
token_credential=credential)
Code samples

For working samples of Microsoft Entra service authentication, see Microsoft Authentication Library (MSAL) for Python.

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

Important

This article includes steps to connect a device using a shared access signature, also called symmetric key authentication. This authentication method is convenient for testing and evaluation, but authenticating a device using X.509 certificates is a more secure approach. To learn more, see Security best practices > Connection security.

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

You can connect a backend service to IoT Hub using the following methods:

  • Shared access policy
  • Microsoft Entra

Important

This article includes steps to connect to a service using a shared access signature. This authentication method is convenient for testing and evaluation, but authenticating to a service with Microsoft Entra ID or managed identities is a more secure approach. To learn more, see Security best practices > Cloud security.

Connect using a shared access policy

Use fromConnectionString to connect to IoT hub. Your application needs the service connect permission to modify desired properties of a device twin, and it needs 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 if a one does not already exist. Supply this shared access policy connection string as a parameter to fromConnectionString. For more information about shared access policies, see Control access to IoT Hub with shared access signatures.

'use strict';
var iothub = require('azure-iothub');
var connectionString = '{Shared access policy connection string}';
var registry = iothub.Registry.fromConnectionString(connectionString);

Connect using Microsoft Entra

A backend app that uses Microsoft Entra must successfully authenticate and obtain a security token credential before connecting to IoT Hub. This token is passed to a IoT Hub connection method. For general information about setting up and using Microsoft Entra for IoT Hub, see Control access to IoT Hub by using Microsoft Entra ID.

For an overview of Node.js SDK authentication, see:

Configure Microsoft Entra app

You must set up a Microsoft Entra app that is configured for your preferred authentication credential. The app contains parameters such as client secret that are used by the backend application to authenticate. The available app authentication configurations are:

  • Client secret
  • Certificate
  • Federated identity credential

Microsoft Entra apps may require specific role permissions depending on operations being performed. For example, IoT Hub Twin Contributor is required to enable read and write access to a IoT Hub device and module twins. For more information, see Manage access to IoT Hub by using Azure RBAC role assignment.

For more information about setting up a Microsoft Entra app, see Quickstart: Register an application with the Microsoft identity platform.

Authenticate using DefaultAzureCredential

The easiest way to use Microsoft Entra to authenticate a backend application is to use DefaultAzureCredential, but it's recommended to use a different method in a production environment including a specific TokenCredential or pared-down ChainedTokenCredential. For simplicity, this section describes authentication using DefaultAzureCredential and Client secret. For more information about the pros and cons of using DefaultAzureCredential, see Credential chains in the Azure Identity client library for JavaScript

DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based on the environment it's executing in. It attempts to use multiple credential types in an order until it finds a working credential.

Microsoft Entra requires this package:

npm install --save @azure/identity

In this example, Microsoft Entra app registration client secret, client ID, and tenant ID have been added to environment variables. These environment variables are used by DefaultAzureCredential to authenticate the application. The result of a successful Microsoft Entra authentication is a security token credential that is passed to an IoT Hub connection method.

import { DefaultAzureCredential } from "@azure/identity";

// Azure SDK clients accept the credential as a parameter
const credential = new DefaultAzureCredential();

The resulting credential token can then be passed to fromTokenCredential to connect to IoT Hub for any SDK client that accepts Microsoft Entra credentials:

fromTokenCredential requires two parameters:

  • The Azure service URL - The Azure service URL should be in the format {Your Entra domain URL}.azure-devices.net without a https:// prefix. For example, MyAzureDomain.azure-devices.net.
  • The Azure credential token

In this example, the Azure credential is obtained using DefaultAzureCredential. The Azure domain URL and credential are then supplied to Registry.fromTokenCredential to create the connection to IoT Hub.

const { DefaultAzureCredential } = require("@azure/identity");

let Registry = require('azure-iothub').Registry;

// Define the client secret values
clientSecretValue = 'xxxxxxxxxxxxxxx'
clientID = 'xxxxxxxxxxxxxx'
tenantID = 'xxxxxxxxxxxxx'

// Set environment variables
process.env['AZURE_CLIENT_SECRET'] = clientSecretValue;
process.env['AZURE_CLIENT_ID'] = clientID;
process.env['AZURE_TENANT_ID'] = tenantID;

// Acquire a credential object
const credential = new DefaultAzureCredential()

// Create an instance of the IoTHub registry
hostName = 'MyAzureDomain.azure-devices.net';
let registry = Registry.fromTokenCredential(hostName,credential);
Code samples

For working samples of Microsoft Entra service authentication, see Azure identity examples.

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.