Repository navigation
ESP32: FAIL_TO_AP mode unreachable after failover; getIP() reports the wrong interface #307
Description
WIFI_MODE_ATTEMPT_INFRASTRUCTURE_FAIL_TO_AP has two defects, both pre-existing before #295 and explicitly deferred there (the PR fixed WIFI_MODE_AP_ONLY only). @rbhbokka analyzed both in this comment on #295 and offered to implement the follow-up; @tobiashennerbichler also noted having local changes ready for this mode. This issue tracks the work so those offers have a home.
1. The mount is unreachable after failover
In WifiControl::loop() (src/WifiControl.cpp:168), the non-AP branch is entered forever in failover mode because WIFI_MODE is a compile-time constant:
if (WIFI_MODE != WIFI_MODE_AP_ONLY)
{
...
if (_status != WL_CONNECTED)
{
infraToAPFailover();
return; // fires on every pass once failed over
}
}
_mount->loop();
tcpLoop();
udpLoop();Once infraToAPFailover() has called startAccessPointMode(), the station is disconnected and WiFi.status() never reports WL_CONNECTED again — so _status != WL_CONNECTED stays true and the return fires on every subsequent pass. _infraStart is zeroed, so the failover call itself is a harmless no-op, but tcpLoop() / udpLoop() are never reached again. The soft-AP is up and establishServers() has bound the port, yet no client is ever serviced.
The underlying problem is that one condition answers two different questions: "should we attempt failover?" (policy) and "are the servers up?" (lifecycle). The sketch from the #295 discussion:
if (WIFI_MODE != WIFI_MODE_AP_ONLY)
{
if (_status != WiFi.status())
{
...
}
if (_status != WL_CONNECTED)
{
infraToAPFailover();
- return;
}
}
+ if (_tcpServer == nullptr || _udp == nullptr)
+ {
+ return;
+ }
+
_mount->loop();
tcpLoop();
udpLoop();infraToAPFailover() is already self-guarding on _infraStart != 0, so it stays a no-op in AP-only mode and after a completed failover; the null check becomes a pure lifecycle guard. The per-loop null guards added by #295 already cover the dereference, so this is about reachability rather than safety.
2. getIP() reports the wrong interface after failover
WifiControl::getIP() (src/WifiControl.cpp:148) keys off the compile-time WIFI_MODE:
return WIFI_MODE == WIFI_MODE_DISABLED ? "NONE"
: WIFI_MODE == WIFI_MODE_AP_ONLY ? WiFi.softAPIP().toString()
: WiFi.localIP().toString();In failover mode it therefore always returns WiFi.localIP() — even after the radio has switched to AP — so the UDP discovery reply and getStatus() advertise 0.0.0.0 or the stale station IP in the failed-over state. This is the same class of bug #295 fixed for AP_ONLY. getStatus()'s AP-specific field handling has the same compile-time keying.
Suggested approach: track the runtime mode (e.g. a small enum or a _failedOver flag set by infraToAPFailover()) and consult it in loop(), getIP(), and getStatus(), keeping the compile-time WIFI_MODE as the policy input.
Scope note
WIFI_MODE_ATTEMPT_INFRASTRUCTURE_FAIL_TO_AP was excluded from #295 by design; everything above reproduces on develop before and after it. Testing requires an ESP32 build configured for failover mode plus an infrastructure network that refuses the credentials.
🤖 Generated with Claude Code
Activity