feat(companion-wifi): recovery AP with TCP rescue CLI when WiFi is down

When a companion WiFi device has no WiFi credentials or can't connect for
60s, it broadcasts an 'EastMesh-WiFi' AP (WPA2 password = device pin
zero-padded to 8 digits; open if no pin set) with the rescue CLI on TCP
port 23, so wifi.ssid/pwd can be fixed without a serial cable.

- rescue CLI command handler now writes to any Stream (Serial or the TCP
  rescue client)
- while the AP is up, STA keeps retrying; the AP shuts down automatically
  once the configured network connects
- 'set wifi.ssid/pwd' keeps AP+STA mode during a rescue session so the
  session isn't dropped mid-config
- guard ESP32-only SD/SPI code in ArchiveStorage so non-ESP32 builds of
  the shared helpers get further

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jared Dohrman
2026-08-09 16:52:50 +10:00
co-authored by Claude Fable 5
parent c6698c5bad
commit a5c9ba3e01
5 changed files with 213 additions and 62 deletions
+18
View File
@@ -111,6 +111,10 @@ void halt() {
#if defined(ESP32) && defined(WIFI_SSID)
bool wifi_needs_reconnect = false;
unsigned long last_wifi_reconnect_attempt = 0;
unsigned long last_wifi_connected = 0;
#ifndef RECOVERY_AP_TIMEOUT_MS
#define RECOVERY_AP_TIMEOUT_MS 60000 // STA not connected this long -> recovery AP
#endif
#endif
void setup() {
@@ -278,5 +282,19 @@ void loop() {
WiFi.reconnect();
last_wifi_reconnect_attempt = millis();
}
// Recovery AP: broadcast our own SSID (with the rescue CLI on TCP) when STA has no
// credentials or hasn't been able to connect, so wifi.ssid/pwd can be fixed in place
if (the_mesh.isRecoveryAPActive()) {
the_mesh.loopRecoveryAP();
if (WiFi.status() == WL_CONNECTED) {
the_mesh.stopRecoveryAP(); // STA is up again; back to normal operation
}
} else if (WiFi.status() == WL_CONNECTED) {
last_wifi_connected = millis();
} else if (the_mesh.getWifiSSID()[0] == 0 ||
millis() - last_wifi_connected > RECOVERY_AP_TIMEOUT_MS) {
the_mesh.startRecoveryAP();
}
#endif
}