1010using System . Text ;
1111using System . Threading ;
1212using System . Web ;
13- using uPLibrary . Networking . M2Mqtt ;
14- using uPLibrary . Networking . M2Mqtt . Messages ;
13+ using nanoFramework . M2Mqtt ;
14+ using nanoFramework . M2Mqtt . Messages ;
1515
1616namespace nanoFramework . Azure . Devices . Client
1717{
@@ -40,6 +40,7 @@ public class DeviceClient
4040 private readonly ArrayList _waitForConfirmation = new ArrayList ( ) ;
4141 private readonly object _lock = new object ( ) ;
4242 private Timer _timerTokenRenew ;
43+ private readonly X509Certificate _azureRootCACert ;
4344
4445 /// <summary>
4546 /// Device twin updated event.
@@ -63,7 +64,8 @@ public class DeviceClient
6364 /// <param name="deviceId">The device ID which is the name of your device.</param>
6465 /// <param name="sasKey">One of the SAS Key either primary, either secondary.</param>
6566 /// <param name="qosLevel">The default quality level delivery for the MQTT messages, default to the lower quality</param>
66- public DeviceClient ( string iotHubName , string deviceId , string sasKey , byte qosLevel = MqttMsgBase . QOS_LEVEL_AT_MOST_ONCE )
67+ /// <param name="azureCert">Azure certificate for the connection to Azure IoT Hub</param>
68+ public DeviceClient ( string iotHubName , string deviceId , string sasKey , MqttQoSLevel qosLevel = MqttQoSLevel . AtMostOnce , X509Certificate azureCert = null )
6769 {
6870 _clientCert = null ;
6971 _privateKey = null ;
@@ -75,6 +77,7 @@ public DeviceClient(string iotHubName, string deviceId, string sasKey, byte qosL
7577 _ioTHubStatus . Message = string . Empty ;
7678 _deviceMessageTopic = $ "devices/{ _deviceId } /messages/devicebound/";
7779 QosLevel = qosLevel ;
80+ _azureRootCACert = azureCert ;
7881 }
7982
8083 /// <summary>
@@ -84,7 +87,8 @@ public DeviceClient(string iotHubName, string deviceId, string sasKey, byte qosL
8487 /// <param name="deviceId">The device ID which is the name of your device.</param>
8588 /// <param name="clientCert">The certificate to connect the device containing both public and private key.</param>
8689 /// <param name="qosLevel">The default quality level delivery for the MQTT messages, default to the lower quality</param>
87- public DeviceClient ( string iotHubName , string deviceId , X509Certificate2 clientCert , byte qosLevel = MqttMsgBase . QOS_LEVEL_AT_MOST_ONCE )
90+ /// /// <param name="azureCert">Azure certificate for the connection to Azure IoT Hub</param>
91+ public DeviceClient ( string iotHubName , string deviceId , X509Certificate2 clientCert , MqttQoSLevel qosLevel = MqttQoSLevel . AtMostOnce , X509Certificate azureCert = null )
8892 {
8993 _clientCert = clientCert ;
9094 _privateKey = Convert . ToBase64String ( clientCert . PrivateKey ) ;
@@ -96,6 +100,7 @@ public DeviceClient(string iotHubName, string deviceId, X509Certificate2 clientC
96100 _ioTHubStatus . Message = string . Empty ;
97101 _deviceMessageTopic = $ "devices/{ _deviceId } /messages/devicebound/";
98102 QosLevel = qosLevel ;
103+ _azureRootCACert = azureCert ;
99104 }
100105
101106 /// <summary>
@@ -111,7 +116,7 @@ public DeviceClient(string iotHubName, string deviceId, X509Certificate2 clientC
111116 /// <summary>
112117 /// The default level quality.
113118 /// </summary>
114- public byte QosLevel { get ; set ; }
119+ public MqttQoSLevel QosLevel { get ; set ; }
115120
116121 /// <summary>
117122 /// True if the device connected
@@ -124,18 +129,12 @@ public DeviceClient(string iotHubName, string deviceId, X509Certificate2 clientC
124129 /// <returns></returns>
125130 public bool Open ( )
126131 {
127- // nanoFramework socket implementation requires a valid root CA to authenticate with.
128- // This can be supplied to the caller (as it's doing on the code bellow) or the Root CA has to be stored in the certificate store
129- // Root CA for Azure from here: https://github.com/Azure/azure-iot-sdk-c/blob/master/certs/certs.c
130- // We are storing this certificate in the resources
131- X509Certificate azureRootCACert = new X509Certificate ( Resources . GetBytes ( Resources . BinaryResources . AzureRoot ) ) ;
132-
133132 // Creates MQTT Client with default port 8883 using TLS protocol
134133 _mqttc = new MqttClient (
135134 _iotHubName ,
136135 8883 ,
137136 true ,
138- azureRootCACert ,
137+ _azureRootCACert ,
139138 _clientCert ,
140139 MqttSslProtocols . TLSv1_2 ) ;
141140
@@ -147,47 +146,51 @@ public bool Open()
147146 _mqttc . ConnectionClosed += ClientConnectionClosed ;
148147
149148 // Now connect the device
150- Reconnect ( ) ;
149+ string key = _clientCert == null ? GetSharedAccessSignature ( null , _sasKey , $ "{ _iotHubName } /devices/{ _deviceId } ", new TimeSpan ( 24 , 0 , 0 ) ) : _privateKey ;
150+ _mqttc . Connect (
151+ _deviceId ,
152+ $ "{ _iotHubName } /{ _deviceId } /api-version=2020-09-30",
153+ key ,
154+ false ,
155+ MqttQoSLevel . ExactlyOnce ,
156+ false , "$iothub/twin/GET/?$rid=999" ,
157+ "Disconnected" ,
158+ true ,
159+ 60
160+ ) ;
151161
152162 if ( _mqttc . IsConnected )
153163 {
154- _ioTHubStatus . Status = Status . Connected ;
155- _ioTHubStatus . Message = string . Empty ;
156- StatusUpdated ? . Invoke ( this , new StatusUpdatedEventArgs ( _ioTHubStatus ) ) ;
157164 _mqttc . Subscribe (
158165 new [ ] {
159- $ "devices/{ _deviceId } /messages/devicebound/#",
160- "$iothub/twin/#" ,
161- "$iothub/methods/POST/#"
166+ $ "devices/{ _deviceId } /messages/devicebound/#",
167+ "$iothub/twin/#" ,
168+ "$iothub/methods/POST/#"
162169 } ,
163170 new [ ] {
164- MqttMsgBase . QOS_LEVEL_AT_LEAST_ONCE ,
165- MqttMsgBase . QOS_LEVEL_AT_LEAST_ONCE ,
166- MqttMsgBase . QOS_LEVEL_AT_LEAST_ONCE
171+ MqttQoSLevel . AtLeastOnce ,
172+ MqttQoSLevel . AtLeastOnce ,
173+ MqttQoSLevel . AtLeastOnce
167174 }
168175 ) ;
176+
177+ _ioTHubStatus . Status = Status . Connected ;
178+ _ioTHubStatus . Message = string . Empty ;
179+ StatusUpdated ? . Invoke ( this , new StatusUpdatedEventArgs ( _ioTHubStatus ) ) ;
180+ // We will renew 10 minutes before just in case
181+ _timerTokenRenew = new Timer ( TimerCallbackReconnect , null , new TimeSpan ( 23 , 50 , 0 ) , TimeSpan . MaxValue ) ;
169182 }
170183
171184 return _mqttc . IsConnected ;
172185 }
173186
174- private void Reconnect ( )
187+ /// <summary>
188+ /// Reconnect to Azure Iot Hub
189+ /// </summary>
190+ public void Reconnect ( )
175191 {
176192 Close ( ) ;
177- _mqttc . Connect (
178- _deviceId ,
179- $ "{ _iotHubName } /{ _deviceId } /api-version=2020-09-30",
180- _clientCert == null ? GetSharedAccessSignature ( null , _sasKey , $ "{ _iotHubName } /devices/{ _deviceId } ", new TimeSpan ( 24 , 0 , 0 ) ) : _privateKey ,
181- false ,
182- MqttMsgBase . QOS_LEVEL_EXACTLY_ONCE ,
183- false , "$iothub/twin/GET/?$rid=999" ,
184- "Disconnected" ,
185- false ,
186- 60
187- ) ;
188-
189- // We will renew 10 minutes before just in case
190- _timerTokenRenew = new Timer ( TimerCallbackReconnect , null , new TimeSpan ( 23 , 50 , 0 ) , TimeSpan . MaxValue ) ;
193+ Open ( ) ;
191194 }
192195
193196 private void TimerCallbackReconnect ( object state )
@@ -204,12 +207,16 @@ public void Close()
204207 if ( _mqttc . IsConnected )
205208 {
206209 _mqttc . Unsubscribe ( new [ ] {
207- $ "devices/{ _deviceId } /messages/devicebound/#",
208- "$iothub/twin/#" ,
209- "$iothub/methods/POST/#"
210+ $ "devices/{ _deviceId } /messages/devicebound/#",
211+ "$iothub/twin/#" ,
212+ "$iothub/methods/POST/#"
210213 } ) ;
211214 _mqttc . Disconnect ( ) ;
215+ // Make sure all get disconnected, cleared
216+ Thread . Sleep ( 1000 ) ;
212217 }
218+
219+ _timerTokenRenew . Dispose ( ) ;
213220 }
214221
215222 /// <summary>
@@ -222,7 +229,7 @@ public void Close()
222229 public Twin GetTwin ( CancellationToken cancellationToken = default )
223230 {
224231 _twinReceived = false ;
225- _mqttc . Publish ( $ "{ TwinDesiredPropertiesTopic } ?$rid={ Guid . NewGuid ( ) } ", Encoding . UTF8 . GetBytes ( "" ) , MqttMsgBase . QOS_LEVEL_AT_LEAST_ONCE , false ) ;
232+ _mqttc . Publish ( $ "{ TwinDesiredPropertiesTopic } ?$rid={ Guid . NewGuid ( ) } ", Encoding . UTF8 . GetBytes ( "" ) , MqttQoSLevel . AtLeastOnce , false ) ;
226233
227234 while ( ! _twinReceived && ! cancellationToken . IsCancellationRequested )
228235 {
@@ -242,7 +249,7 @@ public bool UpdateReportedProperties(TwinCollection reported, CancellationToken
242249 {
243250 string twin = reported . ToJson ( ) ;
244251 Debug . WriteLine ( $ "update twin: { twin } ") ;
245- var rid = _mqttc . Publish ( $ "{ TwinReportedPropertiesTopic } ?$rid={ Guid . NewGuid ( ) } ", Encoding . UTF8 . GetBytes ( twin ) , MqttMsgBase . QOS_LEVEL_AT_MOST_ONCE , false ) ;
252+ var rid = _mqttc . Publish ( $ "{ TwinReportedPropertiesTopic } ?$rid={ Guid . NewGuid ( ) } ", Encoding . UTF8 . GetBytes ( twin ) , MqttQoSLevel . AtLeastOnce , false ) ;
246253 _ioTHubStatus . Status = Status . TwinUpdated ;
247254 _ioTHubStatus . Message = string . Empty ;
248255 StatusUpdated ? . Invoke ( this , new StatusUpdatedEventArgs ( _ioTHubStatus ) ) ;
@@ -380,11 +387,11 @@ private void ClientMqttMsgReceived(object sender, MqttMsgPublishEventArgs e)
380387 try
381388 {
382389 var res = mt . Invoke ( rid , message ) ;
383- _mqttc . Publish ( $ "$iothub/methods/res/200/?$rid={ rid } ", Encoding . UTF8 . GetBytes ( res ) , MqttMsgBase . QOS_LEVEL_AT_LEAST_ONCE , false ) ;
390+ _mqttc . Publish ( $ "$iothub/methods/res/200/?$rid={ rid } ", Encoding . UTF8 . GetBytes ( res ) , MqttQoSLevel . AtLeastOnce , false ) ;
384391 }
385392 catch ( Exception ex )
386393 {
387- _mqttc . Publish ( $ "$iothub/methods/res/504/?$rid={ rid } ", Encoding . UTF8 . GetBytes ( $ "{{\" Exception:\" :\" { ex } \" }}") , MqttMsgBase . QOS_LEVEL_AT_LEAST_ONCE , false ) ;
394+ _mqttc . Publish ( $ "$iothub/methods/res/504/?$rid={ rid } ", Encoding . UTF8 . GetBytes ( $ "{{\" Exception:\" :\" { ex } \" }}") , MqttQoSLevel . AtLeastOnce , false ) ;
388395 }
389396 }
390397 }
0 commit comments