Reconnect with back-off on every disconnect reason and log it

The session is opened again whatever AsyncMqttClient gives as the reason, after 1 s doubling
to 60 s (AlexaReconnectBackoff, reset when a session opens), and only while Wi-Fi is up.
1.1.0 retried a lost TCP connection every 5 s and nothing else, silently: a refused password
or a broker that was restarting left the board offline until a reset.
Every disconnect prints its reason in words and the wait before the next attempt. The first
connect waits for Wi-Fi; a connect without an answer after 30 s counts as failed, because the
MQTT client reports nothing when no TCP connection was made. Keep-alive 30 s.
basicLight: RAM 34,452 -> 34,476 B, flash 337,461 -> 338,281 B; host tests 41 -> 45.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 18:43:00 +00:00
parent cb5c9876fe
commit 2ed52c8721
6 changed files with 194 additions and 23 deletions

View file

@ -753,6 +753,59 @@ void test_other_topics_are_not_directive_topics()
TEST_ASSERT_NULL(AlexaBridgeLogic::directiveEndpoint("root/ESP-01/alexaDirective", "root", nullptr));
}
// --- reconnect ---
void test_wait_doubles_from_a_second_to_a_minute()
{
AlexaReconnectBackoff backoff;
const uint32_t expected[] = {1000, 2000, 4000, 8000, 16000, 32000, 60000, 60000, 60000};
for (uint32_t wait : expected)
{
TEST_ASSERT_EQUAL_UINT32(wait, backoff.wait());
backoff.attempt();
}
}
void test_open_session_starts_the_wait_over()
{
AlexaReconnectBackoff backoff;
for (int i = 0; i < 10; i++)
{
backoff.attempt();
}
TEST_ASSERT_EQUAL_UINT32(60000, backoff.wait());
backoff.reset();
TEST_ASSERT_EQUAL_UINT32(1000, backoff.wait());
backoff.attempt();
TEST_ASSERT_EQUAL_UINT32(2000, backoff.wait());
}
void test_attempt_is_due_when_the_wait_is_over()
{
AlexaReconnectBackoff backoff;
TEST_ASSERT_FALSE(backoff.due(5000, 5000));
TEST_ASSERT_FALSE(backoff.due(5999, 5000));
TEST_ASSERT_TRUE(backoff.due(6000, 5000));
backoff.attempt();
TEST_ASSERT_FALSE(backoff.due(6999, 5000));
TEST_ASSERT_TRUE(backoff.due(7000, 5000));
}
void test_wait_is_counted_across_the_overflow_of_millis()
{
AlexaReconnectBackoff backoff;
const uint32_t since = 0xFFFFFF00u; // 256 ms before millis() starts again at 0
TEST_ASSERT_FALSE(backoff.due(0xFFFFFFFFu, since));
TEST_ASSERT_FALSE(backoff.due(743, since));
TEST_ASSERT_TRUE(backoff.due(744, since));
}
// --- time ---
void test_timestamp_is_iso_8601_in_utc()
@ -848,6 +901,11 @@ int main(int, char **)
RUN_TEST(test_endpoint_is_taken_from_the_directive_topic);
RUN_TEST(test_other_topics_are_not_directive_topics);
RUN_TEST(test_wait_doubles_from_a_second_to_a_minute);
RUN_TEST(test_open_session_starts_the_wait_over);
RUN_TEST(test_attempt_is_due_when_the_wait_is_over);
RUN_TEST(test_wait_is_counted_across_the_overflow_of_millis);
RUN_TEST(test_timestamp_is_iso_8601_in_utc);
RUN_TEST(test_timestamp_needs_a_buffer_of_its_size);
RUN_TEST(test_clock_counts_as_set_from_2024);