Get started with device twins (.NET)

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/free IoT Hub tiers, see Choose the right IoT Hub tier for your solution.

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. For more information about device twins, including when to use device twins, see Understand device twins.

IoT hubs store device twins, which 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 can't contain arrays, but can contain nested objects.

The following illustration shows device twin organization:

Screenshot of a device twin concept diagram.

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 article shows you how to:

  • Use a simulated device app to report 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.

In this article, you create two .NET console apps:

  • AddTagsAndQuery: a back-end app that adds tags and queries device twins.

  • ReportConnectivity: a simulated device app that connects to your IoT hub and reports its connectivity condition.

Note

See Azure IoT SDKs for more information about the SDK tools available to build both device and back-end apps.

Prerequisites

  • Visual Studio.

  • An IoT hub in your Azure subscription. If you don't have a hub yet, you can follow the steps in Create an IoT hub.

  • A device registered in your IoT hub. If you don't have a device in your IoT hub, follow the steps in Register a device.

  • Make sure that port 8883 is open in your firewall. The device sample in this article uses MQTT protocol, which 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).

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

    Screen capture that shows how to add a new shared access policy.

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

  6. Select the copy icon for the Primary connection string and save the value.

    Screen capture that shows how to retrieve the connection string.

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

Create a device app that updates reported properties

In this section, you create a .NET console app that connects to your hub as myDeviceId, and then updates its reported properties to confirm that it's connected using a cellular network.

  1. Open Visual Studio and select Create new project.

  2. Choose Console App (.NET Framework), then select Next.

  3. In Configure your new project, name the project ReportConnectivity, then select Next.

  4. In Solution Explorer, right-click the ReportConnectivity project, and then select Manage NuGet Packages.

  5. Keep the default .NET Framework, then select Create to create the project.

  6. Select Browse and search for and choose Microsoft.Azure.Devices.Client. Select Install.

    This step downloads, installs, and adds a reference to the Azure IoT device SDK NuGet package and its dependencies.

  7. Add the following using statements at the top of the Program.cs file:

    using Microsoft.Azure.Devices.Client;
    using Microsoft.Azure.Devices.Shared;
    using Newtonsoft.Json;
    
  8. Add the following fields to the Program class. Replace {device connection string} with the device connection string you saw when you registered a device in the IoT Hub:

    static string DeviceConnectionString = "HostName=<yourIotHubName>.azure-devices.net;DeviceId=<yourIotDeviceName>;SharedAccessKey=<yourIotDeviceAccessKey>";
    static DeviceClient Client = null;
    
  9. Add the following method to the Program class:

    public static async void InitClient()
    {
        try
        {
            Console.WriteLine("Connecting to hub");
            Client = DeviceClient.CreateFromConnectionString(DeviceConnectionString, 
              TransportType.Mqtt);
            Console.WriteLine("Retrieving twin");
            await Client.GetTwinAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine();
            Console.WriteLine("Error in sample: {0}", ex.Message);
        }
    }
    

    The Client object exposes all the methods you require to interact with device twins from the device. The code shown above initializes the Client object, and then retrieves the device twin for myDeviceId.

  10. Add the following method to the Program class:

    public static async void ReportConnectivity()
    {
        try
        {
            Console.WriteLine("Sending connectivity data as reported property");
    
            TwinCollection reportedProperties, connectivity;
            reportedProperties = new TwinCollection();
            connectivity = new TwinCollection();
            connectivity["type"] = "cellular";
            reportedProperties["connectivity"] = connectivity;
            await Client.UpdateReportedPropertiesAsync(reportedProperties);
        }
        catch (Exception ex)
        {
            Console.WriteLine();
            Console.WriteLine("Error in sample: {0}", ex.Message);
        }
    }
    

    The code above updates the reported property of myDeviceId with the connectivity information.

  11. Finally, add the following lines to the Main method:

    try
    {
        InitClient();
        ReportConnectivity();
    }
    catch (Exception ex)
    {
        Console.WriteLine();
        Console.WriteLine("Error in sample: {0}", ex.Message);
    }
    Console.WriteLine("Press Enter to exit.");
    Console.ReadLine();
    
  12. In Solution Explorer, right-click on your solution, and select Set StartUp Projects.

  13. In Common Properties > Startup Project, select Multiple startup projects. For ReportConnectivity, select Start as the Action. Select OK to save your changes.

  14. Run this app by right-clicking the ReportConnectivity project and selecting Debug, then Start new instance. You should see the app getting the twin information, and then sending connectivity as a reported property.

    Run device app to report connectivity

    After the device reported its connectivity information, it should appear in both queries.

  15. Right-click the AddTagsAndQuery project and select Debug > Start new instance to run the queries again. This time, myDeviceId should appear in both query results.

    Device connectivity reported successfully

Create a service app that updates desired properties and queries twins

In this section, you create a .NET console app, using C#, that adds location metadata to the device twin associated with myDeviceId. The app queries IoT hub for devices located in the US and then queries devices that report a cellular network connection.

  1. In Visual Studio, select File > New > Project. In Create a new project, select Console App (.NET Framework), and then select Next.

  2. In Configure your new project, name the project AddTagsAndQuery, the select Next.

    Screenshot of how to create a new Visual Studio project.

  3. Accept the default version of the .NET Framework, then select Create to create the project.

  4. In Solution Explorer, right-click the AddTagsAndQuery project, and then select Manage NuGet Packages.

  5. Select Browse and search for and select Microsoft.Azure.Devices. Select Install.

    NuGet Package Manager window

    This step downloads, installs, and adds a reference to the Azure IoT service SDK NuGet package and its dependencies.

  6. Add the following using statements at the top of the Program.cs file:

    using Microsoft.Azure.Devices;
    
  7. Add the following fields to the Program class. Replace {iot hub connection string} with the IoT Hub connection string that you copied in Get the IoT hub connection string.

    static RegistryManager registryManager;
    static string connectionString = "{iot hub connection string}";
    
  8. Add the following method to the Program class:

    public static async Task AddTagsAndQuery()
    {
        var twin = await registryManager.GetTwinAsync("myDeviceId");
        var patch =
            @"{
                tags: {
                    location: {
                        region: 'US',
                        plant: 'Redmond43'
                    }
                }
            }";
        await registryManager.UpdateTwinAsync(twin.DeviceId, patch, twin.ETag);
    
        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)));
    
        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)));
    }
    

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

    After updating, it 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.

    The previous code, when it creates the query object, specifies a maximum number of returned documents. The query object contains a HasMoreResults boolean property that you can use to invoke the GetNextAsTwinAsync methods multiple times to retrieve all results. A method called GetNextAsJson is available for results that are not device twins, for example, results of aggregation queries.

  9. Finally, add the following lines to the Main method:

    registryManager = RegistryManager.CreateFromConnectionString(connectionString);
    AddTagsAndQuery().Wait();
    Console.WriteLine("Press Enter to exit.");
    Console.ReadLine();
    
  10. Run this application by right-clicking on the AddTagsAndQuery project and selecting Debug, followed by Start new instance. 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.

    Query results in window

In this article, you:

  • Added device metadata as tags from a back-end app
  • Reported device connectivity information in the device twin
  • Queried the device twin information, using SQL-like IoT Hub query language

Next steps

To learn how to: