From 509396bc3e3cfed8467fe2aff65ab260431c4196 Mon Sep 17 00:00:00 2001 From: Nick Dunklee Date: Fri, 5 Jun 2026 22:12:13 -0600 Subject: [PATCH] feat: wifi companion handling robustiness improvement I am redoing my change from a while back to be more human-readable. It's true, looking at one's earlier code can make one feel terrible! Anyways, the existing implementation of wifi reconnect in MeshCore leverages two reconnects with `WiFi.setAutoReconnect(true)` as well as the manual reconnect loop. From some research, the existing method creates two competing reconnect mechanisms that can fight against each other. My original desire to fix this stemmed from WiFi connections not completing successfully, becoming stale, taking a very long time to reestablish. An older variation of this fix has been running for months now, and the network controller shows a steady stable connection. On the other flavors, wifi would often disconnect, go stale, and periodically disappear until the node was reset. The second PR handles the cli rescue commands to provision wifi. **Improvement Things:** - Utilizes `WiFi.begin()` which does a full re-init and recovers reliably. The existing buggy `reconnect()` calls `esp_wifi_connect()` without reinitializing the stack, which can silently fail on ESP32-S3 under flakey wifi conditions. - Remove `WiFi.setAutoReconnect(true)` so there aren't competing mechanisms. - 30-second reconnect throttle to avoid rapid reconnect shittery in situations like AP not currently being available or put node in the fridge for some reason. - Using `WiFi.persistent(false)` to prevent stale NVS-cached creds from interfering with `WiFi.begin()` calls, both on initial connect, and on each reconnect attempt. - Add flash-stored credential storage: SSID/password are loaded from /wifi_config on SPIFFS at boot, falling back to compiled- in defaults if absent. This allows runtime-provisioning and being able to avoid compiled-in defaults with the subsequent CLI rescue PR to come.) --- examples/companion_radio/main.cpp | 88 ++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index ef9b6bfca4..684e2404c7 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -101,16 +101,15 @@ MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store /* END GLOBAL OBJECTS */ +#if defined(WIFI_SSID) && defined(ESP32) +static char _wifi_ssid[33]; +static char _wifi_pwd[65]; +#endif + void halt() { while (1) ; } -/* WIFI RECONNECT TRACKERS */ -#if defined(ESP32) && defined(WIFI_SSID) - bool wifi_needs_reconnect = false; - unsigned long last_wifi_reconnect_attempt = 0; -#endif - void setup() { Serial.begin(115200); @@ -201,19 +200,29 @@ void setup() { #ifdef WIFI_SSID board.setInhibitSleep(true); // prevent sleep when WiFi is active - WiFi.setAutoReconnect(true); - - WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){ - if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) { - WIFI_DEBUG_PRINTLN("WiFi disconnected. Flagging for reconnect..."); - wifi_needs_reconnect = true; - } else if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) { - WIFI_DEBUG_PRINTLN("WiFi connected successfully!"); - wifi_needs_reconnect = false; - } - }); - - WiFi.begin(WIFI_SSID, WIFI_PWD); + + // Load credentials from flash if provisioned via CLI rescue; fall back to compiled-in defaults + strncpy(_wifi_ssid, WIFI_SSID, sizeof(_wifi_ssid) - 1); + strncpy(_wifi_pwd, WIFI_PWD, sizeof(_wifi_pwd) - 1); + { + File wf = SPIFFS.open("/wifi_config", "r"); + if (wf) { + String ssid = wf.readStringUntil('\n'); + String pwd = wf.readStringUntil('\n'); + wf.close(); + ssid.trim(); + pwd.trim(); + ssid.toCharArray(_wifi_ssid, sizeof(_wifi_ssid)); + pwd.toCharArray(_wifi_pwd, sizeof(_wifi_pwd)); + WIFI_DEBUG_PRINTLN("Loaded credentials from flash, SSID: %s", _wifi_ssid); + } else { + WIFI_DEBUG_PRINTLN("No /wifi_config found, using compiled-in SSID: %s", _wifi_ssid); + } + } + + WiFi.persistent(false); // don't use/overwrite NVS-cached credentials + WiFi.mode(WIFI_STA); + WiFi.begin(_wifi_ssid, _wifi_pwd); serial_interface.begin(TCP_PORT); #elif defined(BLE_PIN_CODE) serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin()); @@ -242,6 +251,39 @@ void setup() { board.onBootComplete(); } +#if defined(WIFI_SSID) && defined(ESP32) +static void wifi_reconnect_check() { + constexpr uint32_t CHECK_INTERVAL_MS = 5000; + constexpr uint32_t RECONNECT_AFTER_MS = 30000; + + static uint32_t last_check = 0; + static uint32_t down_since = 0; + + if (millis() - last_check < CHECK_INTERVAL_MS) return; + last_check = millis(); + + if (WiFi.status() == WL_CONNECTED) { + down_since = 0; + return; + } + + if (down_since == 0) { + down_since = millis(); + WIFI_DEBUG_PRINTLN("WiFi disconnected, waiting to reconnect..."); + return; + } + + if (millis() - down_since >= RECONNECT_AFTER_MS) { + WIFI_DEBUG_PRINTLN("WiFi reconnecting..."); + WiFi.disconnect(true); + WiFi.persistent(false); + WiFi.mode(WIFI_STA); + WiFi.begin(_wifi_ssid, _wifi_pwd); + down_since = 0; + } +} +#endif + void loop() { the_mesh.loop(); sensors.loop(); @@ -257,12 +299,6 @@ void loop() { } #if defined(ESP32) && defined(WIFI_SSID) - // Safely attempt to reconnect every 10 seconds if flagged - if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > 10000)) { - WIFI_DEBUG_PRINTLN("Attempting manual WiFi reconnect..."); - WiFi.disconnect(); - WiFi.reconnect(); - last_wifi_reconnect_attempt = millis(); - } + wifi_reconnect_check(); #endif }