From bad6a622269bd85537d77662e7862ead4005c2f8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 23:39:58 -1000 Subject: [PATCH] [wifi] Fix RP2040 falsely reporting WiFi connected after AP fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs combined to make the RP2040 Pico W immediately think it was connected to WiFi after starting the fallback AP, causing it to disable the AP and stop retrying: 1. wifi_mode_(false, {}) was a no-op for STA disable — restart_adapter() calls this to tear down STA, but the implementation only handled sta=true. The CYW43 STA link state remained CYW43_LINK_JOIN from the timed-out connection attempt. 2. wifi_ap_ip_config_() called WiFi.config(192.168.4.1) which configured the STA interface's IP (not the AP's). When wifi_sta_connect_status_() checked WiFi.status(), CYW43lwIP::status() saw CYW43_LINK_JOIN + localIP().isSet() and returned WL_CONNECTED. Fix wifi_mode_() to call WiFi.disconnect() when sta=false to clear stale link state. Remove the WiFi.config() call from wifi_ap_ip_config_() since WiFi.beginAP() already configures the AP IP internally. Also fix wifi_soft_ap_ip() to use WiFi.softAPIP() instead of WiFi.localIP(). --- .../components/wifi/wifi_component_pico_w.cpp | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index 270425d8c2..f371495975 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -27,6 +27,11 @@ bool WiFiComponent::wifi_mode_(optional sta, optional ap) { if (sta.has_value()) { if (sta.value()) { cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, CYW43_COUNTRY_WORLDWIDE); + } else { + // Disconnect STA to clear stale link state (e.g. CYW43_LINK_JOIN from a + // timed-out connection). Without this, restart_adapter() leaves the STA + // interface joined and wifi_sta_connect_status_() can falsely report CONNECTED. + WiFi.disconnect(); } } @@ -188,19 +193,11 @@ bool WiFiComponent::wifi_scan_start_(bool passive) { #ifdef USE_WIFI_AP bool WiFiComponent::wifi_ap_ip_config_(const optional &manual_ip) { - esphome::network::IPAddress ip_address, gateway, subnet, dns; - if (manual_ip.has_value()) { - ip_address = manual_ip->static_ip; - gateway = manual_ip->gateway; - subnet = manual_ip->subnet; - dns = manual_ip->static_ip; - } else { - ip_address = network::IPAddress(192, 168, 4, 1); - gateway = network::IPAddress(192, 168, 4, 1); - subnet = network::IPAddress(255, 255, 255, 0); - dns = network::IPAddress(192, 168, 4, 1); - } - WiFi.config(ip_address, dns, gateway, subnet); + // AP IP is configured by WiFi.beginAP() internally using defaults (192.168.4.1). + // Do NOT use WiFi.config() here — that configures the STA interface's IP, which + // poisons the STA localIP() and causes wifi_sta_connect_status_() to falsely + // report CONNECTED when the AP is active. + // Manual AP IP is not currently supported on RP2040. return true; } @@ -224,7 +221,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { return true; } -network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {(const ip_addr_t *) WiFi.localIP()}; } +network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {(const ip_addr_t *) WiFi.softAPIP()}; } #endif // USE_WIFI_AP bool WiFiComponent::wifi_disconnect_() {