diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index a377abe380..b70fa4d0ca 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -53,8 +53,8 @@ void CaptivePortal::handle_wifisave(AsyncWebServerRequest *request) { // Defer save to main loop thread to avoid NVS operations from HTTP thread this->defer([ssid, psk]() { wifi::global_wifi_component->save_wifi_sta(ssid, psk); - // Trigger immediate retry to attempt connection with new credentials - wifi::global_wifi_component->retry_connect(); + // Trigger connection attempt (exits cooldown if needed) + wifi::global_wifi_component->connect_soon(); }); request->redirect(ESPHOME_F("/?save")); } diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index f4c19b04d4..c456ad7d33 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -381,8 +381,8 @@ void ESP32ImprovComponent::check_wifi_connection_() { if (this->state_ == improv::STATE_PROVISIONING) { wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(), this->connecting_sta_.get_password()); - // Trigger immediate retry to attempt connection with new credentials - wifi::global_wifi_component->retry_connect(); + // Trigger connection attempt (exits cooldown if needed, no-op if already connected) + wifi::global_wifi_component->connect_soon(); this->connecting_sta_ = {}; this->cancel_timeout("wifi-connect-timeout"); diff --git a/esphome/components/improv_serial/improv_serial_component.cpp b/esphome/components/improv_serial/improv_serial_component.cpp index 52e223670d..51f8c8b839 100644 --- a/esphome/components/improv_serial/improv_serial_component.cpp +++ b/esphome/components/improv_serial/improv_serial_component.cpp @@ -50,8 +50,8 @@ void ImprovSerialComponent::loop() { if (wifi::global_wifi_component->is_connected()) { wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(), this->connecting_sta_.get_password()); - // Trigger immediate retry to attempt connection with new credentials - wifi::global_wifi_component->retry_connect(); + // Trigger connection attempt (exits cooldown if needed, no-op if already connected) + wifi::global_wifi_component->connect_soon(); this->connecting_sta_ = {}; this->cancel_timeout("wifi-connect-timeout"); this->set_state_(improv::STATE_PROVISIONED); diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index fa2ca92e55..401c60267e 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -676,6 +676,14 @@ void WiFiComponent::save_wifi_sta(const std::string &ssid, const std::string &pa this->force_scan_after_provision_ = true; } +void WiFiComponent::connect_soon() { + // Only trigger retry if we're in cooldown - if already connecting/connected, do nothing + if (this->state_ == WIFI_COMPONENT_STATE_COOLDOWN) { + ESP_LOGD(TAG, "Exiting cooldown early due to new WiFi credentials"); + this->retry_connect(); + } +} + void WiFiComponent::start_connecting(const WiFiAP &ap) { // Log connection attempt at INFO level with priority char bssid_s[18]; diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index 270404dff5..c014fc6343 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -292,6 +292,9 @@ class WiFiComponent : public Component { void save_wifi_sta(const std::string &ssid, const std::string &password); + /// Trigger connection attempt soon (exits cooldown if needed, otherwise no-op if already connecting/connected) + void connect_soon(); + // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) /// Setup WiFi interface.