@@ -59,18 +59,11 @@ unsigned long getTime()
5959
6060ArduinoIoTCloudTCP::ArduinoIoTCloudTCP ()
6161: _state{State::ConnectPhy}
62+ , _connection_attempt(0 ,0 )
6263, _tz_offset{0 }
6364, _tz_offset_property{nullptr }
6465, _tz_dst_until{0 }
6566, _tz_dst_until_property{nullptr }
66- , _next_connection_attempt_tick{0 }
67- , _last_connection_attempt_cnt{0 }
68- , _next_device_subscribe_attempt_tick{0 }
69- , _last_device_subscribe_cnt{0 }
70- , _next_thing_subscribe_attempt_tick{0 }
71- , _last_thing_subscribe_attempt_cnt{0 }
72- , _next_sync_attempt_tick{0 }
73- , _last_sync_attempt_cnt{0 }
7467, _mqtt_data_buf{0 }
7568, _mqtt_data_len{0 }
7669, _mqtt_data_request_retransmit{false }
@@ -113,7 +106,12 @@ int ArduinoIoTCloudTCP::begin(ConnectionHandler & connection, bool const enable_
113106#else
114107 _brokerPort = brokerPort;
115108#endif
109+
110+ /* Setup TimeService */
116111 _time_service.begin (&connection);
112+
113+ /* Setup retry timers */
114+ _connection_attempt.begin (AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms, AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms);
117115 return begin (enable_watchdog, _brokerAddress, _brokerPort);
118116}
119117
@@ -132,15 +130,16 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
132130 if (!_password.length ())
133131 {
134132#endif
133+
135134#if defined(BOARD_HAS_SECURE_ELEMENT)
136135 if (!_selement.begin ())
137136 {
138137 DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not initialize secure element." , __FUNCTION__);
139- #if defined(ARDUINO_UNOWIFIR4)
138+ #if defined(ARDUINO_UNOWIFIR4)
140139 if (String (WiFi.firmwareVersion ()) < String (" 0.4.1" )) {
141140 DEBUG_ERROR (" ArduinoIoTCloudTCP::%s In order to read device certificate, WiFi firmware needs to be >= 0.4.1, current %s" , __FUNCTION__, WiFi.firmwareVersion ());
142141 }
143- #endif
142+ #endif
144143 return 0 ;
145144 }
146145 if (!SElementArduinoCloudDeviceId::read (_selement, getDeviceId (), SElementArduinoCloudSlot::DeviceId))
@@ -317,8 +316,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectPhy()
317316{
318317 if (_connection->check () == NetworkConnectionState::CONNECTED)
319318 {
320- bool const is_retry_attempt = (_last_connection_attempt_cnt > 0 );
321- if (!is_retry_attempt || (is_retry_attempt && (millis () > _next_connection_attempt_tick)))
319+ if (!_connection_attempt.isRetry () || (_connection_attempt.isRetry () && _connection_attempt.isExpired ()))
322320 return State::SyncTime;
323321 }
324322
@@ -339,18 +337,20 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
339337{
340338 if (_mqttClient.connect (_brokerAddress.c_str (), _brokerPort))
341339 {
342- _last_connection_attempt_cnt = 0 ;
340+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s connected to %s:%d" , __FUNCTION__, _brokerAddress.c_str (), _brokerPort);
341+ /* Reconfigure timers for next state */
342+ _connection_attempt.begin (AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms, AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms);
343343 return State::SendDeviceProperties;
344344 }
345345
346346 /* Can't connect to the broker. Wait: 2s -> 4s -> 8s -> 16s -> 32s -> 32s ... */
347- _last_connection_attempt_cnt++;
348- unsigned long reconnection_retry_delay = ( 1 << _last_connection_attempt_cnt) * AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms;
349- reconnection_retry_delay = min ( reconnection_retry_delay, static_cast < unsigned long >(AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms) );
350- _next_connection_attempt_tick = millis () + reconnection_retry_delay;
347+ # pragma GCC diagnostic push
348+ # pragma GCC diagnostic ignored "-Wunused-variable"
349+ unsigned long const reconnection_retry_delay = _connection_attempt. retry ( );
350+ # pragma GCC diagnostic pop
351351
352352 DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not connect to %s:%d" , __FUNCTION__, _brokerAddress.c_str (), _brokerPort);
353- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s %d next connection attempt in %d ms" , __FUNCTION__, _last_connection_attempt_cnt , reconnection_retry_delay);
353+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s %d next connection attempt in %d ms" , __FUNCTION__, _connection_attempt. getRetryCount () , reconnection_retry_delay);
354354 /* Go back to ConnectPhy and retry to get time from network (invalid time for SSL handshake?)*/
355355 return State::ConnectPhy;
356356}
@@ -375,11 +375,10 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic()
375375 return State::Disconnect;
376376 }
377377
378- bool const is_retry_attempt = (_last_device_subscribe_cnt > 0 );
379- if (is_retry_attempt && (millis () < _next_device_subscribe_attempt_tick))
378+ if (_connection_attempt.isRetry () && !_connection_attempt.isExpired ())
380379 return State::SubscribeDeviceTopic;
381380
382- if (is_retry_attempt )
381+ if (_connection_attempt. isRetry () )
383382 {
384383 /* Configuration not received or device not attached to a valid thing. Try to resubscribe */
385384 DEBUG_ERROR (" ArduinoIoTCloudTCP::%s device waiting for valid thing_id %d" , __FUNCTION__, _time_service.getTime ());
@@ -396,18 +395,17 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic()
396395 }
397396
398397 /* Max retry than disconnect */
399- if (_last_device_subscribe_cnt > AIOT_CONFIG_DEVICE_TOPIC_MAX_RETRY_CNT)
398+ if (_connection_attempt. getRetryCount () > AIOT_CONFIG_DEVICE_TOPIC_MAX_RETRY_CNT)
400399 {
401- _last_device_subscribe_cnt = 0 ;
402400 return State::Disconnect;
403401 }
404402
405403 /* No device configuration received. Wait: 4s -> 8s -> 16s -> 32s -> 32s ...*/
406- _last_device_subscribe_cnt++;
407- unsigned long subscribe_retry_delay = ( 1 << _last_device_subscribe_cnt) * AIOT_CONFIG_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms;
408- subscribe_retry_delay = min ( subscribe_retry_delay, static_cast < unsigned long >(AIOT_CONFIG_MAX_DEVICE_TOPIC_SUBSCRIBE_RETRY_DELAY_ms) );
409- _next_device_subscribe_attempt_tick = millis () + subscribe_retry_delay;
410- DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s %d next configuration request in %d ms" , __FUNCTION__, _last_device_subscribe_cnt , subscribe_retry_delay);
404+ # pragma GCC diagnostic push
405+ # pragma GCC diagnostic ignored "-Wunused-variable"
406+ unsigned long const subscribe_retry_delay = _connection_attempt. retry ( );
407+ # pragma GCC diagnostic pop
408+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s %d next configuration request in %d ms" , __FUNCTION__, _connection_attempt. getRetryCount () , subscribe_retry_delay);
411409
412410 return State::SubscribeDeviceTopic;
413411}
@@ -426,18 +424,18 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig()
426424 /* Device configuration received, but invalid thing_id. Do not increase counter, but recompute delay.
427425 * Device not attached. Wait: 40s -> 80s -> 160s -> 320s -> 640s -> 1280s -> 1280s ...
428426 */
429- unsigned long attach_retry_delay = ( 1 << _last_device_subscribe_cnt) * AIOT_CONFIG_DEVICE_TOPIC_ATTACH_RETRY_DELAY_ms;
430- attach_retry_delay = min (attach_retry_delay, static_cast < unsigned long >(AIOT_CONFIG_MAX_DEVICE_TOPIC_ATTACH_RETRY_DELAY_ms));
431- _next_device_subscribe_attempt_tick = millis () + attach_retry_delay ;
432-
427+ # pragma GCC diagnostic push
428+ # pragma GCC diagnostic ignored "-Wunused-variable"
429+ unsigned long const attach_retry_delay = _connection_attempt. reconfigure (AIOT_CONFIG_DEVICE_TOPIC_ATTACH_RETRY_DELAY_ms, AIOT_CONFIG_MAX_DEVICE_TOPIC_ATTACH_RETRY_DELAY_ms) ;
430+ # pragma GCC diagnostic pop
433431 DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s device not attached, next configuration request in %d ms" , __FUNCTION__, attach_retry_delay);
434432 return State::SubscribeDeviceTopic;
435433 }
436434
437435 DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s device attached to a new valid thing_id %s %d" , __FUNCTION__, getThingId ().c_str (), _time_service.getTime ());
438436
439- /* Received valid thing_id reset counters and go on */
440- _last_device_subscribe_cnt = 0 ;
437+ /* Received valid thing_id, reconfigure timers for next state and go on */
438+ _connection_attempt. begin (AIOT_CONFIG_THING_TOPICS_SUBSCRIBE_RETRY_DELAY_ms) ;
441439
442440 return State::SubscribeThingTopics;
443441}
@@ -449,18 +447,15 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics()
449447 return State::Disconnect;
450448 }
451449
452- bool const is_retry_attempt = (_last_thing_subscribe_attempt_cnt > 0 );
453- if (is_retry_attempt && (millis () < _next_thing_subscribe_attempt_tick))
450+ if (_connection_attempt.isRetry () && !_connection_attempt.isExpired ())
454451 return State::SubscribeThingTopics;
455452
456- if (_last_thing_subscribe_attempt_cnt > AIOT_CONFIG_THING_TOPICS_SUBSCRIBE_MAX_RETRY_CNT)
453+ if (_connection_attempt. getRetryCount () > AIOT_CONFIG_THING_TOPICS_SUBSCRIBE_MAX_RETRY_CNT)
457454 {
458- _last_thing_subscribe_attempt_cnt = 0 ;
459455 return State::Disconnect;
460456 }
461457
462- _next_thing_subscribe_attempt_tick = millis () + AIOT_CONFIG_THING_TOPICS_SUBSCRIBE_RETRY_DELAY_ms;
463- _last_thing_subscribe_attempt_cnt++;
458+ _connection_attempt.retry ();
464459
465460 if (!_mqttClient.subscribe (_dataTopicIn))
466461 {
@@ -480,6 +475,8 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics()
480475 DEBUG_INFO (" Thing ID: %s" , getThingId ().c_str ());
481476 execCloudEventCallback (ArduinoIoTCloudEvent::CONNECT);
482477
478+ /* Successfully subscribed to thing topics, reconfigure timers for next state and go on */
479+ _connection_attempt.begin (AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms);
483480 return State::RequestLastValues;
484481}
485482
@@ -491,25 +488,21 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_RequestLastValues()
491488 }
492489
493490 /* Check whether or not we need to send a new request. */
494- bool const is_retry_attempt = (_last_sync_attempt_cnt > 0 );
495- if (is_retry_attempt && (millis () < _next_sync_attempt_tick))
491+ if (_connection_attempt.isRetry () && !_connection_attempt.isExpired ())
496492 return State::RequestLastValues;
497493
498- if (_last_sync_attempt_cnt > AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT)
494+ /* Track the number of times a get-last-values request was sent to the cloud.
495+ * If no data is received within a certain number of retry-requests it's a better
496+ * strategy to disconnect and re-establish connection from the ground up.
497+ */
498+ if (_connection_attempt.getRetryCount () > AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT)
499499 {
500- /* Track the number of times a get-last-values request was sent to the cloud.
501- * If no data is received within a certain number of retry-requests it's a better
502- * strategy to disconnect and re-establish connection from the ground up.
503- */
504- _last_sync_attempt_cnt = 0 ;
505500 return State::Disconnect;
506501 }
507502
508- DEBUG_VERBOSE ( " ArduinoIoTCloudTCP::%s [%d] last values requested " , __FUNCTION__, _time_service. getTime () );
503+ _connection_attempt. retry ( );
509504 requestLastValue ();
510- _next_sync_attempt_tick = millis () + AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms;
511- _last_sync_attempt_cnt++;
512-
505+ DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s [%d] last values requested" , __FUNCTION__, _time_service.getTime ());
513506 return State::RequestLastValues;
514507}
515508
@@ -608,10 +601,14 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Disconnect()
608601 } else {
609602 _mqttClient.unsubscribe (_shadowTopicIn);
610603 _mqttClient.unsubscribe (_dataTopicIn);
604+ /* TODO add device topic */
611605 _mqttClient.stop ();
612606 }
613607 DEBUG_INFO (" Disconnected from Arduino IoT Cloud" );
614608 execCloudEventCallback (ArduinoIoTCloudEvent::DISCONNECT);
609+
610+ /* Setup timer for broker connection and restart */
611+ _connection_attempt.begin (AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms, AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms);
615612 return State::ConnectPhy;
616613}
617614
@@ -633,7 +630,6 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
633630 /* Topic for OTA properties and device configuration */
634631 if (_deviceTopicIn == topic) {
635632 CBORDecoder::decode (_device_property_container, (uint8_t *)bytes, length);
636- _last_device_subscribe_cnt = 0 ;
637633 _state = State::CheckDeviceConfig;
638634 }
639635
@@ -649,7 +645,6 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
649645 CBORDecoder::decode (_thing_property_container, (uint8_t *)bytes, length, true );
650646 _time_service.setTimeZoneData (_tz_offset, _tz_dst_until);
651647 execCloudEventCallback (ArduinoIoTCloudEvent::SYNC);
652- _last_sync_attempt_cnt = 0 ;
653648 _state = State::Connected;
654649 }
655650}
0 commit comments