@@ -59,18 +59,11 @@ unsigned long getTime()
59
59
60
60
ArduinoIoTCloudTCP::ArduinoIoTCloudTCP ()
61
61
: _state{State::ConnectPhy}
62
+ , _connection_attempt(0 ,0 )
62
63
, _tz_offset{0 }
63
64
, _tz_offset_property{nullptr }
64
65
, _tz_dst_until{0 }
65
66
, _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 }
74
67
, _mqtt_data_buf{0 }
75
68
, _mqtt_data_len{0 }
76
69
, _mqtt_data_request_retransmit{false }
@@ -113,7 +106,12 @@ int ArduinoIoTCloudTCP::begin(ConnectionHandler & connection, bool const enable_
113
106
#else
114
107
_brokerPort = brokerPort;
115
108
#endif
109
+
110
+ /* Setup TimeService */
116
111
_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);
117
115
return begin (enable_watchdog, _brokerAddress, _brokerPort);
118
116
}
119
117
@@ -132,15 +130,16 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
132
130
if (!_password.length ())
133
131
{
134
132
#endif
133
+
135
134
#if defined(BOARD_HAS_SECURE_ELEMENT)
136
135
if (!_selement.begin ())
137
136
{
138
137
DEBUG_ERROR (" ArduinoIoTCloudTCP::%s could not initialize secure element." , __FUNCTION__);
139
- #if defined(ARDUINO_UNOWIFIR4)
138
+ #if defined(ARDUINO_UNOWIFIR4)
140
139
if (String (WiFi.firmwareVersion ()) < String (" 0.4.1" )) {
141
140
DEBUG_ERROR (" ArduinoIoTCloudTCP::%s In order to read device certificate, WiFi firmware needs to be >= 0.4.1, current %s" , __FUNCTION__, WiFi.firmwareVersion ());
142
141
}
143
- #endif
142
+ #endif
144
143
return 0 ;
145
144
}
146
145
if (!SElementArduinoCloudDeviceId::read (_selement, getDeviceId (), SElementArduinoCloudSlot::DeviceId))
@@ -317,8 +316,7 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectPhy()
317
316
{
318
317
if (_connection->check () == NetworkConnectionState::CONNECTED)
319
318
{
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 ()))
322
320
return State::SyncTime;
323
321
}
324
322
@@ -339,18 +337,20 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
339
337
{
340
338
if (_mqttClient.connect (_brokerAddress.c_str (), _brokerPort))
341
339
{
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);
343
343
return State::SendDeviceProperties;
344
344
}
345
345
346
346
/* 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
351
351
352
352
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);
354
354
/* Go back to ConnectPhy and retry to get time from network (invalid time for SSL handshake?)*/
355
355
return State::ConnectPhy;
356
356
}
@@ -375,11 +375,10 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic()
375
375
return State::Disconnect;
376
376
}
377
377
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 ())
380
379
return State::SubscribeDeviceTopic;
381
380
382
- if (is_retry_attempt )
381
+ if (_connection_attempt. isRetry () )
383
382
{
384
383
/* Configuration not received or device not attached to a valid thing. Try to resubscribe */
385
384
DEBUG_ERROR (" ArduinoIoTCloudTCP::%s device waiting for valid thing_id %d" , __FUNCTION__, _time_service.getTime ());
@@ -396,18 +395,17 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeDeviceTopic()
396
395
}
397
396
398
397
/* 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)
400
399
{
401
- _last_device_subscribe_cnt = 0 ;
402
400
return State::Disconnect;
403
401
}
404
402
405
403
/* 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);
411
409
412
410
return State::SubscribeDeviceTopic;
413
411
}
@@ -426,18 +424,18 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_CheckDeviceConfig()
426
424
/* Device configuration received, but invalid thing_id. Do not increase counter, but recompute delay.
427
425
* Device not attached. Wait: 40s -> 80s -> 160s -> 320s -> 640s -> 1280s -> 1280s ...
428
426
*/
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
433
431
DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s device not attached, next configuration request in %d ms" , __FUNCTION__, attach_retry_delay);
434
432
return State::SubscribeDeviceTopic;
435
433
}
436
434
437
435
DEBUG_VERBOSE (" ArduinoIoTCloudTCP::%s device attached to a new valid thing_id %s %d" , __FUNCTION__, getThingId ().c_str (), _time_service.getTime ());
438
436
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) ;
441
439
442
440
return State::SubscribeThingTopics;
443
441
}
@@ -449,18 +447,15 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics()
449
447
return State::Disconnect;
450
448
}
451
449
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 ())
454
451
return State::SubscribeThingTopics;
455
452
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)
457
454
{
458
- _last_thing_subscribe_attempt_cnt = 0 ;
459
455
return State::Disconnect;
460
456
}
461
457
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 ();
464
459
465
460
if (!_mqttClient.subscribe (_dataTopicIn))
466
461
{
@@ -480,6 +475,8 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics()
480
475
DEBUG_INFO (" Thing ID: %s" , getThingId ().c_str ());
481
476
execCloudEventCallback (ArduinoIoTCloudEvent::CONNECT);
482
477
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);
483
480
return State::RequestLastValues;
484
481
}
485
482
@@ -491,25 +488,21 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_RequestLastValues()
491
488
}
492
489
493
490
/* 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 ())
496
492
return State::RequestLastValues;
497
493
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)
499
499
{
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 ;
505
500
return State::Disconnect;
506
501
}
507
502
508
- DEBUG_VERBOSE ( " ArduinoIoTCloudTCP::%s [%d] last values requested " , __FUNCTION__, _time_service. getTime () );
503
+ _connection_attempt. retry ( );
509
504
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 ());
513
506
return State::RequestLastValues;
514
507
}
515
508
@@ -608,10 +601,14 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Disconnect()
608
601
} else {
609
602
_mqttClient.unsubscribe (_shadowTopicIn);
610
603
_mqttClient.unsubscribe (_dataTopicIn);
604
+ /* TODO add device topic */
611
605
_mqttClient.stop ();
612
606
}
613
607
DEBUG_INFO (" Disconnected from Arduino IoT Cloud" );
614
608
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);
615
612
return State::ConnectPhy;
616
613
}
617
614
@@ -633,7 +630,6 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
633
630
/* Topic for OTA properties and device configuration */
634
631
if (_deviceTopicIn == topic) {
635
632
CBORDecoder::decode (_device_property_container, (uint8_t *)bytes, length);
636
- _last_device_subscribe_cnt = 0 ;
637
633
_state = State::CheckDeviceConfig;
638
634
}
639
635
@@ -649,7 +645,6 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
649
645
CBORDecoder::decode (_thing_property_container, (uint8_t *)bytes, length, true );
650
646
_time_service.setTimeZoneData (_tz_offset, _tz_dst_until);
651
647
execCloudEventCallback (ArduinoIoTCloudEvent::SYNC);
652
- _last_sync_attempt_cnt = 0 ;
653
648
_state = State::Connected;
654
649
}
655
650
}
0 commit comments