diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 6e075d19..8faf8720 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -2382,6 +2382,9 @@ void MyMesh::checkCLIRescueCmd() { #ifndef RECOVERY_CLI_PORT #define RECOVERY_CLI_PORT 23 #endif +#ifndef RECOVERY_STA_RETRY_MS + #define RECOVERY_STA_RETRY_MS 60000 +#endif void MyMesh::startRecoveryAP() { if (_recovery_ap_active) return; @@ -2393,7 +2396,14 @@ void MyMesh::startRecoveryAP() { pwd = ap_pwd; } + // A continuously scanning/reconnecting STA drags the AP's radio across channels, + // so joining clients time out their WPA2 handshake (phones report "wrong password"). + // Quiesce the STA while the AP is up; loopRecoveryAP() retries it once a minute. + WiFi.setAutoReconnect(false); WiFi.mode(_prefs.wifi_ssid[0] ? WIFI_AP_STA : WIFI_AP); // keep trying STA if creds exist + if (_prefs.wifi_ssid[0]) { + WiFi.disconnect(); + } WiFi.softAP(RECOVERY_AP_SSID, pwd); if (_rescue_server == NULL) { @@ -2401,6 +2411,7 @@ void MyMesh::startRecoveryAP() { } _rescue_server->begin(); rescue_cmd[0] = 0; + _next_sta_retry = millis() + RECOVERY_STA_RETRY_MS; _recovery_ap_active = true; Serial.printf("WiFi: recovery AP '%s' up (%s), rescue CLI on %s:%d\n", RECOVERY_AP_SSID, @@ -2414,6 +2425,7 @@ void MyMesh::stopRecoveryAP() { _rescue_server->stop(); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); + WiFi.setAutoReconnect(true); _recovery_ap_active = false; Serial.println("WiFi: recovery AP stopped"); } @@ -2421,6 +2433,13 @@ void MyMesh::stopRecoveryAP() { void MyMesh::loopRecoveryAP() { if (!_recovery_ap_active) return; + // periodic STA retry: brief AP disruption once a minute beats a permanently + // unjoinable AP, and lets the node self-recover when its network comes back + if (_prefs.wifi_ssid[0] && WiFi.status() != WL_CONNECTED && (long)(millis() - _next_sta_retry) >= 0) { + WiFi.begin(_prefs.wifi_ssid, _prefs.wifi_pwd); + _next_sta_retry = millis() + RECOVERY_STA_RETRY_MS; + } + if (!_rescue_client || !_rescue_client.connected()) { WiFiClient next = _rescue_server->available(); if (next) { diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index f72fa9db..b9ea0800 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -250,6 +250,7 @@ private: WiFiServer* _rescue_server = NULL; WiFiClient _rescue_client; char rescue_cmd[80]; + unsigned long _next_sta_retry = 0; #endif uint8_t app_target_ver; uint8_t *sign_data; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 660fdb40..6276772d 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -275,8 +275,12 @@ 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)) { + // Safely attempt to reconnect every 10 seconds if flagged. + // Skipped while the recovery AP is up: constant STA rescans drag the AP's radio + // across channels and break joining clients' WPA2 handshakes; loopRecoveryAP() + // owns the (slower) STA retry cadence in that state. + if (!the_mesh.isRecoveryAPActive() && + wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > 10000)) { WIFI_DEBUG_PRINTLN("Attempting manual WiFi reconnect..."); WiFi.disconnect(); WiFi.reconnect();