Get started with IoT Hub module identities and module identity twins
Module identities and module identity twins are similar to Azure IoT Hub device identities and device twins, but provide finer granularity. While Azure IoT Hub device identities and device twins enable the back-end application to configure a device and provide visibility on the device's conditions, a module identity and module identity twin provide these capabilities for individual components of a device. On capable devices with multiple components, such as operating system devices or firmware devices, module identities and module identity twins allow for isolated configuration and conditions for each component. For more information, see Understand Azure IoT Hub module twins.
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 that view and update module identity twin reported properties and handle requests to update desired properties.
- Service apps that can read and set module identity desired properties.
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
An IoT hub device
An IoT hub device module identity
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).
- Requires Visual Studio
Overview
This article describes how to use the Azure IoT SDK for .NET to create device and backend service application code for module identity twins.
Create a device application
This section describes how to use device application code to:
- Retrieve a module identity twin and examine reported properties
- Update reported module identity twin properties
- Create a module 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.
Required device NuGet package
Device client applications written in C# require the Microsoft.Azure.Devices.Client NuGet package.
Add these using
statements to use the device library.
using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices.Shared;
Connect to a device
The ModuleClient class exposes all methods required to interact with module identity twins from the device.
Connect to the device using the CreateFromConnectionString method with the module identity connection string.
Calling CreateFromConnectionString
without a transport parameter connects using the default AMQP transport.
This example connects to the device using the default AMQP transport.
static string ModuleConnectionString = "{Device module identity connection string}";
private static ModuleClient _moduleClient = null;
_moduleClient = ModuleClient.CreateFromConnectionString(ModuleConnectionString, null);
Retrieve a module identity twin and examine properties
Call GetTwinAsync to retrieve the current module identity twin properties into a Twin object.
This example retrieves and displays module identity twin properties in JSON format.
Console.WriteLine("Retrieving twin...");
Twin twin = await _moduleClient.GetTwinAsync();
Console.WriteLine("\tModule identity twin value received:");
Console.WriteLine(JsonConvert.SerializeObject(twin.Properties));
Update module identity twin reported properties
To update a twin reported property:
- Create a TwinCollection object for the reported property update
- Update one or more reported properties within the
TwinCollection
object - 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 _moduleClient.UpdateReportedPropertiesAsync(reportedProperties);
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine("Error in sample: {0}", ex.Message);
}
Create a desired property update callback handler
Pass the callback handler method name to SetDesiredPropertyUpdateCallbackAsync to create a desired property update callback handler that executes when a desired property is changed in the module identity twin.
For example, this call sets up the system to notify a method named OnDesiredPropertyChangedAsync
whenever a desired module property is changed.
await _moduleClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertyChangedAsync, null);
The module identity 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 _moduleClient.UpdateReportedPropertiesAsync(reportedProperties);
}
SDK module sample
The Azure IoT SDK for .NET provides working samples of device apps that handle module identity twin tasks. For more information, see:
Create a backend application
This section describes how to read and update module identity fields.
The RegistryManager class exposes all methods required to create a backend application to interact with module identity twins from the service.
Required service NuGet package
Backend service applications require the Microsoft.Azure.Devices NuGet package.
Add these using
statements to use the service library.
using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Shared;
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 IoT hub using CreateFromConnectionString.
The UpdateModuleAsync
method used in this section requires the Service Connect shared access policy permission to add desired properties to a module. As a parameter to CreateFromConnectionString
, supply a shared access policy connection string that includes Service Connect permission. For more information about shared access policies, see Control access to IoT Hub with shared access signatures.
For example:
static RegistryManager registryManager;
static string connectionString = "{IoT hub 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 module identity fields
Call GetModuleAsync to retrieve current module identity twin fields into a Module object.
The Module
class includes properties
that correspond to sections of a module identity twin. Use the Module class properties to view and update module identity twin fields. You can use the Module
object properties to update multiple fields before writing the updates to the device using UpdateModuleAsync
.
After making module identity twin field updates, call UpdateModuleAsync to write Module
object field updates back to a device. Use try
and catch
logic coupled with an error handler to catch incorrectly formatted patch errors from UpdateModuleAsync
.
This example retrieves a module into a Module
object, updates the module
LastActivityTime
property, and then updates the module in IoT Hub using UpdateModuleAsync
.
// Retrieve the module
var module = await registryManager.GetModuleAsync("myDeviceId","myModuleId");
// Update the module object
module.LastActivityTime = DateTime.Now;
// Apply the patch to update the device twin tags section
try
{
await registryManager.UpdateModuleAsync(module);
}
catch (Exception e)
{
console.WriteLine("Module update failed.", e.Message);
}
Other module API
- GetModulesOnDeviceAsync - Retrieves the module identities on a device
- RemoveModuleAsync - Deletes a previously registered module from a device
SDK service sample
The Azure IoT SDK for .NET provides a working sample of a service app that handles module identity twin tasks. For more information, see Registry Manager E2E Tests.
- 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.
Overview
This article describes how to use the Azure IoT SDK for Python to create device and backend service application code for module identity twins.
Install packages
The azure-iot-device library must be installed to create device applications.
pip install azure-iot-device
The azure-iot-hub library must be installed to create backend service applications.
pip install azure-iot-hub
The msrest library is used to catch HTTPOperationError exceptions.
pip install msrest
Create a device application
This section describes how to use device application code to:
- Retrieve a module identity twin and examine reported properties
- Update module identity twin reported properties
- Create a module identity twin 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.
Import statements
Add this import
statement to use the device library.
# import the device client library
import asyncio
from azure.iot.device.aio import IoTHubDeviceClient
Connect to a device
The IoTHubModuleClient class contains methods that can be used to work with module identity twins.
To connect an application to a device:
- Call create_from_connection_string to add the module identity connection string
- 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 = "{Device module identity connection string}"
device_client = IoTHubDeviceClient.create_from_connection_string(conn_str)
# connect the application to the device
await device_client.connect()
Retrieve a module identity twin and examine properties
Call get_twin to retrieve the module identity twin from the Azure IoT Hub service. The twin information is placed into a variable that can be 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))
Update module identity twin reported properties
You can apply a patch to update module identity twin reported properties in JSON format.
To apply a patch to update reported properties:
- Assign a reported property JSON patch to a variable.
- Call patch_twin_reported_properties to apply the JSON patch to reported properties.
For example:
# 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)
Create a module identity twin desired property update callback handler
Call on_twin_desired_properties_patch_received to create a handler function or coroutine that is called when a module identity 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 provides a working sample of device apps that handle module identity twin tasks:
- get_twin - Connect to a device and retrieve twin information.
- update_twin_reported_properties - Update twin reported properties.
- receive_twin_desired_properties - Receive and update desired properties.
Create a backend application
This section describes how to create a backend application to retrieve and update module identity twin desired properties.
The IoTHubRegistryManager class exposes all methods required to create a backend application to interact with module identity twins from the service.
Service import statements
Add this import
statement to use the service library.
import sys
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.models import Twin, TwinProperties, QuerySpecification, QueryResult
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.
The update_module_twin
method used in this section requires the Service Connect shared access policy permission to add desired properties to a module. As a parameter to from_connection_string
, supply a shared access policy connection string that includes Service Connect permission. For more information about shared access policies, see Control access to IoT Hub with shared access signatures.
For example:
# Connect to IoT hub
IOTHUB_CONNECTION_STRING = "{IoT hub shared access policy 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:
- IoTHubRegistryManager to create a service connection to IoT Hub using an Entra token credential.
- IoTHubJobManager
- DigitalTwinClient
- IoTHubHttpRuntimeManager
- IoTHubConfigurationManager
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 ahttps://
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.
Retrieve and update module identity twin desired properties
You can update desired properties from a backend application using update_module_twin.
To retrieve and update module identity twin desired properties:
- Call get_module_twin to get the current version of the module identity twin.
- Use the Twin class to add desired properties in JSON format.
- Call
update_module_twin
to apply the patch to the device twin. You can also use replace_module_twin to replace desired properties and tags for a module identity twin.
This example updates the telemetryInterval
desired property to 122
.
try:
module_twin = iothub_registry_manager.get_module_twin(DEVICE_ID, MODULE_ID)
print ( "" )
print ( "Module identity twin properties before update:" )
print ( "{0}".format(module_twin.properties) )
# Update twin
twin_patch = Twin()
twin_patch.properties = TwinProperties(desired={"telemetryInterval": 122})
updated_module_twin = iothub_registry_manager.update_module_twin(
DEVICE_ID, MODULE_ID, twin_patch, module_twin.etag
)
print ( "" )
print ( "Module identity twin properties after update :" )
print ( "{0}".format(updated_module_twin.properties) )
except Exception as ex:
print ( "Unexpected error {0}".format(ex) )
except KeyboardInterrupt:
print ( "IoTHubRegistryManager sample stopped" )
SDK service sample
The Azure IoT SDK for Python provides a working sample of a service app that handles device identity module twin tasks. For more information, see Test IoTHub Registry Manager.
- Requires Node.js version 10.0.x or later
Overview
This article describes how to use the Azure IoT SDK for Node.js to create device and backend service application code for module identity twins.
Create a device application
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 module identity twin and examine reported properties
- Update module identity reported twin properties
- Receive notice of module identity twin 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 module identity twin data.
Choose a transport protocol
The Client
object supports these protocols:
Amqp
Http
- When usingHttp
, theClient
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 Amqp
protocol:
npm install azure-iot-device-amqp --save
For more information about the differences between MQTT, AMQP, and HTTPS support, see Cloud-to-device communications guidance and Choose a device communication protocol.
Create a client object
Create a Client
object using the installed package.
For example:
const Client = require('azure-iot-device').Client;
Create a protocol object
Create a Protocol
object using an installed transport package.
This example assigns the AMQP protocol:
const Protocol = require('azure-iot-device-amqp').Amqp;
Add the device connection string and transport protocol
Call fromConnectionString to supply device connection parameters:
- connStr - The IoT hub identity module connection string.
- transportCtor - The transport protocol.
This example uses the Amqp
transport protocol:
const deviceConnectionString = "{IoT hub identity module connection string}"
const Protocol = require('azure-iot-device-mqtt').Amqp;
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.
For example:
client.open(function(err) {
if (err) {
console.error('error connecting to hub: ' + err);
process.exit(1);
}
})
Retrieve a module identity twin and examine reported properties
Call getTwin to retrieve current module identity twin information into a Twin object.
Device code can then access the module identity twin properties.
For example:
// Retrieve the current module identity twin
client.getTwin(function(err, twin))
if (err)
console.error('could not get twin');
// Display the current properties
console.log('twin contents:');
console.log(twin.properties);
Update module identity twin reported 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 module identity twin patch is stored in the patch
variable. The patch contains a module identity 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.
// Create a patch to send to IoT Hub
var patch = {
updateTime: new Date().toString(),
firmwareVersion:'1.2.1',
weather:{
temperature: 72,
humidity: 17
}
};
// Apply the patch
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 module identity twin desired property changes
Create a module identity twin desired property update event listener that executes when a desired property is changed by passing the callback handler method name to twin.on.
The desired property event listener can take 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:
The
minTemperature
andmaxTemperature
properties are located under a property grouping namedproperties.desired.climate changes
.A backend service application applies this patch to update
minTemperature
andmaxTemperature
desired properties:const twinPatch1 = { properties: { desired: { climate: { minTemperature: 68, maxTemperature: 76, }, }, }, };
This code sets up a desired property 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 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.
A backend application applies this desired property patch:
const twinPatch2 = { properties: { desired: { climate: { hvac: { systemControl: { fanOn: true, }, }, }, }, }, };
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); });
Complete example
This example encapsulates the principles of this section, including multi-level callback function nesting.
var Client = require('azure-iot-device').Client;
var Protocol = require('azure-iot-device-amqp').Amqp;
// Copy/paste your module connection string here.
var connectionString = 'HostName=xxx.azure-devices.net;DeviceId=myFirstDevice2;ModuleId=myFirstModule2;SharedAccessKey=xxxxxxxxxxxxxxxxxx';
// Create a client using the Amqp protocol.
var client = Client.fromConnectionString(connectionString, Protocol);
client.on('error', function (err) {
console.error(err.message);
});
// connect to the hub
client.open(function(err) {
if (err) {
console.error('error connecting to hub: ' + err);
process.exit(1);
}
console.log('client opened');
// Create device Twin
client.getTwin(function(err, twin) {
if (err) {
console.error('error getting twin: ' + err);
process.exit(1);
}
// Output the current properties
console.log('twin contents:');
console.log(twin.properties);
// Add a handler for desired property changes
twin.on('properties.desired', function(delta) {
console.log('new desired properties received:');
console.log(JSON.stringify(delta));
});
// create a patch to send to the hub
var patch = {
updateTime: new Date().toString(),
firmwareVersion:'1.2.1',
weather:{
temperature: 75,
humidity: 20
}
};
// send the patch
twin.properties.reported.update(patch, function(err) {
if (err) throw err;
console.log('twin state reported');
});
});
});
Device SDK samples
The Azure IoT SDK for Node.js provides working samples of device apps that handle module identity twin tasks. For more information, see:
Create a backend application
This section describes how to create a backend application that retrieves a module identity twin and updates desired properties.
Install service SDK package
Run this command to install azure-iothub on your development machine:
npm install azure-iothub --save
Create a Registry object
The Registry class exposes all methods required to interact with module identity twins from a backend application.
let Registry = require('azure-iothub').Registry;
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.
The update
method used in this section requires the Service Connect shared access policy permission to add desired properties to a module. As a parameter to fromConnectionString
, supply a shared access policy connection string that includes Service Connect permission. For more information about shared access policies, see Control access to IoT Hub with shared access signatures.
let connectionString = '{IoT hub shared access policy connection string}';
let registry = Registry.fromConnectionString(serviceConnectionString);
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 ahttps://
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 a module identity twin and update desired properties
You can create a patch that contains desired property updates for a module identity twin.
To update a module identity twin:
Call getModuleTwin to retrieve the device Twin object.
Format a patch that contains the module identity twin update. The patch is formatted in JSON as described in Twin class. A backend service patch contains desired property updates. For more patch format information, see Tags and properties format.
Call update to update the module identity twin with the patch.
In this example, the module identity twin is retrieved for myDeviceId
and myModuleId
. Then a patch is applied to the twins that contains climate
information.
// Insert your device ID and moduleId here.
var deviceId = 'myFirstDevice2';
var moduleId = 'myFirstModule2';
// Retrieve the current module identity twin
registry.getModuleTwin(deviceId, moduleId, function (err, twin) {
console.log('getModuleTwin returned ' + (err ? err : 'success'));
if (err) {
console.log(err);
} else {
console.log('success');
console.log('Current twin:' + JSON.stringify(twin))
// Format a desired property patch
const twinPatch1 = {
properties: {
desired: {
climate: { minTemperature: 69, maxTemperature: 77, },
},
},
};
// Send the desired property patch to IoT Hub
twin.update(twinPatch1, function(err) {
if (err) throw err;
console.log('twin state reported');
});
}
});
Service SDK samples
The Azure IoT SDK for Node.js provides working samples of service apps that handle module identity twin tasks. For more information, see: