From fc0ddb9c034c86d644f417272f71610111292461 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 3 Feb 2022 14:43:25 +0100 Subject: [PATCH 01/21] Split _property_container in _device_property_container and _thing_property container --- src/ArduinoIoTCloud.cpp | 92 +++++++++++++++++++++++++++++------- src/ArduinoIoTCloud.h | 22 ++++++++- src/ArduinoIoTCloudLPWAN.cpp | 6 +-- src/ArduinoIoTCloudTCP.cpp | 32 +++++++------ src/ArduinoIoTCloudTCP.h | 4 +- 5 files changed, 118 insertions(+), 38 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 115ce3a0d..ff83facc1 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -44,12 +44,12 @@ ArduinoIoTCloudClass::ArduinoIoTCloudClass() void ArduinoIoTCloudClass::push() { - requestUpdateForAllProperties(_property_container); + requestUpdateForAllProperties(_thing_property_container); } bool ArduinoIoTCloudClass::setTimestamp(String const & prop_name, unsigned long const timestamp) { - Property * p = getProperty(_property_container, prop_name); + Property * p = getProperty(_thing_property_container, prop_name); if (p == nullptr) return false; @@ -81,20 +81,30 @@ void ArduinoIoTCloudClass::addPropertyReal(Property& property, String name, int } if (seconds == ON_CHANGE) { - addPropertyToContainer(_property_container, property, name, permission, tag).publishOnChange(minDelta, Property::DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn); + addPropertyToContainer(_thing_property_container, property, name, permission, tag).publishOnChange(minDelta, Property::DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn); } else { - addPropertyToContainer(_property_container, property, name, permission, tag).publishEvery(seconds).onUpdate(fn).onSync(synFn); + addPropertyToContainer(_thing_property_container, property, name, permission, tag).publishEvery(seconds).onUpdate(fn).onSync(synFn); } } Property& ArduinoIoTCloudClass::addPropertyReal(Property& property, String name, Permission const permission) { - return addPropertyToContainer(_property_container, property, name, permission); + return addPropertyToContainer(_thing_property_container, property, name, permission); } Property& ArduinoIoTCloudClass::addPropertyReal(Property& property, String name, int tag, Permission const permission) { - return addPropertyToContainer(_property_container, property, name, permission, tag); + return addPropertyToContainer(_thing_property_container, property, name, permission, tag); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(Property& property, PropertyContainer &prop_cont, String name, Permission const permission) +{ + return addPropertyToContainer(prop_cont, property, name, permission, -1); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(Property& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission) +{ + return addPropertyToContainer(prop_cont, property, name, permission, tag); } void ArduinoIoTCloudClass::addPropertyReal(bool& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property)) @@ -110,13 +120,23 @@ void ArduinoIoTCloudClass::addPropertyReal(bool& property, String name, int tag, Property& ArduinoIoTCloudClass::addPropertyReal(bool& property, String name, Permission const permission) { - return addPropertyReal(property, name, -1, permission); + return addPropertyReal(property, _thing_property_container, name, -1, permission); } Property& ArduinoIoTCloudClass::addPropertyReal(bool& property, String name, int tag, Permission const permission) +{ + return addPropertyReal(property, _thing_property_container, name, tag, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(bool& property, PropertyContainer &prop_cont, String name, Permission const permission) +{ + return addPropertyReal(property, prop_cont, name, -1, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(bool& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission) { Property* p = new CloudWrapperBool(property); - return addPropertyToContainer(_property_container, *p, name, permission, tag); + return addPropertyToContainer(prop_cont, *p, name, permission, tag); } void ArduinoIoTCloudClass::addPropertyReal(float& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property)) @@ -132,13 +152,23 @@ void ArduinoIoTCloudClass::addPropertyReal(float& property, String name, int tag Property& ArduinoIoTCloudClass::addPropertyReal(float& property, String name, Permission const permission) { - return addPropertyReal(property, name, -1, permission); + return addPropertyReal(property, _thing_property_container, name, -1, permission); } Property& ArduinoIoTCloudClass::addPropertyReal(float& property, String name, int tag, Permission const permission) +{ + return addPropertyReal(property, _thing_property_container, name, tag, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(float& property, PropertyContainer &prop_cont, String name, Permission const permission) +{ + return addPropertyReal(property, prop_cont, name, -1, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(float& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission) { Property* p = new CloudWrapperFloat(property); - return addPropertyToContainer(_property_container, *p, name, permission, tag); + return addPropertyToContainer(prop_cont, *p, name, permission, tag); } void ArduinoIoTCloudClass::addPropertyReal(int& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property)) @@ -154,13 +184,23 @@ void ArduinoIoTCloudClass::addPropertyReal(int& property, String name, int tag, Property& ArduinoIoTCloudClass::addPropertyReal(int& property, String name, Permission const permission) { - return addPropertyReal(property, name, -1, permission); + return addPropertyReal(property, _thing_property_container, name, -1, permission); } Property& ArduinoIoTCloudClass::addPropertyReal(int& property, String name, int tag, Permission const permission) +{ + return addPropertyReal(property, _thing_property_container, name, tag, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(int& property, PropertyContainer &prop_cont, String name, Permission const permission) +{ + return addPropertyReal(property, prop_cont, name, -1, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(int& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission) { Property* p = new CloudWrapperInt(property); - return addPropertyToContainer(_property_container, *p, name, permission, tag); + return addPropertyToContainer(prop_cont, *p, name, permission, tag); } void ArduinoIoTCloudClass::addPropertyReal(unsigned int& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property)) @@ -176,13 +216,23 @@ void ArduinoIoTCloudClass::addPropertyReal(unsigned int& property, String name, Property& ArduinoIoTCloudClass::addPropertyReal(unsigned int& property, String name, Permission const permission) { - return addPropertyReal(property, name, -1, permission); + return addPropertyReal(property, _thing_property_container, name, -1, permission); } Property& ArduinoIoTCloudClass::addPropertyReal(unsigned int& property, String name, int tag, Permission const permission) +{ + return addPropertyReal(property, _thing_property_container, name, tag, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(unsigned int& property, PropertyContainer &prop_cont, String name, Permission const permission) +{ + return addPropertyReal(property, prop_cont, name, -1, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(unsigned int& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission) { Property* p = new CloudWrapperUnsignedInt(property); - return addPropertyToContainer(_property_container, *p, name, permission, tag); + return addPropertyToContainer(prop_cont, *p, name, permission, tag); } void ArduinoIoTCloudClass::addPropertyReal(String& property, String name, permissionType permission_type, long seconds, void(*fn)(void), float minDelta, void(*synFn)(Property & property)) @@ -198,13 +248,23 @@ void ArduinoIoTCloudClass::addPropertyReal(String& property, String name, int ta Property& ArduinoIoTCloudClass::addPropertyReal(String& property, String name, Permission const permission) { - return addPropertyReal(property, name, -1, permission); + return addPropertyReal(property, _thing_property_container, name, -1, permission); } Property& ArduinoIoTCloudClass::addPropertyReal(String& property, String name, int tag, Permission const permission) +{ + return addPropertyReal(property, _thing_property_container, name, tag, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(String& property, PropertyContainer &prop_cont, String name, Permission const permission) +{ + return addPropertyReal(property, prop_cont, name, -1, permission); +} + +Property& ArduinoIoTCloudClass::addPropertyReal(String& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission) { Property* p = new CloudWrapperString(property); - return addPropertyToContainer(_property_container, *p, name, permission, tag); + return addPropertyToContainer(prop_cont, *p, name, permission, tag); } /****************************************************************************** diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 565a91501..558b8c96f 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -96,6 +96,9 @@ class ArduinoIoTCloudClass inline void setDeviceId(String const device_id) { _device_id = device_id; }; inline String & getDeviceId() { return _device_id; }; + inline bool deviceNotAttached() { return _thing_id == "null";} + inline bool deviceNotConfigured() { return _thing_id == "";} + inline ConnectionHandler * getConnection() { return _connection; } inline unsigned long getInternalTime() { return _time_service.getTime(); } @@ -124,6 +127,20 @@ class ArduinoIoTCloudClass Property& addPropertyReal(unsigned int& property, String name, Permission const permission); Property& addPropertyReal(String& property, String name, Permission const permission); + Property& addPropertyReal(Property& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission); + Property& addPropertyReal(bool& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission); + Property& addPropertyReal(float& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission); + Property& addPropertyReal(int& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission); + Property& addPropertyReal(unsigned int& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission); + Property& addPropertyReal(String& property, PropertyContainer &prop_cont, String name, int tag, Permission const permission); + + Property& addPropertyReal(Property& property, PropertyContainer &prop_cont, String name, Permission const permission); + Property& addPropertyReal(bool& property, PropertyContainer &prop_cont, String name, Permission const permission); + Property& addPropertyReal(float& property, PropertyContainer &prop_cont, String name, Permission const permission); + Property& addPropertyReal(int& property, PropertyContainer &prop_cont, String name, Permission const permission); + Property& addPropertyReal(unsigned int& property, PropertyContainer &prop_cont, String name, Permission const permission); + Property& addPropertyReal(String& property, PropertyContainer &prop_cont, String name, Permission const permission); + /* The following methods are for MKR WAN 1300/1310 LoRa boards since * they use a number to identify a given property within a CBOR message. * This approach reduces the required amount of data which is of great @@ -147,17 +164,18 @@ class ArduinoIoTCloudClass protected: ConnectionHandler * _connection; - PropertyContainer _property_container; + PropertyContainer _device_property_container; + PropertyContainer _thing_property_container; unsigned int _last_checked_property_index; TimeService & _time_service; int _tz_offset; unsigned int _tz_dst_until; + String _thing_id; void execCloudEventCallback(ArduinoIoTCloudEvent const event); private: - String _thing_id; String _device_id; OnCloudEventCallback _cloud_event_callback[3]; }; diff --git a/src/ArduinoIoTCloudLPWAN.cpp b/src/ArduinoIoTCloudLPWAN.cpp index fc85d0471..5d501dd30 100644 --- a/src/ArduinoIoTCloudLPWAN.cpp +++ b/src/ArduinoIoTCloudLPWAN.cpp @@ -121,7 +121,7 @@ ArduinoIoTCloudLPWAN::State ArduinoIoTCloudLPWAN::handle_Connected() /* Check if a primitive property wrapper is locally changed. */ updateTimestampOnLocallyChangedProperties(_property_container); - + /* Decode available data. */ if (_connection->available()) decodePropertiesFromCloud(); @@ -142,7 +142,7 @@ void ArduinoIoTCloudLPWAN::decodePropertiesFromCloud() { lora_msg_buf[bytes_received] = _connection->read(); } - CBORDecoder::decode(_property_container, lora_msg_buf, bytes_received); + CBORDecoder::decode(_thing_property_container, lora_msg_buf, bytes_received); } void ArduinoIoTCloudLPWAN::sendPropertiesToCloud() @@ -150,7 +150,7 @@ void ArduinoIoTCloudLPWAN::sendPropertiesToCloud() int bytes_encoded = 0; uint8_t data[CBOR_LORA_MSG_MAX_SIZE]; - if (CBOREncoder::encode(_property_container, data, sizeof(data), bytes_encoded, _last_checked_property_index, true) == CborNoError) + if (CBOREncoder::encode(_thing_property_container, data, sizeof(data), bytes_encoded, _last_checked_property_index, true) == CborNoError) if (bytes_encoded > 0) writeProperties(data, bytes_encoded); } diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index e78011852..7d154a896 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -243,15 +243,17 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, _dataTopicIn = getTopic_datain(); #if OTA_ENABLED - addPropertyReal(_ota_cap, "OTA_CAP", Permission::Read); - addPropertyReal(_ota_error, "OTA_ERROR", Permission::Read); - addPropertyReal(_ota_img_sha256, "OTA_SHA256", Permission::Read); - addPropertyReal(_ota_url, "OTA_URL", Permission::ReadWrite).onSync(CLOUD_WINS); - addPropertyReal(_ota_req, "OTA_REQ", Permission::ReadWrite).onSync(CLOUD_WINS); + addPropertyReal(_ota_cap, _device_property_container, "OTA_CAP", Permission::Read); + addPropertyReal(_ota_error, _device_property_container, "OTA_ERROR", Permission::Read); + addPropertyReal(_ota_img_sha256, _device_property_container, "OTA_SHA256", Permission::Read); + addPropertyReal(_ota_url, _device_property_container, "OTA_URL", Permission::ReadWrite).onSync(CLOUD_WINS); + addPropertyReal(_ota_req, _device_property_container, "OTA_REQ", Permission::ReadWrite).onSync(CLOUD_WINS); #endif /* OTA_ENABLED */ - addPropertyReal(_tz_offset, "tz_offset", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); - addPropertyReal(_tz_dst_until, "tz_dst_until", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); + addPropertyReal(_tz_offset, _thing_property_container, "tz_offset", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); + addPropertyReal(_tz_dst_until, _thing_property_container, "tz_dst_until", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); + + addPropertyReal(_thing_id, _device_property_container, "thing_id", Permission::ReadWrite); #if OTA_STORAGE_PORTENTA_QSPI #define BOOTLOADER_ADDR (0x8000000) @@ -524,7 +526,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() * the connection from being established due to a wrong data * in the reconstructed certificate. */ - updateTimestampOnLocallyChangedProperties(_property_container); + updateTimestampOnLocallyChangedProperties(_thing_property_container); /* Retransmit data in case there was a lost transaction due * to phy layer or MQTT connectivity loss. @@ -586,13 +588,13 @@ void ArduinoIoTCloudTCP::handleMessage(int length) } if (_dataTopicIn == topic) { - CBORDecoder::decode(_property_container, (uint8_t*)bytes, length); + CBORDecoder::decode(_thing_property_container, (uint8_t*)bytes, length); } if ((_shadowTopicIn == topic) && (_state == State::RequestLastValues)) { DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis()); - CBORDecoder::decode(_property_container, (uint8_t*)bytes, length, true); + CBORDecoder::decode(_thing_property_container, (uint8_t*)bytes, length, true); sendPropertiesToCloud(); _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); execCloudEventCallback(ArduinoIoTCloudEvent::SYNC); @@ -602,7 +604,7 @@ void ArduinoIoTCloudTCP::handleMessage(int length) } } -void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(PropertyContainer & property_container, unsigned int & current_property_index) +void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, PropertyContainer & property_container, unsigned int & current_property_index) { int bytes_encoded = 0; uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE]; @@ -616,13 +618,13 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(PropertyContainer & proper _mqtt_data_len = bytes_encoded; memcpy(_mqtt_data_buf, data, _mqtt_data_len); /* Transmit the properties to the MQTT broker */ - write(_dataTopicOut, _mqtt_data_buf, _mqtt_data_len); + write(topic, _mqtt_data_buf, _mqtt_data_len); } } void ArduinoIoTCloudTCP::sendPropertiesToCloud() { - sendPropertyContainerToCloud(_property_container, _last_checked_property_index); + sendPropertyContainerToCloud(_dataTopicOut, _thing_property_container, _last_checked_property_index); } #if OTA_ENABLED @@ -636,13 +638,13 @@ void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud() ota_property_list.cend(), [this, &ota_property_container ] (String const & name) { - Property* p = getProperty(this->_property_container, name); + Property* p = getProperty(this->_device_property_container, name); if(p != nullptr) addPropertyToContainer(ota_property_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read); } ); - sendPropertyContainerToCloud(ota_property_container, last_ota_property_index); + sendPropertyContainerToCloud(_dataTopicOut, ota_property_container, last_ota_property_index); } #endif diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 59caba7a2..663acd111 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -166,7 +166,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass static void onMessage(int length); void handleMessage(int length); - void sendPropertyContainerToCloud(PropertyContainer & property_container, unsigned int & current_property_index); + void sendPropertyContainerToCloud(String const topic, PropertyContainer & property_container, unsigned int & current_property_index); void sendPropertiesToCloud(); void requestLastValue(); int write(String const topic, byte const data[], int const length); @@ -184,4 +184,4 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass extern ArduinoIoTCloudTCP ArduinoCloud; -#endif \ No newline at end of file +#endif From 1af47011e7f717d586ad8d72b2108f433bbff0c2 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 11 Jan 2022 13:36:47 +0100 Subject: [PATCH 02/21] ArduinoIoTCloudTCP state machine changes to handle thig_id discovery protocol --- src/ArduinoIoTCloud.h | 9 +- src/ArduinoIoTCloudLPWAN.cpp | 2 +- src/ArduinoIoTCloudTCP.cpp | 191 +++++++++++++++++++++++++++++++---- src/ArduinoIoTCloudTCP.h | 29 ++++-- 4 files changed, 202 insertions(+), 29 deletions(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 558b8c96f..bad570c7e 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -96,8 +96,12 @@ class ArduinoIoTCloudClass inline void setDeviceId(String const device_id) { _device_id = device_id; }; inline String & getDeviceId() { return _device_id; }; - inline bool deviceNotAttached() { return _thing_id == "null";} - inline bool deviceNotConfigured() { return _thing_id == "";} + inline void setThingIdOutdatedFlag() { _thing_id_outdated = true ; } + inline void clrThingIdOutdatedFlag() { _thing_id_outdated = false ; } + inline bool getThingIdOutdatedFlag() { return _thing_id_outdated; } + + inline bool deviceNotAttached() { return _thing_id == "null"; } + inline bool deviceNotConfigured() { return _thing_id == ""; } inline ConnectionHandler * getConnection() { return _connection; } @@ -178,6 +182,7 @@ class ArduinoIoTCloudClass String _device_id; OnCloudEventCallback _cloud_event_callback[3]; + bool _thing_id_outdated; }; #ifdef HAS_TCP diff --git a/src/ArduinoIoTCloudLPWAN.cpp b/src/ArduinoIoTCloudLPWAN.cpp index 5d501dd30..fbc42b628 100644 --- a/src/ArduinoIoTCloudLPWAN.cpp +++ b/src/ArduinoIoTCloudLPWAN.cpp @@ -120,7 +120,7 @@ ArduinoIoTCloudLPWAN::State ArduinoIoTCloudLPWAN::handle_Connected() } /* Check if a primitive property wrapper is locally changed. */ - updateTimestampOnLocallyChangedProperties(_property_container); + updateTimestampOnLocallyChangedProperties(_thing_property_container); /* Decode available data. */ if (_connection->available()) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 7d154a896..992b9b2c2 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -69,6 +69,11 @@ extern "C" void updateTimezoneInfo() ArduinoCloud.updateInternalTimezoneInfo(); } +extern "C" void setThingIdOutdated() +{ + ArduinoCloud.setThingIdOutdatedFlag(); +} + /****************************************************************************** CTOR/DTOR ******************************************************************************/ @@ -77,6 +82,8 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() : _state{State::ConnectPhy} , _next_connection_attempt_tick{0} , _last_connection_attempt_cnt{0} +, _next_device_subscribe_attempt_tick{0} +, _last_device_subscribe_cnt{0} , _last_sync_request_tick{0} , _last_sync_request_cnt{0} , _last_subscribe_request_tick{0} @@ -91,10 +98,13 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP() , _password("") #endif , _mqttClient{nullptr} +, _deviceTopicOut("") +, _deviceTopicIn("") , _shadowTopicOut("") , _shadowTopicIn("") , _dataTopicOut("") , _dataTopicIn("") +, _deviceSubscribedToThing{false} #if OTA_ENABLED , _ota_cap{false} , _ota_error{static_cast(OTAError::None)} @@ -237,10 +247,8 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, _mqttClient.setConnectionTimeout(1500); _mqttClient.setId(getDeviceId().c_str()); - _shadowTopicOut = getTopic_shadowout(); - _shadowTopicIn = getTopic_shadowin(); - _dataTopicOut = getTopic_dataout(); - _dataTopicIn = getTopic_datain(); + _deviceTopicOut = getTopic_deviceout(); + _deviceTopicIn = getTopic_devicein(); #if OTA_ENABLED addPropertyReal(_ota_cap, _device_property_container, "OTA_CAP", Permission::Read); @@ -253,7 +261,7 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, addPropertyReal(_tz_offset, _thing_property_container, "tz_offset", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); addPropertyReal(_tz_dst_until, _thing_property_container, "tz_dst_until", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); - addPropertyReal(_thing_id, _device_property_container, "thing_id", Permission::ReadWrite); + addPropertyReal(_thing_id, _device_property_container, "thing_id", Permission::ReadWrite).onUpdate(setThingIdOutdated); #if OTA_STORAGE_PORTENTA_QSPI #define BOOTLOADER_ADDR (0x8000000) @@ -322,12 +330,16 @@ void ArduinoIoTCloudTCP::update() State next_state = _state; switch (_state) { - case State::ConnectPhy: next_state = handle_ConnectPhy(); break; - case State::SyncTime: next_state = handle_SyncTime(); break; - case State::ConnectMqttBroker: next_state = handle_ConnectMqttBroker(); break; - case State::SubscribeMqttTopics: next_state = handle_SubscribeMqttTopics(); break; - case State::RequestLastValues: next_state = handle_RequestLastValues(); break; - case State::Connected: next_state = handle_Connected(); break; + case State::ConnectPhy: next_state = handle_ConnectPhy(); break; + case State::SyncTime: next_state = handle_SyncTime(); break; + case State::ConnectMqttBroker: next_state = handle_ConnectMqttBroker(); break; + case State::SendDeviceProperties: next_state = handle_SendDeviceProperties(); break; + case State::SubscribeDeviceTopic: next_state = handle_SubscribeDeviceTopic(); break; + case State::WaitDeviceConfig: next_state = handle_WaitDeviceConfig(); break; + case State::CheckDeviceConfig: next_state = handle_CheckDeviceConfig(); break; + case State::SubscribeThingTopics: next_state = handle_SubscribeThingTopics(); break; + case State::RequestLastValues: next_state = handle_RequestLastValues(); break; + case State::Connected: next_state = handle_Connected(); break; } _state = next_state; @@ -385,7 +397,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker() if (_mqttClient.connect(_brokerAddress.c_str(), _brokerPort)) { _last_connection_attempt_cnt = 0; - return State::SubscribeMqttTopics; + return State::SendDeviceProperties; } _last_connection_attempt_cnt++; @@ -398,7 +410,127 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker() return State::ConnectPhy; } -ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics() +ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SendDeviceProperties() +{ + if (!_mqttClient.connected()) + { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); + _mqttClient.stop(); + execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); + return State::ConnectPhy; + } + +#if OTA_ENABLED + sendOTAPropertiesToCloud(); +#endif + return State::SubscribeDeviceTopic; +} + +ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic() +{ + if (!_mqttClient.connected()) + { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); + _mqttClient.stop(); + execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); + return State::ConnectPhy; + } + + if (!_mqttClient.subscribe(_deviceTopicIn)) + { + return State::SubscribeDeviceTopic; + } + + if (_last_device_subscribe_cnt > AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT) + { + _last_device_subscribe_cnt = 0; + _next_device_subscribe_attempt_tick = 0; + _mqttClient.stop(); + execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); + return State::ConnectPhy; + } + + unsigned long reconnection_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms; + reconnection_retry_delay = min(reconnection_retry_delay, static_cast(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms)); + _next_device_subscribe_attempt_tick = millis() + reconnection_retry_delay; + _last_device_subscribe_cnt++; + + return State::WaitDeviceConfig; +} + +ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_WaitDeviceConfig() +{ + if (!_mqttClient.connected()) + { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); + _mqttClient.stop(); + execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); + return State::ConnectPhy; + } + + if (millis() > _next_device_subscribe_attempt_tick) + { + /* Configuration not received try to resubscribe */ + if (_mqttClient.unsubscribe(_deviceTopicIn)) + { + return State::SubscribeDeviceTopic; + } + } + + return State::WaitDeviceConfig; +} + +ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig() +{ + if (!_mqttClient.connected()) + { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); + _mqttClient.stop(); + execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); + return State::ConnectPhy; + } + + if(getThingIdOutdatedFlag()) + { + if(_deviceSubscribedToThing == true) + { + /* Unsubscribe from old things topics and go on with a new subsctiption */ + _mqttClient.unsubscribe(_shadowTopicIn); + _mqttClient.unsubscribe(_dataTopicIn); + + _deviceSubscribedToThing = false; + } + } + + updateThingTopics(); + + if (deviceNotConfigured()) + { + /* maybe we have only missed the thing_id property... + * unsubsribe and resubscribe immediately to trigger a new configuration command + */ + _mqttClient.unsubscribe(_deviceTopicIn); + return State::SubscribeDeviceTopic; + } + + if (deviceNotAttached()) + { + /* start long timeout counter + * return return State::SubscribeThingTopics + * if long timeout expired unsubscribe and + * return State::SubscribeDeviceTopic + */ + unsigned long reconnection_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms * 10000; + reconnection_retry_delay = min(reconnection_retry_delay, static_cast(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms)); + _next_device_subscribe_attempt_tick = millis() + reconnection_retry_delay; + _last_device_subscribe_cnt++; + return State::WaitDeviceConfig; + } + + return State::SubscribeThingTopics; +} + +ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics() { if (!_mqttClient.connected()) { @@ -414,7 +546,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics() if (!is_first_subscribe_request && !is_subscribe_retry_delay_expired) { - return State::SubscribeMqttTopics; + return State::SubscribeThingTopics; } if (_last_subscribe_request_cnt > AIOT_CONFIG_SUBSCRIBE_MAX_RETRY_CNT) @@ -435,7 +567,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics() #if !defined(__AVR__) DEBUG_ERROR("Check your thing configuration, and press the reset button on your board."); #endif - return State::SubscribeMqttTopics; + return State::SubscribeThingTopics; } if (_shadowTopicIn != "") @@ -446,14 +578,13 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics() #if !defined(__AVR__) DEBUG_ERROR("Check your thing configuration, and press the reset button on your board."); #endif - return State::SubscribeMqttTopics; + return State::SubscribeThingTopics; } } DEBUG_INFO("Connected to Arduino IoT Cloud"); execCloudEventCallback(ArduinoIoTCloudEvent::CONNECT); - _last_subscribe_request_cnt = 0; - _last_subscribe_request_tick = 0; + _deviceSubscribedToThing = true; if (_shadowTopicIn != "") return State::RequestLastValues; @@ -587,10 +718,20 @@ void ArduinoIoTCloudTCP::handleMessage(int length) bytes[i] = _mqttClient.read(); } + /* Topic for OTA properties and device configuration */ + if (_deviceTopicIn == topic) { + CBORDecoder::decode(_device_property_container, (uint8_t*)bytes, length); + _last_device_subscribe_cnt = 0; + _next_device_subscribe_attempt_tick = 0; + _state = State::CheckDeviceConfig; + } + + /* Topic for user input data */ if (_dataTopicIn == topic) { CBORDecoder::decode(_thing_property_container, (uint8_t*)bytes, length); } + /* Topic for sync Thing last values on connect */ if ((_shadowTopicIn == topic) && (_state == State::RequestLastValues)) { DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis()); @@ -633,7 +774,7 @@ void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud() PropertyContainer ota_property_container; unsigned int last_ota_property_index = 0; - std::list const ota_property_list {"OTA_CAP", "OTA_ERROR", "OTA_SHA256", "OTA_URL", "OTA_REQ"}; + std::list const ota_property_list {"OTA_CAP", "OTA_ERROR", "OTA_SHA256"}; std::for_each(ota_property_list.cbegin(), ota_property_list.cend(), [this, &ota_property_container ] (String const & name) @@ -644,7 +785,7 @@ void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud() } ); - sendPropertyContainerToCloud(_dataTopicOut, ota_property_container, last_ota_property_index); + sendPropertyContainerToCloud(_deviceTopicOut, ota_property_container, last_ota_property_index); } #endif @@ -688,6 +829,16 @@ void ArduinoIoTCloudTCP::onOTARequest() } #endif +void ArduinoIoTCloudTCP::updateThingTopics() +{ + _shadowTopicOut = getTopic_shadowout(); + _shadowTopicIn = getTopic_shadowin(); + _dataTopicOut = getTopic_dataout(); + _dataTopicIn = getTopic_datain(); + + clrThingIdOutdatedFlag(); +} + /****************************************************************************** * EXTERN DEFINITION ******************************************************************************/ diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 663acd111..861482f5e 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -105,7 +105,11 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass ConnectPhy, SyncTime, ConnectMqttBroker, - SubscribeMqttTopics, + SendDeviceProperties, + SubscribeDeviceTopic, + WaitDeviceConfig, + CheckDeviceConfig, + SubscribeThingTopics, RequestLastValues, Connected, }; @@ -114,6 +118,8 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass unsigned long _next_connection_attempt_tick; unsigned int _last_connection_attempt_cnt; + unsigned long _next_device_subscribe_attempt_tick; + unsigned int _last_device_subscribe_cnt; unsigned long _last_sync_request_tick; unsigned int _last_sync_request_cnt; unsigned long _last_subscribe_request_tick; @@ -137,11 +143,15 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass MqttClient _mqttClient; + String _deviceTopicOut; + String _deviceTopicIn; String _shadowTopicOut; String _shadowTopicIn; String _dataTopicOut; String _dataTopicIn; + bool _deviceSubscribedToThing; + #if OTA_ENABLED bool _ota_cap; int _ota_error; @@ -152,15 +162,21 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass onOTARequestCallbackFunc _get_ota_confirmation; #endif /* OTA_ENABLED */ - inline String getTopic_shadowout() { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/shadow/o"); } - inline String getTopic_shadowin () { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/shadow/i"); } - inline String getTopic_dataout () { return ( getThingId().length() == 0) ? String("/a/d/" + getDeviceId() + "/e/o") : String("/a/t/" + getThingId() + "/e/o"); } - inline String getTopic_datain () { return ( getThingId().length() == 0) ? String("/a/d/" + getDeviceId() + "/e/i") : String("/a/t/" + getThingId() + "/e/i"); } + inline String getTopic_deviceout() { return String("/a/d/" + getDeviceId() + "/e/o");} + inline String getTopic_devicein () { return String("/a/d/" + getDeviceId() + "/e/i");} + inline String getTopic_shadowout() { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/shadow/o"); } + inline String getTopic_shadowin () { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/shadow/i"); } + inline String getTopic_dataout () { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/e/o"); } + inline String getTopic_datain () { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/e/i"); } State handle_ConnectPhy(); State handle_SyncTime(); State handle_ConnectMqttBroker(); - State handle_SubscribeMqttTopics(); + State handle_SendDeviceProperties(); + State handle_WaitDeviceConfig(); + State handle_CheckDeviceConfig(); + State handle_SubscribeDeviceTopic(); + State handle_SubscribeThingTopics(); State handle_RequestLastValues(); State handle_Connected(); @@ -176,6 +192,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass void sendOTAPropertiesToCloud(); #endif + void updateThingTopics(); }; /****************************************************************************** From f4af0d2ecdbe921273e8c1220779fa7d9d59eec3 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 7 Dec 2021 09:04:33 +0100 Subject: [PATCH 03/21] If board has a valid _dataTopicIn also _shadowTopicIn is valid --- src/ArduinoIoTCloudTCP.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 992b9b2c2..b8eafb9ff 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -570,27 +570,20 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics() return State::SubscribeThingTopics; } - if (_shadowTopicIn != "") + if (!_mqttClient.subscribe(_shadowTopicIn)) { - if (!_mqttClient.subscribe(_shadowTopicIn)) - { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not subscribe to %s", __FUNCTION__, _shadowTopicIn.c_str()); + DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not subscribe to %s", __FUNCTION__, _shadowTopicIn.c_str()); #if !defined(__AVR__) - DEBUG_ERROR("Check your thing configuration, and press the reset button on your board."); + DEBUG_ERROR("Check your thing configuration, and press the reset button on your board."); #endif - return State::SubscribeThingTopics; - } + return State::SubscribeThingTopics; } DEBUG_INFO("Connected to Arduino IoT Cloud"); execCloudEventCallback(ArduinoIoTCloudEvent::CONNECT); _deviceSubscribedToThing = true; - if (_shadowTopicIn != "") - return State::RequestLastValues; - else - return State::Connected; - + return State::RequestLastValues; } ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_RequestLastValues() From 79656c40e6b78abdfdc8b1ac9368930196238097 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 10 Dec 2021 15:59:56 +0100 Subject: [PATCH 04/21] Add configuration flag to sendOTAPropertiesToCloud() fuction in order to append OTA_REQ property --- src/ArduinoIoTCloudTCP.cpp | 10 ++++++---- src/ArduinoIoTCloudTCP.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index b8eafb9ff..c657993c1 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -762,14 +762,16 @@ void ArduinoIoTCloudTCP::sendPropertiesToCloud() } #if OTA_ENABLED -void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud() +void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud(bool include_ota_req) { PropertyContainer ota_property_container; unsigned int last_ota_property_index = 0; - std::list const ota_property_list {"OTA_CAP", "OTA_ERROR", "OTA_SHA256"}; - std::for_each(ota_property_list.cbegin(), - ota_property_list.cend(), + std::list ota_property_list {"OTA_CAP", "OTA_ERROR", "OTA_SHA256"}; + if (include_ota_req) + ota_property_list.push_back("OTA_REQ"); + std::for_each(ota_property_list.begin(), + ota_property_list.end(), [this, &ota_property_container ] (String const & name) { Property* p = getProperty(this->_device_property_container, name); diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 861482f5e..dd7c3ebb8 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -189,7 +189,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass #if OTA_ENABLED void onOTARequest(); - void sendOTAPropertiesToCloud(); + void sendOTAPropertiesToCloud(bool include_ota_req = false); #endif void updateThingTopics(); From 48494faa610869eaf2faee63b9e4b9bbb5dedfa2 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 10 Dec 2021 16:22:47 +0100 Subject: [PATCH 05/21] Execute handle_CheckDeviceConfig() only on thing_id changes ignoring other messages on device topic --- src/ArduinoIoTCloudTCP.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index c657993c1..1c2459c5c 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -326,6 +326,11 @@ void ArduinoIoTCloudTCP::update() #endif + if(getThingIdOutdatedFlag()) { + DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s Thing id outdated, reconfiguring...", __FUNCTION__); + _state = State::CheckDeviceConfig; + } + /* Run through the state machine. */ State next_state = _state; switch (_state) @@ -476,7 +481,6 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_WaitDeviceConfig() return State::SubscribeDeviceTopic; } } - return State::WaitDeviceConfig; } @@ -490,16 +494,13 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig() return State::ConnectPhy; } - if(getThingIdOutdatedFlag()) + if(_deviceSubscribedToThing == true) { - if(_deviceSubscribedToThing == true) - { - /* Unsubscribe from old things topics and go on with a new subsctiption */ - _mqttClient.unsubscribe(_shadowTopicIn); - _mqttClient.unsubscribe(_dataTopicIn); + /* Unsubscribe from old things topics and go on with a new subsctiption */ + _mqttClient.unsubscribe(_shadowTopicIn); + _mqttClient.unsubscribe(_dataTopicIn); - _deviceSubscribedToThing = false; - } + _deviceSubscribedToThing = false; } updateThingTopics(); @@ -716,7 +717,6 @@ void ArduinoIoTCloudTCP::handleMessage(int length) CBORDecoder::decode(_device_property_container, (uint8_t*)bytes, length); _last_device_subscribe_cnt = 0; _next_device_subscribe_attempt_tick = 0; - _state = State::CheckDeviceConfig; } /* Topic for user input data */ From 65b82e6f8f2dd19d676ed5e5d9a258b32ae73baa Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 23 Dec 2021 14:52:02 +0100 Subject: [PATCH 06/21] Do not try to reconfigure device if connection is dropped --- src/ArduinoIoTCloudTCP.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 1c2459c5c..b69484e29 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -328,7 +328,8 @@ void ArduinoIoTCloudTCP::update() if(getThingIdOutdatedFlag()) { DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s Thing id outdated, reconfiguring...", __FUNCTION__); - _state = State::CheckDeviceConfig; + if (_mqttClient.connected()) + _state = State::CheckDeviceConfig; } /* Run through the state machine. */ From 850095ddda61743dcfdb7f6369ed9a36f28ce8b3 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 10 Jan 2022 09:53:54 +0100 Subject: [PATCH 07/21] There is no more distinction between not configured and not attached --- src/ArduinoIoTCloud.h | 3 +-- src/ArduinoIoTCloudTCP.cpp | 9 --------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index bad570c7e..ee1d4d812 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -100,8 +100,7 @@ class ArduinoIoTCloudClass inline void clrThingIdOutdatedFlag() { _thing_id_outdated = false ; } inline bool getThingIdOutdatedFlag() { return _thing_id_outdated; } - inline bool deviceNotAttached() { return _thing_id == "null"; } - inline bool deviceNotConfigured() { return _thing_id == ""; } + inline bool deviceNotAttached() { return _thing_id == ""; } inline ConnectionHandler * getConnection() { return _connection; } diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index b69484e29..fcfbd0613 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -506,15 +506,6 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig() updateThingTopics(); - if (deviceNotConfigured()) - { - /* maybe we have only missed the thing_id property... - * unsubsribe and resubscribe immediately to trigger a new configuration command - */ - _mqttClient.unsubscribe(_deviceTopicIn); - return State::SubscribeDeviceTopic; - } - if (deviceNotAttached()) { /* start long timeout counter From 08964b394c84a5e93bd0a6d7721ca77a0740e3af Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 10 Jan 2022 11:22:09 +0100 Subject: [PATCH 08/21] Move thing_id outdated flag check outside update function and add handle_Disconnect() function --- src/ArduinoIoTCloud.cpp | 1 + src/ArduinoIoTCloudTCP.cpp | 76 ++++++++++++++++++-------------------- src/ArduinoIoTCloudTCP.h | 2 + 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index ff83facc1..91c5ac9d2 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -34,6 +34,7 @@ ArduinoIoTCloudClass::ArduinoIoTCloudClass() , _thing_id{""} , _device_id{""} , _cloud_event_callback{nullptr} +, _thing_id_outdated{false} { } diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index fcfbd0613..52cadbd46 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -326,12 +326,6 @@ void ArduinoIoTCloudTCP::update() #endif - if(getThingIdOutdatedFlag()) { - DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s Thing id outdated, reconfiguring...", __FUNCTION__); - if (_mqttClient.connected()) - _state = State::CheckDeviceConfig; - } - /* Run through the state machine. */ State next_state = _state; switch (_state) @@ -346,6 +340,7 @@ void ArduinoIoTCloudTCP::update() case State::SubscribeThingTopics: next_state = handle_SubscribeThingTopics(); break; case State::RequestLastValues: next_state = handle_RequestLastValues(); break; case State::Connected: next_state = handle_Connected(); break; + case State::Disconnect: next_state = handle_Disconnect(); break; } _state = next_state; @@ -420,10 +415,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SendDeviceProperties() { if (!_mqttClient.connected()) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); - _mqttClient.stop(); - execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); - return State::ConnectPhy; + return State::Disconnect; } #if OTA_ENABLED @@ -436,10 +428,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic() { if (!_mqttClient.connected()) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); - _mqttClient.stop(); - execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); - return State::ConnectPhy; + return State::Disconnect; } if (!_mqttClient.subscribe(_deviceTopicIn)) @@ -468,10 +457,12 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_WaitDeviceConfig() { if (!_mqttClient.connected()) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); - _mqttClient.stop(); - execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); - return State::ConnectPhy; + return State::Disconnect; + } + + if (getThingIdOutdatedFlag()) + { + return State::CheckDeviceConfig; } if (millis() > _next_device_subscribe_attempt_tick) @@ -489,10 +480,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig() { if (!_mqttClient.connected()) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); - _mqttClient.stop(); - execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); - return State::ConnectPhy; + return State::Disconnect; } if(_deviceSubscribedToThing == true) @@ -527,10 +515,12 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics() { if (!_mqttClient.connected()) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); - _mqttClient.stop(); - execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); - return State::ConnectPhy; + return State::Disconnect; + } + + if (getThingIdOutdatedFlag()) + { + return State::CheckDeviceConfig; } unsigned long const now = millis(); @@ -583,10 +573,12 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_RequestLastValues() { if (!_mqttClient.connected()) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); - _mqttClient.stop(); - execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); - return State::ConnectPhy; + return State::Disconnect; + } + + if (getThingIdOutdatedFlag()) + { + return State::CheckDeviceConfig; } /* Check whether or not we need to send a new request. */ @@ -620,22 +612,18 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() { if (!_mqttClient.connected()) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); - - /* Forcefully disconnect MQTT client and trigger a reconnection. */ - _mqttClient.stop(); - /* The last message was definitely lost, trigger a retransmit. */ _mqtt_data_request_retransmit = true; - - /* We are not connected anymore, trigger the callback for a disconnected event. */ - execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); - - return State::ConnectPhy; + return State::Disconnect; } /* We are connected so let's to our stuff here. */ else { + if (getThingIdOutdatedFlag()) + { + return State::CheckDeviceConfig; + } + /* Check if a primitive property wrapper is locally changed. * This function requires an existing time service which in * turn requires an established connection. Not having that @@ -689,6 +677,14 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() } } +ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Disconnect() +{ + DEBUG_ERROR("ArduinoIoTCloudTCP::%s MQTT client connection lost", __FUNCTION__); + _mqttClient.stop(); + execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); + return State::ConnectPhy; +} + void ArduinoIoTCloudTCP::onMessage(int length) { ArduinoCloud.handleMessage(length); diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index dd7c3ebb8..103f10cff 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -112,6 +112,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass SubscribeThingTopics, RequestLastValues, Connected, + Disconnect, }; State _state; @@ -179,6 +180,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass State handle_SubscribeThingTopics(); State handle_RequestLastValues(); State handle_Connected(); + State handle_Disconnect(); static void onMessage(int length); void handleMessage(int length); From 95eeec8a89a52432442ba09c8959783da3ca28f4 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 3 Feb 2022 13:17:33 +0100 Subject: [PATCH 09/21] Use specific macros to define device topic subscription delays --- src/AIoTC_Config.h | 18 ++++++++++-------- src/ArduinoIoTCloudTCP.cpp | 19 ++++++++----------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 6949524d6..abcdd38ee 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -140,14 +140,16 @@ * CONSTANTS ******************************************************************************/ -#define AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms (1000UL) -#define AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms (32000UL) -#define AIOT_CONFIG_SUBSCRIBE_RETRY_DELAY_ms (1000UL) -#define AIOT_CONFIG_SUBSCRIBE_MAX_RETRY_CNT (10UL) -#define AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms (30000UL) -#define AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT (10UL) - -#define AIOT_CONFIG_RP2040_OTA_HTTP_HEADER_RECEIVE_TIMEOUT_ms (10*1000UL) +#define AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms (1000UL) +#define AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms (32000UL) +#define AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms (5*1000UL) +#define AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms (32000UL) +#define AIOT_CONFIG_SUBSCRIBE_RETRY_DELAY_ms (1000UL) +#define AIOT_CONFIG_SUBSCRIBE_MAX_RETRY_CNT (10UL) +#define AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms (30000UL) +#define AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT (10UL) + +#define AIOT_CONFIG_RP2040_OTA_HTTP_HEADER_RECEIVE_TIMEOUT_ms (10*1000UL) #define AIOT_CONFIG_RP2040_OTA_HTTP_DATA_RECEIVE_TIMEOUT_ms (4*60*1000UL) #endif /* ARDUINO_AIOTC_CONFIG_H_ */ diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 52cadbd46..6191b722e 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -445,9 +445,10 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic() return State::ConnectPhy; } - unsigned long reconnection_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms; - reconnection_retry_delay = min(reconnection_retry_delay, static_cast(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms)); - _next_device_subscribe_attempt_tick = millis() + reconnection_retry_delay; + /* No device configuration reply. Wait: 5s -> 10s -> 20s -> 30s */ + unsigned long subscribe_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms; + subscribe_retry_delay = min(subscribe_retry_delay, static_cast(AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms)); + _next_device_subscribe_attempt_tick = millis() + subscribe_retry_delay; _last_device_subscribe_cnt++; return State::WaitDeviceConfig; @@ -496,14 +497,10 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig() if (deviceNotAttached()) { - /* start long timeout counter - * return return State::SubscribeThingTopics - * if long timeout expired unsubscribe and - * return State::SubscribeDeviceTopic - */ - unsigned long reconnection_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms * 10000; - reconnection_retry_delay = min(reconnection_retry_delay, static_cast(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms)); - _next_device_subscribe_attempt_tick = millis() + reconnection_retry_delay; + /* Configuration received but device not attached. Wait: 40s */ + unsigned long subscribe_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms * 10; + subscribe_retry_delay = min(subscribe_retry_delay, static_cast(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms * 10)); + _next_device_subscribe_attempt_tick = millis() + subscribe_retry_delay; _last_device_subscribe_cnt++; return State::WaitDeviceConfig; } From ae45d0c93c2dc6c07403acbe5669e3d3613c34bf Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 11 Jan 2022 11:05:38 +0100 Subject: [PATCH 10/21] Use incremental long delay before retry subscribtion when the device is not attached to a thing --- src/AIoTC_Config.h | 1 + src/ArduinoIoTCloudTCP.cpp | 15 +++++++++------ src/ArduinoIoTCloudTCP.h | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index abcdd38ee..363c3a070 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -146,6 +146,7 @@ #define AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms (32000UL) #define AIOT_CONFIG_SUBSCRIBE_RETRY_DELAY_ms (1000UL) #define AIOT_CONFIG_SUBSCRIBE_MAX_RETRY_CNT (10UL) +#define AIOT_CONFIG_MAX_DEVICE_TOPIC_ATTACH_RETRY_DELAY_ms (1280000UL) #define AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms (30000UL) #define AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT (10UL) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 6191b722e..65b7d02f3 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -468,7 +468,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_WaitDeviceConfig() if (millis() > _next_device_subscribe_attempt_tick) { - /* Configuration not received try to resubscribe */ + /* Configuration not received or device not attached to a valid thing. Try to resubscribe */ if (_mqttClient.unsubscribe(_deviceTopicIn)) { return State::SubscribeDeviceTopic; @@ -489,7 +489,6 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig() /* Unsubscribe from old things topics and go on with a new subsctiption */ _mqttClient.unsubscribe(_shadowTopicIn); _mqttClient.unsubscribe(_dataTopicIn); - _deviceSubscribedToThing = false; } @@ -498,13 +497,16 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig() if (deviceNotAttached()) { /* Configuration received but device not attached. Wait: 40s */ - unsigned long subscribe_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms * 10; - subscribe_retry_delay = min(subscribe_retry_delay, static_cast(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms * 10)); - _next_device_subscribe_attempt_tick = millis() + subscribe_retry_delay; - _last_device_subscribe_cnt++; + unsigned long attach_retry_delay = (1 << _last_device_attach_cnt) * AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms; + attach_retry_delay = min(attach_retry_delay, static_cast(AIOT_CONFIG_MAX_DEVICE_TOPIC_ATTACH_RETRY_DELAY_ms)); + _next_device_subscribe_attempt_tick = millis() + attach_retry_delay; + _last_device_attach_cnt++; return State::WaitDeviceConfig; } + DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s Device attached to a new valid Thing %s", __FUNCTION__, getThingId().c_str()); + _last_device_attach_cnt = 0; + return State::SubscribeThingTopics; } @@ -563,6 +565,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics() execCloudEventCallback(ArduinoIoTCloudEvent::CONNECT); _deviceSubscribedToThing = true; + /*Add retry wait time otherwise we are trying to reconnect every 250ms...*/ return State::RequestLastValues; } diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 103f10cff..79e43aaed 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -121,6 +121,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass unsigned int _last_connection_attempt_cnt; unsigned long _next_device_subscribe_attempt_tick; unsigned int _last_device_subscribe_cnt; + unsigned int _last_device_attach_cnt; unsigned long _last_sync_request_tick; unsigned int _last_sync_request_cnt; unsigned long _last_subscribe_request_tick; From 221b176ba3a2ee7147185fb87aef1798fa5fc3dc Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Jan 2022 16:25:10 +0100 Subject: [PATCH 11/21] Add LIB_VERSION property to let cloud decide to use thing_topic or device_topic for OTA properties --- src/AIoTC_Config.h | 2 ++ src/ArduinoIoTCloud.cpp | 1 + src/ArduinoIoTCloud.h | 1 + src/ArduinoIoTCloudTCP.cpp | 3 ++- 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 363c3a070..6fb33ba43 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -153,4 +153,6 @@ #define AIOT_CONFIG_RP2040_OTA_HTTP_HEADER_RECEIVE_TIMEOUT_ms (10*1000UL) #define AIOT_CONFIG_RP2040_OTA_HTTP_DATA_RECEIVE_TIMEOUT_ms (4*60*1000UL) +#define AIOT_CONFIG_LIB_VERSION "1.5.0" + #endif /* ARDUINO_AIOTC_CONFIG_H_ */ diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 91c5ac9d2..0b2794ade 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -33,6 +33,7 @@ ArduinoIoTCloudClass::ArduinoIoTCloudClass() , _tz_dst_until{0} , _thing_id{""} , _device_id{""} +, _lib_version{AIOT_CONFIG_LIB_VERSION} , _cloud_event_callback{nullptr} , _thing_id_outdated{false} { diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index ee1d4d812..8be318b25 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -174,6 +174,7 @@ class ArduinoIoTCloudClass int _tz_offset; unsigned int _tz_dst_until; String _thing_id; + String _lib_version; void execCloudEventCallback(ArduinoIoTCloudEvent const event); diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 65b7d02f3..fa47c0c6a 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -250,6 +250,7 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, _deviceTopicOut = getTopic_deviceout(); _deviceTopicIn = getTopic_devicein(); + addPropertyReal(_lib_version, _device_property_container, "LIB_VERSION", Permission::Read); #if OTA_ENABLED addPropertyReal(_ota_cap, _device_property_container, "OTA_CAP", Permission::Read); addPropertyReal(_ota_error, _device_property_container, "OTA_ERROR", Permission::Read); @@ -755,7 +756,7 @@ void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud(bool include_ota_req) PropertyContainer ota_property_container; unsigned int last_ota_property_index = 0; - std::list ota_property_list {"OTA_CAP", "OTA_ERROR", "OTA_SHA256"}; + std::list ota_property_list {"LIB_VERSION", "OTA_CAP", "OTA_ERROR", "OTA_SHA256"}; if (include_ota_req) ota_property_list.push_back("OTA_REQ"); std::for_each(ota_property_list.begin(), From 4aa628a70f10e2338d83d074f4383b8b6ffb8aaf Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Jan 2022 16:31:28 +0100 Subject: [PATCH 12/21] Spit sendPropertiesToCloud() in sendThingPropertiesToCloud() and sendDevicePropertiesToCloud(). Provide functions to clear OTA_REQ flag and update OTA_ERROR and OTA_URL. --- src/ArduinoIoTCloudTCP.cpp | 85 ++++++++++++++++++++++++++++++++------ src/ArduinoIoTCloudTCP.h | 7 +++- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index fa47c0c6a..607db79f1 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -261,7 +261,6 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, addPropertyReal(_tz_offset, _thing_property_container, "tz_offset", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); addPropertyReal(_tz_dst_until, _thing_property_container, "tz_dst_until", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); - addPropertyReal(_thing_id, _device_property_container, "thing_id", Permission::ReadWrite).onUpdate(setThingIdOutdated); #if OTA_STORAGE_PORTENTA_QSPI @@ -419,9 +418,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SendDeviceProperties() return State::Disconnect; } -#if OTA_ENABLED - sendOTAPropertiesToCloud(); -#endif + sendDevicePropertiesToCloud(); return State::SubscribeDeviceTopic; } @@ -656,18 +653,26 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() _ota_error = static_cast(OTAError::None); /* Clear the request flag. */ _ota_req = false; - /* Transmit the cleared error and request flags to the cloud. */ - sendOTAPropertiesToCloud(); + /* Transmit the cleared request flags to the cloud. */ + sendClearedOTARequestToCloud(); /* Call member function to handle OTA request. */ onOTARequest(); + /* If something fails send the OTA error to the cloud */ + sendOTAErrorToCloud(); } } + + /* Check if we have received the OTA_URL property and provide + * echo to the cloud. + */ + sendOTAUrlToCloud(); + #endif /* OTA_ENABLED */ /* Check if any properties need encoding and send them to * the cloud if necessary. */ - sendPropertiesToCloud(); + sendThingPropertiesToCloud(); unsigned long const internal_posix_time = _time_service.getTime(); if(internal_posix_time < _tz_dst_until) { @@ -718,7 +723,6 @@ void ArduinoIoTCloudTCP::handleMessage(int length) { DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis()); CBORDecoder::decode(_thing_property_container, (uint8_t*)bytes, length, true); - sendPropertiesToCloud(); _time_service.setTimeZoneData(_tz_offset, _tz_dst_until); execCloudEventCallback(ArduinoIoTCloudEvent::SYNC); _last_sync_request_cnt = 0; @@ -745,20 +749,75 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, Proper } } -void ArduinoIoTCloudTCP::sendPropertiesToCloud() +void ArduinoIoTCloudTCP::sendThingPropertiesToCloud() { sendPropertyContainerToCloud(_dataTopicOut, _thing_property_container, _last_checked_property_index); } +void ArduinoIoTCloudTCP::sendDevicePropertiesToCloud() +{ + PropertyContainer ro_device_property_container; + unsigned int last_device_property_index = 0; + + std::list ro_device_property_list {"LIB_VERSION", "OTA_CAP", "OTA_ERROR", "OTA_SHA256"}; + std::for_each(ro_device_property_list.begin(), + ro_device_property_list.end(), + [this, &ro_device_property_container ] (String const & name) + { + Property* p = getProperty(this->_device_property_container, name); + if(p != nullptr) + addPropertyToContainer(ro_device_property_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read); + } + ); + + sendPropertyContainerToCloud(_deviceTopicOut, ro_device_property_container, last_device_property_index); +} + #if OTA_ENABLED -void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud(bool include_ota_req) +void ArduinoIoTCloudTCP::sendClearedOTARequestToCloud() +{ + PropertyContainer ota_property_container; + unsigned int last_ota_property_index = 0; + + std::list ota_property_list {"OTA_REQ"}; + std::for_each(ota_property_list.begin(), + ota_property_list.end(), + [this, &ota_property_container ] (String const & name) + { + Property* p = getProperty(this->_device_property_container, name); + if(p != nullptr) + addPropertyToContainer(ota_property_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read); + } + ); + + sendPropertyContainerToCloud(_deviceTopicOut, ota_property_container, last_ota_property_index); +} + +void ArduinoIoTCloudTCP::sendOTAErrorToCloud() +{ + PropertyContainer ota_property_container; + unsigned int last_ota_property_index = 0; + + std::list ota_property_list {"OTA_ERROR"}; + std::for_each(ota_property_list.begin(), + ota_property_list.end(), + [this, &ota_property_container ] (String const & name) + { + Property* p = getProperty(this->_device_property_container, name); + if(p != nullptr) + addPropertyToContainer(ota_property_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read); + } + ); + + sendPropertyContainerToCloud(_deviceTopicOut, ota_property_container, last_ota_property_index); +} + +void ArduinoIoTCloudTCP::sendOTAUrlToCloud() { PropertyContainer ota_property_container; unsigned int last_ota_property_index = 0; - std::list ota_property_list {"LIB_VERSION", "OTA_CAP", "OTA_ERROR", "OTA_SHA256"}; - if (include_ota_req) - ota_property_list.push_back("OTA_REQ"); + std::list ota_property_list {"OTA_URL"}; std::for_each(ota_property_list.begin(), ota_property_list.end(), [this, &ota_property_container ] (String const & name) diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 79e43aaed..787df535c 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -186,13 +186,16 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass static void onMessage(int length); void handleMessage(int length); void sendPropertyContainerToCloud(String const topic, PropertyContainer & property_container, unsigned int & current_property_index); - void sendPropertiesToCloud(); + void sendThingPropertiesToCloud(); + void sendDevicePropertiesToCloud(); void requestLastValue(); int write(String const topic, byte const data[], int const length); #if OTA_ENABLED void onOTARequest(); - void sendOTAPropertiesToCloud(bool include_ota_req = false); + void sendClearedOTARequestToCloud(); + void sendOTAErrorToCloud(); + void sendOTAUrlToCloud(); #endif void updateThingTopics(); From 0ebefe8e97ccff39f31c5e65a951d0a85e269aee Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Jan 2022 15:33:18 +0100 Subject: [PATCH 13/21] Remove the onSync callback end event from device properties --- src/ArduinoIoTCloudTCP.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 607db79f1..ceb4391f7 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -255,8 +255,8 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress, addPropertyReal(_ota_cap, _device_property_container, "OTA_CAP", Permission::Read); addPropertyReal(_ota_error, _device_property_container, "OTA_ERROR", Permission::Read); addPropertyReal(_ota_img_sha256, _device_property_container, "OTA_SHA256", Permission::Read); - addPropertyReal(_ota_url, _device_property_container, "OTA_URL", Permission::ReadWrite).onSync(CLOUD_WINS); - addPropertyReal(_ota_req, _device_property_container, "OTA_REQ", Permission::ReadWrite).onSync(CLOUD_WINS); + addPropertyReal(_ota_url, _device_property_container, "OTA_URL", Permission::ReadWrite); + addPropertyReal(_ota_req, _device_property_container, "OTA_REQ", Permission::ReadWrite); #endif /* OTA_ENABLED */ addPropertyReal(_tz_offset, _thing_property_container, "tz_offset", Permission::ReadWrite).onSync(CLOUD_WINS).onUpdate(updateTimezoneInfo); From 366bde189317bf1eb0a62447da2b5ad57b795d86 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Jan 2022 15:33:54 +0100 Subject: [PATCH 14/21] Use a single function to keep OTA properties in sync with cloud --- src/ArduinoIoTCloudTCP.cpp | 68 +++++++------------------------------- src/ArduinoIoTCloudTCP.h | 4 +-- 2 files changed, 13 insertions(+), 59 deletions(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index ceb4391f7..e76651309 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -654,18 +654,18 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected() /* Clear the request flag. */ _ota_req = false; /* Transmit the cleared request flags to the cloud. */ - sendClearedOTARequestToCloud(); + sendDevicePropertyToCloud("OTA_REQ"); /* Call member function to handle OTA request. */ onOTARequest(); /* If something fails send the OTA error to the cloud */ - sendOTAErrorToCloud(); + sendDevicePropertyToCloud("OTA_ERROR"); } } /* Check if we have received the OTA_URL property and provide * echo to the cloud. */ - sendOTAUrlToCloud(); + sendDevicePropertyToCloud("OTA_URL"); #endif /* OTA_ENABLED */ @@ -774,61 +774,17 @@ void ArduinoIoTCloudTCP::sendDevicePropertiesToCloud() } #if OTA_ENABLED -void ArduinoIoTCloudTCP::sendClearedOTARequestToCloud() +void ArduinoIoTCloudTCP::sendDevicePropertyToCloud(String const name) { - PropertyContainer ota_property_container; - unsigned int last_ota_property_index = 0; - - std::list ota_property_list {"OTA_REQ"}; - std::for_each(ota_property_list.begin(), - ota_property_list.end(), - [this, &ota_property_container ] (String const & name) - { - Property* p = getProperty(this->_device_property_container, name); - if(p != nullptr) - addPropertyToContainer(ota_property_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read); - } - ); - - sendPropertyContainerToCloud(_deviceTopicOut, ota_property_container, last_ota_property_index); -} - -void ArduinoIoTCloudTCP::sendOTAErrorToCloud() -{ - PropertyContainer ota_property_container; - unsigned int last_ota_property_index = 0; - - std::list ota_property_list {"OTA_ERROR"}; - std::for_each(ota_property_list.begin(), - ota_property_list.end(), - [this, &ota_property_container ] (String const & name) - { - Property* p = getProperty(this->_device_property_container, name); - if(p != nullptr) - addPropertyToContainer(ota_property_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read); - } - ); - - sendPropertyContainerToCloud(_deviceTopicOut, ota_property_container, last_ota_property_index); -} - -void ArduinoIoTCloudTCP::sendOTAUrlToCloud() -{ - PropertyContainer ota_property_container; - unsigned int last_ota_property_index = 0; - - std::list ota_property_list {"OTA_URL"}; - std::for_each(ota_property_list.begin(), - ota_property_list.end(), - [this, &ota_property_container ] (String const & name) - { - Property* p = getProperty(this->_device_property_container, name); - if(p != nullptr) - addPropertyToContainer(ota_property_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read); - } - ); + PropertyContainer temp_device_property_container; + unsigned int last_device_property_index = 0; - sendPropertyContainerToCloud(_deviceTopicOut, ota_property_container, last_ota_property_index); + Property* p = getProperty(this->_device_property_container, name); + if(p != nullptr) + { + addPropertyToContainer(temp_device_property_container, *p, p->name(), p->isWriteableByCloud() ? Permission::ReadWrite : Permission::Read); + sendPropertyContainerToCloud(_deviceTopicOut, temp_device_property_container, last_device_property_index); + } } #endif diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h index 787df535c..b704f6762 100644 --- a/src/ArduinoIoTCloudTCP.h +++ b/src/ArduinoIoTCloudTCP.h @@ -193,9 +193,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass #if OTA_ENABLED void onOTARequest(); - void sendClearedOTARequestToCloud(); - void sendOTAErrorToCloud(); - void sendOTAUrlToCloud(); + void sendDevicePropertyToCloud(String const name); #endif void updateThingTopics(); From e0a1d5ac4a93ee2818af081f1f6669697c7a183b Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 24 Jan 2022 17:32:14 +0100 Subject: [PATCH 15/21] Use better define name to distinguish between topic and device SUBSCRIBE_RETRY_DELAY --- src/AIoTC_Config.h | 4 ++-- src/ArduinoIoTCloudTCP.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index 6fb33ba43..eed12f5fc 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -144,8 +144,8 @@ #define AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms (32000UL) #define AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms (5*1000UL) #define AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms (32000UL) -#define AIOT_CONFIG_SUBSCRIBE_RETRY_DELAY_ms (1000UL) -#define AIOT_CONFIG_SUBSCRIBE_MAX_RETRY_CNT (10UL) +#define AIOT_CONFIG_THING_TOPICS_SUBSCRIBE_RETRY_DELAY_ms (1000UL) +#define AIOT_CONFIG_THING_TOPICS_SUBSCRIBE_MAX_RETRY_CNT (10UL) #define AIOT_CONFIG_MAX_DEVICE_TOPIC_ATTACH_RETRY_DELAY_ms (1280000UL) #define AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms (30000UL) #define AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT (10UL) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index e76651309..88081c8a9 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -521,7 +521,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics() } unsigned long const now = millis(); - bool const is_subscribe_retry_delay_expired = (now - _last_subscribe_request_tick) > AIOT_CONFIG_SUBSCRIBE_RETRY_DELAY_ms; + bool const is_subscribe_retry_delay_expired = (now - _last_subscribe_request_tick) > AIOT_CONFIG_THING_TOPICS_SUBSCRIBE_RETRY_DELAY_ms; bool const is_first_subscribe_request = (_last_subscribe_request_cnt == 0); if (!is_first_subscribe_request && !is_subscribe_retry_delay_expired) @@ -529,7 +529,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics() return State::SubscribeThingTopics; } - if (_last_subscribe_request_cnt > AIOT_CONFIG_SUBSCRIBE_MAX_RETRY_CNT) + if (_last_subscribe_request_cnt > AIOT_CONFIG_THING_TOPICS_SUBSCRIBE_MAX_RETRY_CNT) { _last_subscribe_request_cnt = 0; _last_subscribe_request_tick = 0; From 12d3b26ca01708211aefc98329a8b5a9de5f4880 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 3 Feb 2022 13:36:16 +0100 Subject: [PATCH 16/21] Remove extern C declaration from local module functions --- src/ArduinoIoTCloudLPWAN.cpp | 2 +- src/ArduinoIoTCloudTCP.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ArduinoIoTCloudLPWAN.cpp b/src/ArduinoIoTCloudLPWAN.cpp index fbc42b628..0f96d36db 100644 --- a/src/ArduinoIoTCloudLPWAN.cpp +++ b/src/ArduinoIoTCloudLPWAN.cpp @@ -37,7 +37,7 @@ static size_t const CBOR_LORA_MSG_MAX_SIZE = 255; LOCAL MODULE FUNCTIONS ******************************************************************************/ -extern "C" unsigned long getTime() +unsigned long getTime() { return ArduinoCloud.getInternalTime(); } diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 88081c8a9..964152a8d 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -59,17 +59,17 @@ extern RTC_HandleTypeDef RTCHandle; LOCAL MODULE FUNCTIONS ******************************************************************************/ -extern "C" unsigned long getTime() +unsigned long getTime() { return ArduinoCloud.getInternalTime(); } -extern "C" void updateTimezoneInfo() +void updateTimezoneInfo() { ArduinoCloud.updateInternalTimezoneInfo(); } -extern "C" void setThingIdOutdated() +void setThingIdOutdated() { ArduinoCloud.setThingIdOutdatedFlag(); } From c35be6f4d5bf97210d2518448ff0dd5c9c83e06d Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 3 Feb 2022 14:08:05 +0100 Subject: [PATCH 17/21] Do not print Thing ID at startup because its value will be ignored --- src/ArduinoIoTCloudTCP.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 964152a8d..6329b68ef 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -366,7 +366,6 @@ void ArduinoIoTCloudTCP::printDebugInfo() { DEBUG_INFO("***** Arduino IoT Cloud - configuration info *****"); DEBUG_INFO("Device ID: %s", getDeviceId().c_str()); - DEBUG_INFO("Thing ID: %s", getThingId().c_str()); DEBUG_INFO("MQTT Broker: %s:%d", _brokerAddress.c_str(), _brokerPort); } From c9cd3f51e2d5251f2cf4dd2b2bef1136aa7b1ee5 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 3 Feb 2022 15:38:22 +0100 Subject: [PATCH 18/21] Print Thing ID on serial monitor when board connects to the cloud --- src/ArduinoIoTCloudTCP.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 6329b68ef..554c48ce0 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -559,6 +559,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics() } DEBUG_INFO("Connected to Arduino IoT Cloud"); + DEBUG_INFO("Thing ID: %s", getThingId().c_str()); execCloudEventCallback(ArduinoIoTCloudEvent::CONNECT); _deviceSubscribedToThing = true; From d3734054b07615bb543218345f6915e043b7618e Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 3 Feb 2022 15:40:26 +0100 Subject: [PATCH 19/21] Call DISCONNECT event when device is detached from a thing and print "Disconnected from Arduino IoT Cloud" on serial monitor --- src/ArduinoIoTCloudTCP.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 554c48ce0..b00670811 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -487,6 +487,8 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig() _mqttClient.unsubscribe(_shadowTopicIn); _mqttClient.unsubscribe(_dataTopicIn); _deviceSubscribedToThing = false; + DEBUG_INFO("Disconnected from Arduino IoT Cloud"); + execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT); } updateThingTopics(); From 4a121ae40ee60fd76e021f15327ab4b29df31e8b Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 8 Feb 2022 11:07:05 +0100 Subject: [PATCH 20/21] Add DEBUG_ERROR if device fails to subscribe to _deviceTopicIn --- src/ArduinoIoTCloudTCP.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index b00670811..7958ff71e 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -430,6 +430,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic() if (!_mqttClient.subscribe(_deviceTopicIn)) { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s could not subscribe to %s", __FUNCTION__, _deviceTopicIn.c_str()); return State::SubscribeDeviceTopic; } From 93d6fa85ebcb7a836afd241f6207b823cffec29f Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 8 Feb 2022 11:38:28 +0100 Subject: [PATCH 21/21] Add DEBUG_ERROR if device is not receiving a valid thing_id from the cloud --- src/ArduinoIoTCloudTCP.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 7958ff71e..ed0e46cd4 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -469,6 +469,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_WaitDeviceConfig() /* Configuration not received or device not attached to a valid thing. Try to resubscribe */ if (_mqttClient.unsubscribe(_deviceTopicIn)) { + DEBUG_ERROR("ArduinoIoTCloudTCP::%s device waiting for valid thing_id", __FUNCTION__); return State::SubscribeDeviceTopic; } }