@@ -69,6 +69,11 @@ extern "C" void updateTimezoneInfo()
6969 ArduinoCloud.updateInternalTimezoneInfo ();
7070}
7171
72+ extern " C" void setThingIdOutdated ()
73+ {
74+ ArduinoCloud.setThingIdOutdatedFlag ();
75+ }
76+
7277/* *****************************************************************************
7378 CTOR/DTOR
7479 ******************************************************************************/
@@ -77,6 +82,8 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
7782: _state{State::ConnectPhy}
7883, _next_connection_attempt_tick{0 }
7984, _last_connection_attempt_cnt{0 }
85+ , _next_device_subscribe_attempt_tick{0 }
86+ , _last_device_subscribe_cnt{0 }
8087, _last_sync_request_tick{0 }
8188, _last_sync_request_cnt{0 }
8289, _last_subscribe_request_tick{0 }
@@ -91,10 +98,13 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
9198, _password(" " )
9299 #endif
93100, _mqttClient{nullptr }
101+ , _deviceTopicOut(" " )
102+ , _deviceTopicIn(" " )
94103, _shadowTopicOut(" " )
95104, _shadowTopicIn(" " )
96105, _dataTopicOut(" " )
97106, _dataTopicIn(" " )
107+ , _deviceSubscribedToThing{false }
98108#if OTA_ENABLED
99109, _ota_cap{false }
100110, _ota_error{static_cast <int >(OTAError::None)}
@@ -237,10 +247,8 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
237247 _mqttClient.setConnectionTimeout (1500 );
238248 _mqttClient.setId (getDeviceId ().c_str ());
239249
240- _shadowTopicOut = getTopic_shadowout ();
241- _shadowTopicIn = getTopic_shadowin ();
242- _dataTopicOut = getTopic_dataout ();
243- _dataTopicIn = getTopic_datain ();
250+ _deviceTopicOut = getTopic_deviceout ();
251+ _deviceTopicIn = getTopic_devicein ();
244252
245253#if OTA_ENABLED
246254 addPropertyReal (_ota_cap, _device_property_container, " OTA_CAP" , Permission::Read);
@@ -253,7 +261,7 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
253261 addPropertyReal (_tz_offset, _thing_property_container, " tz_offset" , Permission::ReadWrite).onSync (CLOUD_WINS).onUpdate (updateTimezoneInfo);
254262 addPropertyReal (_tz_dst_until, _thing_property_container, " tz_dst_until" , Permission::ReadWrite).onSync (CLOUD_WINS).onUpdate (updateTimezoneInfo);
255263
256- addPropertyReal (_thing_id, _device_property_container, " thing_id" , Permission::ReadWrite);
264+ addPropertyReal (_thing_id, _device_property_container, " thing_id" , Permission::ReadWrite). onUpdate (setThingIdOutdated) ;
257265
258266#if OTA_STORAGE_PORTENTA_QSPI
259267 #define BOOTLOADER_ADDR (0x8000000 )
@@ -322,12 +330,16 @@ void ArduinoIoTCloudTCP::update()
322330 State next_state = _state;
323331 switch (_state)
324332 {
325- case State::ConnectPhy: next_state = handle_ConnectPhy (); break ;
326- case State::SyncTime: next_state = handle_SyncTime (); break ;
327- case State::ConnectMqttBroker: next_state = handle_ConnectMqttBroker (); break ;
328- case State::SubscribeMqttTopics: next_state = handle_SubscribeMqttTopics (); break ;
329- case State::RequestLastValues: next_state = handle_RequestLastValues (); break ;
330- case State::Connected: next_state = handle_Connected (); break ;
333+ case State::ConnectPhy: next_state = handle_ConnectPhy (); break ;
334+ case State::SyncTime: next_state = handle_SyncTime (); break ;
335+ case State::ConnectMqttBroker: next_state = handle_ConnectMqttBroker (); break ;
336+ case State::SendDeviceProperties: next_state = handle_SendDeviceProperties (); break ;
337+ case State::SubscribeDeviceTopic: next_state = handle_SubscribeDeviceTopic (); break ;
338+ case State::WaitDeviceConfig: next_state = handle_WaitDeviceConfig (); break ;
339+ case State::CheckDeviceConfig: next_state = handle_CheckDeviceConfig (); break ;
340+ case State::SubscribeThingTopics: next_state = handle_SubscribeThingTopics (); break ;
341+ case State::RequestLastValues: next_state = handle_RequestLastValues (); break ;
342+ case State::Connected: next_state = handle_Connected (); break ;
331343 }
332344 _state = next_state;
333345
@@ -385,7 +397,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
385397 if (_mqttClient.connect (_brokerAddress.c_str (), _brokerPort))
386398 {
387399 _last_connection_attempt_cnt = 0 ;
388- return State::SubscribeMqttTopics ;
400+ return State::SendDeviceProperties ;
389401 }
390402
391403 _last_connection_attempt_cnt++;
@@ -398,7 +410,127 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
398410 return State::ConnectPhy;
399411}
400412
401- ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics ()
413+ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SendDeviceProperties ()
414+ {
415+ if (!_mqttClient.connected ())
416+ {
417+ DEBUG_ERROR (" ArduinoIoTCloudTCP::%s MQTT client connection lost" , __FUNCTION__);
418+ _mqttClient.stop ();
419+ execCloudEventCallback (ArduinoIoTCloudEvent::DISCONNECT);
420+ return State::ConnectPhy;
421+ }
422+
423+ #if OTA_ENABLED
424+ sendOTAPropertiesToCloud ();
425+ #endif
426+ return State::SubscribeDeviceTopic;
427+ }
428+
429+ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic ()
430+ {
431+ if (!_mqttClient.connected ())
432+ {
433+ DEBUG_ERROR (" ArduinoIoTCloudTCP::%s MQTT client connection lost" , __FUNCTION__);
434+ _mqttClient.stop ();
435+ execCloudEventCallback (ArduinoIoTCloudEvent::DISCONNECT);
436+ return State::ConnectPhy;
437+ }
438+
439+ if (!_mqttClient.subscribe (_deviceTopicIn))
440+ {
441+ return State::SubscribeDeviceTopic;
442+ }
443+
444+ if (_last_device_subscribe_cnt > AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT)
445+ {
446+ _last_device_subscribe_cnt = 0 ;
447+ _next_device_subscribe_attempt_tick = 0 ;
448+ _mqttClient.stop ();
449+ execCloudEventCallback (ArduinoIoTCloudEvent::DISCONNECT);
450+ return State::ConnectPhy;
451+ }
452+
453+ unsigned long reconnection_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms;
454+ reconnection_retry_delay = min (reconnection_retry_delay, static_cast <unsigned long >(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms));
455+ _next_device_subscribe_attempt_tick = millis () + reconnection_retry_delay;
456+ _last_device_subscribe_cnt++;
457+
458+ return State::WaitDeviceConfig;
459+ }
460+
461+ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_WaitDeviceConfig ()
462+ {
463+ if (!_mqttClient.connected ())
464+ {
465+ DEBUG_ERROR (" ArduinoIoTCloudTCP::%s MQTT client connection lost" , __FUNCTION__);
466+ _mqttClient.stop ();
467+ execCloudEventCallback (ArduinoIoTCloudEvent::DISCONNECT);
468+ return State::ConnectPhy;
469+ }
470+
471+ if (millis () > _next_device_subscribe_attempt_tick)
472+ {
473+ /* Configuration not received try to resubscribe */
474+ if (_mqttClient.unsubscribe (_deviceTopicIn))
475+ {
476+ return State::SubscribeDeviceTopic;
477+ }
478+ }
479+
480+ return State::WaitDeviceConfig;
481+ }
482+
483+ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig ()
484+ {
485+ if (!_mqttClient.connected ())
486+ {
487+ DEBUG_ERROR (" ArduinoIoTCloudTCP::%s MQTT client connection lost" , __FUNCTION__);
488+ _mqttClient.stop ();
489+ execCloudEventCallback (ArduinoIoTCloudEvent::DISCONNECT);
490+ return State::ConnectPhy;
491+ }
492+
493+ if (getThingIdOutdatedFlag ())
494+ {
495+ if (_deviceSubscribedToThing == true )
496+ {
497+ /* Unsubscribe from old things topics and go on with a new subsctiption */
498+ _mqttClient.unsubscribe (_shadowTopicIn);
499+ _mqttClient.unsubscribe (_dataTopicIn);
500+
501+ _deviceSubscribedToThing = false ;
502+ }
503+ }
504+
505+ updateThingTopics ();
506+
507+ if (deviceNotConfigured ())
508+ {
509+ /* maybe we have only missed the thing_id property...
510+ * unsubsribe and resubscribe immediately to trigger a new configuration command
511+ */
512+ _mqttClient.unsubscribe (_deviceTopicIn);
513+ return State::SubscribeDeviceTopic;
514+ }
515+
516+ if (deviceNotAttached ())
517+ {
518+ /* start long timeout counter
519+ * return return State::SubscribeThingTopics
520+ * if long timeout expired unsubscribe and
521+ * return State::SubscribeDeviceTopic
522+ */
523+ unsigned long reconnection_retry_delay = (1 << _last_device_subscribe_cnt) * AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms * 10000 ;
524+ reconnection_retry_delay = min (reconnection_retry_delay, static_cast <unsigned long >(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms));
525+ _next_device_subscribe_attempt_tick = millis () + reconnection_retry_delay;
526+ _last_device_subscribe_cnt++;
527+ return State::WaitDeviceConfig;
528+ }
529+
530+ return State::SubscribeThingTopics;
531+ }
532+
533+ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics ()
402534{
403535 if (!_mqttClient.connected ())
404536 {
@@ -414,7 +546,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics()
414546
415547 if (!is_first_subscribe_request && !is_subscribe_retry_delay_expired)
416548 {
417- return State::SubscribeMqttTopics ;
549+ return State::SubscribeThingTopics ;
418550 }
419551
420552 if (_last_subscribe_request_cnt > AIOT_CONFIG_SUBSCRIBE_MAX_RETRY_CNT)
@@ -435,7 +567,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics()
435567#if !defined(__AVR__)
436568 DEBUG_ERROR (" Check your thing configuration, and press the reset button on your board." );
437569#endif
438- return State::SubscribeMqttTopics ;
570+ return State::SubscribeThingTopics ;
439571 }
440572
441573 if (_shadowTopicIn != " " )
@@ -446,14 +578,13 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics()
446578#if !defined(__AVR__)
447579 DEBUG_ERROR (" Check your thing configuration, and press the reset button on your board." );
448580#endif
449- return State::SubscribeMqttTopics ;
581+ return State::SubscribeThingTopics ;
450582 }
451583 }
452584
453585 DEBUG_INFO (" Connected to Arduino IoT Cloud" );
454586 execCloudEventCallback (ArduinoIoTCloudEvent::CONNECT);
455- _last_subscribe_request_cnt = 0 ;
456- _last_subscribe_request_tick = 0 ;
587+ _deviceSubscribedToThing = true ;
457588
458589 if (_shadowTopicIn != " " )
459590 return State::RequestLastValues;
@@ -587,10 +718,20 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
587718 bytes[i] = _mqttClient.read ();
588719 }
589720
721+ /* Topic for OTA properties and device configuration */
722+ if (_deviceTopicIn == topic) {
723+ CBORDecoder::decode (_device_property_container, (uint8_t *)bytes, length);
724+ _last_device_subscribe_cnt = 0 ;
725+ _next_device_subscribe_attempt_tick = 0 ;
726+ _state = State::CheckDeviceConfig;
727+ }
728+
729+ /* Topic for user input data */
590730 if (_dataTopicIn == topic) {
591731 CBORDecoder::decode (_thing_property_container, (uint8_t *)bytes, length);
592732 }
593733
734+ /* Topic for sync Thing last values on connect */
594735 if ((_shadowTopicIn == topic) && (_state == State::RequestLastValues))
595736 {
596737 DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values received" , __FUNCTION__, millis ());
@@ -633,7 +774,7 @@ void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud()
633774 PropertyContainer ota_property_container;
634775 unsigned int last_ota_property_index = 0 ;
635776
636- std::list<String> const ota_property_list {" OTA_CAP" , " OTA_ERROR" , " OTA_SHA256" , " OTA_URL " , " OTA_REQ " };
777+ std::list<String> const ota_property_list {" OTA_CAP" , " OTA_ERROR" , " OTA_SHA256" };
637778 std::for_each (ota_property_list.cbegin (),
638779 ota_property_list.cend (),
639780 [this , &ota_property_container ] (String const & name)
@@ -644,7 +785,7 @@ void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud()
644785 }
645786 );
646787
647- sendPropertyContainerToCloud (_dataTopicOut , ota_property_container, last_ota_property_index);
788+ sendPropertyContainerToCloud (_deviceTopicOut , ota_property_container, last_ota_property_index);
648789}
649790#endif
650791
@@ -688,6 +829,16 @@ void ArduinoIoTCloudTCP::onOTARequest()
688829}
689830#endif
690831
832+ void ArduinoIoTCloudTCP::updateThingTopics ()
833+ {
834+ _shadowTopicOut = getTopic_shadowout ();
835+ _shadowTopicIn = getTopic_shadowin ();
836+ _dataTopicOut = getTopic_dataout ();
837+ _dataTopicIn = getTopic_datain ();
838+
839+ clrThingIdOutdatedFlag ();
840+ }
841+
691842/* *****************************************************************************
692843 * EXTERN DEFINITION
693844 ******************************************************************************/
0 commit comments