Skip to content

Commit 6f31510

Browse files
authored
Improving P&P facilitating writable property and improving documentation (#25)
1 parent 0979506 commit 6f31510

File tree

5 files changed

+142
-7
lines changed

5 files changed

+142
-7
lines changed

Azure.Devices.DeviceClient/Azure.Devices.DeviceClient.nfproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
<Compile Include="MethodCallback.cs" />
3838
<Compile Include="DeviceClient.cs" />
3939
<Compile Include="Properties\AssemblyInfo.cs" />
40+
<Compile Include="PropertyAcknowledge.cs" />
41+
<Compile Include="PropertyStatus.cs" />
4042
<Compile Include="ProvisioningDeviceClient.cs" />
4143
<Compile Include="ProvisioningRegistrationAdditionalData.cs" />
4244
<Compile Include="ProvisioningRegistrationStatusType.cs" />

Azure.Devices.DeviceClient/DeviceClient.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public bool Open()
156156
if (!string.IsNullOrEmpty(ModelId))
157157
{
158158
userName += $"&model-id={HttpUtility.UrlEncode(ModelId)}";
159-
159+
160160
}
161161

162162
// Now connect the device
@@ -276,9 +276,10 @@ public bool UpdateReportedProperties(TwinCollection reported, CancellationToken
276276
{
277277
cancellationToken.WaitHandle.WaitOne(200, true);
278278
}
279+
280+
_waitForConfirmation.Remove(conf);
279281
}
280282

281-
_waitForConfirmation.Remove(conf);
282283
return conf.Received;
283284
}
284285

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

312-
var rid = _mqttc.Publish(_telemetryTopic, Encoding.UTF8.GetBytes(message), QosLevel, false);
315+
if (!string.IsNullOrEmpty(dtdlComponentname))
316+
{
317+
topic += $"$.sub={dtdlComponentname}";
318+
}
319+
320+
var rid = _mqttc.Publish(topic, Encoding.UTF8.GetBytes(message), QosLevel, false);
321+
ConfirmationStatus conf = new(rid);
313322

314323
if (cancellationToken.CanBeCanceled)
315324
{
316-
ConfirmationStatus conf = new(rid);
325+
317326
_waitForConfirmation.Add(conf);
318327
while (!conf.Received && !cancellationToken.IsCancellationRequested)
319328
{
320329
cancellationToken.WaitHandle.WaitOne(200, true);
321330
}
322331

323332
_waitForConfirmation.Remove(conf);
324-
return conf.Received;
325333
}
326334

327-
return false;
335+
return conf.Received;
328336
}
329337

330338
private void ClientMqttMsgReceived(object sender, MqttMsgPublishEventArgs e)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Collections;
5+
6+
namespace nanoFramework.Azure.Devices.Client
7+
{
8+
/// <summary>
9+
/// Property
10+
/// </summary>
11+
public class PropertyAcknowledge
12+
{
13+
private const string TwinVersion = "av";
14+
private const string TwinDescription = "ad";
15+
private const string TwinStatus = "ac";
16+
private const string TwinValue = "value";
17+
18+
/// <summary>
19+
/// Gets or sets the version.
20+
/// </summary>
21+
public int Version { get; set; }
22+
23+
/// <summary>
24+
/// Gets or sets the Description.
25+
/// </summary>
26+
public string Description { get; set; }
27+
28+
/// <summary>
29+
/// Gets or sets the status;
30+
/// </summary>
31+
public PropertyStatus Status { get; set; }
32+
33+
/// <summary>
34+
/// The value to report.
35+
/// </summary>
36+
public object Value { get; set; }
37+
38+
/// <summary>
39+
/// Bluid the acknowledge to return to IoT plug and play.
40+
/// </summary>
41+
/// <returns>A hashtable that will be serialized.</returns>
42+
public Hashtable BuildAcknowledge()
43+
{
44+
Hashtable toReport = new();
45+
toReport.Add(TwinVersion, Version);
46+
toReport.Add(TwinDescription, Description);
47+
toReport.Add(TwinStatus, Status);
48+
toReport.Add(TwinValue, Value);
49+
return toReport;
50+
}
51+
}
52+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace nanoFramework.Azure.Devices.Client
5+
{
6+
/// <summary>
7+
/// Status code for the Azure Plug and Play reported values.
8+
/// </summary>
9+
public enum PropertyStatus
10+
{
11+
/// <summary>Completed</summary>
12+
Completed = 200,
13+
14+
/// <summary>InProgress</summary>
15+
InProgress = 202,
16+
17+
/// <summary>NotFound</summary>
18+
NotFound = 404,
19+
20+
/// <summary>BadRequest</summary>
21+
BadRequest = 400,
22+
23+
/// <summary>BadRequest</summary>
24+
InternalError = 500
25+
}
26+
}

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,53 @@ DeviceClient azureIoT = new DeviceClient(IotBrokerAddress, DeviceID, SasKey, mod
110110

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

113+
#### Reporting properties
114+
115+
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:
116+
117+
```csharp
118+
const string TargetTemerature = "targetTemperature";
119+
DeviceClient azureIoT = new DeviceClient(Secrets.IotHub, Secrets.DeviceName, Secrets.SasKey, azureCert: new X509Certificate(Resource.GetBytes(Resource.BinaryResources.AzureRoot)), modelId: "dtmi:com:example:Thermostat;1");
120+
azureIoT.TwinUpated += AzureTwinUpdated;
121+
azureIoT.Open();
122+
123+
void AzureTwinUpdated(object sender, TwinUpdateEventArgs e)
124+
{
125+
if (e.Twin.Contains(TargetTemerature))
126+
{
127+
// We got an update for the target temperature
128+
var target = e.Twin[TargetTemerature];
129+
Debug.WriteLine($"Target temperature updated: {target}");
130+
PropertyAcknowledge targetReport = new() { Version = (int)e.Twin.Version, Status = PropertyStatus.Completed, Description = "All perfect", Value = target };
131+
TwinCollection twin = new TwinCollection();
132+
twin.Add(TargetTemerature, targetReport.BuildAcknowledge());
133+
azureIoT.UpdateReportedProperties(twin);
134+
}
135+
}
136+
```
137+
138+
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.
139+
140+
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.
141+
142+
#### Receiving commands
143+
144+
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.
145+
146+
```csharp
147+
DeviceClient azureIoT = new DeviceClient(Secrets.IotHub, Secrets.DeviceName, Secrets.SasKey, azureCert: new X509Certificate(Resource.GetBytes(Resource.BinaryResources.AzureRoot)), modelId: "dtmi:com:example:Thermostat;1");
148+
azureIoT.AddMethodCallback(getMaxMinReport);
149+
azureIoT.Open();
150+
151+
string getMaxMinReport(int rid, string payload)
152+
{
153+
TemperatureReporting reporting = new() { avgTemp = 20, maxTemp = 42, minTemp = 12.34, startTime = DateTime.UtcNow.AddDays(-10), endTime = DateTime.UtcNow };
154+
return JsonConvert.SerializeObject(reporting);
155+
}
156+
```
157+
158+
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.
159+
113160
### Getting and updating Twin
114161

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

0 commit comments

Comments
 (0)