Tutorial: Connect an IoT Plug and Play module (C#)
This tutorial shows you how to connect a generic IoT Plug and Play module.
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.
A device is an IoT Plug and Play device if it:
- Publishes its model ID when it connects to an IoT hub.
- Implements the properties and methods described in the Digital Twins Definition Language (DTDL) model identified by the model ID.
To learn more about how devices use a DTDL and model ID, see IoT Plug and Play developer guide. Modules use model IDs and DTDL models in the same way.
To demonstrate how to implement an IoT Plug and Play module, this tutorial shows you how to:
- Add a device with a module to your IoT hub.
- Convert the thermostat C# device sample into a generic module.
- Use the service SDK to interact with the module.
Prerequisites
Before you continue, make sure you've set up your environment, including your IoT hub.
To complete this tutorial, install the following software in your local development environment:
- Install the latest .NET for your operating system from https://dot.net.
- Git.
Use the Azure IoT explorer tool to add a new device called my-module-device to your IoT hub.
Add a module called my-module to the my-module-device:
In the Azure IoT explorer tool, navigate to the my-module-device device.
Select Module identity, and then select + Add.
Enter my-module as the module identity name and select Save.
In the list of module identities, select my-module. Then copy the primary connection string. You use this module connection string later in this tutorial.
Select the Module twin tab and notice that there are no desired or reported properties:
{ "deviceId": "my-module-device", "moduleId": "my-module", "etag": "AAAAAAAAAAE=", "deviceEtag": "NjgzMzQ1MzQ1", "status": "enabled", "statusUpdateTime": "0001-01-01T00:00:00Z", "connectionState": "Disconnected", "lastActivityTime": "0001-01-01T00:00:00Z", "cloudToDeviceMessageCount": 0, "authenticationType": "sas", "x509Thumbprint": { "primaryThumbprint": null, "secondaryThumbprint": null }, "modelId": "", "version": 2, "properties": { "desired": { "$metadata": { "$lastUpdated": "0001-01-01T00:00:00Z" }, "$version": 1 }, "reported": { "$metadata": { "$lastUpdated": "0001-01-01T00:00:00Z" }, "$version": 1 } } }
Download the code
If you haven't already done so, clone the Azure IoT Hub Device C# SDK GitHub repository to your local machine:
Open a command prompt in a folder of your choice. Use the following command to clone the Azure IoT C# SDK GitHub repository into this location:
git clone https://github.com/Azure/azure-iot-sdk-csharp.git
Prepare the project
To open and prepare the sample project:
Navigate to the azure-iot-sdk-csharp/iothub/device/samples/solutions/PnpDeviceSamples/Thermostat folder.
Add the following environment variables to your shell environment:
Name Value IOTHUB_DEVICE_SECURITY_TYPE connectionString IOTHUB_MODULE_CONNECTION_STRING The module connection string you made a note of previously To learn more about the sample configuration, see the sample readme.
Modify the code
To modify the code to work as a module instead of a device:
In your text editor or IDE, open Parameter.cs and modify the line that sets the PrimaryConnectionString variable as follows:
public string PrimaryConnectionString { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_MODULE_CONNECTION_STRING");
In your text editor or IDE, open Program.cs and replace the nine instances of the
DeviceClient
class with theModuleClient
class.Tip
Use the Visual Studio search and replace feature with Match case and Match whole word enabled to replace
DeviceClient
withModuleClient
.In your text editor or IDE, open Thermostat.cs and replace both instances of the
DeviceClient
class with theModuleClient
class.Save the changes to the files you modified.
To run the sample in your shell environment, make sure you're in the azure-iot-sdk-csharp/iothub/device/samples/solutions/PnpDeviceSamples/Thermostat folder and that the environment variables are set. Then run:
dotnet build dotnet run
If you run the code and then use the Azure IoT explorer to view the updated module twin, you see the updated device twin with the model ID and module reported property:
{
"deviceId": "my-module-device",
"moduleId": "my-module",
"etag": "AAAAAAAAAAE=",
"deviceEtag": "MTk0ODMyMjI4",
"status": "enabled",
"statusUpdateTime": "0001-01-01T00:00:00Z",
"connectionState": "Connected",
"lastActivityTime": "2022-11-16T13:56:43.1711257Z",
"cloudToDeviceMessageCount": 0,
"authenticationType": "sas",
"x509Thumbprint": {
"primaryThumbprint": null,
"secondaryThumbprint": null
},
"modelId": "dtmi:com:example:Thermostat;1",
"version": 5,
"properties": {
"desired": {
"$metadata": {
"$lastUpdated": "0001-01-01T00:00:00Z"
},
"$version": 1
},
"reported": {
"targetTemperature": {
"value": 0,
"ac": 203,
"av": 0,
"ad": "Initialized with default value"
},
"maxTempSinceLastReboot": 23.4,
"$metadata": {
"$lastUpdated": "2022-11-16T14:06:59.4376422Z",
"targetTemperature": {
"$lastUpdated": "2022-11-16T13:55:55.6688872Z",
"value": {
"$lastUpdated": "2022-11-16T13:55:55.6688872Z"
},
"ac": {
"$lastUpdated": "2022-11-16T13:55:55.6688872Z"
},
"av": {
"$lastUpdated": "2022-11-16T13:55:55.6688872Z"
},
"ad": {
"$lastUpdated": "2022-11-16T13:55:55.6688872Z"
}
},
"maxTempSinceLastReboot": {
"$lastUpdated": "2022-11-16T14:06:59.4376422Z"
}
},
"$version": 2
}
}
}
Interact with a device module
The service SDKs let you retrieve the model ID of connected IoT Plug and Play devices and modules. You can use the service SDKs to set writable properties and call commands:
In another shell environment, navigate to the azure-iot-sdk-csharp\iothub\service\samples\solutions\PnpServiceSamples\Thermostat folder.
Add the following environment variables to your shell environment:
Name Value IOTHUB_DEVICE_ID my-module-device IOTHUB_CONNECTION_STRING The value you made a note of when you completed Set up your environment Tip
You can also find your IoT hub connection string in the Azure IoT explorer tool.
In your text editor or IDE, open the ThermostatSample.cs file and modify the line that calls a command as follows:
CloudToDeviceMethodResult result = await _serviceClient.InvokeDeviceMethodAsync(_deviceId, "my-module", commandInvocation);
In the ThermostatSample.cs file, modify the line that retrieves the device twin as follows:
Twin twin = await s_registryManager.GetTwinAsync(s_deviceId, "my-module");
Save your changes.
Make sure the module client sample is still running, and then run this service sample:
dotnet build dotnet run
The output from the service sample shows the model ID from the device twin and the command call:
[11/16/2022 14:27:56]dbug: Microsoft.Azure.Devices.Samples.ThermostatSample[0]
Get the my-module-device device twin.
...
[11/16/2022 14:27:58]dbug: Microsoft.Azure.Devices.Samples.ThermostatSample[0]
The my-module-device device twin has a model with ID dtmi:com:example:Thermostat;1.
[11/16/2022 14:27:58]dbug: Microsoft.Azure.Devices.Samples.ThermostatSample[0]
Update the targetTemperature property on the my-module-device device twin to 44.
[11/16/2022 14:27:58]dbug: Microsoft.Azure.Devices.Samples.ThermostatSample[0]
Get the my-module-device device twin.
...
[11/16/2022 14:27:58]dbug: Microsoft.Azure.Devices.Samples.ThermostatSample[0]
Invoke the getMaxMinReport command on my-module-device device twin.
[11/16/2022 14:27:59]dbug: Microsoft.Azure.Devices.Samples.ThermostatSample[0]
Command getMaxMinReport was invoked on device twin my-module-device.
Device returned status: 200.
Report: {"maxTemp":23.4,"minTemp":23.4,"avgTemp":23.39999999999999,"startTime":"2022-11-16T14:26:00.7446533+00:00","endTime":"2022-11-16T14:27:54.3102604+00:00"}
The output from the module client shows the command handler's response:
[11/16/2022 14:27:59]Microsoft.Azure.Devices.Client.Samples.ThermostatSample[0] Command: Received - Generating max, min and avg temperature report since 16/11/2022 14:25:58.
[11/16/2022 14:27:59]Microsoft.Azure.Devices.Client.Samples.ThermostatSample[0] Command: MaxMinReport since 16/11/2022 14:25:58: maxTemp=23.4, minTemp=23.4, avgTemp=23.39999999999999, startTime=16/11/2022 14:26:00, endTime=16/11/2022 14:27:54
Convert to an IoT Edge module
To convert this sample to work as an IoT Plug and Play IoT Edge module, you must containerize the application. You don't need to make any further code changes. The connection string environment variable is injected by the IoT Edge runtime at startup. To learn more, see Use Visual Studio 2019 to develop and debug modules for Azure IoT Edge.
To learn how to deploy your containerized module, see:
- Run Azure IoT Edge on Ubuntu Virtual Machines.
- Install the Azure IoT Edge runtime on Debian-based Linux systems.
You can use the Azure IoT Explorer tool to see:
- The model ID of your IoT Edge device in the module twin.
- Telemetry from the IoT Edge device.
- IoT Edge module twin property updates triggering IoT Plug and Play notifications.
- The IoT Edge module reacts to your IoT Plug and Play commands.
Clean up resources
If you plan to continue with more device developer articles, you can keep and reuse the resources you used in this article. Otherwise, you can delete the resources you created in this article to avoid more charges.
You can delete both the hub and registered device at once by deleting the entire resource group with the following Azure CLI command. Don't use this command if these resources are sharing a resource group with other resources you want to keep.
az group delete --name <YourResourceGroupName>
To delete just the IoT hub, run the following command using Azure CLI:
az iot hub delete --name <YourIoTHubName>
To delete just the device identity you registered with your IoT hub, run the following command using Azure CLI:
az iot hub device-identity delete --hub-name <YourIoTHubName> --device-id <YourDeviceID>
You may also want to remove the cloned sample files from your development machine.
Next steps
In this tutorial, you've learned how to connect an IoT Plug and Play device with modules to an IoT hub. To learn more about IoT Plug and Play device models, see: