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
@@ -439,70 +444,104 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
439
444
/* Topic for OTA properties and device configuration */
440
445
if (_deviceTopicIn == topic) {
441
446
CBORDecoder::decode (_device.getPropertyContainer (), (uint8_t *)bytes, length);
442
-
443
- /* Temporary check to avoid flooding device state machine with usless messages */
444
- if (_thing_id_property->isDifferentFromCloud ()) {
445
- _thing_id_property->fromCloudToLocal ();
446
-
447
- Message message;
448
- /* If we are attached we need first to detach */
449
- if (_device.isAttached ()) {
450
- detachThing ();
451
- message = { DeviceDetachedCmdId };
452
- }
453
- /* If received thing id is valid attach to the new thing */
454
- if (_thing_id.length ()) {
455
- attachThing ();
456
- message = { DeviceAttachedCmdId };
457
- } else {
458
- /* Send message to device state machine to inform we have received a null thing-id */
459
- _thing_id = " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ;
460
- message = { DeviceRegisteredCmdId };
461
- }
462
- _device.handleMessage (&message);
463
- }
464
447
}
465
448
466
449
/* Topic for user input data */
467
450
if (_dataTopicIn == topic) {
468
451
CBORDecoder::decode (_thing.getPropertyContainer (), (uint8_t *)bytes, length);
469
452
}
470
453
471
- /* Topic for sync Thing last values on connect */
472
- if (_shadowTopicIn == topic) {
473
- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values received" , __FUNCTION__, millis ());
474
- /* Decode last values property array */
475
- CBORDecoder::decode (_thing.getPropertyContainer (), (uint8_t *)bytes, length, true );
476
- /* Unlock thing state machine waiting last values */
477
- Message message = { LastValuesUpdateCmdId };
478
- _thing.handleMessage (&message);
479
- /* Call ArduinoIoTCloud sync user callback*/
480
- 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
+ if ( _thing_id != String (command.thingUpdateCmd .params .thing_id )) {
469
+ _thing_id = String (command.thingUpdateCmd .params .thing_id );
470
+ Message message;
471
+ /* If we are attached we need first to detach */
472
+ if (_device.isAttached ()) {
473
+ detachThing ();
474
+ message = { DeviceDetachedCmdId };
475
+ }
476
+ /* If received thing id is valid attach to the new thing */
477
+ if (_thing_id.length ()) {
478
+ attachThing ();
479
+ message = { DeviceAttachedCmdId };
480
+ } else {
481
+ /* Send message to device state machine to inform we have received a null thing-id */
482
+ _thing_id = " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ;
483
+ message = { DeviceRegisteredCmdId };
484
+ }
485
+ _device.handleMessage (&message);
486
+ }
487
+ }
488
+ break ;
489
+
490
+ case CommandId::LastValuesUpdateCmdId:
491
+ {
492
+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values received" , __FUNCTION__, millis ());
493
+ CBORDecoder::decode (_thing.getPropertyContainer (),
494
+ (uint8_t *)command.lastValuesUpdateCmd .params .last_values ,
495
+ command.lastValuesUpdateCmd .params .length , true );
496
+ _thing.handleMessage ((Message*)&command);
497
+ execCloudEventCallback (ArduinoIoTCloudEvent::SYNC);
498
+
499
+ /*
500
+ * NOTE: in this current version properties are not properly integrated with the new paradigm of
501
+ * modeling the messages with C structs. The current CBOR library allocates an array in the heap
502
+ * thus we need to delete it after decoding it with the old CBORDecoder
503
+ */
504
+ free (command.lastValuesUpdateCmd .params .last_values );
505
+ }
506
+ break ;
507
+
508
+ default :
509
+ break ;
510
+ }
511
+ }
481
512
}
482
513
}
483
514
484
515
void ArduinoIoTCloudTCP::sendMessage (Message * msg)
485
516
{
486
- switch (msg->id )
487
- {
488
- case DeviceBeginCmdId:
489
- sendDevicePropertiesToCloud ();
490
- break ;
517
+ uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE];
518
+ size_t bytes_encoded = sizeof (data);
519
+ CBORMessageEncoder encoder;
491
520
492
- case ThingBeginCmdId:
493
- requestThingId ();
494
- break ;
521
+ switch (msg->id ) {
522
+ case PropertiesUpdateCmdId:
523
+ return sendPropertyContainerToCloud (_dataTopicOut,
524
+ _thing.getPropertyContainer (),
525
+ _thing.getPropertyContainerIndex ());
526
+ break ;
495
527
496
- case LastValuesBeginCmdId:
497
- requestLastValue ();
498
- break ;
528
+ #if OTA_ENABLED
529
+ case DeviceBeginCmdId:
530
+ sendDevicePropertyToCloud (" OTA_CAP" );
531
+ sendDevicePropertyToCloud (" OTA_ERROR" );
532
+ sendDevicePropertyToCloud (" OTA_SHA256" );
533
+ break ;
534
+ #endif
499
535
500
- case PropertiesUpdateCmdId :
501
- sendThingPropertiesToCloud () ;
502
- break ;
536
+ default :
537
+ break ;
538
+ }
503
539
504
- default :
505
- break ;
540
+ if (encoder.encode (msg, data, bytes_encoded) == Encoder::Status::Complete &&
541
+ bytes_encoded > 0 ) {
542
+ write (_messageTopicOut, data, bytes_encoded);
543
+ } else {
544
+ DEBUG_ERROR (" error encoding %d" , msg->id );
506
545
}
507
546
}
508
547
@@ -526,29 +565,6 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, Proper
526
565
}
527
566
}
528
567
529
- void ArduinoIoTCloudTCP::sendThingPropertiesToCloud ()
530
- {
531
- sendPropertyContainerToCloud (_dataTopicOut, _thing.getPropertyContainer (), _thing.getPropertyContainerIndex ());
532
- }
533
-
534
- void ArduinoIoTCloudTCP::sendDevicePropertiesToCloud ()
535
- {
536
- PropertyContainer ro_device_property_container;
537
- unsigned int last_device_property_index = 0 ;
538
-
539
- std::list<String> ro_device_property_list {" LIB_VERSION" , " OTA_CAP" , " OTA_ERROR" , " OTA_SHA256" };
540
- std::for_each (ro_device_property_list.begin (),
541
- ro_device_property_list.end (),
542
- [this , &ro_device_property_container ] (String const & name)
543
- {
544
- Property* p = getProperty (this ->_device .getPropertyContainer (), name);
545
- if (p != nullptr )
546
- addPropertyToContainer (ro_device_property_container, *p, p->name (), p->isWriteableByCloud () ? Permission::ReadWrite : Permission::Read);
547
- }
548
- );
549
- sendPropertyContainerToCloud (_deviceTopicOut, ro_device_property_container, last_device_property_index);
550
- }
551
-
552
568
#if OTA_ENABLED
553
569
void ArduinoIoTCloudTCP::sendDevicePropertyToCloud (String const name)
554
570
{
@@ -564,26 +580,6 @@ void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
564
580
}
565
581
#endif
566
582
567
- void ArduinoIoTCloudTCP::requestLastValue ()
568
- {
569
- // Send the getLastValues CBOR message to the cloud
570
- // [{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
571
- // Use http://cbor.me to easily generate CBOR encoding
572
- 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 };
573
- write (_shadowTopicOut, CBOR_REQUEST_LAST_VALUE_MSG, sizeof (CBOR_REQUEST_LAST_VALUE_MSG));
574
- }
575
-
576
- void ArduinoIoTCloudTCP::requestThingId ()
577
- {
578
- if (!_mqttClient.subscribe (_deviceTopicIn))
579
- {
580
- /* If device_id is wrong the board can't connect to the broker so this condition
581
- * should never happen.
582
- */
583
- DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not subscribe to %s" , __FUNCTION__, _deviceTopicIn.c_str ());
584
- }
585
- }
586
-
587
583
void ArduinoIoTCloudTCP::attachThing ()
588
584
{
589
585
@@ -595,14 +591,6 @@ void ArduinoIoTCloudTCP::attachThing()
595
591
return ;
596
592
}
597
593
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
- return ;
604
- }
605
-
606
594
DEBUG_INFO (" Connected to Arduino IoT Cloud" );
607
595
DEBUG_INFO (" Thing ID: %s" , getThingId ().c_str ());
608
596
execCloudEventCallback (ArduinoIoTCloudEvent::CONNECT);
@@ -615,11 +603,6 @@ void ArduinoIoTCloudTCP::detachThing()
615
603
return ;
616
604
}
617
605
618
- if (!_mqttClient.unsubscribe (_shadowTopicIn)) {
619
- DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not unsubscribe from %s" , __FUNCTION__, _shadowTopicIn.c_str ());
620
- return ;
621
- }
622
-
623
606
DEBUG_INFO (" Disconnected from Arduino IoT Cloud" );
624
607
execCloudEventCallback (ArduinoIoTCloudEvent::DISCONNECT);
625
608
}
0 commit comments