Skip to content

Commit 3a0b4ce

Browse files
committed
ArduinoIoTCloudTCP: switch to messages
1 parent 04d7bf8 commit 3a0b4ce

File tree

2 files changed

+107
-126
lines changed

2 files changed

+107
-126
lines changed

Diff for: src/ArduinoIoTCloudTCP.cpp

+96-115
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <algorithm>
4444
#include "cbor/CBOREncoder.h"
4545
#include "utility/watchdog/Watchdog.h"
46+
#include <typeinfo>
4647

4748
/******************************************************************************
4849
LOCAL MODULE FUNCTIONS
@@ -62,7 +63,6 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
6263
, _connection_attempt(0,0)
6364
, _message_stream(std::bind(&ArduinoIoTCloudTCP::sendMessage, this, std::placeholders::_1))
6465
, _thing(&_message_stream)
65-
, _thing_id_property{nullptr}
6666
, _device(&_message_stream)
6767
, _mqtt_data_buf{0}
6868
, _mqtt_data_len{0}
@@ -76,8 +76,8 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
7676
, _mqttClient{nullptr}
7777
, _deviceTopicOut("")
7878
, _deviceTopicIn("")
79-
, _shadowTopicOut("")
80-
, _shadowTopicIn("")
79+
, _messageTopicOut("")
80+
, _messageTopicIn("")
8181
, _dataTopicOut("")
8282
, _dataTopicIn("")
8383
#if OTA_ENABLED
@@ -181,24 +181,22 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
181181
_mqttClient.setUsernamePassword(getDeviceId(), _password);
182182
}
183183
#endif
184+
184185
_mqttClient.onMessage(ArduinoIoTCloudTCP::onMessage);
185186
_mqttClient.setKeepAliveInterval(30 * 1000);
186187
_mqttClient.setConnectionTimeout(1500);
187188
_mqttClient.setId(getDeviceId().c_str());
188189

189190
_deviceTopicOut = getTopic_deviceout();
190191
_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();
197194

198195
_thing.begin();
199196
_device.begin();
200197

201198
#if OTA_ENABLED
199+
Property* p;
202200
p = new CloudWrapperBool(_ota_cap);
203201
addPropertyToContainer(_device.getPropertyContainer(), *p, "OTA_CAP", Permission::Read, -1);
204202
p = new CloudWrapperInt(_ota_error);
@@ -322,9 +320,16 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
322320
{
323321
if (_mqttClient.connect(_brokerAddress.c_str(), _brokerPort))
324322
{
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+
326329
/* Reconfigure timers for next state */
327330
_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);
328333
return State::Connected;
329334
}
330335

@@ -413,7 +418,6 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Disconnect()
413418
_thing.handleMessage(&message);
414419
_device.handleMessage(&message);
415420

416-
_thing_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
417421
DEBUG_INFO("Disconnected from Arduino IoT Cloud");
418422
execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT);
419423

@@ -440,68 +444,101 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
440444
/* Topic for OTA properties and device configuration */
441445
if (_deviceTopicIn == topic) {
442446
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-
}
463447
}
464448

465449
/* Topic for user input data */
466450
if (_dataTopicIn == topic) {
467451
CBORDecoder::decode(_thing.getPropertyContainer(), (uint8_t*)bytes, length);
468452
}
469453

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+
}
480509
}
481510
}
482511

483512
void ArduinoIoTCloudTCP::sendMessage(Message * msg)
484513
{
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;
490517

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;
494524

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
498532

499-
case PropertiesUpdateCmdId:
500-
sendThingPropertiesToCloud();
501-
break;
533+
default:
534+
break;
535+
}
502536

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);
505542
}
506543
}
507544

@@ -525,29 +562,6 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, Proper
525562
}
526563
}
527564

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-
551565
#if OTA_ENABLED
552566
void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
553567
{
@@ -563,28 +577,9 @@ void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
563577
}
564578
#endif
565579

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)
587581
{
582+
_thing_id = thingId;
588583

589584
_dataTopicIn = getTopic_datain();
590585
_dataTopicOut = getTopic_dataout();
@@ -595,15 +590,6 @@ void ArduinoIoTCloudTCP::attachThing()
595590
return;
596591
}
597592

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-
607593
Message message;
608594
message = { DeviceAttachedCmdId };
609595
_device.handleMessage(&message);
@@ -620,11 +606,6 @@ void ArduinoIoTCloudTCP::detachThing()
620606
return;
621607
}
622608

623-
if (!_mqttClient.unsubscribe(_shadowTopicIn)) {
624-
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not unsubscribe from %s", __FUNCTION__, _shadowTopicIn.c_str());
625-
return;
626-
}
627-
628609
Message message;
629610
message = { DeviceDetachedCmdId };
630611
_device.handleMessage(&message);

Diff for: src/ArduinoIoTCloudTCP.h

+11-11
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@
5656
#include <utility/ota/OTA.h>
5757
#endif
5858

59+
#include "cbor/MessageDecoder.h"
60+
#include "cbor/MessageEncoder.h"
61+
5962
/******************************************************************************
6063
CONSTANTS
6164
******************************************************************************/
@@ -125,7 +128,6 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
125128
TimedAttempt _connection_attempt;
126129
MessageStream _message_stream;
127130
ArduinoCloudThing _thing;
128-
Property * _thing_id_property;
129131
ArduinoCloudDevice _device;
130132

131133
String _brokerAddress;
@@ -165,8 +167,8 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
165167

166168
String _deviceTopicOut;
167169
String _deviceTopicIn;
168-
String _shadowTopicOut;
169-
String _shadowTopicIn;
170+
String _messageTopicOut;
171+
String _messageTopicIn;
170172
String _dataTopicOut;
171173
String _dataTopicIn;
172174

@@ -182,8 +184,10 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
182184

183185
inline String getTopic_deviceout() { return String("/a/d/" + getDeviceId() + "/e/o");}
184186
inline String getTopic_devicein () { return String("/a/d/" + getDeviceId() + "/e/i");}
185-
inline String getTopic_shadowout() { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/shadow/o"); }
186-
inline String getTopic_shadowin () { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/shadow/i"); }
187+
188+
inline String getTopic_messageout() { return String("/a/d/" + getDeviceId() + "/c/up");}
189+
inline String getTopic_messagein () { return String("/a/d/" + getDeviceId() + "/c/dw");}
190+
187191
inline String getTopic_dataout () { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/e/o"); }
188192
inline String getTopic_datain () { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/e/i"); }
189193

@@ -197,18 +201,14 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
197201
void handleMessage(int length);
198202
void sendMessage(Message * msg);
199203
void sendPropertyContainerToCloud(String const topic, PropertyContainer & property_container, unsigned int & current_property_index);
200-
void sendThingPropertiesToCloud();
201-
void sendDevicePropertiesToCloud();
202-
void requestLastValue();
203-
void requestThingId();
204-
void attachThing();
204+
205+
void attachThing(String thingId);
205206
void detachThing();
206207
int write(String const topic, byte const data[], int const length);
207208

208209
#if OTA_ENABLED
209210
void sendDevicePropertyToCloud(String const name);
210211
#endif
211-
212212
};
213213

214214
/******************************************************************************

0 commit comments

Comments
 (0)