@@ -69,6 +69,11 @@ extern "C" void updateTimezoneInfo()
69
69
ArduinoCloud.updateInternalTimezoneInfo ();
70
70
}
71
71
72
+ extern " C" void setThingIdOutdated ()
73
+ {
74
+ ArduinoCloud.setThingIdOutdatedFlag ();
75
+ }
76
+
72
77
/* *****************************************************************************
73
78
CTOR/DTOR
74
79
******************************************************************************/
@@ -77,6 +82,8 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
77
82
: _state{State::ConnectPhy}
78
83
, _next_connection_attempt_tick{0 }
79
84
, _last_connection_attempt_cnt{0 }
85
+ , _next_device_subscribe_attempt_tick{0 }
86
+ , _last_device_subscribe_cnt{0 }
80
87
, _last_sync_request_tick{0 }
81
88
, _last_sync_request_cnt{0 }
82
89
, _last_subscribe_request_tick{0 }
@@ -91,10 +98,13 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
91
98
, _password(" " )
92
99
#endif
93
100
, _mqttClient{nullptr }
101
+ , _deviceTopicOut(" " )
102
+ , _deviceTopicIn(" " )
94
103
, _shadowTopicOut(" " )
95
104
, _shadowTopicIn(" " )
96
105
, _dataTopicOut(" " )
97
106
, _dataTopicIn(" " )
107
+ , _deviceSubscribedToThing{false }
98
108
#if OTA_ENABLED
99
109
, _ota_cap{false }
100
110
, _ota_error{static_cast <int >(OTAError::None)}
@@ -237,10 +247,8 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
237
247
_mqttClient.setConnectionTimeout (1500 );
238
248
_mqttClient.setId (getDeviceId ().c_str ());
239
249
240
- _shadowTopicOut = getTopic_shadowout ();
241
- _shadowTopicIn = getTopic_shadowin ();
242
- _dataTopicOut = getTopic_dataout ();
243
- _dataTopicIn = getTopic_datain ();
250
+ _deviceTopicOut = getTopic_deviceout ();
251
+ _deviceTopicIn = getTopic_devicein ();
244
252
245
253
#if OTA_ENABLED
246
254
addPropertyReal (_ota_cap, _device_property_container, " OTA_CAP" , Permission::Read);
@@ -253,7 +261,7 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
253
261
addPropertyReal (_tz_offset, _thing_property_container, " tz_offset" , Permission::ReadWrite).onSync (CLOUD_WINS).onUpdate (updateTimezoneInfo);
254
262
addPropertyReal (_tz_dst_until, _thing_property_container, " tz_dst_until" , Permission::ReadWrite).onSync (CLOUD_WINS).onUpdate (updateTimezoneInfo);
255
263
256
- addPropertyReal (_thing_id, _device_property_container, " thing_id" , Permission::ReadWrite);
264
+ addPropertyReal (_thing_id, _device_property_container, " thing_id" , Permission::ReadWrite). onUpdate (setThingIdOutdated) ;
257
265
258
266
#if OTA_STORAGE_PORTENTA_QSPI
259
267
#define BOOTLOADER_ADDR (0x8000000 )
@@ -322,12 +330,16 @@ void ArduinoIoTCloudTCP::update()
322
330
State next_state = _state;
323
331
switch (_state)
324
332
{
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 ;
331
343
}
332
344
_state = next_state;
333
345
@@ -385,7 +397,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
385
397
if (_mqttClient.connect (_brokerAddress.c_str (), _brokerPort))
386
398
{
387
399
_last_connection_attempt_cnt = 0 ;
388
- return State::SubscribeMqttTopics ;
400
+ return State::SendDeviceProperties ;
389
401
}
390
402
391
403
_last_connection_attempt_cnt++;
@@ -398,7 +410,127 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
398
410
return State::ConnectPhy;
399
411
}
400
412
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 ()
402
534
{
403
535
if (!_mqttClient.connected ())
404
536
{
@@ -414,7 +546,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics()
414
546
415
547
if (!is_first_subscribe_request && !is_subscribe_retry_delay_expired)
416
548
{
417
- return State::SubscribeMqttTopics ;
549
+ return State::SubscribeThingTopics ;
418
550
}
419
551
420
552
if (_last_subscribe_request_cnt > AIOT_CONFIG_SUBSCRIBE_MAX_RETRY_CNT)
@@ -435,7 +567,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics()
435
567
#if !defined(__AVR__)
436
568
DEBUG_ERROR (" Check your thing configuration, and press the reset button on your board." );
437
569
#endif
438
- return State::SubscribeMqttTopics ;
570
+ return State::SubscribeThingTopics ;
439
571
}
440
572
441
573
if (_shadowTopicIn != " " )
@@ -446,14 +578,13 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics()
446
578
#if !defined(__AVR__)
447
579
DEBUG_ERROR (" Check your thing configuration, and press the reset button on your board." );
448
580
#endif
449
- return State::SubscribeMqttTopics ;
581
+ return State::SubscribeThingTopics ;
450
582
}
451
583
}
452
584
453
585
DEBUG_INFO (" Connected to Arduino IoT Cloud" );
454
586
execCloudEventCallback (ArduinoIoTCloudEvent::CONNECT);
455
- _last_subscribe_request_cnt = 0 ;
456
- _last_subscribe_request_tick = 0 ;
587
+ _deviceSubscribedToThing = true ;
457
588
458
589
if (_shadowTopicIn != " " )
459
590
return State::RequestLastValues;
@@ -587,10 +718,20 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
587
718
bytes[i] = _mqttClient.read ();
588
719
}
589
720
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 */
590
730
if (_dataTopicIn == topic) {
591
731
CBORDecoder::decode (_thing_property_container, (uint8_t *)bytes, length);
592
732
}
593
733
734
+ /* Topic for sync Thing last values on connect */
594
735
if ((_shadowTopicIn == topic) && (_state == State::RequestLastValues))
595
736
{
596
737
DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values received" , __FUNCTION__, millis ());
@@ -633,7 +774,7 @@ void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud()
633
774
PropertyContainer ota_property_container;
634
775
unsigned int last_ota_property_index = 0 ;
635
776
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" };
637
778
std::for_each (ota_property_list.cbegin (),
638
779
ota_property_list.cend (),
639
780
[this , &ota_property_container ] (String const & name)
@@ -644,7 +785,7 @@ void ArduinoIoTCloudTCP::sendOTAPropertiesToCloud()
644
785
}
645
786
);
646
787
647
- sendPropertyContainerToCloud (_dataTopicOut , ota_property_container, last_ota_property_index);
788
+ sendPropertyContainerToCloud (_deviceTopicOut , ota_property_container, last_ota_property_index);
648
789
}
649
790
#endif
650
791
@@ -688,6 +829,16 @@ void ArduinoIoTCloudTCP::onOTARequest()
688
829
}
689
830
#endif
690
831
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
+
691
842
/* *****************************************************************************
692
843
* EXTERN DEFINITION
693
844
******************************************************************************/
0 commit comments