33
33
#include " cbor/CBOREncoder.h"
34
34
#include " cbor/CBORDecoder.h"
35
35
#include " utility/watchdog/Watchdog.h"
36
+ #include < typeinfo>
36
37
37
38
/* *****************************************************************************
38
39
LOCAL MODULE FUNCTIONS
@@ -51,7 +52,6 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
51
52
: _state{State::ConnectPhy}
52
53
, _device_id{" " }
53
54
, _thing_id{" " }
54
- , _thing_id_property{nullptr }
55
55
, _connection_attempt(0 ,0 )
56
56
, _mqtt_data_buf{0 }
57
57
, _mqtt_data_len{0 }
@@ -60,23 +60,15 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
60
60
, _password(" " )
61
61
#endif
62
62
, _mqttClient{nullptr }
63
- , _deviceTopicOut(" " )
64
- , _deviceTopicIn(" " )
65
- , _shadowTopicOut(" " )
66
- , _shadowTopicIn(" " )
63
+ , _messageTopicOut(" " )
64
+ , _messageTopicIn(" " )
67
65
, _dataTopicOut(" " )
68
66
, _dataTopicIn(" " )
69
67
, _message_stream(std::bind(&ArduinoIoTCloudTCP::sendMessage, this , std::placeholders::_1))
70
68
, _thing(&_message_stream)
71
69
, _device(&_message_stream)
72
70
#if OTA_ENABLED
73
71
, _ota(&_message_stream)
74
- , _ota_cap{false }
75
- , _ota_error{static_cast <int >(ota::OTAError::None)}
76
- , _ota_img_sha256{" Inv." }
77
- , _ota_url{" " }
78
- , _ota_progress{" Resume" }
79
- , _ota_req{false }
80
72
, _ask_user_before_executing_ota{false }
81
73
, _get_ota_confirmation{nullptr }
82
74
#endif /* OTA_ENABLED */
@@ -166,43 +158,19 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
166
158
_mqttClient.setUsernamePassword (getDeviceId (), _password);
167
159
}
168
160
#endif
161
+
169
162
_mqttClient.onMessage (ArduinoIoTCloudTCP::onMessage);
170
163
_mqttClient.setKeepAliveInterval (30 * 1000 );
171
164
_mqttClient.setConnectionTimeout (1500 );
172
165
_mqttClient.setId (getDeviceId ().c_str ());
173
166
174
- _deviceTopicOut = getTopic_deviceout ();
175
- _deviceTopicIn = getTopic_devicein ();
176
-
177
- Property* p;
178
- p = new CloudWrapperString (_lib_version);
179
- addPropertyToContainer (_device.getPropertyContainer (), *p, " LIB_VERSION" , Permission::Read, -1 );
180
- p = new CloudWrapperString (_thing_id);
181
- _thing_id_property = &addPropertyToContainer (_device.getPropertyContainer (), *p, " thing_id" , Permission::ReadWrite, -1 );
167
+ _messageTopicOut = getTopic_messageout ();
168
+ _messageTopicIn = getTopic_messagein ();
182
169
183
170
_thing.begin ();
184
171
_device.begin ();
185
172
186
173
#if OTA_ENABLED
187
- p = new CloudWrapperBool (_ota_cap);
188
- addPropertyToContainer (_device.getPropertyContainer (), *p, " OTA_CAP" , Permission::Read, -1 ).publishOnChange (0 .0f , 0 );
189
- p = new CloudWrapperInt (_ota_error);
190
- addPropertyToContainer (_device.getPropertyContainer (), *p, " OTA_ERROR" , Permission::Read, -1 ).publishOnChange (0 .0f , 0 );
191
- p = new CloudWrapperString (_ota_progress);
192
- addPropertyToContainer (_device.getPropertyContainer (), *p, " OTA_PROGRESS" , Permission::Read, -1 ).publishOnChange (0 .0f , 0 );
193
- p = new CloudWrapperString (_ota_img_sha256);
194
- addPropertyToContainer (_device.getPropertyContainer (), *p, " OTA_SHA256" , Permission::Read, -1 ).publishOnChange (0 .0f , 0 );
195
- p = new CloudWrapperString (_ota_url);
196
- _ota_url_property = &addPropertyToContainer (_device.getPropertyContainer (), *p, " OTA_URL" , Permission::ReadWrite, -1 ).publishOnChange (0 .0f , 0 ).writeOnDemand ();
197
- p = new CloudWrapperBool (_ota_req);
198
- addPropertyToContainer (_device.getPropertyContainer (), *p, " OTA_REQ" , Permission::ReadWrite, -1 ).publishOnChange (0 .0f , 0 );
199
-
200
- _ota_cap =_ota.isOtaCapable ();
201
-
202
- // Sha256 is calculated when the ota fsm reaches its second state
203
- _ota.update ();
204
- _ota.update ();
205
-
206
174
_ota.setClient (&_otaClient);
207
175
#endif // OTA_ENABLED
208
176
@@ -313,6 +281,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
313
281
{
314
282
if (_mqttClient.connect (_brokerAddress.c_str (), _brokerPort))
315
283
{
284
+ _mqttClient.subscribe (getTopic_messagein ());
316
285
DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s connected to %s:%d" , __FUNCTION__, _brokerAddress.c_str (), _brokerPort);
317
286
/* Reconfigure timers for next state */
318
287
_connection_attempt.begin (AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms, AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms);
@@ -336,8 +305,8 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
336
305
}
337
306
338
307
_device.update ();
308
+
339
309
#if OTA_ENABLED
340
- handle_OTARequest ();
341
310
_ota.update ();
342
311
#endif // OTA_ENABLED
343
312
@@ -356,53 +325,11 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
356
325
return State::Connected;
357
326
}
358
327
359
- #if OTA_ENABLED
360
- void ArduinoIoTCloudTCP::handle_OTARequest () {
361
- /* Request a OTA download if the hidden property
362
- * OTA request has been set.
363
- */
364
-
365
- if (_ota_req)
366
- {
367
- bool const ota_execution_allowed_by_user = (_get_ota_confirmation != nullptr && _get_ota_confirmation ());
368
- bool const perform_ota_now = ota_execution_allowed_by_user || !_ask_user_before_executing_ota;
369
- if (perform_ota_now) {
370
- /* Clear the error flag. */
371
- _ota_error = static_cast <int >(ota::OTAError::None);
372
- /* Clear the request flag. */
373
- _ota_req = false ;
374
- /* Transmit the cleared request flags to the cloud. */
375
- sendDevicePropertyToCloud (" OTA_REQ" );
376
- /* Call member function to handle OTA request. */
377
- // _ota_error = OTA::onRequest(_ota_url, _connection->getInterface());
378
- /* If something fails send the OTA error to the cloud */
379
- sendDevicePropertyToCloud (" OTA_ERROR" );
380
-
381
- struct OtaUpdateCmdDown cmd = {
382
- OtaUpdateCmdDownId,
383
- " 123456" ,
384
- };
385
-
386
- strncpy (cmd.params .url , _ota_url.c_str (), URL_SIZE);
387
-
388
- _ota.handleMessage ((Message*) &cmd);
389
- }
390
- }
391
-
392
- /* Check if we have received the OTA_URL property and provide
393
- * echo to the cloud.
394
- */
395
- sendDevicePropertyToCloud (" OTA_URL" );
396
- }
397
- #endif /* OTA_ENABLED */
398
-
399
-
400
328
ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Disconnect ()
401
329
{
402
330
if (!_mqttClient.connected ()) {
403
331
DEBUG_ERROR (" ArduinoIoTCloudTCP::%s MQTT client connection lost" , __FUNCTION__);
404
332
} else {
405
- _mqttClient.unsubscribe (_shadowTopicIn);
406
333
_mqttClient.unsubscribe (_dataTopicIn);
407
334
/* TODO add device topic */
408
335
_mqttClient.stop ();
@@ -435,82 +362,88 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
435
362
bytes[i] = _mqttClient.read ();
436
363
}
437
364
438
- /* Topic for OTA properties and device configuration */
439
- if (_deviceTopicIn == topic) {
440
- CBORDecoder::decode (_device.getPropertyContainer (), (uint8_t *)bytes, length);
441
- /* Unlock device state machine waiting thing_id*/
442
- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] device configuration received" , __FUNCTION__, millis ());
443
- ThingGetIdCmdDown message;
444
- message.c .id = AttachThing;
445
- strcpy (message.params .thing_id , _thing_id.c_str ());
446
- Serial.println (_thing_id.c_str ());
447
- _device.handleMessage ((Message*)&message);
448
- }
449
-
450
365
/* Topic for user input data */
451
366
if (_dataTopicIn == topic) {
452
- CBORDecoder::decode (_thing .getPropertyContainer (), (uint8_t *)bytes, length);
367
+ CBORDecoder::decode (getThing () .getPropertyContainer (), (uint8_t *)bytes, length);
453
368
}
454
369
455
- /* Topic for sync Thing last values on connect */
456
- if (_shadowTopicIn == topic) {
457
- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values received" , __FUNCTION__, millis ());
458
- CBORDecoder::decode (_thing.getPropertyContainer (), (uint8_t *)bytes, length, true );
459
- execCloudEventCallback (ArduinoIoTCloudEvent::SYNC);
460
- /* Unlock thing state machine waiting last values */
461
- Message message;
462
- message.id = LastValues;
463
- _thing.handleMessage (&message);
370
+ /* Topic for device commands */
371
+ if (_messageTopicIn == topic) {
372
+ CommandDown command;
373
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] received %d bytes" , __FUNCTION__, millis (), length);
374
+ CBORMessageDecoder decoder;
375
+
376
+ size_t buffer_length = length;
377
+ if (decoder.decode ((Message*)&command, bytes, buffer_length) != Decoder::Status::Error) {
378
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] received command id %d" , __FUNCTION__, millis (), command.c .id );
379
+ switch (command.c .id )
380
+ {
381
+ case CommandID::ThingGetIdCmdDownId:
382
+ {
383
+ ThingGetIdCmdDown * msg = (ThingGetIdCmdDown *)&command;
384
+ _thing_id = String (msg->params .thing_id );
385
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] device configuration received" , __FUNCTION__, millis ());
386
+ _device.handleMessage ((Message*)&command);
387
+ }
388
+ break ;
389
+
390
+ case CommandID::ThingGetLastValueCmdDownId:
391
+ {
392
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values received" , __FUNCTION__, millis ());
393
+ ThingGetLastValueCmdDown * msg = (ThingGetLastValueCmdDown*)&command;
394
+ CBORDecoder::decode (getThing ().getPropertyContainer (), (uint8_t *)msg->params .last_values , msg->params .length , true );
395
+ _thing.handleMessage ((Message*)&command);
396
+ execCloudEventCallback (ArduinoIoTCloudEvent::SYNC);
397
+
398
+ /*
399
+ * NOTE: in this current version properties are not properly integrated with the new paradigm of
400
+ * modeling the messages with C structs. The current CBOR library allocates an array in the heap
401
+ * thus we need to delete it after decoding it with the old CBORDecoder
402
+ */
403
+ free (msg->params .last_values );
404
+ }
405
+ break ;
406
+
407
+ #if OTA_ENABLED
408
+ case CommandID::OtaUpdateCmdDownId:
409
+ {
410
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] ota update received" , __FUNCTION__, millis ());
411
+ _ota.handleMessage ((Message*)&command);
412
+ }
413
+ #endif
414
+
415
+ default :
416
+ break ;
417
+ }
418
+ }
464
419
}
465
420
}
466
421
467
422
void ArduinoIoTCloudTCP::sendMessage (Message * msg)
468
423
{
469
424
switch (msg->id )
470
425
{
471
- case SendCapabilities:
472
- sendDevicePropertiesToCloud ();
473
- break ;
474
426
case SendProperties:
475
- sendThingPropertiesToCloud ();
476
- break ;
477
- case GetLastValues:
478
- requestLastValue ();
479
- break ;
480
- case GetThingId:
481
- requestThingId ();
427
+ return sendThingPropertiesToCloud ();
482
428
break ;
429
+
483
430
case AttachThing:
484
- attachThing ();
485
- break ;
486
- #if OTA_ENABLED
487
- case OtaBeginUpId:
488
- {
489
- OtaBeginUp *ota_begin_cmd = (OtaBeginUp*)msg;
490
- String sha256_str;
491
- std::for_each (ota_begin_cmd->params .sha ,
492
- ota_begin_cmd->params .sha + SHA256::HASH_SIZE,
493
- [&sha256_str](uint8_t const elem) {
494
- char buf[4 ];
495
- snprintf (buf, 4 , " %02X" , elem);
496
- sha256_str += buf;
497
- });
498
- _ota_img_sha256 = sha256_str;
499
- }
431
+ return attachThing ();
500
432
break ;
501
- case OtaProgressCmdUpId:
502
- {
503
- OtaProgressCmdUp *ota_progress_cmd = (OtaProgressCmdUp*)msg;
504
- _ota_progress = OTACloudProcessInterface::STATE_NAMES[ota_progress_cmd->params .state < 0 ? OTACloudProcessInterface::Fail - ota_progress_cmd->params .state : ota_progress_cmd->params .state ];
505
- Serial.println (" This is not a bug from Andrea code" );
506
- /* If something fails send the OTA error to the cloud */
507
- sendDevicePropertyToCloud (" OTA_PROGRESS" );
508
- }
509
- break ;
510
- #endif
511
433
default :
512
434
break ;
513
435
}
436
+
437
+ uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE];
438
+ size_t bytes_encoded = sizeof (data);
439
+ CBORMessageEncoder encoder;
440
+
441
+ if (encoder.encode (msg, data, bytes_encoded) == Encoder::Status::Complete &&
442
+ bytes_encoded > 0 ) {
443
+ write (_messageTopicOut, data, bytes_encoded);
444
+ } else {
445
+ DEBUG_ERROR (" error encoding %d" , msg->id );
446
+ }
514
447
}
515
448
516
449
void ArduinoIoTCloudTCP::sendPropertyContainerToCloud (String const topic, PropertyContainer & container, unsigned int & current_property_index)
@@ -538,60 +471,6 @@ void ArduinoIoTCloudTCP::sendThingPropertiesToCloud()
538
471
sendPropertyContainerToCloud (_dataTopicOut, _thing.getPropertyContainer (), _thing.getPropertyContainerIndex ());
539
472
}
540
473
541
- void ArduinoIoTCloudTCP::sendDevicePropertiesToCloud ()
542
- {
543
- PropertyContainer ro_device_container;
544
- unsigned int last_device_property_index = 0 ;
545
-
546
- std::list<String> ro_device_property_list {" LIB_VERSION" , " OTA_CAP" , " OTA_ERROR" , " OTA_SHA256" };
547
- std::for_each (ro_device_property_list.begin (),
548
- ro_device_property_list.end (),
549
- [this , &ro_device_container ] (String const & name)
550
- {
551
- Property* p = getProperty (this ->_device .getPropertyContainer (), name);
552
- if (p != nullptr )
553
- addPropertyToContainer (ro_device_container, *p, p->name (), p->isWriteableByCloud () ? Permission::ReadWrite : Permission::Read);
554
- }
555
- );
556
- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s announce device to the Cloud %d" , __FUNCTION__, _time_service.getTime ());
557
- sendPropertyContainerToCloud (_deviceTopicOut, ro_device_container, last_device_property_index);
558
- }
559
-
560
- #if OTA_ENABLED
561
- void ArduinoIoTCloudTCP::sendDevicePropertyToCloud (String const name)
562
- {
563
- PropertyContainer temp_device_container;
564
- unsigned int last_device_property_index = 0 ;
565
-
566
- Property* p = getProperty (this ->_device .getPropertyContainer (), name);
567
- if (p != nullptr )
568
- {
569
- addPropertyToContainer (temp_device_container, *p, p->name (), p->isWriteableByCloud () ? Permission::ReadWrite : Permission::Read);
570
- sendPropertyContainerToCloud (_deviceTopicOut, temp_device_container, last_device_property_index);
571
- }
572
- }
573
- #endif
574
-
575
- void ArduinoIoTCloudTCP::requestLastValue ()
576
- {
577
- // Send the getLastValues CBOR message to the cloud
578
- // [{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
579
- // Use http://cbor.me to easily generate CBOR encoding
580
- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s at time [%d]" , __FUNCTION__, getTime ());
581
- 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 };
582
- write (_shadowTopicOut, CBOR_REQUEST_LAST_VALUE_MSG, sizeof (CBOR_REQUEST_LAST_VALUE_MSG));
583
- }
584
-
585
- void ArduinoIoTCloudTCP::requestThingId ()
586
- {
587
- if (!_mqttClient.subscribe (_deviceTopicIn))
588
- {
589
- /* If device_id is wrong the board can't connect to the broker so this condition
590
- * should never happen.
591
- */
592
- DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not subscribe to %s" , __FUNCTION__, _deviceTopicIn.c_str ());
593
- }
594
- }
595
474
596
475
void ArduinoIoTCloudTCP::attachThing ()
597
476
{
@@ -604,15 +483,6 @@ void ArduinoIoTCloudTCP::attachThing()
604
483
return ;
605
484
}
606
485
607
- _shadowTopicIn = getTopic_shadowin ();
608
- _shadowTopicOut = getTopic_shadowout ();
609
- if (!_mqttClient.subscribe (_shadowTopicIn))
610
- {
611
- DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not subscribe to %s" , __FUNCTION__, _shadowTopicIn.c_str ());
612
- DEBUG_ERROR (" Check your thing configuration, and press the reset button on your board." );
613
- return ;
614
- }
615
-
616
486
DEBUG_INFO (" Connected to Arduino IoT Cloud" );
617
487
DEBUG_INFO (" Thing ID: %s" , getThingId ().c_str ());
618
488
execCloudEventCallback (ArduinoIoTCloudEvent::CONNECT);
0 commit comments