Skip to content

Commit d118491

Browse files
pennamandreagilardoni
authored andcommitted
ArduinoIoTCloudTCP: switch to messages
1 parent fa9bab2 commit d118491

File tree

2 files changed

+81
-225
lines changed

2 files changed

+81
-225
lines changed

src/ArduinoIoTCloudTCP.cpp

Lines changed: 72 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "cbor/CBOREncoder.h"
3434
#include "cbor/CBORDecoder.h"
3535
#include "utility/watchdog/Watchdog.h"
36+
#include <typeinfo>
3637

3738
/******************************************************************************
3839
LOCAL MODULE FUNCTIONS
@@ -51,7 +52,6 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
5152
: _state{State::ConnectPhy}
5253
, _device_id{""}
5354
, _thing_id{""}
54-
, _thing_id_property{nullptr}
5555
, _connection_attempt(0,0)
5656
, _mqtt_data_buf{0}
5757
, _mqtt_data_len{0}
@@ -60,23 +60,15 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
6060
, _password("")
6161
#endif
6262
, _mqttClient{nullptr}
63-
, _deviceTopicOut("")
64-
, _deviceTopicIn("")
65-
, _shadowTopicOut("")
66-
, _shadowTopicIn("")
63+
, _messageTopicOut("")
64+
, _messageTopicIn("")
6765
, _dataTopicOut("")
6866
, _dataTopicIn("")
6967
, _message_stream(std::bind(&ArduinoIoTCloudTCP::sendMessage, this, std::placeholders::_1))
7068
, _thing(&_message_stream)
7169
, _device(&_message_stream)
7270
#if OTA_ENABLED
7371
, _ota(&_message_stream)
74-
, _ota_cap{false}
75-
, _ota_error{static_cast<int>(ota::OTAError::None)}
76-
, _ota_img_sha256{"Inv."}
77-
, _ota_url{""}
78-
, _ota_progress{"Resume"}
79-
, _ota_req{false}
8072
, _ask_user_before_executing_ota{false}
8173
, _get_ota_confirmation{nullptr}
8274
#endif /* OTA_ENABLED */
@@ -166,43 +158,19 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
166158
_mqttClient.setUsernamePassword(getDeviceId(), _password);
167159
}
168160
#endif
161+
169162
_mqttClient.onMessage(ArduinoIoTCloudTCP::onMessage);
170163
_mqttClient.setKeepAliveInterval(30 * 1000);
171164
_mqttClient.setConnectionTimeout(1500);
172165
_mqttClient.setId(getDeviceId().c_str());
173166

174-
_deviceTopicOut = getTopic_deviceout();
175-
_deviceTopicIn = getTopic_devicein();
176-
177-
Property* p;
178-
p = new CloudWrapperString(_lib_version);
179-
addPropertyToContainer(_device.getPropertyContainer(), *p, "LIB_VERSION", Permission::Read, -1);
180-
p = new CloudWrapperString(_thing_id);
181-
_thing_id_property = &addPropertyToContainer(_device.getPropertyContainer(), *p, "thing_id", Permission::ReadWrite, -1);
167+
_messageTopicOut = getTopic_messageout();
168+
_messageTopicIn = getTopic_messagein();
182169

183170
_thing.begin();
184171
_device.begin();
185172

186173
#if OTA_ENABLED
187-
p = new CloudWrapperBool(_ota_cap);
188-
addPropertyToContainer(_device.getPropertyContainer(), *p, "OTA_CAP", Permission::Read, -1).publishOnChange(0.0f, 0);
189-
p = new CloudWrapperInt(_ota_error);
190-
addPropertyToContainer(_device.getPropertyContainer(), *p, "OTA_ERROR", Permission::Read, -1).publishOnChange(0.0f, 0);
191-
p = new CloudWrapperString(_ota_progress);
192-
addPropertyToContainer(_device.getPropertyContainer(), *p, "OTA_PROGRESS", Permission::Read, -1).publishOnChange(0.0f, 0);
193-
p = new CloudWrapperString(_ota_img_sha256);
194-
addPropertyToContainer(_device.getPropertyContainer(), *p, "OTA_SHA256", Permission::Read, -1).publishOnChange(0.0f, 0);
195-
p = new CloudWrapperString(_ota_url);
196-
_ota_url_property = &addPropertyToContainer(_device.getPropertyContainer(), *p, "OTA_URL", Permission::ReadWrite, -1).publishOnChange(0.0f, 0).writeOnDemand();
197-
p = new CloudWrapperBool(_ota_req);
198-
addPropertyToContainer(_device.getPropertyContainer(), *p, "OTA_REQ", Permission::ReadWrite, -1).publishOnChange(0.0f, 0);
199-
200-
_ota_cap =_ota.isOtaCapable();
201-
202-
// Sha256 is calculated when the ota fsm reaches its second state
203-
_ota.update();
204-
_ota.update();
205-
206174
_ota.setClient(&_otaClient);
207175
#endif // OTA_ENABLED
208176

@@ -313,6 +281,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
313281
{
314282
if (_mqttClient.connect(_brokerAddress.c_str(), _brokerPort))
315283
{
284+
_mqttClient.subscribe(getTopic_messagein());
316285
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s connected to %s:%d", __FUNCTION__, _brokerAddress.c_str(), _brokerPort);
317286
/* Reconfigure timers for next state */
318287
_connection_attempt.begin(AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms, AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms);
@@ -336,8 +305,8 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
336305
}
337306

338307
_device.update();
308+
339309
#if OTA_ENABLED
340-
handle_OTARequest();
341310
_ota.update();
342311
#endif // OTA_ENABLED
343312

@@ -356,53 +325,11 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
356325
return State::Connected;
357326
}
358327

359-
#if OTA_ENABLED
360-
void ArduinoIoTCloudTCP::handle_OTARequest() {
361-
/* Request a OTA download if the hidden property
362-
* OTA request has been set.
363-
*/
364-
365-
if (_ota_req)
366-
{
367-
bool const ota_execution_allowed_by_user = (_get_ota_confirmation != nullptr && _get_ota_confirmation());
368-
bool const perform_ota_now = ota_execution_allowed_by_user || !_ask_user_before_executing_ota;
369-
if (perform_ota_now) {
370-
/* Clear the error flag. */
371-
_ota_error = static_cast<int>(ota::OTAError::None);
372-
/* Clear the request flag. */
373-
_ota_req = false;
374-
/* Transmit the cleared request flags to the cloud. */
375-
sendDevicePropertyToCloud("OTA_REQ");
376-
/* Call member function to handle OTA request. */
377-
//_ota_error = OTA::onRequest(_ota_url, _connection->getInterface());
378-
/* If something fails send the OTA error to the cloud */
379-
sendDevicePropertyToCloud("OTA_ERROR");
380-
381-
struct OtaUpdateCmdDown cmd = {
382-
OtaUpdateCmdDownId,
383-
"123456",
384-
};
385-
386-
strncpy(cmd.params.url, _ota_url.c_str(), URL_SIZE);
387-
388-
_ota.handleMessage((Message*) &cmd);
389-
}
390-
}
391-
392-
/* Check if we have received the OTA_URL property and provide
393-
* echo to the cloud.
394-
*/
395-
sendDevicePropertyToCloud("OTA_URL");
396-
}
397-
#endif /* OTA_ENABLED */
398-
399-
400328
ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Disconnect()
401329
{
402330
if (!_mqttClient.connected()) {
403331
DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__);
404332
} else {
405-
_mqttClient.unsubscribe(_shadowTopicIn);
406333
_mqttClient.unsubscribe(_dataTopicIn);
407334
/* TODO add device topic */
408335
_mqttClient.stop();
@@ -435,82 +362,88 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
435362
bytes[i] = _mqttClient.read();
436363
}
437364

438-
/* Topic for OTA properties and device configuration */
439-
if (_deviceTopicIn == topic) {
440-
CBORDecoder::decode(_device.getPropertyContainer(), (uint8_t*)bytes, length);
441-
/* Unlock device state machine waiting thing_id*/
442-
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] device configuration received", __FUNCTION__, millis());
443-
ThingGetIdCmdDown message;
444-
message.c.id = AttachThing;
445-
strcpy(message.params.thing_id, _thing_id.c_str());
446-
Serial.println(_thing_id.c_str());
447-
_device.handleMessage((Message*)&message);
448-
}
449-
450365
/* Topic for user input data */
451366
if (_dataTopicIn == topic) {
452-
CBORDecoder::decode(_thing.getPropertyContainer(), (uint8_t*)bytes, length);
367+
CBORDecoder::decode(getThing().getPropertyContainer(), (uint8_t*)bytes, length);
453368
}
454369

455-
/* Topic for sync Thing last values on connect */
456-
if (_shadowTopicIn == topic) {
457-
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis());
458-
CBORDecoder::decode(_thing.getPropertyContainer(), (uint8_t*)bytes, length, true);
459-
execCloudEventCallback(ArduinoIoTCloudEvent::SYNC);
460-
/* Unlock thing state machine waiting last values */
461-
Message message;
462-
message.id = LastValues;
463-
_thing.handleMessage(&message);
370+
/* Topic for device commands */
371+
if (_messageTopicIn == topic) {
372+
CommandDown command;
373+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] received %d bytes", __FUNCTION__, millis(), length);
374+
CBORMessageDecoder decoder;
375+
376+
size_t buffer_length = length;
377+
if (decoder.decode((Message*)&command, bytes, buffer_length) != Decoder::Status::Error) {
378+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] received command id %d", __FUNCTION__, millis(), command.c.id);
379+
switch (command.c.id)
380+
{
381+
case CommandID::ThingGetIdCmdDownId:
382+
{
383+
ThingGetIdCmdDown * msg = (ThingGetIdCmdDown *)&command;
384+
_thing_id = String(msg->params.thing_id);
385+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] device configuration received", __FUNCTION__, millis());
386+
_device.handleMessage((Message*)&command);
387+
}
388+
break;
389+
390+
case CommandID::ThingGetLastValueCmdDownId:
391+
{
392+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis());
393+
ThingGetLastValueCmdDown * msg = (ThingGetLastValueCmdDown*)&command;
394+
CBORDecoder::decode(getThing().getPropertyContainer(), (uint8_t*)msg->params.last_values, msg->params.length, true);
395+
_thing.handleMessage((Message*)&command);
396+
execCloudEventCallback(ArduinoIoTCloudEvent::SYNC);
397+
398+
/*
399+
* NOTE: in this current version properties are not properly integrated with the new paradigm of
400+
* modeling the messages with C structs. The current CBOR library allocates an array in the heap
401+
* thus we need to delete it after decoding it with the old CBORDecoder
402+
*/
403+
free(msg->params.last_values);
404+
}
405+
break;
406+
407+
#if OTA_ENABLED
408+
case CommandID::OtaUpdateCmdDownId:
409+
{
410+
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] ota update received", __FUNCTION__, millis());
411+
_ota.handleMessage((Message*)&command);
412+
}
413+
#endif
414+
415+
default:
416+
break;
417+
}
418+
}
464419
}
465420
}
466421

467422
void ArduinoIoTCloudTCP::sendMessage(Message * msg)
468423
{
469424
switch (msg->id)
470425
{
471-
case SendCapabilities:
472-
sendDevicePropertiesToCloud();
473-
break;
474426
case SendProperties:
475-
sendThingPropertiesToCloud();
476-
break;
477-
case GetLastValues:
478-
requestLastValue();
479-
break;
480-
case GetThingId:
481-
requestThingId();
427+
return sendThingPropertiesToCloud();
482428
break;
429+
483430
case AttachThing:
484-
attachThing();
485-
break;
486-
#if OTA_ENABLED
487-
case OtaBeginUpId:
488-
{
489-
OtaBeginUp *ota_begin_cmd = (OtaBeginUp*)msg;
490-
String sha256_str;
491-
std::for_each(ota_begin_cmd->params.sha,
492-
ota_begin_cmd->params.sha + SHA256::HASH_SIZE,
493-
[&sha256_str](uint8_t const elem) {
494-
char buf[4];
495-
snprintf(buf, 4, "%02X", elem);
496-
sha256_str += buf;
497-
});
498-
_ota_img_sha256 = sha256_str;
499-
}
431+
return attachThing();
500432
break;
501-
case OtaProgressCmdUpId:
502-
{
503-
OtaProgressCmdUp *ota_progress_cmd = (OtaProgressCmdUp*)msg;
504-
_ota_progress = OTACloudProcessInterface::STATE_NAMES[ota_progress_cmd->params.state < 0? OTACloudProcessInterface::Fail - ota_progress_cmd->params.state : ota_progress_cmd->params.state];
505-
Serial.println("This is not a bug from Andrea code");
506-
/* If something fails send the OTA error to the cloud */
507-
sendDevicePropertyToCloud("OTA_PROGRESS");
508-
}
509-
break;
510-
#endif
511433
default:
512434
break;
513435
}
436+
437+
uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE];
438+
size_t bytes_encoded = sizeof(data);
439+
CBORMessageEncoder encoder;
440+
441+
if (encoder.encode(msg, data, bytes_encoded) == Encoder::Status::Complete &&
442+
bytes_encoded > 0) {
443+
write(_messageTopicOut, data, bytes_encoded);
444+
} else {
445+
DEBUG_ERROR("error encoding %d", msg->id);
446+
}
514447
}
515448

516449
void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, PropertyContainer & container, unsigned int & current_property_index)
@@ -538,60 +471,6 @@ void ArduinoIoTCloudTCP::sendThingPropertiesToCloud()
538471
sendPropertyContainerToCloud(_dataTopicOut, _thing.getPropertyContainer(), _thing.getPropertyContainerIndex());
539472
}
540473

541-
void ArduinoIoTCloudTCP::sendDevicePropertiesToCloud()
542-
{
543-
PropertyContainer ro_device_container;
544-
unsigned int last_device_property_index = 0;
545-
546-
std::list<String> ro_device_property_list {"LIB_VERSION", "OTA_CAP", "OTA_ERROR", "OTA_SHA256"};
547-
std::for_each(ro_device_property_list.begin(),
548-
ro_device_property_list.end(),
549-
[this, &ro_device_container ] (String const & name)
550-
{
551-
Property* p = getProperty(this->_device.getPropertyContainer(), name);
552-
if(p != nullptr)
553-
addPropertyToContainer(ro_device_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read);
554-
}
555-
);
556-
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s announce device to the Cloud %d", __FUNCTION__, _time_service.getTime());
557-
sendPropertyContainerToCloud(_deviceTopicOut, ro_device_container, last_device_property_index);
558-
}
559-
560-
#if OTA_ENABLED
561-
void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name)
562-
{
563-
PropertyContainer temp_device_container;
564-
unsigned int last_device_property_index = 0;
565-
566-
Property* p = getProperty(this->_device.getPropertyContainer(), name);
567-
if(p != nullptr)
568-
{
569-
addPropertyToContainer(temp_device_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read);
570-
sendPropertyContainerToCloud(_deviceTopicOut, temp_device_container, last_device_property_index);
571-
}
572-
}
573-
#endif
574-
575-
void ArduinoIoTCloudTCP::requestLastValue()
576-
{
577-
// Send the getLastValues CBOR message to the cloud
578-
// [{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
579-
// Use http://cbor.me to easily generate CBOR encoding
580-
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s at time [%d]", __FUNCTION__, getTime());
581-
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 };
582-
write(_shadowTopicOut, CBOR_REQUEST_LAST_VALUE_MSG, sizeof(CBOR_REQUEST_LAST_VALUE_MSG));
583-
}
584-
585-
void ArduinoIoTCloudTCP::requestThingId()
586-
{
587-
if (!_mqttClient.subscribe(_deviceTopicIn))
588-
{
589-
/* If device_id is wrong the board can't connect to the broker so this condition
590-
* should never happen.
591-
*/
592-
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not subscribe to %s", __FUNCTION__, _deviceTopicIn.c_str());
593-
}
594-
}
595474

596475
void ArduinoIoTCloudTCP::attachThing()
597476
{
@@ -604,15 +483,6 @@ void ArduinoIoTCloudTCP::attachThing()
604483
return;
605484
}
606485

607-
_shadowTopicIn = getTopic_shadowin();
608-
_shadowTopicOut = getTopic_shadowout();
609-
if (!_mqttClient.subscribe(_shadowTopicIn))
610-
{
611-
DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not subscribe to %s", __FUNCTION__, _shadowTopicIn.c_str());
612-
DEBUG_ERROR("Check your thing configuration, and press the reset button on your board.");
613-
return;
614-
}
615-
616486
DEBUG_INFO("Connected to Arduino IoT Cloud");
617487
DEBUG_INFO("Thing ID: %s", getThingId().c_str());
618488
execCloudEventCallback(ArduinoIoTCloudEvent::CONNECT);

0 commit comments

Comments
 (0)