Skip to content

Commit 073bdb9

Browse files
pennamandreagilardoni
authored andcommitted
ArduinoIoTCloudTCP: switch to messages
1 parent 105ca85 commit 073bdb9

File tree

2 files changed

+108
-124
lines changed

2 files changed

+108
-124
lines changed

Diff for: src/ArduinoIoTCloudTCP.cpp

+98-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

@@ -341,6 +346,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
341346
{
342347
if (!_mqttClient.connected() || !_thing.connected() || !_device.connected())
343348
{
349+
Serial.println("State::Disconnect");
344350
return State::Disconnect;
345351
}
346352

@@ -439,70 +445,104 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
439445
/* Topic for OTA properties and device configuration */
440446
if (_deviceTopicIn == topic) {
441447
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-
}
464448
}
465449

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

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);
455+
/* Topic for device commands */
456+
if (_messageTopicIn == topic) {
457+
CommandDown command;
458+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] received %d bytes", __FUNCTION__, millis(), length);
459+
CBORMessageDecoder decoder;
460+
461+
size_t buffer_length = length;
462+
if (decoder.decode((Message*)&command, bytes, buffer_length) != Decoder::Status::Error) {
463+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] received command id %d", __FUNCTION__, millis(), command.c.id);
464+
switch (command.c.id)
465+
{
466+
case CommandId::ThingUpdateCmdId:
467+
{
468+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] device configuration received", __FUNCTION__, millis());
469+
if ( _thing_id != String(command.thingBeginCmd.params.thing_id)) {
470+
_thing_id = String(command.thingBeginCmd.params.thing_id);
471+
Message message;
472+
/* If we are attached we need first to detach */
473+
if (_device.isAttached()) {
474+
detachThing();
475+
message = { DeviceDetachedCmdId };
476+
}
477+
/* If received thing id is valid attach to the new thing */
478+
if (_thing_id.length()) {
479+
attachThing();
480+
message = { DeviceAttachedCmdId };
481+
} else {
482+
/* Send message to device state machine to inform we have received a null thing-id */
483+
_thing_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
484+
message = { DeviceRegisteredCmdId };
485+
}
486+
_device.handleMessage(&message);
487+
}
488+
}
489+
break;
490+
491+
case CommandId::LastValuesUpdateCmdId:
492+
{
493+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis());
494+
CBORDecoder::decode(_thing.getPropertyContainer(),
495+
(uint8_t*)command.lastValuesUpdateCmd.params.last_values,
496+
command.lastValuesUpdateCmd.params.length, true);
497+
_thing.handleMessage((Message*)&command);
498+
execCloudEventCallback(ArduinoIoTCloudEvent::SYNC);
499+
500+
/*
501+
* NOTE: in this current version properties are not properly integrated with the new paradigm of
502+
* modeling the messages with C structs. The current CBOR library allocates an array in the heap
503+
* thus we need to delete it after decoding it with the old CBORDecoder
504+
*/
505+
free(command.lastValuesUpdateCmd.params.last_values);
506+
}
507+
break;
508+
509+
default:
510+
break;
511+
}
512+
}
481513
}
482514
}
483515

484516
void ArduinoIoTCloudTCP::sendMessage(Message * msg)
485517
{
486-
switch (msg->id)
487-
{
488-
case DeviceBeginCmdId:
489-
sendDevicePropertiesToCloud();
490-
break;
518+
uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE];
519+
size_t bytes_encoded = sizeof(data);
520+
CBORMessageEncoder encoder;
491521

492-
case ThingBeginCmdId:
493-
requestThingId();
494-
break;
522+
switch (msg->id) {
523+
case PropertiesUpdateCmdId:
524+
return sendPropertyContainerToCloud(_dataTopicOut,
525+
_thing.getPropertyContainer(),
526+
_thing.getPropertyContainerIndex());
527+
break;
495528

496-
case LastValuesBeginCmdId:
497-
requestLastValue();
498-
break;
529+
#if OTA_ENABLED
530+
case DeviceBeginCmdId:
531+
sendDevicePropertyToCloud("OTA_CAP");
532+
sendDevicePropertyToCloud("OTA_ERROR");
533+
sendDevicePropertyToCloud("OTA_SHA256");
534+
break;
535+
#endif
499536

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

504-
default:
505-
break;
541+
if (encoder.encode(msg, data, bytes_encoded) == Encoder::Status::Complete &&
542+
bytes_encoded > 0) {
543+
write(_messageTopicOut, data, bytes_encoded);
544+
} else {
545+
DEBUG_ERROR("error encoding %d", msg->id);
506546
}
507547
}
508548

@@ -526,29 +566,6 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, Proper
526566
}
527567
}
528568

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-
552569
#if OTA_ENABLED
553570
void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
554571
{
@@ -564,26 +581,6 @@ void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
564581
}
565582
#endif
566583

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-
587584
void ArduinoIoTCloudTCP::attachThing()
588585
{
589586

@@ -595,14 +592,6 @@ void ArduinoIoTCloudTCP::attachThing()
595592
return;
596593
}
597594

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-
606595
DEBUG_INFO("Connected to Arduino IoT Cloud");
607596
DEBUG_INFO("Thing ID: %s", getThingId().c_str());
608597
execCloudEventCallback(ArduinoIoTCloudEvent::CONNECT);
@@ -615,11 +604,6 @@ void ArduinoIoTCloudTCP::detachThing()
615604
return;
616605
}
617606

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

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)