20
20
#include " CloudSerial.h"
21
21
#include " ArduinoIoTCloud.h"
22
22
23
+ #ifdef ARDUINO_ARCH_SAMD
24
+ #include < RTCZero.h>
25
+ RTCZero rtc;
26
+ #endif
27
+
23
28
const static int keySlot = 0 ;
24
29
const static int compressedCertSlot = 10 ;
25
30
const static int serialNumberAndAuthorityKeyIdentifierSlot = 11 ;
@@ -37,11 +42,21 @@ static unsigned long getTime() {
37
42
return time ;
38
43
}
39
44
45
+ static unsigned long getTimestamp () {
46
+ #ifdef ARDUINO_ARCH_SAMD
47
+ return rtc.getEpoch ();
48
+ #else
49
+ #warning "No RTC available on this architecture - ArduinoIoTCloud will not keep track of local change timestamps ."
50
+ return 0 ;
51
+ #endif
52
+ }
53
+
40
54
ArduinoIoTCloudClass::ArduinoIoTCloudClass () :
41
55
_thing_id (" " ),
42
56
_bearSslClient(NULL ),
43
57
_mqttClient (NULL ),
44
- connection (NULL )
58
+ connection (NULL ),
59
+ _lastSyncRequestTickTime(0 )
45
60
{
46
61
}
47
62
@@ -64,6 +79,9 @@ int ArduinoIoTCloudClass::begin(ConnectionManager *c, String brokerAddress, uint
64
79
Client &connectionClient = c->getClient ();
65
80
_brokerAddress = brokerAddress;
66
81
_brokerPort = brokerPort;
82
+ #ifdef ARDUINO_ARCH_SAMD
83
+ rtc.begin ();
84
+ #endif
67
85
return begin (connectionClient, _brokerAddress, _brokerPort);
68
86
}
69
87
@@ -148,6 +166,8 @@ void ArduinoIoTCloudClass::mqttClientBegin()
148
166
else {
149
167
_dataTopicIn = " /a/t/" + _thing_id + " /e/i" ;
150
168
_dataTopicOut = " /a/t/" + _thing_id + " /e/o" ;
169
+ _shadowTopicIn = " /a/t/" + _thing_id + " /shadow/i" ;
170
+ _shadowTopicOut = " /a/t/" + _thing_id + " /shadow/o" ;
151
171
}
152
172
153
173
// use onMessage as callback for received mqtt messages
@@ -166,6 +186,10 @@ int ArduinoIoTCloudClass::connect()
166
186
}
167
187
_mqttClient->subscribe (_stdinTopic);
168
188
_mqttClient->subscribe (_dataTopicIn);
189
+ _mqttClient->subscribe (_shadowTopicIn);
190
+
191
+ _syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES;
192
+ _lastSyncRequestTickTime = 0 ;
169
193
170
194
return 1 ;
171
195
}
@@ -182,14 +206,18 @@ void ArduinoIoTCloudClass::poll()
182
206
update ();
183
207
}
184
208
185
- void ArduinoIoTCloudClass::update ()
209
+ void ArduinoIoTCloudClass::update (CallbackFunc onSyncCompleteCallback )
186
210
{
187
211
// If user call update() without parameters use the default ones
188
- update (MAX_RETRIES, RECONNECTION_TIMEOUT);
212
+ update (MAX_RETRIES, RECONNECTION_TIMEOUT, onSyncCompleteCallback );
189
213
}
190
214
191
- void ArduinoIoTCloudClass::update (int const reconnectionMaxRetries, int const reconnectionTimeoutMs)
215
+ void ArduinoIoTCloudClass::update (int const reconnectionMaxRetries, int const reconnectionTimeoutMs, CallbackFunc onSyncCompleteCallback )
192
216
{
217
+ unsigned long const timestamp = getTimestamp ();
218
+ // check if a property is changed
219
+ if (timestamp != 0 ) Thing.updateTimestampOnChangedProperties (timestamp);
220
+
193
221
connectionCheck ();
194
222
if (iotStatus != IOT_STATUS_CLOUD_CONNECTED){
195
223
return ;
@@ -198,6 +226,26 @@ void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const re
198
226
// MTTQClient connected!, poll() used to retrieve data from MQTT broker
199
227
_mqttClient->poll ();
200
228
229
+ switch (_syncStatus) {
230
+ case ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED:
231
+ sendPropertiesToCloud ();
232
+ break ;
233
+ case ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES:
234
+ if (millis () - _lastSyncRequestTickTime > TIMEOUT_FOR_LASTVALUES_SYNC) {
235
+ requestLastValue ();
236
+ _lastSyncRequestTickTime = millis ();
237
+ }
238
+ break ;
239
+ case ArduinoIoTSynchronizationStatus::SYNC_STATUS_VALUES_PROCESSED:
240
+ if (onSyncCompleteCallback != NULL )
241
+ (*onSyncCompleteCallback)();
242
+ _syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED;
243
+ break ;
244
+ }
245
+ }
246
+
247
+ void ArduinoIoTCloudClass::sendPropertiesToCloud ()
248
+ {
201
249
uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE];
202
250
int const length = Thing.encode (data, sizeof (data));
203
251
if (length > 0 ) {
@@ -254,6 +302,23 @@ int ArduinoIoTCloudClass::writeStdout(const byte data[], int length)
254
302
return 1 ;
255
303
}
256
304
305
+ int ArduinoIoTCloudClass::writeShadowOut (const byte data[], int length)
306
+ {
307
+ if (!_mqttClient->beginMessage (_shadowTopicOut, length, false , 0 )) {
308
+ return 0 ;
309
+ }
310
+
311
+ if (!_mqttClient->write (data, length)) {
312
+ return 0 ;
313
+ }
314
+
315
+ if (!_mqttClient->endMessage ()) {
316
+ return 0 ;
317
+ }
318
+
319
+ return 1 ;
320
+ }
321
+
257
322
void ArduinoIoTCloudClass::onMessage (int length)
258
323
{
259
324
ArduinoCloud.handleMessage (length);
@@ -276,6 +341,20 @@ void ArduinoIoTCloudClass::handleMessage(int length)
276
341
if (_dataTopicIn == topic) {
277
342
Thing.decode ((uint8_t *)bytes, length);
278
343
}
344
+ if ((_shadowTopicIn == topic) && _syncStatus == ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES) {
345
+ Thing.decode ((uint8_t *)bytes, length, true );
346
+ sendPropertiesToCloud ();
347
+ _syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_VALUES_PROCESSED;
348
+ }
349
+ }
350
+
351
+ void ArduinoIoTCloudClass::requestLastValue ()
352
+ {
353
+ // Send the getLastValues CBOR message to the cloud
354
+ // [{0: "r:m", 3: "getLastValues"}] = 81 A2 00 63 72 3A 6D 03 6D 67 65 74 4C 61 73 74 56 61 6C 75 65 73
355
+ // Use http://cbor.me to easily generate CBOR encoding
356
+ const uint8_t CBOR_REQUEST_LAST_VALUE_MSG[] = { 0x81 , 0xA2 , 0x00 , 0x63 , 0x72 , 0x3A , 0x6D , 0x03 , 0x6D , 0x67 , 0x65 , 0x74 , 0x4C , 0x61 , 0x73 , 0x74 , 0x56 , 0x61 , 0x6C , 0x75 , 0x65 , 0x73 };
357
+ writeShadowOut (CBOR_REQUEST_LAST_VALUE_MSG, sizeof (CBOR_REQUEST_LAST_VALUE_MSG));
279
358
}
280
359
281
360
void ArduinoIoTCloudClass::connectionCheck ()
@@ -332,6 +411,11 @@ void ArduinoIoTCloudClass::connectionCheck()
332
411
CloudSerial.begin (9600 );
333
412
CloudSerial.println (" Hello from Cloud Serial!" );
334
413
}
414
+ #ifdef ARDUINO_ARCH_SAMD
415
+ unsigned long const epoch = getTime ();
416
+ if (epoch!=0 )
417
+ rtc.setEpoch (epoch);
418
+ #endif
335
419
break ;
336
420
}
337
421
}
0 commit comments