IoT Plug and Play lets you build IoT devices that advertise their capabilities to Azure IoT applications. IoT Plug and Play devices don't require manual configuration when a customer connects them to IoT Plug and Play-enabled applications.
IoT Plug and Play lets you use devices that announce their model ID to your IoT hub. For example, you can access the properties and commands of a device directly.
If you're using IoT Central, you can use the IoT Central UI and REST API to interact with IoT Plug and Play devices connected to your application.
Важно
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 for IoT solutions > Cloud security.
Service SDKs
Use the Azure IoT service SDKs in your solution to interact with devices and modules. For example, you can use the service SDKs to read and update twin properties and invoke commands. Supported languages include C#, Java, Node.js, and Python.
The Azure IoT service SDKs contain code to facilitate building applications that interact directly with IoT Hub to manage devices and security.
The service SDKs let you access device information from a solution component such as a desktop or web application. The service SDKs include two namespaces and object models that you can use to retrieve the model ID:
Iot Hub service client. This service exposes the model ID as a device twin property.
Digital Twins client. The new Digital Twins API operates on Digital Twins Definition Language (DTDL) model constructs such as components, properties, and commands. The Digital Twin APIs make it easier for solution builders to create IoT Plug and Play solutions.
This section shows C# examples using the IoT Hub service client and the RegistryManager and ServiceClient classes. You use the RegistryManager class to interact with the device state using device twins. You can also use the RegistryManager class to query device registrations in your IoT Hub. You use the ServiceClient class to call commands on the device. The DTDL model for the device defines the properties and commands the device implements. In the code snippets, the deviceTwinId variable holds the device ID of the IoT Plug and Play device registered with your IoT hub.
Get the device twin and model ID
To get the device twin and model ID of the IoT Plug and Play device that connected to your IoT hub:
The following code snippet shows how to update the targetTemperature property on a device. The sample shows how you need to get the twin's ETag before you update it. The property is defined in the default component of the device:
Twin twin = await registryManager.GetTwinAsync(deviceTwinId);
int desiredTargetTemperature = 60;
// Update the twin
var twinPatch = new Twin();
twinPatch.Properties.Desired["targetTemperature"] = desiredTargetTemperature;
Console.WriteLine($"Update the targetTemperature property to {desiredTargetTemperature}.");
await registryManager.UpdateTwinAsync(deviceTwinId, twinPatch, twin.ETag);
The following snippet shows how to update the targetTemperature property on a component. The sample shows how you need to get the twin's ETag before you update it. The property is defined in the Thermostat1 component:
Twin twin = await registryManager.GetTwinAsync(deviceTwinId);
int desiredTargetTemperature = 60;
var twinPatch = CreatePropertyPatch("targetTemperature", desiredTargetTemperature, "thermostat1");
await registryManager.UpdateTwinAsync(deviceTwinId, twinPatch, twin.ETag);
// ...
private static Twin CreatePropertyPatch(string propertyName, object propertyValue, string componentName)
{
var twinPatch = new Twin();
twinPatch.Properties.Desired[componentName] = new
{
__t = "c"
};
twinPatch.Properties.Desired[componentName][propertyName] = JsonConvert.SerializeObject(propertyValue);
return twinPatch;
}
For a property in a component, the property patch looks like the following example:
The following snippet shows how to invoke the getMaxMinReport command defined in a default component:
ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(parameters.HubConnectionString);
var commandInvocation = new CloudToDeviceMethod("getMaxMinReport") { ResponseTimeout = TimeSpan.FromSeconds(30) };
// Set command payload
DateTimeOffset since = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(2));
string componentCommandPayload = JsonConvert.SerializeObject(since);
commandInvocation.SetPayloadJson(componentCommandPayload);
try
{
CloudToDeviceMethodResult result = await serviceClient.InvokeDeviceMethodAsync(deviceTwinId, commandInvocation);
Console.WriteLine($"Command getMaxMinReport was invoked." +
$"\nDevice returned status: {result.Status}. \nReport: {result.GetPayloadAsJson()}");
}
catch (DeviceNotFoundException)
{
Console.WriteLine($"Unable to execute command getMaxMinReport on {deviceTwinId}.";
}
The following snippet shows how to call the getMaxMinReport command on a component. The command is defined in the Thermostat1 component:
// Create command name to invoke for component. The command is formatted as <component name>*<command name>
string commandToInvoke = "thermostat1*getMaxMinReport";
var commandInvocation = new CloudToDeviceMethod(commandToInvoke) { ResponseTimeout = TimeSpan.FromSeconds(30) };
// Set command payload
DateTimeOffset since = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(2));
string componentCommandPayload = JsonConvert.SerializeObject(since);
commandInvocation.SetPayloadJson(componentCommandPayload);
try
{
CloudToDeviceMethodResult result = await serviceClient.InvokeDeviceMethodAsync(deviceTwinId, commandInvocation);
Console.WriteLine($"Command getMaxMinReport was invoked on component thermostat1." +
$"\nDevice returned status: {result.Status}. \nReport: {result.GetPayloadAsJson()}");
}
catch (DeviceNotFoundException)
{
Console.WriteLine("Unable to execute command getMaxMinReport on component thermostat1.");
}
IoT Hub digital twin examples
You use the DigitalTwinClient class to interact with the device state using digital twins. The DTDL model for the device defines the properties and commands the device implements.
This section shows C# examples using the Digital Twins API. The following snippets use the following classes to represent the digital twin of the thermostat and temperature controller devices:
using Microsoft.Azure.Devices.Serialization;
using Newtonsoft.Json;
using System;
namespace Microsoft.Azure.Devices.Samples
{
internal class ThermostatTwin : BasicDigitalTwin
{
[JsonProperty("$metadata")]
public new ThermostatMetadata Metadata { get; set; }
[JsonProperty("maxTempSinceLastReboot")]
public double? MaxTempSinceLastReboot { get; set; }
[JsonProperty("targetTemperature")]
public double? TargetTemperature { get; set; }
}
internal class ThermostatMetadata : DigitalTwinMetadata
{
[JsonProperty("maxTempSinceLastReboot")]
public ReportedPropertyMetadata MaxTempSinceLastReboot { get; set; }
[JsonProperty("targetTemperature")]
public WritableProperty TargetTemperature { get; set; }
}
internal class ReportedPropertyMetadata
{
[JsonProperty("lastUpdateTime")]
public DateTimeOffset LastUpdateTime { get; set; }
}
internal class TemperatureControllerTwin : BasicDigitalTwin
{
[JsonProperty("$metadata")]
public new TemperatureControllerMetadata Metadata { get; set; }
[JsonProperty("serialNumber")]
public string SerialNumber { get; set; }
[JsonProperty("thermostat1")]
public ThermostatTwin Thermostat1 { get; set; }
[JsonProperty("thermostat2")]
public ThermostatTwin Thermostat2 { get; set; }
}
internal class TemperatureControllerMetadata : DigitalTwinMetadata
{
[JsonProperty("serialNumber")]
public ReportedPropertyMetadata SerialNumber { get; set; }
[JsonProperty("thermostat1")]
public WritableProperty Thermostat1 { get; set; }
[JsonProperty("thermostat2")]
public WritableProperty Thermostat2 { get; set; }
}
}
The digitalTwinId variable holds the device ID of the IoT Plug and Play device registered with your IoT hub.
Get the digital twin and model ID
To get the digital twin and model ID of the IoT Plug and Play device that connected to your IoT hub:
The following code snippet shows how to update the targetTemperature property on a device. The property is defined in the default component of the device:
var updateOperation = new UpdateOperationsUtility();
int desiredTargetTemperature = 60;
// Get the current value of the targetTemperature property
HttpOperationResponse<ThermostatTwin, DigitalTwinGetHeaders> getDigitalTwinResponse = await digitalTwinClient
.GetDigitalTwinAsync<ThermostatTwin>(digitalTwinId);
double? currentTargetTemperature = getDigitalTwinResponse.Body.TargetTemperature;
// Has the targetTemperature property previously been set?
if (currentTargetTemperature != null)
{
// Update the existing property
// Prepend the property path with a '/'
updateOperation.AppendReplacePropertyOp($"/targetTemperature", desiredTargetTemperature);
}
else
{
// Add a new property
// Prepend the property path with a '/'
updateOperation.AppendAddPropertyOp($"/targetTemperature", desiredTargetTemperature);
}
// Update the targetTemperature property on the digital twin
HttpOperationHeaderResponse<DigitalTwinUpdateHeaders> updateDigitalTwinResponse = await digitalTwinClient
.UpdateDigitalTwinAsync(digitalTwinId, updateOperation.Serialize());
Console.WriteLine($"Update {digitalTwinId} digital twin response: {updateDigitalTwinResponse.Response.StatusCode}.");
The following snippet shows how to update the targetTemperature property on a component. The property is defined in the Thermostat1 component:
int desiredTargetTemperature = 60;
var updateOperation = new UpdateOperationsUtility();
// Look at when the property was updated and what was it set to.
HttpOperationResponse<TemperatureControllerTwin, DigitalTwinGetHeaders> getDigitalTwinResponse = await digitalTwinClient
.GetDigitalTwinAsync<TemperatureControllerTwin>(digitalTwinId);
ThermostatTwin thermostat1 = getDigitalTwinResponse.Body.Thermostat1;
if (thermostat1 != null)
{
// Thermostat1 is present in the TemperatureController twin. You can add/replace the component-level property "targetTemperature"
double? currentComponentTargetTemperature = getDigitalTwinResponse.Body.Thermostat1.TargetTemperature;
if (currentComponentTargetTemperature != null)
{
DateTimeOffset targetTemperatureDesiredLastUpdateTime = getDigitalTwinResponse.Body.Thermostat1.Metadata.TargetTemperature.LastUpdateTime;
// The property path to be replaced should be prepended with a '/'
updateOperation.AppendReplacePropertyOp("/thermostat1/targetTemperature", desiredTargetTemperature);
}
else
{
// The property path to be added should be prepended with a '/'
updateOperation.AppendAddPropertyOp("/thermostat1/targetTemperature", desiredTargetTemperature);
}
}
else
{
// Thermostat1 is not present in the TemperatureController twin. Add the component.
var componentProperty = new Dictionary<string, object> { { "targetTemperature", desiredTargetTemperature }, { "$metadata", new object() } };
// The property path to be replaced should be prepended with a '/'
updateOperation.AppendAddComponentOp("/thermostat1", componentProperty);
}
HttpOperationHeaderResponse<DigitalTwinUpdateHeaders> updateDigitalTwinResponse = await digitalTwinClient
.UpdateDigitalTwinAsync(digitalTwinId, updateOperation.Serialize());
Console.WriteLine($"Update {digitalTwinId} digital twin response: {updateDigitalTwinResponse.Response.StatusCode}.");
Call command
The following snippet shows how to invoke the getMaxMinReport command defined in a default component:
DateTimeOffset since = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(2));
try
{
HttpOperationResponse<DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders> invokeCommandResponse = await digitalTwinClient
.InvokeCommandAsync(digitalTwinId, "getMaxMinReport", JsonConvert.SerializeObject(since));
Console.WriteLine($"Command getMaxMinReport was invoked. \nDevice returned status: {invokeCommandResponse.Body.Status}." +
$"\nReport: {invokeCommandResponse.Body.Payload}");
}
catch (HttpOperationException e)
{
if (e.Response.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine($"Unable to execute command getMaxMinReport on {digitalTwinId}.");
}
}
The following snippet shows how to call the getMaxMinReport command on a component. The command is defined in the Thermostat1 component:
DateTimeOffset since = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(2));
try
{
HttpOperationResponse<DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders> invokeCommandResponse = await digitalTwinClient
.InvokeComponentCommandAsync(digitalTwinId, "thermostat1", "getMaxMinReport", JsonConvert.SerializeObject(since));
Console.WriteLine("Command getMaxMinReport was invoked on component thermostat1." +
$"\nDevice returned status: {invokeCommandResponse.Body.Status}. \nReport: {invokeCommandResponse.Body.Payload}");
}
catch (HttpOperationException e)
{
if (e.Response.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine("Unable to execute command getMaxMinReport on component thermostat1.");
}
}
await using EventHubConsumerClient consumer = new EventHubConsumerClient(EventHubConsumerClient.DefaultConsumerGroupName, connectionString, EventHubName);
Console.WriteLine("Listening for messages on all partitions");
try
{
await foreach (PartitionEvent partitionEvent in consumer.ReadEventsAsync(cancellationToken))
{
Console.WriteLine("Message received on partition {0}:", partitionEvent.Partition.PartitionId);
string data = Encoding.UTF8.GetString(partitionEvent.Data.Body.ToArray());
Console.WriteLine("\t{0}:", data);
Console.WriteLine("Application properties (set by device):");
foreach (var prop in partitionEvent.Data.Properties)
{
Console.WriteLine("\t{0}: {1}", prop.Key, prop.Value);
}
Console.WriteLine("System properties (set by IoT Hub):");
foreach (var prop in partitionEvent.Data.SystemProperties)
{
Console.WriteLine("\t{0}: {1}", prop.Key, prop.Value);
}
}
}
catch (TaskCanceledException)
{
// This is expected when the token is signaled; it should not be considered an
// error in this scenario.
}
The following output from the previous code shows the temperature telemetry sent by the no-component Thermostat IoT Plug and Play device that only has the default component. The dt-dataschema system property shows the model ID:
Message received on partition 1:
{ "temperature": 25.5 }:
Application properties (set by device):
System properties (set by IoT Hub):
iothub-connection-device-id: my-pnp-device
iothub-connection-auth-method: {"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}
iothub-connection-auth-generation-id: 637375045610235418
iothub-enqueuedtime: 05/10/2020 14:30:58
iothub-message-source: Telemetry
dt-dataschema: dtmi:com:example:Thermostat;1
content-type: application/json
content-encoding: utf-8
The following output from the previous code shows the temperature telemetry sent by the multi-component TemperatureController IoT Plug and Play device. The dt-subject system property shows the name of the component that sent the telemetry. In this example, the two components are thermostat1 and thermostat2 as defined in the DTDL model. The dt-dataschema system property shows the model ID:
Message received on partition 1:
{"temperature":11.1}:
Application properties (set by device):
System properties (set by IoT Hub):
dt-subject: thermostat1
iothub-connection-device-id: my-pnp-device
iothub-connection-auth-method: {"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}
iothub-connection-auth-generation-id: 637375045610235418
iothub-enqueuedtime: 05/10/2020 14:23:36
iothub-message-source: Telemetry
dt-dataschema: dtmi:com:example:TemperatureController;1
content-type: application/json
content-encoding: utf-8
Message received on partition 1:
{"temperature":41.2}:
Application properties (set by device):
System properties (set by IoT Hub):
dt-subject: thermostat2
iothub-connection-device-id: my-pnp-device
iothub-connection-auth-method: {"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}
iothub-connection-auth-generation-id: 637375045610235418
iothub-enqueuedtime: 05/10/2020 14:23:36
iothub-message-source: Telemetry
dt-dataschema: dtmi:com:example:TemperatureController;1
content-type: application/json
content-encoding: utf-8
The code shown in the previous C# code snippet generates the following output when IoT Hub generates device twin change notifications for a no-component thermostat device. The application properties iothub-message-schema and opType give you information about the type of change notification:
Message received on partition 1:
{"version":3,"properties":{"reported":{"maxTempSinceLastReboot":9.6,"$metadata":{"$lastUpdated":"2020-10-06T10:17:41.7408552Z","maxTempSinceLastReboot":{"$lastUpdated":"2020-10-06T10:17:41.7408552Z"}},"$version":2}}}:
Application properties (set by device):
hubName: my-pnp-hub
deviceId: my-pnp-device
operationTimestamp: 2020-10-06T10:17:41.7408552+00:00
iothub-message-schema: twinChangeNotification
opType: updateTwin
System properties (set by IoT Hub):
iothub-connection-device-id: my-pnp-device
iothub-enqueuedtime: 06/10/2020 10:17:41
iothub-message-source: twinChangeEvents
user-id: System.ArraySegment`1[System.Byte]
correlation-id: 61394e8ba7d
content-type: application/json
content-encoding: utf-8
The code shown in the previous C# code snippet generates the following output when IoT Hub generates device twin change notifications for a device with components. This example shows the output when a temperature sensor device with a thermostat component generates notifications. The application properties iothub-message-schema and opType give you information about the type of change notification:
Message received on partition 1:
{"version":5,"properties":{"reported":{"thermostat1":{"__t":"c","maxTempSinceLastReboot":9.6},"$metadata":{"$lastUpdated":"2020-10-06T10:27:59.515972Z","thermostat1":{"$lastUpdated":"2020-10-06T10:27:59.515972Z","__t":{"$lastUpdated":"2020-10-06T10:27:59.515972Z"},"maxTempSinceLastReboot":{"$lastUpdated":"2020-10-06T10:27:59.515972Z"}}},"$version":4}}}:
Application properties (set by device):
hubName: my-pnp-hub
deviceId: my-pnp-device
operationTimestamp: 2020-10-06T10:27:59.5159720+00:00
iothub-message-schema: twinChangeNotification
opType: updateTwin
System properties (set by IoT Hub):
iothub-connection-device-id: my-pnp-device
iothub-enqueuedtime: 06/10/2020 10:27:59
iothub-message-source: twinChangeEvents
user-id: System.ArraySegment`1[System.Byte]
correlation-id: 615051f364e
content-type: application/json
content-encoding: utf-8
The code shown in the previous C# code snippet generates the following output when IoT Hub generates digital twin change notifications for a no-component thermostat device. The application properties iothub-message-schema and opType give you information about the type of change notification:
Message received on partition 1:
[{"op":"add","path":"/$metadata/maxTempSinceLastReboot","value":{"lastUpdateTime":"2020-10-06T10:39:16.0209836Z"}},{"op":"add","path":"/maxTempSinceLastReboot","value":34.9}]:
Application properties (set by device):
hubName: my-pnp-hub
deviceId: my-pnp-device
operationTimestamp: 2020-10-06T10:39:16.0209836+00:00
iothub-message-schema: digitalTwinChangeNotification
opType: updateTwin
System properties (set by IoT Hub):
iothub-connection-device-id: my-pnp-device
iothub-enqueuedtime: 06/10/2020 10:39:16
iothub-message-source: digitalTwinChangeEvents
user-id: System.ArraySegment`1[System.Byte]
correlation-id: 6169857bf8c
content-type: application/json-patch+json
content-encoding: utf-8
The code shown in the previous C# code snippet generates the following output when IoT Hub generates digital twin change notifications for a device with components. This example shows the output when a temperature sensor device with a thermostat component generates notifications. The application properties iothub-message-schema and opType give you information about the type of change notification:
Message received on partition 1:
[{"op":"add","path":"/thermostat1","value":{"$metadata":{"maxTempSinceLastReboot":{"lastUpdateTime":"2020-10-06T10:41:44.8312666Z"}},"maxTempSinceLastReboot":29.1}}]:
Application properties (set by device):
hubName: my-pnp-hub
deviceId: my-pnp-device
operationTimestamp: 2020-10-06T10:41:44.8312666+00:00
iothub-message-schema: digitalTwinChangeNotification
opType: updateTwin
System properties (set by IoT Hub):
iothub-connection-device-id: my-pnp-device
iothub-enqueuedtime: 06/10/2020 10:41:44
iothub-message-source: digitalTwinChangeEvents
user-id: System.ArraySegment`1[System.Byte]
correlation-id: 616f108f0e3
content-type: application/json-patch+json
content-encoding: utf-8
This section shows Java examples using the IoT Hub service client and the DeviceTwin and DeviceMethod classes from the com.microsoft.azure.sdk.iot.service.devicetwin namespace. You use the DeviceTwin class to interact with the device state using device twins. You can also use the DeviceTwin class to query device registrations in your IoT Hub. You use the DeviceMethod class to call commands on the device. The DTDL model for the device defines the properties and commands the device implements. In the code snippets, the deviceId variable holds the device ID of the IoT Plug and Play device registered with your IoT hub.
Get the device twin and model ID
To get the device twin and model ID of the IoT Plug and Play device that connected to your IoT hub:
DeviceTwin twinClient = DeviceTwin.createFromConnectionString(iotHubConnectionString);
// ...
DeviceTwinDevice twin = new DeviceTwinDevice(deviceId);
twinClient.getTwin(twin);
System.out.println("Model Id of this Twin is: " + twin.getModelId());
Update device twin
The following code snippet shows how to update the targetTemperature property on a device. You must get the twin before you update it. The property is defined in the default component of the device:
The following snippet shows how to update the targetTemperature property on a component. You must get the twin before you update it. The property is defined in the thermostat1 component:
The following snippet shows how to invoke the getMaxMinReport command defined in a default component:
DeviceMethod methodClient = DeviceMethod.createFromConnectionString(iotHubConnectionString);
Long responseTimeout = TimeUnit.SECONDS.toSeconds(200);
Long connectTimeout = TimeUnit.SECONDS.toSeconds(5);
String commandInput = ZonedDateTime.now(ZoneOffset.UTC).minusMinutes(5).format(DateTimeFormatter.ISO_DATE_TIME);
MethodResult result = methodClient.invoke(deviceId, "getMaxMinReport", responseTimeout, connectTimeout, commandInput);
System.out.println("Method result status is: " + result.getStatus());
The following snippet shows how to call the getMaxMinReport command on a component. The command is defined in the thermostat1 component:
DeviceMethod methodClient = DeviceMethod.createFromConnectionString(iotHubConnectionString);
Long responseTimeout = TimeUnit.SECONDS.toSeconds(200);
Long connectTimeout = TimeUnit.SECONDS.toSeconds(5);
String commandInput = ZonedDateTime.now(ZoneOffset.UTC).minusMinutes(5).format(DateTimeFormatter.ISO_DATE_TIME);
MethodResult result = methodClient.invoke(deviceId, "thermostat1*getMaxMinReport", responseTimeout, connectTimeout, commandInput);
System.out.println("Method result status is: " + result.getStatus());
IoT Hub digital twin examples
You use the DigitalTwinAsyncClient class in the com.microsoft.azure.sdk.iot.service.digitaltwin namespace to interact with the device state using digital twins. The following examples also use the UpdateOperationUtility and BasicDigitalTwin classes from the same namespace. The DTDL model for the device defines the properties and commands the device implements.
The digitalTwinid variable holds the device ID of the IoT Plug and Play device registered with your IoT hub.
Get the digital twin and model ID
To get the digital twin and model ID of the IoT Plug and Play device that connected to your IoT hub:
The following code snippet shows how to update the targetTemperature property on a device. The property is defined in the default component of the device:
DigitalTwinAsyncClient asyncClient = DigitalTwinAsyncClient.createFromConnectionString(iotHubConnectionString);
CountDownLatch latch1 = new CountDownLatch(1);
UpdateOperationUtility updateOperationUtility = new UpdateOperationUtility();
// Add a new property.
updateOperationUtility.appendAddPropertyOperation("/" + "targetTemperature", 35);
asyncClient.updateDigitalTwin(digitalTwinid, updateOperationUtility.getUpdateOperations())
.subscribe(
getResponse ->
{
System.out.println("Updated Digital Twin");
latch1.countDown();
},
error ->
{
System.out.println("Update Digital Twin failed: " + error);
latch1.countDown();
});
latch1.await(10, TimeUnit.SECONDS);
GetDigitalTwin();
// Replace an existing property.
CountDownLatch latch2 = new CountDownLatch(1);
updateOperationUtility.appendReplacePropertyOperation("/targetTemperature", 50);
asyncClient.updateDigitalTwin(digitalTwinid, updateOperationUtility.getUpdateOperations())
.subscribe(
getResponse ->
{
System.out.println("Updated Digital Twin");
latch2.countDown();
},
error ->
{
System.out.println("Update Digital Twin failed: " + error);
latch2.countDown();
});
latch2.await(10, TimeUnit.SECONDS);
GetDigitalTwin();
The following snippet shows how to update the targetTemperature property on a component. The property is defined in the thermostat1 component:
DigitalTwinClient client = DigitalTwinClient.createFromConnectionString(iotHubConnectionString);
// Get digital twin.
ServiceResponseWithHeaders<String, DigitalTwinGetHeaders> getResponse = client.getDigitalTwinWithResponse(digitalTwinid, String.class);
// Construct the options for conditional update.
DigitalTwinUpdateRequestOptions options = new DigitalTwinUpdateRequestOptions();
options.setIfMatch(getResponse.headers().eTag());
UpdateOperationUtility updateOperationUtility = new UpdateOperationUtility();
Map<String, Object> t1properties = new HashMap<>();
t1properties.put("targetTemperature", 50);
updateOperationUtility.appendReplaceComponentOperation("/thermostat1", t1properties);
digitalTwinUpdateOperations = updateOperationUtility.getUpdateOperations();
updateResponse = client.updateDigitalTwinWithResponse(digitalTwinid, digitalTwinUpdateOperations, options);
System.out.println("Update Digital Twin response status: " + updateResponse.response().message());
getResponse = client.getDigitalTwinWithResponse(digitalTwinid, String.class);
Call command
The following snippet shows how to invoke the getMaxMinReport command defined in a default component:
CountDownLatch latch = new CountDownLatch(1);
String commandInput = ZonedDateTime.now(ZoneOffset.UTC).minusMinutes(5).format(DateTimeFormatter.ISO_DATE_TIME);
// Invoke a method on root level.
asyncClient.invokeCommand(digitalTwinid, "getMaxMinReport", commandInput)
.subscribe(
response ->
{
System.out.println("Invoked Command getMaxMinReport response: " + prettyString(response.getPayload()));
latch.countDown();
},
error ->
{
RestException ex = (RestException)error;
if(ex.response().code() == 404) {
System.out.println("Invoked Command getMaxMinReport failed: " + error);
}
else {
System.out.println("Ensure the device sample is running for this sample to succeed");
}
latch.countDown();
});
latch.await(10, TimeUnit.SECONDS);
// ...
private static String prettyString(String str)
{
Gson gson = new Gson();
Gson gsonBuilder = new GsonBuilder().setPrettyPrinting().create();
return gsonBuilder.toJson(gson.fromJson(str, Object.class));
}
The following snippet shows how to call the getMaxMinReport command on a component. The command is defined in the thermostat1 component:
import com.azure.messaging.eventhubs.EventHubClientBuilder;
import com.azure.messaging.eventhubs.EventHubConsumerAsyncClient;
// ...
EventHubClientBuilder eventHubClientBuilder = new EventHubClientBuilder()
.consumerGroup(EventHubClientBuilder.DEFAULT_CONSUMER_GROUP_NAME)
.connectionString(eventHubCompatibleConnectionString);
try (EventHubConsumerAsyncClient eventHubConsumerAsyncClient = eventHubClientBuilder.buildAsyncConsumerClient()) {
receiveFromAllPartitions(eventHubConsumerAsyncClient);
}
// ...
private static void receiveFromAllPartitions(EventHubConsumerAsyncClient eventHubConsumerAsyncClient) {
eventHubConsumerAsyncClient
.receive(false) // set this to false to read only the newly available events
.subscribe(partitionEvent -> {
System.out.println();
System.out.printf("%nTelemetry received from partition %s:%n%s",
partitionEvent.getPartitionContext().getPartitionId(), partitionEvent.getData().getBodyAsString());
System.out.printf("%nApplication properties (set by device):%n%s", partitionEvent.getData().getProperties());
System.out.printf("%nSystem properties (set by IoT Hub):%n%s",
partitionEvent.getData().getSystemProperties());
}, ex -> {
System.out.println("Error receiving events " + ex);
}, () -> {
System.out.println("Completed receiving events");
});
}
The following output from the previous code shows the temperature telemetry sent by the no-component Thermostat IoT Plug and Play device that only has the default component. The dt-dataschema system property shows the model ID:
Telemetry received from partition 1:
{"temperature": 10.700000}
Application properties (set by device):
{$.cdid=my-pnp-device}
System properties (set by IoT Hub):
{correlation-id=aaaa0000-bb11-2222-33cc-444444dddddd, content-encoding=UTF-8, iothub-connection-auth-method={"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}, iothub-enqueuedtime=Tue Oct 20 12:28:10 BST 2020, dt-dataschema=dtmi:com:example:Thermostat;1, absolute-expiry-time=0, iothub-connection-device-id=my-pnp-device, iothub-connection-auth-generation-id=637375776990653481, group-sequence=0, iothub-message-source=Telemetry, creation-time=0, message-id=aaaabbbb-0000-cccc-1111-dddd2222eeee, content-type=application/json}
Telemetry received from partition 1:
{"temperature": 10.700000}
Application properties (set by device):
{$.cdid=my-pnp-device}
System properties (set by IoT Hub):
{correlation-id=bbbb1111-cc22-3333-44dd-555555eeeeee, content-encoding=UTF-8, iothub-connection-auth-method={"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}, iothub-enqueuedtime=Tue Oct 20 12:28:15 BST 2020, dt-dataschema=dtmi:com:example:Thermostat;1, absolute-expiry-time=0, iothub-connection-device-id=my-pnp-device, iothub-connection-auth-generation-id=637375776990653481, group-sequence=0, iothub-message-source=Telemetry, creation-time=0, message-id=bbbbcccc-1111-dddd-2222-eeee3333ffff, content-type=application/json}
The following output from the previous code shows the temperature telemetry sent by the multi-component TemperatureController IoT Plug and Play device. The dt-subject system property shows the name of the component that sent the telemetry. In this example, the two components are thermostat1 and thermostat2 as defined in the DTDL model. The dt-dataschema system property shows the model ID:
Telemetry received from partition 1:
null
Application properties (set by device):
{$.cdid=my-pnp-device}
System properties (set by IoT Hub):
{correlation-id=cccc2222-dd33-4444-55ee-666666ffffff, content-encoding=UTF-8, iothub-connection-auth-method={"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}, iothub-enqueuedtime=Tue Oct 20 12:31:14 BST 2020, dt-dataschema=dtmi:com:example:TemperatureController;1, absolute-expiry-time=0, iothub-connection-device-id=my-pnp-device, iothub-connection-auth-generation-id=637387902591517456, group-sequence=0, iothub-message-source=Telemetry, creation-time=0, message-id=ccccdddd-2222-eeee-3333-ffff4444aaaa, content-type=application/json, dt-subject=thermostat1}
Telemetry received from partition 1:
null
Application properties (set by device):
{$.cdid=my-pnp-device}
System properties (set by IoT Hub):
{correlation-id=dddd3333-ee44-5555-66ff-777777aaaaaa, content-encoding=UTF-8, iothub-connection-auth-method={"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}, iothub-enqueuedtime=Tue Oct 20 12:31:14 BST 2020, dt-dataschema=dtmi:com:example:TemperatureController;1, absolute-expiry-time=0, iothub-connection-device-id=my-pnp-device, iothub-connection-auth-generation-id=637387902591517456, group-sequence=0, iothub-message-source=Telemetry, creation-time=0, message-id=ddddeeee-3333-ffff-4444-aaaa5555bbbb, content-type=application/json, dt-subject=thermostat2}
The code shown in the previous Java code snippet generates the following output when IoT Hub generates device twin change notifications for a no-component thermostat device. The application properties iothub-message-schema and opType give you information about the type of change notification:
Telemetry received from partition 1:
{"version":11,"properties":{"reported":{"maxTempSinceLastReboot":43.4,"$metadata":{"$lastUpdated":"2020-10-20T11:50:41.123127Z","maxTempSinceLastReboot":{"$lastUpdated":"2020-10-20T11:50:41.123127Z"}},"$version":10}}}
Application properties (set by device):
{operationTimestamp=2020-10-20T11:50:41.1231270+00:00, opType=updateTwin, hubName=my-pnp-hub, deviceId=my-pnp-device, iothub-message-schema=twinChangeNotification}
System properties (set by IoT Hub):
{user-id=[B@12fd5bb4, correlation-id=11339418426a, content-encoding=utf-8, iothub-enqueuedtime=Tue Oct 20 12:50:41 BST 2020, absolute-expiry-time=0, iothub-connection-device-id=my-pnp-device, group-sequence=0, iothub-message-source=twinChangeEvents, creation-time=0, content-type=application/json}
The code shown in the previous Java code snippet generates the following output when IoT Hub generates device twin change notifications for a device with components. This example shows the output when a temperature sensor device with a thermostat component generates notifications. The application properties iothub-message-schema and opType give you information about the type of change notification:
Telemetry received from partition 1:
{"version":9,"properties":{"reported":{"thermostat1":{"__t":"c","maxTempSinceLastReboot":32.5},"$metadata":{"$lastUpdated":"2020-10-20T11:48:01.2960851Z","thermostat1":{"$lastUpdated":"2020-10-20T11:48:01.2960851Z","__t":{"$lastUpdated":"2020-10-20T11:48:01.2960851Z"},"maxTempSinceLastReboot":{"$lastUpdated":"2020-10-20T11:48:01.2960851Z"}}},"$version":8}}}
Application properties (set by device):
{operationTimestamp=2020-10-20T11:48:01.2960851+00:00, opType=updateTwin, hubName=my-pnp-hub, deviceId=my-pnp-device, iothub-message-schema=twinChangeNotification}
System properties (set by IoT Hub):
{user-id=[B@23949bae, correlation-id=113334d542e1, content-encoding=utf-8, iothub-enqueuedtime=Tue Oct 20 12:48:01 BST 2020, absolute-expiry-time=0, iothub-connection-device-id=my-pnp-device, group-sequence=0, iothub-message-source=twinChangeEvents, creation-time=0, content-type=application/json}
The code shown in the previous Java code snippet generates the following output when IoT Hub generates digital twin change notifications for a no-component thermostat device. The application properties iothub-message-schema and opType give you information about the type of change notification:
Telemetry received from partition 1:
[{"op":"replace","path":"/$metadata/maxTempSinceLastReboot/lastUpdateTime","value":"2020-10-20T11:52:40.627628Z"},{"op":"replace","path":"/maxTempSinceLastReboot","value":16.9}]
Application properties (set by device):
{operationTimestamp=2020-10-20T11:52:40.6276280+00:00, opType=updateTwin, hubName=my-pnp-hub, deviceId=my-pnp-device, iothub-message-schema=digitalTwinChangeNotification}
System properties (set by IoT Hub):
{user-id=[B@4475ce2a, correlation-id=1133db52c0e0, content-encoding=utf-8, iothub-enqueuedtime=Tue Oct 20 12:52:40 BST 2020, absolute-expiry-time=0, iothub-connection-device-id=my-pnp-device, group-sequence=0, iothub-message-source=digitalTwinChangeEvents, creation-time=0, content-type=application/json-patch+json}
The code shown in the previous Java code snippet generates the following output when IoT Hub generates digital twin change notifications for a device with components. This example shows the output when a temperature sensor device with a thermostat component generates notifications. The application properties iothub-message-schema and opType give you information about the type of change notification:
Telemetry received from partition 1:
[{"op":"add","path":"/thermostat1","value":{"$metadata":{"maxTempSinceLastReboot":{"lastUpdateTime":"2020-10-20T11:31:04.7811405Z"}},"maxTempSinceLastReboot":27.2}}]
Application properties (set by device):
{operationTimestamp=2020-10-20T11:31:04.7811405+00:00, opType=updateTwin, hubName=my-pnp-hub, deviceId=my-pnp-device, iothub-message-schema=digitalTwinChangeNotification}
System properties (set by IoT Hub):
{user-id=[B@75981aa, correlation-id=1130d6f4d212, content-encoding=utf-8, iothub-enqueuedtime=Tue Oct 20 12:31:04 BST 2020, absolute-expiry-time=0, iothub-connection-device-id=my-pnp-device, group-sequence=0, iothub-message-source=digitalTwinChangeEvents, creation-time=0, content-type=application/json-patch+json}
This section shows JavaScript examples using the IoT Hub service client and the Registry and Client classes. You use the Registry class to interact with the device state using device twins. You can also use the Registry class to query device registrations in your IoT Hub. You use the Client class to call commands on the device. The DTDL model for the device defines the properties and commands the device implements. In the code snippets, the deviceId variable holds the device ID of the IoT Plug and Play device registered with your IoT hub.
Get the device twin and model ID
To get the device twin and model ID of the IoT Plug and Play device that connected to your IoT hub:
The following code snippet shows how to update the targetTemperature property on a device. The sample shows how you need to get the twin before you update it. The property is defined in the default component of the device:
var Registry = require('azure-iothub').Registry;
var registry = Registry.fromConnectionString(connectionString);
registry.getTwin(deviceId, function(err, twin) {
if (err) {
console.error(err.message);
} else {
var twinPatch = {
properties: {
desired: {
targetTemperature: 42
}
}
};
twin.update(twinPatch, function(err, twin) {
if (err) {
console.error(err.message);
} else {
console.log(JSON.stringify(twin, null, 2));
}
}
}
}
The following snippet shows how to update the targetTemperature property on a component. The sample shows how you need to get the twin before you update it. The property is defined in the thermostat1 component:
The following snippet shows how to invoke the getMaxMinReport command defined in a default component:
var Client = require('azure-iothub').Client;
// ...
var client = Client.fromConnectionString(connectionString);
var methodParams = {
methodName: "getMaxMinReport",
payload: new Date().getMinutes -2,
responseTimeoutInSeconds: 15
};
client.invokeDeviceMethod(deviceId, methodParams, function (err, result) {
if (err) {
console.error('Failed to invoke method \'' + methodParams.methodName + '\': ' + err.message);
} else {
console.log(methodParams.methodName + ' on ' + deviceId + ':');
console.log(JSON.stringify(result, null, 2));
}
});
The following snippet shows how to call the getMaxMinReport command on a component. The command is defined in the thermostat1 component:
var Client = require('azure-iothub').Client;
// ...
var client = Client.fromConnectionString(connectionString);
var methodParams = {
methodName: "thermostat1*getMaxMinReport",
payload: new Date().getMinutes -2,
responseTimeoutInSeconds: 15
};
client.invokeDeviceMethod(deviceId, methodParams, function (err, result) {
if (err) {
console.error('Failed to invoke method \'' + methodParams.methodName + '\': ' + err.message);
} else {
console.log(methodParams.methodName + ' on ' + deviceId + ':');
console.log(JSON.stringify(result, null, 2));
}
});
IoT Hub digital twin examples
You use the DigitalTwinClient class to interact with the device state using digital twins. The DTDL model for the device defines the properties and commands the device implements.
This section shows JavaScript examples using the Digital Twins API.
The digitalTwinId variable holds the device ID of the IoT Plug and Play device registered with your IoT hub.
Get the digital twin and model ID
To get the digital twin and model ID of the IoT Plug and Play device that connected to your IoT hub:
The following code snippet shows how to update the targetTemperature property on a device. The property is defined in the default component of the device:
const { EventHubConsumerClient } = require("@azure/event-hubs");
var printError = function (err) {
console.log(err.message);
};
var printMessages = function (messages) {
for (const message of messages) {
console.log("Telemetry received: ");
console.log(JSON.stringify(message.body));
console.log("Properties (set by device): ");
console.log(JSON.stringify(message.properties));
console.log("System properties (set by IoT Hub): ");
console.log(JSON.stringify(message.systemProperties));
console.log("");
}
};
// ...
const clientOptions = {};
const consumerClient = new EventHubConsumerClient("$Default", connectionString, clientOptions);
consumerClient.subscribe({
processEvents: printMessages,
processError: printError,
});
The following output from the previous code shows the temperature telemetry sent by the multi-component TemperatureController IoT Plug and Play device. The dt-subject system property shows the name of the component that sent the telemetry. In this example, the two components are thermostat1 and thermostat2 as defined in the DTDL model. The dt-dataschema system property shows the model ID:
Telemetry received:
{"temperature":68.77370855171125}
Properties (set by device):
undefined
System properties (set by IoT Hub):
{"iothub-connection-device-id":"my-pnp-device","iothub-connection-auth-method":"{\"scope\":\"device\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}","iothub-connection-auth-generation-id":"637388034455888246","iothub-enqueuedtime":1603206669320,"iothub-message-source":"Telemetry","dt-subject":"thermostat1","dt-dataschema":"dtmi:com:example:TemperatureController;1","contentType":"application/json","contentEncoding":"utf-8"}
Telemetry received:
{"temperature":30.833394506549226}
Properties (set by device):
undefined
System properties (set by IoT Hub):
{"iothub-connection-device-id":"my-pnp-device","iothub-connection-auth-method":"{\"scope\":\"device\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}","iothub-connection-auth-generation-id":"637388034455888246","iothub-enqueuedtime":1603206665835,"iothub-message-source":"Telemetry","dt-subject":"thermostat2","dt-dataschema":"dtmi:com:example:TemperatureController;1","contentType":"application/json","contentEncoding":"utf-8"}
The code shown in the previous JavaScript code snippet generates the following output when IoT Hub generates device twin change notifications for a no-component thermostat device. The application properties iothub-message-schema and opType give you information about the type of change notification:
Telemetry received:
{"version":4,"properties":{"reported":{"maxTempSinceLastReboot":42.1415152639582,"$metadata":{"$lastUpdated":"2020-10-21T10:01:40.1281138Z","maxTempSinceLastReboot":{"$lastUpdated":"2020-10-21T10:01:40.1281138Z"}},"$version":3}}}
Properties (set by device):
{"hubName":"my-pnp-hub","deviceId":"my-pnp-device","operationTimestamp":"2020-10-21T10:01:40.1281138+00:00","iothub-message-schema":"twinChangeNotification","opType":"updateTwin"}
System properties (set by IoT Hub):
{"iothub-connection-device-id":"my-pnp-device","iothub-enqueuedtime":1603274500282,"iothub-message-source":"twinChangeEvents","userId":{"type":"Buffer","data":[109,121,45,112,110,112,45,104,117,98]},"correlationId":"11ed82d13f50","contentType":"application/json","contentEncoding":"utf-8"}
The code shown in the previous JavaScript code snippet generates the following output when IoT Hub generates device twin change notifications for a device with components. This example shows the output when a temperature sensor device with a thermostat component generates notifications. The application properties iothub-message-schema and opType give you information about the type of change notification:
Telemetry received:
{"version":4,"properties":{"reported":{"thermostat1":{"maxTempSinceLastReboot":3.5592971602417913,"__t":"c"},"$metadata":{"$lastUpdated":"2020-10-21T10:07:51.8284866Z","thermostat1":{"$lastUpdated":"2020-10-21T10:07:51.8284866Z","maxTempSinceLastReboot":{"$lastUpdated":"2020-10-21T10:07:51.8284866Z"},"__t":{"$lastUpdated":"2020-10-21T10:07:51.8284866Z"}}},"$version":3}}}
Properties (set by device):
{"hubName":"my-pnp-hub","deviceId":"my-pnp-device","operationTimestamp":"2020-10-21T10:07:51.8284866+00:00","iothub-message-schema":"twinChangeNotification","opType":"updateTwin"}
System properties (set by IoT Hub):
{"iothub-connection-device-id":"my-pnp-device","iothub-enqueuedtime":1603274871951,"iothub-message-source":"twinChangeEvents","userId":{"type":"Buffer","data":[109,121,45,112,110,112,45,104,117,98]},"correlationId":"11ee605b195f","contentType":"application/json","contentEncoding":"utf-8"}
The code shown in the previous JavaScript code snippet generates the following output when IoT Hub generates digital twin change notifications for a no-component thermostat device. The application properties iothub-message-schema and opType give you information about the type of change notification:
Telemetry received:
[{"op":"add","path":"/$metadata/maxTempSinceLastReboot","value":{"lastUpdateTime":"2020-10-21T10:01:40.1281138Z"}},{"op":"add","path":"/maxTempSinceLastReboot","value":42.1415152639582}]
Properties (set by device):
{"hubName":"my-pnp-hub","deviceId":"my-pnp-device","operationTimestamp":"2020-10-21T10:01:40.1281138+00:00","iothub-message-schema":"digitalTwinChangeNotification","opType":"updateTwin"}
System properties (set by IoT Hub):
{"iothub-connection-device-id":"my-pnp-device","iothub-enqueuedtime":1603274500282,"iothub-message-source":"digitalTwinChangeEvents","userId":{"type":"Buffer","data":[109,121,45,112,110,112,45,104,117,98]},"correlationId":"11ed82d13f50","contentType":"application/json-patch+json","contentEncoding":"utf-8"}
The code shown in the previous JavaScript code snippet generates the following output when IoT Hub generates digital twin change notifications for a device with components. This example shows the output when a temperature sensor device with a thermostat component generates notifications. The application properties iothub-message-schema and opType give you information about the type of change notification:
Telemetry received:
[{"op":"add","path":"/thermostat1","value":{"$metadata":{"maxTempSinceLastReboot":{"lastUpdateTime":"2020-10-21T10:07:51.8284866Z"}},"maxTempSinceLastReboot":3.5592971602417913}}]
Properties (set by device):
{"hubName":"my-pnp-hub","deviceId":"my-pnp-device","operationTimestamp":"2020-10-21T10:07:51.8284866+00:00","iothub-message-schema":"digitalTwinChangeNotification","opType":"updateTwin"}
System properties (set by IoT Hub):
{"iothub-connection-device-id":"my-pnp-device","iothub-enqueuedtime":1603274871951,"iothub-message-source":"digitalTwinChangeEvents","userId":{"type":"Buffer","data":[109,121,45,112,110,112,45,104,117,98]},"correlationId":"11ee605b195f","contentType":"application/json-patch+json","contentEncoding":"utf-8"}
This section shows Python examples using the IoT Hub service client and the IoTHubRegistryManager and CloudToDeviceMethod classes. You use the IoTHubRegistryManager class to interact with the device state using device twins. You can also use the IoTHubRegistryManager class to query device registrations in your IoT Hub. You use the CloudToDeviceMethod class to call commands on the device. The DTDL model for the device defines the properties and commands the device implements. In the code snippets, the device_id variable holds the device ID of the IoT Plug and Play device registered with your IoT hub.
Get the device twin and model ID
To get the device twin and model ID of the IoT Plug and Play device that connected to your IoT hub:
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.models import Twin, TwinProperties
iothub_registry_manager = IoTHubRegistryManager(iothub_connection_str)
# ...
twin = iothub_registry_manager.get_twin(device_id)
print("The device twin is: ")
print("")
print(twin)
print("")
additional_props = twin.additional_properties
if "modelId" in additional_props:
print("The Model ID for this device is:")
print(additional_props["modelId"])
print("")
Update device twin
The following code snippet shows how to update the targetTemperature property on a device. The sample shows how you need to get the twin's etag before you update it. The property is defined in the default component of the device:
The following snippet shows how to update the targetTemperature property on a component. The sample shows how you need to get the twin's ETag before you update it. The property is defined in the thermostat1 component:
The following snippet shows how to invoke the getMaxMinReport command defined in a default component:
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.models import CloudToDeviceMethod
# ...
iothub_registry_manager = IoTHubRegistryManager(iothub_connection_str)
method_payload = datetime.datetime.now() - datetime.timedelta(minutes=2)
device_method = CloudToDeviceMethod(method_name="getMaxMinReport", payload=method_payload)
result = iothub_registry_manager.invoke_device_method(device_id, device_method)
print(result.payload)
The following snippet shows how to call the getMaxMinReport command on a component. The command is defined in the thermostat1 component:
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.models import CloudToDeviceMethod
# ...
iothub_registry_manager = IoTHubRegistryManager(iothub_connection_str)
method_payload = datetime.datetime.now() - datetime.timedelta(minutes=2)
device_method = CloudToDeviceMethod(method_name="thermostat1*getMaxMinReport", payload=method_payload)
result = iothub_registry_manager.invoke_device_method(device_id, device_method)
print(result.payload)
IoT Hub digital twin examples
You use the DigitalTwinClient class to interact with the device state using digital twins. The DTDL model for the device defines the properties and commands the device implements.
The device_id variable holds the device ID of the IoT Plug and Play device registered with your IoT hub.
Get the digital twin and model ID
To get the digital twin and model ID of the IoT Plug and Play device that connected to your IoT hub:
The following code snippet shows how to update the targetTemperature property on a device. The property is defined in the default component of the device:
import asyncio
from azure.eventhub import TransportType
from azure.eventhub.aio import EventHubConsumerClient
# Define callbacks to process events
async def on_event_batch(partition_context, events):
for event in events:
print("Received event from partition: {}.".format(partition_context.partition_id))
print("Telemetry received: ", event.body_as_str())
print("Properties (set by device): ", event.properties)
print("System properties (set by IoT Hub): ", event.system_properties)
print()
await partition_context.update_checkpoint()
async def on_error(partition_context, error):
# ...
loop = asyncio.get_event_loop()
client = EventHubConsumerClient.from_connection_string(
conn_str=CONNECTION_STR,
consumer_group="$default",
)
try:
loop.run_until_complete(client.receive_batch(on_event_batch=on_event_batch, on_error=on_error))
except KeyboardInterrupt:
print("Receiving has stopped.")
finally:
loop.run_until_complete(client.close())
loop.stop()
The following output from the previous code shows the temperature telemetry sent by the no-component Thermostat IoT Plug and Play device that only has the default component. The dt-dataschema system property shows the model ID:
Received event from partition: 1.
Telemetry received: {"temperature": 12}
Properties (set by device): None
System properties (set by IoT Hub): {b'content-type': b'application/json', b'content-encoding': b'utf-8', b'iothub-connection-device-id': b'my-pnp-device', b'iothub-connection-auth-method': b'{"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}', b'iothub-connection-auth-generation-id': b'637388855582764406', b'iothub-enqueuedtime': 1603288810715, b'iothub-message-source': b'Telemetry', b'dt-dataschema': b'dtmi:com:example:Thermostat;1', b'x-opt-sequence-number': 13280, b'x-opt-offset': b'12890070640', b'x-opt-enqueued-time': 1603288810824}
The following output from the previous code shows the temperature telemetry sent by the multi-component TemperatureController IoT Plug and Play device. The dt-subject system property shows the name of the component that sent the telemetry. In this example, the two components are thermostat1 and thermostat2 as defined in the DTDL model. The dt-dataschema system property shows the model ID:
Received event from partition: 1.
Telemetry received: {"temperature": 45}
Properties (set by device): None
System properties (set by IoT Hub): {b'content-type': b'application/json', b'content-encoding': b'utf-8', b'iothub-connection-device-id': b'my-pnp-device', b'iothub-connection-auth-method': b'{"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}', b'iothub-connection-auth-generation-id': b'637388858939631652', b'iothub-enqueuedtime': 1603289127844, b'iothub-message-source': b'Telemetry', b'dt-subject': b'thermostat1', b'dt-dataschema': b'dtmi:com:example:TemperatureController;1', b'x-opt-sequence-number': 13328, b'x-opt-offset': b'12890095440', b'x-opt-enqueued-time': 1603289128001}
Received event from partition: 1.
Telemetry received: {"temperature": 49}
Properties (set by device): None
System properties (set by IoT Hub): {b'content-type': b'application/json', b'content-encoding': b'utf-8', b'iothub-connection-device-id': b'my-pnp-device', b'iothub-connection-auth-method': b'{"scope":"device","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}', b'iothub-connection-auth-generation-id': b'637388858939631652', b'iothub-enqueuedtime': 1603289133017, b'iothub-message-source': b'Telemetry', b'dt-subject': b'thermostat2', b'dt-dataschema': b'dtmi:com:example:TemperatureController;1', b'x-opt-sequence-number': 13329, b'x-opt-offset': b'12890095928', b'x-opt-enqueued-time': 1603289133173}
The code shown in the previous Python code snippet generates the following output when IoT Hub generates device twin change notifications for a no-component thermostat device. The application properties iothub-message-schema and opType give you information about the type of change notification:
Received event from partition: 1.
Telemetry received: {"version":3,"properties":{"reported":{"maxTempSinceLastReboot":10.96,"$metadata":{"$lastUpdated":"2020-10-21T14:10:42.4171263Z","maxTempSinceLastReboot":{"$lastUpdated":"2020-10-21T14:10:42.4171263Z"}},"$version":2}}}
Properties (set by device): {b'hubName': b'my-pnp-hub', b'deviceId': b'my-pnp-device', b'operationTimestamp': b'2020-10-21T14:10:42.4171263+00:00', b'iothub-message-schema': b'twinChangeNotification', b'opType': b'updateTwin'}
System properties (set by IoT Hub): {b'user-id': b'my-pnp-hub\x81\x0e\xa4\x7f', b'correlation-id': b'12104ced5402', b'content-type': b'application/json', b'content-encoding': b'utf-8', b'iothub-connection-device-id': b'my-pnp-device', b'iothub-enqueuedtime': 1603289442519, b'iothub-message-source': b'twinChangeEvents', b'x-opt-sequence-number': 13332, b'x-opt-offset': b'12890097392', b'x-opt-enqueued-time': 1603289442738}
The code shown in the previous Python code snippet generates the following output when IoT Hub generates device twin change notifications for a device with components. This example shows the output when a temperature sensor device with a thermostat component generates notifications. The application properties iothub-message-schema and opType give you information about the type of change notification:
Received event from partition: 1.
Telemetry received: {"version":4,"properties":{"reported":{"thermostat1":{"maxTempSinceLastReboot":98.34,"__t":"c"},"$metadata":{"$lastUpdated":"2020-10-21T14:13:39.36491Z","thermostat1":{"$lastUpdated":"2020-10-21T14:13:39.36491Z","maxTempSinceLastReboot":{"$lastUpdated":"2020-10-21T14:13:39.36491Z"},"__t":{"$lastUpdated":"2020-10-21T14:13:39.36491Z"}}},"$version":3}}}
Properties (set by device): {b'hubName': b'my-pnp-hub', b'deviceId': b'my-pnp-device', b'operationTimestamp': b'2020-10-21T14:13:39.3649100+00:00', b'iothub-message-schema': b'twinChangeNotification', b'opType': b'updateTwin'}
System properties (set by IoT Hub): {b'user-id': b'my-pnp-hub', b'correlation-id': b'1210b664ab83', b'content-type': b'application/json', b'content-encoding': b'utf-8', b'iothub-connection-device-id': b'my-pnp-device', b'iothub-enqueuedtime': 1603289619481, b'iothub-message-source': b'twinChangeEvents', b'x-opt-sequence-number': 13341, b'x-opt-offset': b'12890102216', b'x-opt-enqueued-time': 1603289619668}
The code shown in the previous Python code snippet generates the following output when IoT Hub generates digital twin change notifications for a no-component thermostat device. The application properties iothub-message-schema and opType give you information about the type of change notification:
Received event from partition: 1.
Telemetry received: [{"op":"add","path":"/$metadata/maxTempSinceLastReboot","value":{"lastUpdateTime":"2020-10-21T14:10:42.4171263Z"}},{"op":"add","path":"/maxTempSinceLastReboot","value":10.96}]
Properties (set by device): {b'hubName': b'my-pnp-hub', b'deviceId': b'my-pnp-device', b'operationTimestamp': b'2020-10-21T14:10:42.4171263+00:00', b'iothub-message-schema': b'digitalTwinChangeNotification', b'opType': b'updateTwin'}
System properties (set by IoT Hub): {b'user-id': b'my-pnp-hub\x81\x0e\xa4\x7f', b'correlation-id': b'12104ced5402', b'content-type': b'application/json-patch+json', b'content-encoding': b'utf-8', b'iothub-connection-device-id': b'my-pnp-device', b'iothub-enqueuedtime': 1603289442519, b'iothub-message-source': b'digitalTwinChangeEvents', b'x-opt-sequence-number': 13333, b'x-opt-offset': b'12890098024', b'x-opt-enqueued-time': 1603289442738}
The code shown in the previous Python code snippet generates the following output when IoT Hub generates digital twin change notifications for a device with components. This example shows the output when a temperature sensor device with a thermostat component generates notifications. The application properties iothub-message-schema and opType give you information about the type of change notification:
Received event from partition: 1.
Telemetry received: [{"op":"add","path":"/thermostat1","value":{"$metadata":{"maxTempSinceLastReboot":{"lastUpdateTime":"2020-10-21T14:13:39.36491Z"}},"maxTempSinceLastReboot":98.34}}]
Properties (set by device): {b'hubName': b'my-pnp-hub', b'deviceId': b'my-pnp-device', b'operationTimestamp': b'2020-10-21T14:13:39.3649100+00:00', b'iothub-message-schema': b'digitalTwinChangeNotification', b'opType': b'updateTwin'}
System properties (set by IoT Hub): {b'user-id': b'my-pnp-hub', b'correlation-id': b'1210b664ab83', b'content-type': b'application/json-patch+json', b'content-encoding': b'utf-8', b'iothub-connection-device-id': b'my-pnp-device', b'iothub-enqueuedtime': 1603289619481, b'iothub-message-source': b'digitalTwinChangeEvents', b'x-opt-sequence-number': 13342, b'x-opt-offset': b'12890102984', b'x-opt-enqueued-time': 1603289619668}
Next steps
Now that you've learned about device modeling, here are some more resources:
Stream simulated operational telemetry data from physical assets to Azure Digital Twins and visualize data in Unity and mixed reality. Learn how to use an ARM template, create a user interface in Unity, and identify performance events before deploying to a HoloLens 2.