Skip to content

Commit 8f0c243

Browse files
committed
ArduinoIoTCloudTCP: switch to messages
1 parent 24de8e6 commit 8f0c243

File tree

2 files changed

+107
-124
lines changed

2 files changed

+107
-124
lines changed

Diff for: src/ArduinoIoTCloudTCP.cpp

+97-114
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

@@ -439,70 +444,104 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
439444
/* Topic for OTA properties and device configuration */
440445
if (_deviceTopicIn == topic) {
441446
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-
}
464447
}
465448

466449
/* Topic for user input data */
467450
if (_dataTopicIn == topic) {
468451
CBORDecoder::decode(_thing.getPropertyContainer(), (uint8_t*)bytes, length);
469452
}
470453

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+
}
481512
}
482513
}
483514

484515
void ArduinoIoTCloudTCP::sendMessage(Message * msg)
485516
{
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;
491520

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

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
499535

500-
case PropertiesUpdateCmdId:
501-
sendThingPropertiesToCloud();
502-
break;
536+
default:
537+
break;
538+
}
503539

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);
506545
}
507546
}
508547

@@ -526,29 +565,6 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, Proper
526565
}
527566
}
528567

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-
552568
#if OTA_ENABLED
553569
void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
554570
{
@@ -564,26 +580,6 @@ void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
564580
}
565581
#endif
566582

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-
587583
void ArduinoIoTCloudTCP::attachThing()
588584
{
589585

@@ -595,14 +591,6 @@ void ArduinoIoTCloudTCP::attachThing()
595591
return;
596592
}
597593

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-
606594
DEBUG_INFO("Connected to Arduino IoT Cloud");
607595
DEBUG_INFO("Thing ID: %s", getThingId().c_str());
608596
execCloudEventCallback(ArduinoIoTCloudEvent::CONNECT);
@@ -615,11 +603,6 @@ void ArduinoIoTCloudTCP::detachThing()
615603
return;
616604
}
617605

618-
if (!_mqttClient.unsubscribe(_shadowTopicIn)) {
619-
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not unsubscribe from %s", __FUNCTION__, _shadowTopicIn.c_str());
620-
return;
621-
}
622-
623606
DEBUG_INFO("Disconnected from Arduino IoT Cloud");
624607
execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT);
625608
}

Diff for: src/ArduinoIoTCloudTCP.h

+10-10
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+
204205
void attachThing();
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)