From 1b1ea21c16a20ee38389abdfe85f0a5603022a01 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 18 Oct 2026 17:41:59 -0700 Subject: [PATCH] fix(wifi): keep FAIL_TO_AP mode reachable and truthful after failover WIFI_MODE_ATTEMPT_INFRASTRUCTURE_FAIL_TO_AP had two pre-existing defects, deferred from #295: 1. After infraToAPFailover() switched the radio to the access point, WifiControl::loop() kept hitting the return in the _status != WL_CONNECTED branch on every pass, so tcpLoop()/udpLoop() were never reached again - the soft-AP was up but no client was ever serviced. Split the concerns: the station-monitoring block now stops once _failedOver is set, and a _tcpServer/_udp null-check lifecycle guard controls the early return instead of the connection status. 2. getIP() and getStatus() keyed off the compile-time WIFI_MODE, so after failover the UDP discovery reply and :GN# response advertised the station IP (0.0.0.0) instead of the AP address, and reported station status/SSID fields that no longer applied. Track the failover in the new _failedOver flag and consult it at runtime; after failover the mount now reports exactly what a WIFI_MODE_AP_ONLY mount would. Fixes #307 Co-Authored-By: Claude Code --- src/WifiControl.cpp | 30 ++++++++++++++++++++++-------- src/WifiControl.hpp | 1 + 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/WifiControl.cpp b/src/WifiControl.cpp index 2d177682..e0ba3efd 100644 --- a/src/WifiControl.cpp +++ b/src/WifiControl.cpp @@ -111,10 +111,12 @@ String WifiControl::getStatus() } else if (WIFI_MODE == WIFI_MODE_ATTEMPT_INFRASTRUCTURE_FAIL_TO_AP) { - result += "Infra-Fail-To-AP,"; + result += _failedOver ? "Access Point," : "Infra-Fail-To-AP,"; } - if (WIFI_MODE != WIFI_MODE_AP_ONLY) + // Station-interface fields only apply while we are (still) running as a station + bool stationMode = (WIFI_MODE != WIFI_MODE_AP_ONLY) && !_failedOver; + if (stationMode) { result += wifiStatus(WiFi.status()) + ","; } @@ -124,7 +126,7 @@ String WifiControl::getStatus() #endif result += getIP() + ":" + WIFI_PORT + ","; - if (WIFI_MODE != WIFI_MODE_AP_ONLY) + if (stationMode) { result += String(WIFI_INFRASTRUCTURE_MODE_SSID) + ","; } @@ -147,9 +149,15 @@ void WifiControl::establishServers() String WifiControl::getIP() { - return WIFI_MODE == WIFI_MODE_DISABLED ? "NONE" - : WIFI_MODE == WIFI_MODE_AP_ONLY ? WiFi.softAPIP().toString() - : WiFi.localIP().toString(); + if (WIFI_MODE == WIFI_MODE_DISABLED) + { + return "NONE"; + } + if (WIFI_MODE == WIFI_MODE_AP_ONLY || _failedOver) + { + return WiFi.softAPIP().toString(); + } + return WiFi.localIP().toString(); } void WifiControl::clearCmd() @@ -165,7 +173,8 @@ void WifiControl::loop() return; } - if (WIFI_MODE != WIFI_MODE_AP_ONLY) + // Monitor the station interface until we operate as an access point + if (WIFI_MODE != WIFI_MODE_AP_ONLY && !_failedOver) { if (_status != WiFi.status()) { @@ -184,10 +193,14 @@ void WifiControl::loop() if (_status != WL_CONNECTED) { infraToAPFailover(); - return; } } + if (_tcpServer == nullptr || _udp == nullptr) + { + return; + } + _mount->loop(); tcpLoop(); @@ -201,6 +214,7 @@ void WifiControl::infraToAPFailover() WiFi.disconnect(); startAccessPointMode(); _infraStart = 0; + _failedOver = true; LOG(DEBUG_WIFI, "[WIFI]: Could not connect to Infra, Starting AP."); } diff --git a/src/WifiControl.hpp b/src/WifiControl.hpp index 3039617e..233cc136 100644 --- a/src/WifiControl.hpp +++ b/src/WifiControl.hpp @@ -46,6 +46,7 @@ class WifiControl unsigned long _infraStart = 0; unsigned long _infraWait = 30000; // 30 second timeout for + bool _failedOver = false; // true once failover mode has switched to the access point static constexpr size_t _defaultCapacity = 32; static constexpr size_t _maxCapacity = 128; };