This article is contributed. See the original author and article here.

We just added new APIs in preview in the Azure IoT SDK for C# that will make it easier for device developers to implement IoT Plug and Play, and we’d love to have your feedback.  


Since we released IoT Plug and Play back in September 2020, we provided the PnP-specific helpers functions in the form of samples to help demonstrate the PnP convention eg. how to format PnP telemetry message, how to ack on properties updates, etc. 


As IoT Plug and Play is becoming the “new normal” for connecting devices to Azure IoT, it is important that there is a solid set of APIs in the C# client SDK to help you efficiently implement IoT Plug and Play in your devices. PnP models expose components, telemetry, commands, and properties. These new APIs format and send messages for telemetry and property updates. They can also help the client receive and ack writable property update requests and incoming command invocations. 


These additions to the C# SDK can become the foundation of your solution, taking the load off your plate when it comes to formatting data and making your devices future proof. We introduced these functions in preview for now, so you can test them in your scenarios and give us feedback on the design.. As long we are in preview, it is easy to change these APIs, so it is the right time to give it a try and let us know if that fits your needs or if you see some improvements. 


The NuGet package can be found here: https://www.nuget.org/packages/Microsoft.Azure.Devices.Client/1.38.0-preview-001 


 


We have created a couple of samples to help you get started with these new APIs, have a look at: 


https://github.com/Azure/azure-iot-sdk-csharp/blob/preview/iothub/device/samples/convention-based-samples/readme.md 


 


In these new APIs, we introduced a couple of new types to help with convention operations. For telemetry, we expose TelemetryMessage that simplifies message formatting for the telemetry: 


 

// Send telemetry "serialNumber".
string serialNumber = "SR-1234";
using var telemetryMessage = new TelemetryMessage
{
    MessageId = Guid.NewGuid().ToString(),
    Telemetry = { ["serialNumber"] = serialNumber },
};
await _deviceClient.SendTelemetryAsync(telemetryMessage, cancellationToken);

 


and in the case you use a component (here thermostat1) you can prepare the telemetry message this way: 


 

using var telemetryMessage = new TelemetryMessage("thermostat1")
{
    MessageId = Guid.NewGuid().ToString(),
    Telemetry = { ["serialNumber"] = serialNumber },
};
await _deviceClient.SendTelemetryAsync(telemetryMessage, cancellationToken);

 


For properties, we introduced the type ClientProperties which exposes the method TryGetValue.  
With this new type, accessing a device twin property becomes: 


 

// Retrieve the client's properties.
 ClientProperties properties = await _deviceClient.GetClientPropertiesAsync(cancellationToken);

// To fetch the value of client reported property "serialNumber" under component "thermostat1".
bool isSerialNumberReported = properties.TryGetValue("thermostat1", "serialNumber", out string serialNumberReported);

// To fetch the value of service requested "targetTemperature" value under component "thermostat1".
bool isTargetTemperatureUpdateRequested = properties.Writable.TryGetValue("thermostat1", "targetTemperature", out double targetTemperatureUpdateRequest);

 


Note that in that case, we have a component named thermostat1, first we get the serialNumber and second for a writable property, we use properties.Writable. 


Same pattern for reporting properties, we have now the ClientPropertyCollection, that helps to update properties by batch, as we have here a collection and exposing the method AddComponentProperty: 


 

// Update the property "serialNumber" under component "thermostat1".
var propertiesToBeUpdated = new ClientPropertyCollection();
propertiesToBeUpdated.AddComponentProperty("thermostat1", "serialNumber", "SR-1234");

ClientPropertiesUpdateResponse updateResponse = await _deviceClient
    .UpdateClientPropertiesAsync(propertiesToBeUpdated, cancellationToken);
long updatedVersion = updateResponse.Version;

 


With this, it became much easier to Respond to top-level property update requests even for a component model:


 

await _deviceClient.SubscribeToWritablePropertiesEventAsync(
    async (writableProperties, userContext) =>
    {
        if (writableProperties.TryGetValue("thermostat1", "targetTemperature", out double targetTemperature))
        {
            IWritablePropertyResponse writableResponse = _deviceClient
                .PayloadConvention
                .PayloadSerializer
                .CreateWritablePropertyResponse(targetTemperature, CommonClientResponseCodes.OK, writableProperties.Version, "The operation completed successfully.");

            var propertiesToBeUpdated = new ClientPropertyCollection();
            propertiesToBeUpdated.AddComponentProperty("thermostat1", "targetTemperature", writableResponse);

            ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(propertiesToBeUpdated, cancellationToken);
        }

 


As long as we stay in preview for these APIs, you‘ll find the set of usual PnP samples, migrated to use these news APIs in the code repository, in the preview branch: 


https://github.com/Azure/azure-iot-sdk-csharp/tree/preview/iothub/device/samples/convention-based-samples 


See project Thermostat for the non-component sample and TemperatureController for the component sample. 


 


Again, it is the right time to let us know any feedback and comments on these APIs. Contact us, open an issue, and help us providing the right PnP API you need. 


 


Happy testing, 


Eric for the Azure IoT Managed SDK team 


 


 

Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.