From 4d945851ce876e67bde47b7ef355ad870cdab4e4 Mon Sep 17 00:00:00 2001 From: Florian Date: Mon, 1 Jun 2026 08:50:12 -0500 Subject: [PATCH] [SYS] Add WiFi reconnect watchdog to self-heal from wedged WiFi stack (#2319) When the network drops at runtime and the WiFi stack is wedged (e.g. the ESP32 driver getting stuck after a long uptime, see #2276), the main loop kept calling wifi_reconnect_bypass() forever with no recovery: the device stayed stale until a manual reboot. The reboot watchdog only existed in the ESPWifiManualSetup path, which the default WiFiManager build doesn't compile. Count consecutive reconnection failures in the runtime loop and ESPRestart(2) once they exceed maxRetryWatchDog, mirroring the existing manual-setup watchdog. Gated behind the new WifiReconnectWatchDog flag (default on) so environments where an unexpected reboot is undesirable can opt out; disabled for theengs-plug to avoid interrupting the relay state. Co-authored-by: Claude --- environments.ini | 1 + main/User_config.h | 8 ++++++++ main/main.cpp | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/environments.ini b/environments.ini index bf50179..c60cca2 100644 --- a/environments.ini +++ b/environments.ini @@ -183,6 +183,7 @@ build_flags = '-DWM_PWD_FROM_MAC=true' '-DUSE_MAC_AS_GATEWAY_NAME' '-DDEFAULT_LOW_POWER_MODE=DEACTIVATED' + '-DWifiReconnectWatchDog=false' ; Don't reboot on persistent WiFi loss, it would interrupt the relay state '-DGATEWAY_MANUFACTURER="Theengs"' '-DGATEWAY_MODEL="TPLUG01"' '-UZwebUI="WebUI"' ; Disable WebUI diff --git a/main/User_config.h b/main/User_config.h index 3ac82d2..4a2af04 100644 --- a/main/User_config.h +++ b/main/User_config.h @@ -135,6 +135,14 @@ #define maxConnectionRetryNetwork 5 //maximum Wifi connection attempts with existing credential at start (used to bypass ESP32 issue on wifi connect) #define maxRetryWatchDog 11 //maximum Wifi or MQTT re-connection attempts before restarting +// WifiReconnectWatchDog: restart the ESP if the network can't be recovered after maxRetryWatchDog +// consecutive reconnection attempts in the main loop. This allows the gateway to self-heal from a +// wedged WiFi stack (e.g. the ESP32 driver getting stuck after a long uptime). Disable it on +// environments where an unexpected reboot is undesirable (e.g. a smart plug that would lose its relay state). +#ifndef WifiReconnectWatchDog +# define WifiReconnectWatchDog true +#endif + //set minimum quality of signal so it ignores AP's under that quality #define MinimumWifiSignalQuality 8 diff --git a/main/main.cpp b/main/main.cpp index 1012a2a..79a12d2 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2594,6 +2594,13 @@ void loop() { THEENGS_LOG_WARNING(F("Network disconnected" CR)); gatewayState = GatewayState::NTWK_DISCONNECTED; if (!wifi_reconnect_bypass()) { + failure_number_ntwk++; + THEENGS_LOG_WARNING(F("failure_number_ntwk: %d" CR), failure_number_ntwk); + // Self-heal from a wedged WiFi stack: if reconnection keeps failing, restart the ESP. + // Disabled on environments where an unexpected reboot is undesirable (e.g. a smart plug). + if (WifiReconnectWatchDog && failure_number_ntwk > maxRetryWatchDog) { + ESPRestart(2); + } sleep(); } else { gatewayState = GatewayState::NTWK_CONNECTED;