Getting Started with Azure Device Provisioning Service

Azure and IoT Hub provide the ability to register and connect individual IoT devices so that their telemetry data can be sent and received in the cloud. This is great but what do you do if you have hundreds or even thousands of devices? Individually registering them is not feasible and would be a maintenance nightmare. We need a solution for these types of scenarios.

This article will describe what the Azure Device Provisioning Service is and how you can use it to maintain multiple IoT devices with Azure at scale.

What is Device Provisioning Service?

Azure Device Provisioning Service (DPS) is a cloud-based service that helps Azure IoT Hub provide automatic provisioning features with no human intervention. DPS provides the ability to provision up to millions of IoT devices in a secure and scalable effort. Support is also included for IoT devices with Trusted Platform Module (TPM), symmetric keys and X.509 certificate authentications.

A common scenario to use DPS would be when you need to provision multiple IoT devices without hardcoding the IoT Hub information (connection string, device ID). DPS provides zero-touch provisioning support so that you are freed from having to manually provision each device in your solution. Other scenarios where DPS is a good fit are when you need to load-balance devices across multiple IoT hubs, reprovisioning when a change is made on the device, and connecting devices to an IoT hub with the lowest latency.

Additional information and a listing of all the features of the Device Provisioning Service can be found here.

How to setup an instance of DPS

This section describes how to setup an initial instance of the Device Provisioning Service in Azure. It is assumed you have an active Azure subscription (free trial here). I will be showing you how to do this in the Azure Portal. Alternatively, you can follow these steps to do the setup with the Azure CLI or here with an ARM template.

Sign into your Azure portal. From the homepage, click on the +Create a Resource button to get started.

Figure 1: Creating an Azure Resource

Enter Device Provisioning Service in the search box and press Enter.

Figure 2: Searching for Device Provisioning Service

A list of matching resources will appear. Select IoT Hub Device Provisioning Service and click Create to begin the installation wizard.

Figure 3: Device Provisioning Service in Azure Marketplace

The displayed page allows you to enter the necessary information to create an instance of DPS. Please enter a globally-unique name for your DPS service, along with what Azure subscription you would like it created in. You can create a new resource group or select an existing one, and then finally choose the Location you want the service to be created in. Click Create to create the service.

Figure 4: Device Provisioning Service creation information

Once created, you can navigate to the resource and information about the service is displayed on the Overview page.

Figure 5: Device Provisioning Service Overview Page

Linking an IoT Hub to DPS

The next step is to connect an IoT Hub instance to the Device Provisioning Service, so that DPS can provision IoT devices to an associated hub. You will need to have a previously created IoT Hub available in your Azure subscriptions.

In order to link an IoT Hub to the Device Provisioning Service, navigate to the Linked IoT Hubs page from the Device Provisioning Service’s menu.

Figure 6: Linking an IoT Hub to Device Provisioning Service

From here, click the +Add button to link an IoT Hub instance to DPS. A blade will appear asking you to enter information about the IoT Hub you want to link.

Figure 7: Linking IoT Hub Details

Selecting an entry in the IoT Hub dropdown will then display an Access Policy dropdown, to which you are required to make a selection here before you can click the Save button to add the IoT Hub as linked to DPS. Once complete, you will see an entry in the Linked IoT Hubs section.

Enrolling devices to DPS

Once you have one or more IoT Hubs linked to the Device Provisioning Service, you are now ready to begin enrolling devices to your service. There are two ways to enroll devices:

  • Individual Enrollments
  • Enrollment Groups

Individual enrollments represent an entry for a single device and are a good choice if your device has a unique initial configuration or can only use Shared Access Signature (SAS) tokens via TPM as the attestation mechanism. X.509 certificates are also supported with individual enrollments.

Enrollment Groups represent a group of devices that share an attestation mechanism. Groups are a good choice for a large number of devices that share an initial configuration or devices in the same tenant. Enrollment groups use either Symmetric Keys or X.509 certificates. Specifying X.509 certificates indicate that all devices share a signing certificate in the X.509 certificate chain.

Individual Enrollments

The process of enrolling a single IoT device with the Device Provisioning Service is pretty straightforward and you will only need a few pieces of information to complete the process. You can start the process by navigating to the Manage Enrollments section in your DPS instance and then clicking on +Add individual enrollment:

Figure 8: Individual Enrollment

A page will be displayed that asks that you enter some information about the enrollment.

Figure 9: Individual Enrollment Information

Select the Attestation Mechanism such as X.509, Symmetric Key or TPM. Your selection here will display different controls to enter information. For example, selecting Symmetric Key will display Primary/Secondary Key information, along with Registration ID for the device.

Figure 10: Symmetric Key Attestation Mechanism

Selecting TPM will then ask for an Endorsement Key, while X.509 will ask for a primary and secondary certificate file.

Figure 11: X.509 Attestation Mechanism

The IoT Hub Device ID can be specified as the name of your device (as seen in IoT Hub). If you leave this blank the system uses the Registration ID value. You are also able to specify whether the device is an IoT Edge device.

There are a few other fields to look at here:

  • Allocation Policy – Allows you to specify how the system assigns the device to a linked IoT Hub (lowest latency, evenly weighted, static or custom)
  • IoT Hub(s) device is assigned to – allows selection of one or more linked IoT Hubs
  • Re-provisioning Policy – allows either resetting to initial configuration or maintaining device configuration and migrating the data
  • Enable Entry – Specifies whether the device is enabled or disabled when the enrollment is created

Finally, there is the definition of the Initial Device Twin for the device. You can add any Desired Properties or Tags that you need for your scenario.

Figure 12: Initial Device Twin

Once the enrollment is successful the next step would be to update the code on the IoT device and execute the device code.

Group Enrollments

The process for enrolling a group of devices is similar to individual enrollments but with some significant differences. You can start the process by navigating to the Manage Enrollments section in your DPS instance and then clicking on +Add enrollment group:

Figure 13: Enrollment Groups

A page will be displayed that asks that you enter some information about the enrollment.

Figure 14: Enrollment Groups Information

The Allocation Policy, IoT Hub(s) device assigned to, Re-provisioning Policy, Enable Entry and Initial Device Twin State fields are identical in functionality to individual enrollments. Please note that there are only two (2) attestation types for group enrollments: Certificate and Symmetric Key.

Figure 15: Enrollment Groups Attestation Types

Selecting Symmetric Key will display the Primary/Secondary key entries, just like with Individual Enrollments. However, selecting Certificate will require that you select a Primary Certificate and optional Secondary Certificate from a CA (certificate authority). You will also notice that you can specify the Certificate Type as CA Certificate or Intermediate Certificate. This specifies whether the primary/secondary certificate you specify is either a root or intermediate certificate. Please see the Using Certificates section below for further details.

Using Certificates

Using X.509 certificates for either individual or group enrollments in DPS requires that you follow a specific process to properly sign your devices with these certificates.

For individual enrollments, specifying a X.509 certificate requires that your device has a specific certificate that is unique to that device only. That means when you create the certificate for a specific device it is validated against the code on the device. This is necessary to prevent any tampering of the code on the device (meaning it will fail device attestation). The Azure MXChip IoT DevKit example for DPS shows how to use individual enrollment with an MXChip device (https://docs.microsoft.com/en-us/samples/azure-samples/mxchip-iot-devkit-dps/sample/).

Group enrollments require that you verify your root CA certificate with a verification certificate that you can create device certificates with (when deploying device code securely). This allows the device certificate to be validated up through the chain (to the root CA) when attestation occurs for a device.

The first step in this process is to create a root CA certificate that you will use in your group enrollment. You can use tools like OpenSSL to help you generate a root CA certificate.

Once you have your root certificate, return to the Azure Portal and navigate to the Certificates section under Settings in your DPS instance.

Figure 16: Certificates in Device Provisioning Service

Click on +Add to create a new certificate associated with the Device Provisioning Service. Provide a descriptive name for your cert and add the certificate file (.pem or .cer) and click Save.

Figure 17: Adding a Certificate to Device Provisioning Service

Once added, you will be returned to the Certificates page in DPS, which will now show you the certificate you just added. Note the Status will say Unverified.

Figure 18: Unverified Certificate in Device Provisioning Service

You now need to verify the root certificate before you can use it in a group enrollment. This is done by creating a verification certificate using a verification code generated by DPS. Click on the certificate record you just created. A blade will open on the right side of the page with information about your certificate. Click the Generate Verification Code button towards the bottom and the system will generate a code for you. You will use this code to generate a verification certificate file. The Azure IoT SDK source files on GitHub has a certGen.sh tool that will allow you to create this verification certificate with the verification code that was generated.

Figure 19: Generate Verification Code

Once generated, return to the Certificate Details page in Azure Device Provisioning Service and add your verification certificate by clicking on Verification Certificate. Once uploaded, the Verify button should light up and you can click on that to have DPS verify the certificate. If successful, you will see that the certificate status will now show as Verified.

Figure 20: Verified Certificate in Device Provisioning Service

The next step is to create the group enrollment in DPS and select the Primary Certificate with the root CA certificate you just uploaded and verified in DPS. Navigate to the Manage Enrollments page in DPS and click on +Add enrollment group to create a group enrollment record. Give the group a name and make sure the Attestation Type is set to Certificate. When you open the dropdown for Primary Certificate you should see the certificate name you created earlier. Select this as your primary certificate and fill out the remaining information and then click Save.

Figure 21: Selecting Verified Certificate in Group Enrollment

The final step in this process is to create a device certificate for each device in your scenario, using the verified root CA certificate you created earlier. You can then use that device certificate in your device code to authenticate to IoT Hub.

Demos

Please see my video here for demos using Device Provisioning Service.

Individual Enrollments

Enrollment Groups

Conclusion

I hope this article was helpful in explaining what Azure Device Provisioning Service is and how you can use it to deploy your devices securely and at scale. For more information on Device Provisioning Service please visit https://docs.microsoft.com/en-us/azure/iot-dps/.

Starting Out with Azure IoT Edge

In today’s article I’d like to discuss Azure IoT Edge and how you can get started with it. I will be explaining the benefits of Azure IoT Edge and providing a couple of demos to demonstrate how you can create a very simple IoT solution using an IoT Edge device.

Benefits of Azure IoT Edge

Azure IoT Edge is Microsoft’s fully managed service built on IoT Hub, which enables users to perform edge computing on one or more IoT Edge devices. Edge computing is the idea that the IoT devices (at the “edge” of the network) are the ones performing the heavy computing instead of server processes in the cloud.

Figure 1: Azure IoT Edge Diagram

This is beneficial as the individual devices can perform the calculation/processing/analysis and send the resulting insights to the cloud, instead of the devices sending all the raw data to the cloud for processing. Using edge computing results in reduced bandwidth costs, faster response times and reduced traffic.

Azure IoT Edge Components

There are three components that make up Azure IoT Edge:

Figure 2: Azure IoT Edge Components
  • IoT Edge Modules
  • IoT Edge Runtime
  • Cloud Interface

IoT Edge Modules are the Azure or third-party services that run in containers. You can also provide your own code. These modules are deployed to the IoT Edge devices and run locally on those devices. They provide the Edge “magic” as they can perform calculation/processing/analysis of your device data.

The IoT Edge Runtime is the code that runs on each IoT Edge device and manages the modules running on the device. The runtime also performs tasks such as maintaining security on the device, reporting module health to the cloud and managing communications between any downstream leaf devices and the IoT Edge device, between modules on the IoT Edge device and between the cloud and the IoT Edge device.

The cloud interface provides the ability to centrally manage the lifecycle for your IoT Edge devices. You can create and configure one or more workloads for your devices, as well as deploy them to all of your devices. You can also monitor your devices for any errors or devices that are not behaving properly.

Figure 3: IoT Edge Cloud Interface

Deploying an IoT Edge Module

The first demo I’d like to show you involves setting up a virtual IoT Edge device and deploying some sample code. We will also create an IoT Hub so the device can send its data to it.

Prerequisites

For both of these demos there are a couple of prerequisites that you will need. The first is an Azure subscription as we will be creating some cloud resources in these demos. You can sign up for a free account here.

The other prerequisite is installation of the Azure IoT Extension for Azure Cloud Shell. You can add this extension by launching a Cloud Shell session after logging into your Azure Portal. Once the shell window displays enter the following command to install the extension:

az extension add --name azure-iot

You only need to run this once.

Setup of IoT Edge Device

We will be using a virtual machine (VM) hosted in Azure as our IoT Edge device. I will run through the setup and configuration of this VM using Linux (there are similar steps if you wish to use a Windows VM).

There are two ways you can create a VM in Azure. The first way is to manually go through the steps in the Azure Portal to provision a VM. You should select the latest Ubuntu Server build for your image if you’re provisioning a Linux VM. This will give you a standard VM with no additional components installed. You would then be required to manually install the Azure IoT Edge components afterwards.

The second way to create this VM is to use the Azure Cloud Shell. I prefer this way as you can select a custom IoT Edge image that also automatically installs all the components needed to run IoT Edge on the VM (acting as a device). Accept the terms of use and create a VM by executing these commands:

az vm image terms accept --urn microsoft_iot_edge:iot_edge_vm_ubuntu:ubuntu_1604_edgeruntimeonly:latest
az vm create --resource-group IoTEdgeResources --name EdgeVM --image microsoft_iot_edge:iot_edge_vm_ubuntu:ubuntu_1604_edgeruntimeonly:latest --admin-username azureuser --generate-ssh-keys

Note that the commands expect you have a resource group created called IoTEdgeResources. The VM will be provisioned with a name of EdgeVM, and with an administrator username of azureuser and SSH public key authentication. You can see the command-line switch of –generate-ssh-keys which will generate the public and private keys and store them in the ~/.ssh folder in your Azure Cloud Shell instance.

Creating Azure IoT Hub and Device Registration

The next step is to provision an instance of Azure IoT Hub and register an IoT Edge device. Again, you can do this in two ways. The first is to manually run through the steps in the Azure Portal to provision IoT Hub and register your IoT Edge device.

The other way is to use the Azure Cloud Shell. Here are the commands to instantiate IoT Hub and register an IoT Edge device. Please note the resource group of IoTEdgeResources and make sure you enter your own name for the IoT Hub and Edge device. Take note of the –edge-enabled command-line switch, as this is what tells Azure to register a device as an IoT Edge device.

az iot hub create --resource-group IoTEdgeResources --name {hub_name} --sku F1 --partition-count 2
az iot hub device-identity create --hub-name {hub_name} --device-id {device_name} --edge-enabled

Once these commands finish, run the following command to display the device connection string and save it for a later step.

az iot hub device-identity show-connection-string --device-id {device_name} --hub-name {hub_name}
Figure 5: IoT Edge Device in Azure IoT Hub

Configure IoT Edge Device

Now that we have Azure IoT Hub and a registered IoT Edge device, we need to set the connection string with the value you saved previously from your registered IoT Edge device in IoT Hub. This will configure the VM to send its data to that registered device in Azure.

In your Azure Cloud Shell instance enter the following command, replacing for the IoT Edge device connection string:

az vm run-command invoke -g IoTEdgeResources -n EdgeVM --command-id RunShellScript --script "/etc/iotedge/configedge.sh '{device_connection_string}'"

Please note that running this command expects that the IoT Edge runtime is already installed on the VM. Since we used the Azure IoT Edge on Ubuntu image when provisioning the VM, this has already been installed. When complete, the output should look similar to this:

Figure 6: Set Connection String for IoT Edge Device

Once this command is complete you will need to connect to the VM using the public IP address that was given when the VM was created. This can be done right in the Azure Cloud Shell with this command:

ssh azureuser@{publicIpAddress}

The first time you do this you will be prompted to establish the authenticity of the host. Enter yes to continue connecting. This will also add an entry into a known_hosts file (so you are not prompted in the future).

Figure 7: SSH Host Authentication

Alternatively, you can use an SSH client (like PuTTY) to SSH into your VM. However, be aware that you need to copy the public and private SSH keys from your Azure Cloud Shell locally and create a .ppk file that PuTTY can use for authentication. Instructions on how to do this are located here.

Verify that the IoT Edge security daemon is running properly as a system service by executing the following command:

sudo systemctl status iotedge
Figure 8: IoT Edge Security Daemon

You can also view the running modules on the device. At this point you should only see the edgeAgent running.

sudo iotedge list
Figure 9: Running Modules on IoT Edge Device

Deploy IoT Edge Module

We can now deploy our module to the IoT Edge device. We are going to use a pre-built module from the IoT Edge section of the Azure Marketplace, which sends simulated temperature and pressure data to the cloud. You can also use your own custom code.

Note that we don’t have to access the device to deploy this module – we can perform the deployment right from the cloud. IoT Edge modules are executable packages implemented as containers. In order to deploy our module, navigate to your IoT Hub in the Azure Portal. Click on IoT Edge under Automatic Device Management from the left-hand pane.

Figure 10: Automatic Device Management

Click on your device in the list and select Set Modules from the upper bar. Click on the Add button to dropdown a menu selection. Click on +Marketplace Module to add a module from the marketplace.

Figure 11: Selecting a Marketplace Module

Enter simulated temperature sensor in the search box and select the results displayed. Click Routes to continue.

Figure 12: Simulated Temperature Sensor Module

You also need to configure the routes, which define how messages are passed between the module and IoT Hub. For our example, we want all the messages from the module to be sent to IoT Hub ($upstream), so add the following code for the Value for $upstream (if not auto-populated):

FROM /messages/* INTO $upstream

Click Review + Create and then Create to deploy the module.

After a few minutes if you refresh the page in the Azure Portal that lists the modules running on your device, you will see the SimulatedTemperatureSensor appear and show that its runtime status as running. Azure doesn’t push anything to your device when you add a module – the device checks Azure periodically for updates and when it sees that a module needs to be deployed it then pulls that module image from the cloud to start running it locally.

Figure 13: Simulated Temperature Sensor

Viewing the Data

You can view the simulated data from your IoT Edge device in two places. If you SSH into the VM and run the following command you can see the Simulated Temperature Sensor module executing and displaying the data it is sending to the cloud.

sudo iotedge logs SimulatedTemperatureSensor -f

You can also see the messages being received in your IoT Hub in the Azure Portal on the Overview page:

Figure 14: Azure IoT Hub Overview

Deploying to a Physical Device

The second demo I’d like to show you is how to deploy IoT Edge to a physical device. Using simulated devices is great for initial learning but I always like to actually deploy to a physical device since you will need to do this on an actual project! You will need a device that supports IoT Edge – I am using a Raspberry Pi 4 for this demo. You can use whatever device as long as the operating system can run containers. Please see this link for more details.

Most of the steps for the first demo still apply – the only difference is that instead of creating a virtual machine to simulate the IoT Edge device we will be using a real device (Raspberry Pi in our case). With that in mind, the first thing you should do is install the latest version of Raspian OS on your Pi.

Once you have the OS installed and you can SSH into the device, you will need to install the container runtime and the Azure IoT Edge components. The recommended container runtime is Moby. Run the following Bash commands on your device to update the package lists and install the Moby engine.

sudo apt-get update
sudo apt-get install moby-engine

You can optionally install the Moby command-line interface, which is helpful for development environments. When I ran this command the system indicated it was already installed when I installed the Moby engine.

sudo apt-get install moby-cli

After the container runtime is installed the next step is to install the Azure IoT Edge security daemon. This provides and maintains security standards on the device and bootstraps the device by starting the IoT Edge runtime when you boot up the device. Run the following Bash command to install the security daemon.

sudo apt-get update
sudo apt-get install iotedge

Once the security daemon is installed you then need to configure the IoT Edge device with the device connection string from your IoT Edge device in IoT Hub. This links your physical device to the device identity in the cloud. Open the configuration file at /etc/iotedge/config.yaml with this command:

sudo nano /etc/iotedge/config.yaml

Scroll down to the Manual Provisioning section and update the value of device_connection_string with your device connection string. Save the file when you are finished.

Figure 15: Configure Connection String for IoT Edge Device

You need to restart the security daemon to have the changes you made take effect, so run this command to restart IoT Edge on the device:

sudo systemctl restart iotedge

You can list the running modules on your device with this command. Please note that this point you should only see the edgeAgent module (since we haven’t deployed a module to the device yet).

sudo iotedge list

From this point you can follow the remaining steps from the first demo as they are identical. You would deploy your module from Azure IoT Hub in the portal, and once you do that you should be able to check the running modules on your physical device and see telemetry data (from the Simulated Temperature Sensor module) being sent to Azure IoT Hub.

Figure 16: IoT Edge Modules running on Physical Device

Congratulations! You have deployed an IoT Edge module to an actual physical device! You can now experiment further on creating other modules that can be deployed to your device.

I hope this article was helpful in explaining what Azure IoT Edge was and how you can deploy it to a simulated and real IoT Edge device. For more information on IoT Edge please visit https://docs.microsoft.com/en-us/azure/iot-edge/.

Thanks for reading!

Using Device Twins with Azure IoT Hub

In today’s article I’d like to discuss Device Twins and how you can use them with Azure IoT Hub. I will be discussing what Device Twins are, how they are used and then provide a code example of using them with Azure IoT Hub.

What are Device Twins?

Device Twins are JSON documents that store state information about IoT devices. This includes state information along with metadata about the device. Configurations and conditions on the device are also stored. Azure IoT Hub maintains a device twin for each registered device that is connected to that hub.

You can use Device Twins to store specific metadata about your devices in the cloud. For example, you can keep track of a device location by storing location metadata about that device in its Device Twin.

Device Twins can also be used to report state information about the device. This can be useful to determine if a device is connected to IoT Hub, or if it is connected to a WiFi network.

Additionally, the process of updating the firmware on one or more devices can benefit from Device Twins, as firmware installation progress can be reported to a back-end application.

Device Twin Structure

The JSON document that makes up a Device Twin has a few components that I will describe in this section. Here is an example of the overall JSON structure of a Device Twin:

Figure 1: Device Twin Structure

Tags

The Tags section is used exclusively by a back-end solution. Device applications cannot see or query tags at all, but a back-end solution does have the capability to read/write tag values to this section of the Device Twin. The information in this section can be whatever identifying data you need on the back-end solution side. Here is an example, which shows tags for the device location:

{
…
    "tags": {
        "deviceLocation": {
            "city": "Chicago",
            "building": "Willis Tower",
            "floor": "12",
            "room": "NE Conf 1"
        }
    },
…
}

Reported Properties

This section is used in coordination with the Desired Properties section to synchronize device configurations. The device application has the capability to read and write data to this section while a back-end solution can read information from this section as well as receive change notifications when data changes. Typically, this section is used by the device application to report its current state to the cloud.

For example, let us say that we want to report to a back-end solution the current WiFi information for the device. We would serialize the following JSON string into the proper format for Reported Properties and then report the state to the IoT Hub that the device is registered with.

{
…
    "properties": {
…
        "reported": {
            "wifi.wifiIP": “192.168.3.100”,
            "wifi.wifiMask": “255.255.255.0”
        }
    }
}
Figure 2: Sending Reported Properties (device app)

The IoT Hub that maintains the Device Twin for the registered device would update the information being received from the device. In our example, the WiFi IP and Mask values would be updated accordingly in the device’s device twin. A solution back-end can then query the Reported Properties to retrieve these values.

Figure 3: Reading Reported Properties (back-end solution)

Desired Properties

This section is used in coordination with the Reported Properties section to synchronize device configurations. A back-end solution has the capability to read and write data to this section, and the device application can read and receive change notifications for this section. Typically, this section is used by a back-end solution to communicate to the device of some change requested that the device application should handle.

For example, let us say that we want to change the interval time value on the device that is used for sending data to IoT Hub. A back-end solution could update the desired properties and that change would be communicated to the device. As shown in the JSON snippet below we can set the ‘sendDataInterval’ value in the Desired Properties section to ‘5000’ indicating we want to set the interval value on the device to 5 seconds.

{
…
    "properties": {
        "desired": {
            "sendDataInterval": "5000
        },
…
    }
}
Figure 4: Update Desired Properties (back-end solution)

When a change is made to the Desired Properties for a device, a notification event is sent to that device informing the device of the change. Code on the device would configure a Device Twin callback method that would be fired when the change notification is sent to the device.

Figure 5: Configure Device Twin Callback Method (device app)

The callback method would extract the JSON information which would contain the Desired Properties section of that device’s Device Twin record. The code would then be able to interpret what has changed and perform whatever necessary actions are required.

Figure 6: Device Twin Callback Method (device app)

A device application should perform whatever actions necessary to process the change in the Desired Properties and then send back an update (via the Reported Properties) to the cloud.

Device Identity Properties

This is the root of the JSON document and contains the read-only properties that specify the device identity. This information can be used to retrieve the device identity along with connection state and authentication type.

{
    "deviceId": "devA",
    "etag": "AAAAAAAAAAc=", 
    "status": "enabled",
    "statusReason": "provisioned",
    "statusUpdateTime": "0001-01-01T00:00:00",
    "connectionState": "connected",
    "lastActivityTime": "2015-02-30T16:24:48.789Z",
    "cloudToDeviceMessageCount": 0, 
    "authenticationType": "sas",
    "x509Thumbprint": {     
        "primaryThumbprint": null, 
        "secondaryThumbprint": null 
    }, 
    "version": 2, 
…
}

I hope this article was helpful in explaining the details of Device Twins. For more detailed information please visit https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-device-twins.

If you would like to download the full source code for this example, please visit my github repository here.

Thanks for reading!