43
43
#include < algorithm>
44
44
#include " cbor/CBOREncoder.h"
45
45
#include " utility/watchdog/Watchdog.h"
46
+ #include < typeinfo>
46
47
47
48
/* *****************************************************************************
48
49
LOCAL MODULE FUNCTIONS
@@ -62,7 +63,6 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
62
63
, _connection_attempt(0 ,0 )
63
64
, _message_stream(std::bind(&ArduinoIoTCloudTCP::sendMessage, this , std::placeholders::_1))
64
65
, _thing(&_message_stream)
65
- , _thing_id_property{nullptr }
66
66
, _device(&_message_stream)
67
67
, _mqtt_data_buf{0 }
68
68
, _mqtt_data_len{0 }
@@ -76,8 +76,8 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
76
76
, _mqttClient{nullptr }
77
77
, _deviceTopicOut(" " )
78
78
, _deviceTopicIn(" " )
79
- , _shadowTopicOut (" " )
80
- , _shadowTopicIn (" " )
79
+ , _messageTopicOut (" " )
80
+ , _messageTopicIn (" " )
81
81
, _dataTopicOut(" " )
82
82
, _dataTopicIn(" " )
83
83
#if OTA_ENABLED
@@ -181,24 +181,22 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
181
181
_mqttClient.setUsernamePassword (getDeviceId (), _password);
182
182
}
183
183
#endif
184
+
184
185
_mqttClient.onMessage (ArduinoIoTCloudTCP::onMessage);
185
186
_mqttClient.setKeepAliveInterval (30 * 1000 );
186
187
_mqttClient.setConnectionTimeout (1500 );
187
188
_mqttClient.setId (getDeviceId ().c_str ());
188
189
189
190
_deviceTopicOut = getTopic_deviceout ();
190
191
_deviceTopicIn = getTopic_devicein ();
191
-
192
- Property* p;
193
- p = new CloudWrapperString (_lib_version);
194
- addPropertyToContainer (_device.getPropertyContainer (), *p, " LIB_VERSION" , Permission::Read, -1 );
195
- p = new CloudWrapperString (_thing_id);
196
- _thing_id_property = &addPropertyToContainer (_device.getPropertyContainer (), *p, " thing_id" , Permission::ReadWrite, -1 ).writeOnDemand ();
192
+ _messageTopicIn = getTopic_messagein ();
193
+ _messageTopicOut = getTopic_messageout ();
197
194
198
195
_thing.begin ();
199
196
_device.begin ();
200
197
201
198
#if OTA_ENABLED
199
+ Property* p;
202
200
p = new CloudWrapperBool (_ota_cap);
203
201
addPropertyToContainer (_device.getPropertyContainer (), *p, " OTA_CAP" , Permission::Read, -1 );
204
202
p = new CloudWrapperInt (_ota_error);
@@ -322,9 +320,16 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
322
320
{
323
321
if (_mqttClient.connect (_brokerAddress.c_str (), _brokerPort))
324
322
{
325
- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s connected to %s:%d" , __FUNCTION__, _brokerAddress.c_str (), _brokerPort);
323
+ /* Subscribe to message topic to receive commands */
324
+ _mqttClient.subscribe (_messageTopicIn);
325
+
326
+ /* Temoporarly subscribe to device topic to receive OTA properties */
327
+ _mqttClient.subscribe (_deviceTopicIn);
328
+
326
329
/* Reconfigure timers for next state */
327
330
_connection_attempt.begin (AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms, AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms);
331
+
332
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s connected to %s:%d" , __FUNCTION__, _brokerAddress.c_str (), _brokerPort);
328
333
return State::Connected;
329
334
}
330
335
@@ -413,7 +418,6 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Disconnect()
413
418
_thing.handleMessage (&message);
414
419
_device.handleMessage (&message);
415
420
416
- _thing_id = " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ;
417
421
DEBUG_INFO (" Disconnected from Arduino IoT Cloud" );
418
422
execCloudEventCallback (ArduinoIoTCloudEvent::DISCONNECT);
419
423
@@ -440,68 +444,101 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
440
444
/* Topic for OTA properties and device configuration */
441
445
if (_deviceTopicIn == topic) {
442
446
CBORDecoder::decode (_device.getPropertyContainer (), (uint8_t *)bytes, length);
443
-
444
- /* Temporary check to avoid flooding device state machine with usless messages */
445
- if (_thing_id_property->isDifferentFromCloud ()) {
446
- _thing_id_property->fromCloudToLocal ();
447
-
448
- if (!_thing_id.length ()) {
449
- /* Send message to device state machine to inform we have received a null thing-id */
450
- _thing_id = " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ;
451
- Message message;
452
- message = { DeviceRegisteredCmdId };
453
- _device.handleMessage (&message);
454
- } else {
455
- if (_device.isAttached ()) {
456
- detachThing ();
457
- }
458
- if (!_device.isAttached ()) {
459
- attachThing ();
460
- }
461
- }
462
- }
463
447
}
464
448
465
449
/* Topic for user input data */
466
450
if (_dataTopicIn == topic) {
467
451
CBORDecoder::decode (_thing.getPropertyContainer (), (uint8_t *)bytes, length);
468
452
}
469
453
470
- /* Topic for sync Thing last values on connect */
471
- if (_shadowTopicIn == topic) {
472
- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values received" , __FUNCTION__, millis ());
473
- /* Decode last values property array */
474
- CBORDecoder::decode (_thing.getPropertyContainer (), (uint8_t *)bytes, length, true );
475
- /* Unlock thing state machine waiting last values */
476
- Message message = { LastValuesUpdateCmdId };
477
- _thing.handleMessage (&message);
478
- /* Call ArduinoIoTCloud sync user callback*/
479
- execCloudEventCallback (ArduinoIoTCloudEvent::SYNC);
454
+ /* Topic for device commands */
455
+ if (_messageTopicIn == topic) {
456
+ CommandDown command;
457
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] received %d bytes" , __FUNCTION__, millis (), length);
458
+ CBORMessageDecoder decoder;
459
+
460
+ size_t buffer_length = length;
461
+ if (decoder.decode ((Message*)&command, bytes, buffer_length) != Decoder::Status::Error) {
462
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] received command id %d" , __FUNCTION__, millis (), command.c .id );
463
+ switch (command.c .id )
464
+ {
465
+ case CommandId::ThingUpdateCmdId:
466
+ {
467
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] device configuration received" , __FUNCTION__, millis ());
468
+ String new_thing_id = String (command.thingUpdateCmd .params .thing_id );
469
+
470
+ if (!new_thing_id.length ()) {
471
+ /* Send message to device state machine to inform we have received a null thing-id */
472
+ _thing_id = " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ;
473
+ Message message;
474
+ message = { DeviceRegisteredCmdId };
475
+ _device.handleMessage (&message);
476
+ } else {
477
+ if (_device.isAttached () && _thing_id != new_thing_id) {
478
+ detachThing ();
479
+ }
480
+ if (!_device.isAttached ()) {
481
+ attachThing (new_thing_id);
482
+ }
483
+ }
484
+ }
485
+ break ;
486
+
487
+ case CommandId::LastValuesUpdateCmdId:
488
+ {
489
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values received" , __FUNCTION__, millis ());
490
+ CBORDecoder::decode (_thing.getPropertyContainer (),
491
+ (uint8_t *)command.lastValuesUpdateCmd .params .last_values ,
492
+ command.lastValuesUpdateCmd .params .length , true );
493
+ _thing.handleMessage ((Message*)&command);
494
+ execCloudEventCallback (ArduinoIoTCloudEvent::SYNC);
495
+
496
+ /*
497
+ * NOTE: in this current version properties are not properly integrated with the new paradigm of
498
+ * modeling the messages with C structs. The current CBOR library allocates an array in the heap
499
+ * thus we need to delete it after decoding it with the old CBORDecoder
500
+ */
501
+ free (command.lastValuesUpdateCmd .params .last_values );
502
+ }
503
+ break ;
504
+
505
+ default :
506
+ break ;
507
+ }
508
+ }
480
509
}
481
510
}
482
511
483
512
void ArduinoIoTCloudTCP::sendMessage (Message * msg)
484
513
{
485
- switch (msg->id )
486
- {
487
- case DeviceBeginCmdId:
488
- sendDevicePropertiesToCloud ();
489
- break ;
514
+ uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE];
515
+ size_t bytes_encoded = sizeof (data);
516
+ CBORMessageEncoder encoder;
490
517
491
- case ThingBeginCmdId:
492
- requestThingId ();
493
- break ;
518
+ switch (msg->id ) {
519
+ case PropertiesUpdateCmdId:
520
+ return sendPropertyContainerToCloud (_dataTopicOut,
521
+ _thing.getPropertyContainer (),
522
+ _thing.getPropertyContainerIndex ());
523
+ break ;
494
524
495
- case LastValuesBeginCmdId:
496
- requestLastValue ();
497
- break ;
525
+ #if OTA_ENABLED
526
+ case DeviceBeginCmdId:
527
+ sendDevicePropertyToCloud (" OTA_CAP" );
528
+ sendDevicePropertyToCloud (" OTA_ERROR" );
529
+ sendDevicePropertyToCloud (" OTA_SHA256" );
530
+ break ;
531
+ #endif
498
532
499
- case PropertiesUpdateCmdId :
500
- sendThingPropertiesToCloud () ;
501
- break ;
533
+ default :
534
+ break ;
535
+ }
502
536
503
- default :
504
- break ;
537
+ if (encoder.encode (msg, data, bytes_encoded) == Encoder::Status::Complete &&
538
+ bytes_encoded > 0 ) {
539
+ write (_messageTopicOut, data, bytes_encoded);
540
+ } else {
541
+ DEBUG_ERROR (" error encoding %d" , msg->id );
505
542
}
506
543
}
507
544
@@ -525,29 +562,6 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, Proper
525
562
}
526
563
}
527
564
528
- void ArduinoIoTCloudTCP::sendThingPropertiesToCloud ()
529
- {
530
- sendPropertyContainerToCloud (_dataTopicOut, _thing.getPropertyContainer (), _thing.getPropertyContainerIndex ());
531
- }
532
-
533
- void ArduinoIoTCloudTCP::sendDevicePropertiesToCloud ()
534
- {
535
- PropertyContainer ro_device_property_container;
536
- unsigned int last_device_property_index = 0 ;
537
-
538
- std::list<String> ro_device_property_list {" LIB_VERSION" , " OTA_CAP" , " OTA_ERROR" , " OTA_SHA256" };
539
- std::for_each (ro_device_property_list.begin (),
540
- ro_device_property_list.end (),
541
- [this , &ro_device_property_container ] (String const & name)
542
- {
543
- Property* p = getProperty (this ->_device .getPropertyContainer (), name);
544
- if (p != nullptr )
545
- addPropertyToContainer (ro_device_property_container, *p, p->name (), p->isWriteableByCloud () ? Permission::ReadWrite : Permission::Read);
546
- }
547
- );
548
- sendPropertyContainerToCloud (_deviceTopicOut, ro_device_property_container, last_device_property_index);
549
- }
550
-
551
565
#if OTA_ENABLED
552
566
void ArduinoIoTCloudTCP::sendDevicePropertyToCloud (String const name)
553
567
{
@@ -563,28 +577,9 @@ void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
563
577
}
564
578
#endif
565
579
566
- void ArduinoIoTCloudTCP::requestLastValue ()
567
- {
568
- // Send the getLastValues CBOR message to the cloud
569
- // [{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
570
- // Use http://cbor.me to easily generate CBOR encoding
571
- 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 };
572
- write (_shadowTopicOut, CBOR_REQUEST_LAST_VALUE_MSG, sizeof (CBOR_REQUEST_LAST_VALUE_MSG));
573
- }
574
-
575
- void ArduinoIoTCloudTCP::requestThingId ()
576
- {
577
- if (!_mqttClient.subscribe (_deviceTopicIn))
578
- {
579
- /* If device_id is wrong the board can't connect to the broker so this condition
580
- * should never happen.
581
- */
582
- DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not subscribe to %s" , __FUNCTION__, _deviceTopicIn.c_str ());
583
- }
584
- }
585
-
586
- void ArduinoIoTCloudTCP::attachThing ()
580
+ void ArduinoIoTCloudTCP::attachThing (String thingId)
587
581
{
582
+ _thing_id = thingId;
588
583
589
584
_dataTopicIn = getTopic_datain ();
590
585
_dataTopicOut = getTopic_dataout ();
@@ -595,15 +590,6 @@ void ArduinoIoTCloudTCP::attachThing()
595
590
return ;
596
591
}
597
592
598
- _shadowTopicIn = getTopic_shadowin ();
599
- _shadowTopicOut = getTopic_shadowout ();
600
- if (!_mqttClient.subscribe (_shadowTopicIn)) {
601
- DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not subscribe to %s" , __FUNCTION__, _shadowTopicIn.c_str ());
602
- DEBUG_ERROR (" Check your thing configuration, and press the reset button on your board." );
603
- _thing_id = " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ;
604
- return ;
605
- }
606
-
607
593
Message message;
608
594
message = { DeviceAttachedCmdId };
609
595
_device.handleMessage (&message);
@@ -620,11 +606,6 @@ void ArduinoIoTCloudTCP::detachThing()
620
606
return ;
621
607
}
622
608
623
- if (!_mqttClient.unsubscribe (_shadowTopicIn)) {
624
- DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not unsubscribe from %s" , __FUNCTION__, _shadowTopicIn.c_str ());
625
- return ;
626
- }
627
-
628
609
Message message;
629
610
message = { DeviceDetachedCmdId };
630
611
_device.handleMessage (&message);
0 commit comments