Get started with device twins (Node.js)

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.

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 IoT Hub tiers, see Choose the right IoT Hub tier.

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.

Device twins are designed for synchronization and for querying device configurations and conditions. More information on when to use device twins can be found in Understand device twins.

Device twins are stored in an IoT hub and contain the following elements:

  • Tags. Device metadata accessible only by the solution back end.

  • Desired properties. JSON objects modifiable by the solution back end and observable by the device app.

  • Reported properties. JSON objects modifiable by the device app and readable by the solution back end.

Tags and properties cannot contain arrays, but objects can be nested.

The following illustration shows device twin organization:

Device twin image showing functionality

Additionally, the solution back end can query device twins based on all the above data. For more information about device twins, see Understand device twins. For more information about querying, see IoT Hub query language.

This tutorial shows you how to:

  • Create a back-end app that adds tags to a device twin, and a simulated device app that reports its connectivity channel as a reported property on the device twin.

  • Query devices from your back-end app using filters on the tags and properties previously created.

At the end of this tutorial, you will have two Node.js console apps:

  • AddTagsAndQuery.js, a Node.js back-end app, which adds tags and queries device twins.

  • TwinSimulatedDevice.js, a Node.js app, which simulates a device that connects to your IoT hub with the device identity created earlier, and reports its connectivity condition.

Note

The article Azure IoT SDKs provides information about the Azure IoT SDKs that you can use to build both device and back-end apps.

Prerequisites

To complete this tutorial, you need:

  • Node.js version 10.0.x or later.

  • An active Azure account. (If you don't have an account, you can create a free account in just a couple of minutes.)

Create an IoT hub

This section describes how to create an IoT hub using the Azure portal.

  1. Sign in to the Azure portal.

  2. From the Azure homepage, select the + Create a resource button, and then enter IoT Hub in the Search the Marketplace field.

  3. Select IoT Hub from the search results, and then select Create.

  4. On the Basics tab, complete the fields as follows:

    • Subscription: Select the subscription to use for your hub.

    • Resource Group: Select a resource group or create a new one. To create a new one, select Create new and fill in the name you want to use. To use an existing resource group, select that resource group. For more information, see Manage Azure Resource Manager resource groups.

    • Region: Select the region in which you want your hub to be located. Select the location closest to you.

    • IoT Hub Name: Enter a name for your hub. This name must be globally unique. If the name you enter is available, a green check mark appears.

    Important

    Because the IoT hub will be publicly discoverable as a DNS endpoint, be sure to avoid entering any sensitive or personally identifiable information when you name it.

    Create a hub in the Azure portal

  5. Select Next: Size and scale to continue creating your hub.

    Set the size and scale for a new hub using the Azure portal

    This screen allows you to set the following values:

    • Pricing and scale tier: Your selected tier. You can choose from several tiers, depending on how many features you want and how many messages you send through your solution per day. The free tier is intended for testing and evaluation. It allows 500 devices to be connected to the hub and up to 8,000 messages per day. Each Azure subscription can create one IoT hub in the free tier.

    • IoT Hub units: The number of messages allowed per unit per day depends on your hub's pricing tier. For example, if you want the hub to support ingress of 700,000 messages, you choose two S1 tier units. For details about the other tier options, see Choosing the right IoT Hub tier.

    • Advanced Settings > Device-to-cloud partitions: This property relates the device-to-cloud messages to the number of simultaneous readers of the messages. Most hubs need only four partitions.

  6. For this article, accept the default choices, and then select Review + create to review your choices. You see something similar to this screen.

    Review information for creating the new hub

  7. Select Create to create your new hub. Creating the hub takes a few minutes.

Register a new device in the IoT hub

In this section, you use the Azure CLI to create a device identity for this article. Device IDs are case sensitive.

  1. Open Azure Cloud Shell.

  2. In Azure Cloud Shell, run the following command to install the Microsoft Azure IoT Extension for Azure CLI:

    az extension add --name azure-cli-iot-ext
    
  3. Create a new device identity called myDeviceId and retrieve the device connection string with these commands:

    az iot hub device-identity create --device-id myDeviceId --hub-name {Your IoT Hub name}
    az iot hub device-identity show-connection-string --device-id myDeviceId --hub-name {Your IoT Hub name} -o table
    

    Important

    The device ID may be visible in the logs collected for customer support and troubleshooting, so make sure to avoid any sensitive information while naming it.

Make a note of the device connection string from the result. This device connection string is used by the device app to connect to your IoT Hub as a device.

Get the IoT hub 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.

  4. Under Add a shared access policy, enter a descriptive name for your policy, such as serviceAndRegistryRead. Under Permissions, select Registry read and Service connect, and then select Create.

    Show how to add a new shared access policy

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

  6. Under Shared access keys, select the copy icon for the Connection string -- primary key and save the value.

    Show how to retrieve the connection string

For more information about IoT Hub shared access policies and permissions, see Access control and permissions.

Create the service app

In this section, you create a Node.js console app that adds location metadata to the device twin associated with myDeviceId. It then queries the device twins stored in the IoT hub selecting the devices located in the US, and then the ones that are reporting a cellular connection.

  1. Create a new empty folder called addtagsandqueryapp. In the addtagsandqueryapp folder, create a new package.json file using the following command at your command prompt. The --yes parameter accepts all the defaults.

    npm init --yes
    
  2. At your command prompt in the addtagsandqueryapp folder, run the following command to install the azure-iothub package:

    npm install azure-iothub --save
    
  3. Using a text editor, create a new AddTagsAndQuery.js file in the addtagsandqueryapp folder.

  4. Add the following code to the AddTagsAndQuery.js file. Replace {iot hub connection string} with the IoT Hub connection string you copied in Get the IoT hub connection string.

         'use strict';
         var iothub = require('azure-iothub');
         var connectionString = '{iot hub connection string}';
         var registry = iothub.Registry.fromConnectionString(connectionString);
    
         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();
                   }
                 });
             }
         });
    

    The Registry object exposes all the methods required to interact with device twins from the service. The previous code first initializes the Registry object, then retrieves the device twin for myDeviceId, and finally updates its tags with the desired location information.

    After updating the tags it calls the queryTwins function.

  5. Add the following code at the end of AddTagsAndQuery.js to implement the queryTwins function:

         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(','));
                 }
             });
    
             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(','));
                 }
             });
         };
    

    The previous code executes 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 cellular network.

    When the code creates the query object, it specifies the maximum number of returned documents in the second parameter. The query object contains a hasMoreResults boolean property that you can use to invoke the nextAsTwin methods multiple times to retrieve all results. A method called next is available for results that are not device twins, for example, the results of aggregation queries.

  6. Run the application with:

        node AddTagsAndQuery.js
    

    You should see one device in the results for the query asking for all devices located in Redmond43 and none for the query that restricts the results to devices that use a cellular network.

    See the one device in the query results

In the next section, you create a device app that reports the connectivity information and changes the result of the query in the previous section.

Create the device app

In this section, you create a Node.js console app that connects to your hub as myDeviceId, and then updates its device twin's reported properties to contain the information that it is connected using a cellular network.

  1. Create a new empty folder called reportconnectivity. In the reportconnectivity folder, create a new package.json file using the following command at your command prompt. The --yes parameter accepts all the defaults.

    npm init --yes
    
  2. At your command prompt in the reportconnectivity folder, run the following command to install the azure-iot-device, and azure-iot-device-mqtt packages:

    npm install azure-iot-device azure-iot-device-mqtt --save
    
  3. Using a text editor, create a new ReportConnectivity.js file in the reportconnectivity folder.

  4. Add the following code to the ReportConnectivity.js file. Replace {device connection string} with the device connection string you copied when you created the myDeviceId device identity in Register a new device in the IoT hub.

        'use strict';
        var Client = require('azure-iot-device').Client;
        var Protocol = require('azure-iot-device-mqtt').Mqtt;
    
        var connectionString = '{device connection string}';
        var client = Client.fromConnectionString(connectionString, Protocol);
    
        client.open(function(err) {
        if (err) {
            console.error('could not open IotHub client');
        }  else {
            console.log('client opened');
    
            client.getTwin(function(err, twin) {
            if (err) {
                console.error('could not get twin');
            } else {
                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();
                    }
                });
            }
            });
        }
        });
    

    The Client object exposes all the methods you require to interact with device twins from the device. The previous code, after it initializes the Client object, retrieves the device twin for myDeviceId and updates its reported property with the connectivity information.

  5. Run the device app

        node ReportConnectivity.js
    

    You should see the message twin state reported.

  6. Now that the device reported its connectivity information, it should appear in both queries. Go back in the addtagsandqueryapp folder and run the queries again:

        node AddTagsAndQuery.js
    

    This time myDeviceId should appear in both query results.

    Show myDeviceId in both query results

Next steps

In this tutorial, you configured a new IoT hub in the Azure portal, and then created a device identity in the IoT hub's identity registry. You added device metadata as tags from a back-end app, and wrote a simulated device app to report device connectivity information in the device twin. You also learned how to query this information using the SQL-like IoT Hub query language.

Use the following resources to learn how to: