Skip to content

Commit b090cad

Browse files
authored
Adding Device Provisioning Service in Azure IoT SDK
1 parent 8a126e8 commit b090cad

12 files changed

+788
-38
lines changed

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,19 @@
3030
<ItemGroup>
3131
<Compile Include="CloudToDeviceMessage.cs" />
3232
<Compile Include="ConfirmationStatus.cs" />
33+
<Compile Include="DeviceRegistrationResult.cs" />
34+
<Compile Include="Helper.cs" />
3335
<Compile Include="HMACSHA256.cs" />
3436
<Compile Include="IoTHubStatus.cs" />
3537
<Compile Include="MethodCalback.cs" />
3638
<Compile Include="DeviceClient.cs" />
3739
<Compile Include="Properties\AssemblyInfo.cs" />
40+
<Compile Include="ProvisioningDeviceClient.cs" />
41+
<Compile Include="ProvisioningRegistrationAdditionalData.cs" />
42+
<Compile Include="ProvisioningRegistrationStatusType.cs" />
43+
<Compile Include="ProvisioningRegistrationSubstatusType.cs" />
44+
<Compile Include="RegistrationOperationStatus.cs" />
45+
<Compile Include="RegistrationState.cs" />
3846
<Compile Include="Status.cs" />
3947
<Compile Include="StatusUpdatedEventArgs.cs" />
4048
<Compile Include="Twin.cs" />
@@ -46,8 +54,8 @@
4654
<None Include="packages.config" />
4755
</ItemGroup>
4856
<ItemGroup>
49-
<Reference Include="mscorlib, Version=1.10.5.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
50-
<HintPath>..\packages\nanoFramework.CoreLibrary.1.10.5-preview.18\lib\mscorlib.dll</HintPath>
57+
<Reference Include="mscorlib, Version=1.10.5.4, Culture=neutral, PublicKeyToken=c07d481e9758c731">
58+
<HintPath>..\packages\nanoFramework.CoreLibrary.1.10.5\lib\mscorlib.dll</HintPath>
5159
<Private>True</Private>
5260
<SpecificVersion>True</SpecificVersion>
5361
</Reference>

Azure.Devices.DeviceClient/DeviceClient.cs

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,21 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using nanoFramework.Azure.Devices.Shared;
5+
using nanoFramework.M2Mqtt;
6+
using nanoFramework.M2Mqtt.Messages;
57
using System;
68
using System.Collections;
79
using System.Diagnostics;
8-
using System.Security.Cryptography;
910
using System.Security.Cryptography.X509Certificates;
1011
using System.Text;
1112
using System.Threading;
12-
using System.Web;
13-
using nanoFramework.M2Mqtt;
14-
using nanoFramework.M2Mqtt.Messages;
1513

1614
namespace nanoFramework.Azure.Devices.Client
1715
{
1816
/// <summary>
1917
/// Azure IoT Client SDK for .NET nanoFramework using MQTT
2018
/// </summary>
21-
public class DeviceClient
22-
19+
public class DeviceClient : IDisposable
2320
{
2421
const string TwinReportedPropertiesTopic = "$iothub/twin/PATCH/properties/reported/";
2522
const string TwinDesiredPropertiesTopic = "$iothub/twin/GET/";
@@ -146,7 +143,7 @@ public bool Open()
146143
_mqttc.ConnectionClosed += ClientConnectionClosed;
147144

148145
// Now connect the device
149-
string key = _clientCert == null ? GetSharedAccessSignature(null, _sasKey, $"{_iotHubName}/devices/{_deviceId}", new TimeSpan(24, 0, 0)) : _privateKey;
146+
string key = _clientCert == null ? Helper.GetSharedAccessSignature(null, _sasKey, $"{_iotHubName}/devices/{_deviceId}", new TimeSpan(24, 0, 0)) : _privateKey;
150147
_mqttc.Connect(
151148
_deviceId,
152149
$"{_iotHubName}/{_deviceId}/api-version=2020-09-30",
@@ -473,37 +470,26 @@ private void ClientConnectionClosed(object sender, EventArgs e)
473470
StatusUpdated?.Invoke(this, new StatusUpdatedEventArgs(_ioTHubStatus));
474471
}
475472

476-
private string GetSharedAccessSignature(string keyName, string sharedAccessKey, string resource, TimeSpan tokenTimeToLive)
473+
/// <inheritdoc/>
474+
public void Dispose()
477475
{
478-
// http://msdn.microsoft.com/en-us/library/azure/dn170477.aspx
479-
// the canonical Uri scheme is http because the token is not amqp specific
480-
// signature is computed from joined encoded request Uri string and expiry string
481-
482-
var exp = DateTime.UtcNow.ToUnixTimeSeconds() + (long)tokenTimeToLive.TotalSeconds;
483-
484-
string expiry = exp.ToString();
485-
string encodedUri = HttpUtility.UrlEncode(resource);
476+
if (_mqttc != null)
477+
{
478+
// Making sure we unregister to events
479+
_mqttc.MqttMsgPublishReceived -= ClientMqttMsgReceived;
480+
_mqttc.MqttMsgPublished -= ClientMqttMsgPublished;
481+
_mqttc.ConnectionClosed -= ClientConnectionClosed;
482+
// Closing and waiting for the connection to be properly closed
483+
Close();
484+
while (_mqttc.IsConnected)
485+
{
486+
Thread.Sleep(100);
486487

487-
var hmacsha256 = new HMACSHA256(Convert.FromBase64String(sharedAccessKey));
488-
byte[] hmac = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(encodedUri + "\n" + expiry));
489-
string sig = Convert.ToBase64String(hmac);
488+
}
490489

491-
if (keyName != null)
492-
{
493-
return String.Format(
494-
"SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
495-
encodedUri,
496-
HttpUtility.UrlEncode(sig),
497-
HttpUtility.UrlEncode(expiry),
498-
HttpUtility.UrlEncode(keyName));
499-
}
500-
else
501-
{
502-
return String.Format(
503-
"SharedAccessSignature sr={0}&sig={1}&se={2}",
504-
encodedUri,
505-
HttpUtility.UrlEncode(sig),
506-
HttpUtility.UrlEncode(expiry));
490+
// Cleaning
491+
GC.SuppressFinalize(_mqttc);
492+
_mqttc = null;
507493
}
508494
}
509495
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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;
5+
6+
namespace nanoFramework.Azure.Devices.Provisioning.Client
7+
{
8+
/// <summary>
9+
/// The result of a registration operation.
10+
/// </summary>
11+
public class DeviceRegistrationResult
12+
{
13+
/// <summary>
14+
/// Used internally by the SDK to create a new instance of the DeviceRegistrationResult class.
15+
/// This constructor is exposed to allow serialization and unit testing of applications using this SDK.
16+
/// </summary>
17+
public DeviceRegistrationResult(
18+
string registrationId,
19+
DateTime createdDateTimeUtc,
20+
string assignedHub,
21+
string deviceId,
22+
ProvisioningRegistrationStatusType status,
23+
string generationId,
24+
DateTime lastUpdatedDateTimeUtc,
25+
int errorCode,
26+
string errorMessage,
27+
string etag) : this(registrationId, createdDateTimeUtc, assignedHub, deviceId, status, ProvisioningRegistrationSubstatusType.InitialAssignment, generationId, lastUpdatedDateTimeUtc, errorCode, errorMessage, etag)
28+
{
29+
}
30+
31+
/// <summary>
32+
/// Used internally by the SDK to create a new instance of the DeviceRegistrationResult class.
33+
/// This constructor is exposed to allow serialization and unit testing of applications using this SDK.
34+
/// </summary>
35+
public DeviceRegistrationResult(
36+
string registrationId,
37+
DateTime createdDateTimeUtc,
38+
string assignedHub,
39+
string deviceId,
40+
ProvisioningRegistrationStatusType status,
41+
ProvisioningRegistrationSubstatusType substatus,
42+
string generationId,
43+
DateTime lastUpdatedDateTimeUtc,
44+
int errorCode,
45+
string errorMessage,
46+
string etag)
47+
{
48+
RegistrationId = registrationId;
49+
CreatedDateTimeUtc = createdDateTimeUtc;
50+
AssignedHub = assignedHub;
51+
DeviceId = deviceId;
52+
Status = status;
53+
Substatus = substatus;
54+
GenerationId = generationId;
55+
LastUpdatedDateTimeUtc = lastUpdatedDateTimeUtc;
56+
ErrorCode = errorCode;
57+
ErrorMessage = errorMessage;
58+
Etag = etag;
59+
}
60+
61+
/// <summary>
62+
///. Constructor to allow return data
63+
/// </summary>
64+
public DeviceRegistrationResult(
65+
string registrationId,
66+
DateTime createdDateTimeUtc,
67+
string assignedHub,
68+
string deviceId,
69+
ProvisioningRegistrationStatusType status,
70+
ProvisioningRegistrationSubstatusType substatus,
71+
string generationId,
72+
DateTime lastUpdatedDateTimeUtc,
73+
int errorCode,
74+
string errorMessage,
75+
string etag,
76+
string returnData)
77+
{
78+
RegistrationId = registrationId;
79+
CreatedDateTimeUtc = createdDateTimeUtc;
80+
AssignedHub = assignedHub;
81+
DeviceId = deviceId;
82+
Status = status;
83+
Substatus = substatus;
84+
GenerationId = generationId;
85+
LastUpdatedDateTimeUtc = lastUpdatedDateTimeUtc;
86+
ErrorCode = errorCode;
87+
ErrorMessage = errorMessage;
88+
Etag = etag;
89+
JsonPayload = returnData;
90+
}
91+
92+
/// <summary>
93+
/// The registration id.
94+
/// </summary>
95+
public string RegistrationId { get; protected set; }
96+
97+
/// <summary>
98+
/// The time when the device originally registered with the service.
99+
/// </summary>
100+
public DateTime CreatedDateTimeUtc { get; protected set; }
101+
102+
/// <summary>
103+
/// The assigned Azure IoT Hub.
104+
/// </summary>
105+
public string AssignedHub { get; protected set; }
106+
107+
/// <summary>
108+
/// The Device Id.
109+
/// </summary>
110+
public string DeviceId { get; protected set; }
111+
112+
/// <summary>
113+
/// The status of the operation.
114+
/// </summary>
115+
public ProvisioningRegistrationStatusType Status { get; protected set; }
116+
117+
/// <summary>
118+
/// The substatus of the operation.
119+
/// </summary>
120+
public ProvisioningRegistrationSubstatusType Substatus { get; protected set; }
121+
122+
/// <summary>
123+
/// The generation Id.
124+
/// </summary>
125+
public string GenerationId { get; protected set; }
126+
127+
/// <summary>
128+
/// The time when the device last refreshed the registration.
129+
/// </summary>
130+
public DateTime LastUpdatedDateTimeUtc { get; protected set; }
131+
132+
/// <summary>
133+
/// Error code.
134+
/// </summary>
135+
public int ErrorCode { get; protected set; }
136+
137+
/// <summary>
138+
/// Error message.
139+
/// </summary>
140+
public string ErrorMessage { get; protected set; }
141+
142+
/// <summary>
143+
/// The Etag.
144+
/// </summary>
145+
public string Etag { get; protected set; }
146+
147+
/// <summary>
148+
/// The Custom data returned from the webhook to the device.
149+
/// </summary>
150+
public string JsonPayload { get; private set; }
151+
}
152+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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;
5+
using System.Security.Cryptography;
6+
using System.Text;
7+
using System.Web;
8+
9+
namespace nanoFramework.Azure.Devices
10+
{
11+
internal static class Helper
12+
{
13+
public static string GetSharedAccessSignature(string keyName, string sharedAccessKey, string resource, TimeSpan tokenTimeToLive)
14+
{
15+
// http://msdn.microsoft.com/en-us/library/azure/dn170477.aspx
16+
// the canonical Uri scheme is http because the token is not amqp specific
17+
// signature is computed from joined encoded request Uri string and expiry string
18+
19+
var exp = DateTime.UtcNow.ToUnixTimeSeconds() + (long)tokenTimeToLive.TotalSeconds;
20+
21+
string expiry = exp.ToString();
22+
string encodedUri = HttpUtility.UrlEncode(resource);
23+
24+
var hmacsha256 = new HMACSHA256(Convert.FromBase64String(sharedAccessKey));
25+
byte[] hmac = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(encodedUri + "\n" + expiry));
26+
string sig = Convert.ToBase64String(hmac);
27+
28+
if (keyName != null)
29+
{
30+
return String.Format(
31+
"SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
32+
encodedUri,
33+
HttpUtility.UrlEncode(sig),
34+
HttpUtility.UrlEncode(expiry),
35+
HttpUtility.UrlEncode(keyName));
36+
}
37+
else
38+
{
39+
return String.Format(
40+
"SharedAccessSignature sr={0}&sig={1}&se={2}",
41+
encodedUri,
42+
HttpUtility.UrlEncode(sig),
43+
HttpUtility.UrlEncode(expiry));
44+
}
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)