Skip to content

Commit

Permalink
Improving P&P facilitating writable property and improving documentat…
Browse files Browse the repository at this point in the history
…ion (#25)
  • Loading branch information
Ellerbach authored Nov 25, 2021
1 parent 0979506 commit 6f31510
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 7 deletions.
2 changes: 2 additions & 0 deletions Azure.Devices.DeviceClient/Azure.Devices.DeviceClient.nfproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
<Compile Include="MethodCallback.cs" />
<Compile Include="DeviceClient.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyAcknowledge.cs" />
<Compile Include="PropertyStatus.cs" />
<Compile Include="ProvisioningDeviceClient.cs" />
<Compile Include="ProvisioningRegistrationAdditionalData.cs" />
<Compile Include="ProvisioningRegistrationStatusType.cs" />
Expand Down
22 changes: 15 additions & 7 deletions Azure.Devices.DeviceClient/DeviceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public bool Open()
if (!string.IsNullOrEmpty(ModelId))
{
userName += $"&model-id={HttpUtility.UrlEncode(ModelId)}";

}

// Now connect the device
Expand Down Expand Up @@ -276,9 +276,10 @@ public bool UpdateReportedProperties(TwinCollection reported, CancellationToken
{
cancellationToken.WaitHandle.WaitOne(200, true);
}

_waitForConfirmation.Remove(conf);
}

_waitForConfirmation.Remove(conf);
return conf.Received;
}

Expand All @@ -305,26 +306,33 @@ public void RemoveMethodCallback(MethodCallback methodCallback)
/// </summary>
/// <param name="message">The message to send.</param>
/// <param name="cancellationToken">A cancellation token. If you use the default one, the confirmation of delivery will not be awaited.</param>
/// <param name="dtdlComponentname">The DTDL component name.</param>
/// <returns>True for successful message delivery.</returns>
public bool SendMessage(string message, CancellationToken cancellationToken = default)
public bool SendMessage(string message, CancellationToken cancellationToken = default, string dtdlComponentname = "")
{
string topic = _telemetryTopic;

var rid = _mqttc.Publish(_telemetryTopic, Encoding.UTF8.GetBytes(message), QosLevel, false);
if (!string.IsNullOrEmpty(dtdlComponentname))
{
topic += $"$.sub={dtdlComponentname}";
}

var rid = _mqttc.Publish(topic, Encoding.UTF8.GetBytes(message), QosLevel, false);
ConfirmationStatus conf = new(rid);

if (cancellationToken.CanBeCanceled)
{
ConfirmationStatus conf = new(rid);

_waitForConfirmation.Add(conf);
while (!conf.Received && !cancellationToken.IsCancellationRequested)
{
cancellationToken.WaitHandle.WaitOne(200, true);
}

_waitForConfirmation.Remove(conf);
return conf.Received;
}

return false;
return conf.Received;
}

private void ClientMqttMsgReceived(object sender, MqttMsgPublishEventArgs e)
Expand Down
52 changes: 52 additions & 0 deletions Azure.Devices.DeviceClient/PropertyAcknowledge.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections;

namespace nanoFramework.Azure.Devices.Client
{
/// <summary>
/// Property
/// </summary>
public class PropertyAcknowledge
{
private const string TwinVersion = "av";
private const string TwinDescription = "ad";
private const string TwinStatus = "ac";
private const string TwinValue = "value";

/// <summary>
/// Gets or sets the version.
/// </summary>
public int Version { get; set; }

/// <summary>
/// Gets or sets the Description.
/// </summary>
public string Description { get; set; }

/// <summary>
/// Gets or sets the status;
/// </summary>
public PropertyStatus Status { get; set; }

/// <summary>
/// The value to report.
/// </summary>
public object Value { get; set; }

/// <summary>
/// Bluid the acknowledge to return to IoT plug and play.
/// </summary>
/// <returns>A hashtable that will be serialized.</returns>
public Hashtable BuildAcknowledge()
{
Hashtable toReport = new();
toReport.Add(TwinVersion, Version);
toReport.Add(TwinDescription, Description);
toReport.Add(TwinStatus, Status);
toReport.Add(TwinValue, Value);
return toReport;
}
}
}
26 changes: 26 additions & 0 deletions Azure.Devices.DeviceClient/PropertyStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace nanoFramework.Azure.Devices.Client
{
/// <summary>
/// Status code for the Azure Plug and Play reported values.
/// </summary>
public enum PropertyStatus
{
/// <summary>Completed</summary>
Completed = 200,

/// <summary>InProgress</summary>
InProgress = 202,

/// <summary>NotFound</summary>
NotFound = 404,

/// <summary>BadRequest</summary>
BadRequest = 400,

/// <summary>BadRequest</summary>
InternalError = 500
}
}
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,53 @@ DeviceClient azureIoT = new DeviceClient(IotBrokerAddress, DeviceID, SasKey, mod

Note: the model ID has to be passed at the creation of the DeviceClient, it is not possible to pass it later on.

#### Reporting properties

Reporting Plug & Play properties is supported. He is a comprehensive example and how you can check if you have received one property that you're interested in:

```csharp
const string TargetTemerature = "targetTemperature";
DeviceClient azureIoT = new DeviceClient(Secrets.IotHub, Secrets.DeviceName, Secrets.SasKey, azureCert: new X509Certificate(Resource.GetBytes(Resource.BinaryResources.AzureRoot)), modelId: "dtmi:com:example:Thermostat;1");
azureIoT.TwinUpated += AzureTwinUpdated;
azureIoT.Open();

void AzureTwinUpdated(object sender, TwinUpdateEventArgs e)
{
if (e.Twin.Contains(TargetTemerature))
{
// We got an update for the target temperature
var target = e.Twin[TargetTemerature];
Debug.WriteLine($"Target temperature updated: {target}");
PropertyAcknowledge targetReport = new() { Version = (int)e.Twin.Version, Status = PropertyStatus.Completed, Description = "All perfect", Value = target };
TwinCollection twin = new TwinCollection();
twin.Add(TargetTemerature, targetReport.BuildAcknowledge());
azureIoT.UpdateReportedProperties(twin);
}
}
```

In this example, the property we are interested in to receive is called `targetTemperature`. To receive its update, we are subscribing to the twin update. And we can get the value thu the `e.Twin[TargetTemerature]` once we've checked that the property exist.

The patter to publish a writable property is then quite simple. it's about building a `PropertyAcknowledge`, creating a TwinCollection, adding it to it with the property name, here our `targetTemperature`. You can add more properties to report of course. Note that what you add to the TwinCollection is not directly the object but `BuildAcknowledge()`. One done, just ask the library to update the twin through the `UpdateReportedProperties` method.

#### Receiving commands

An IoT Plug & Play command is a method callback. See further in this document how you can use them. In our case, the method is called `getMaxMinReport`. The name of the method in C# **must** be the exact same as the name from the DTDL file.

```csharp
DeviceClient azureIoT = new DeviceClient(Secrets.IotHub, Secrets.DeviceName, Secrets.SasKey, azureCert: new X509Certificate(Resource.GetBytes(Resource.BinaryResources.AzureRoot)), modelId: "dtmi:com:example:Thermostat;1");
azureIoT.AddMethodCallback(getMaxMinReport);
azureIoT.Open();

string getMaxMinReport(int rid, string payload)
{
TemperatureReporting reporting = new() { avgTemp = 20, maxTemp = 42, minTemp = 12.34, startTime = DateTime.UtcNow.AddDays(-10), endTime = DateTime.UtcNow };
return JsonConvert.SerializeObject(reporting);
}
```

In this example, the expected result is an object. Just populate the object and serialize it as a json as the command expect and return it. If any parameter to this command, it will be in the payload.

### Getting and updating Twin

You can request your Azure IoT Twin simply by calling the `GetTwin` function.
Expand Down

0 comments on commit 6f31510

Please sign in to comment.