diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index af5ec9314c..7a03d8f8ad 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -25,10 +25,6 @@ namespace esphome::api { static const char *const TAG = "api"; -// Grace period before dropping API clients when network disconnects -// Allows for brief disconnections during WiFi roaming -static constexpr uint32_t NETWORK_DISCONNECT_GRACE_MS = 10000; - // APIServer APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) @@ -110,10 +106,8 @@ void APIServer::setup() { } #endif - // Initialize timestamps for timeout tracking - const uint32_t now = App.get_loop_component_start_time(); - this->last_connected_ = now; - this->network_last_connected_ = now; + // Initialize last_connected_ for reboot timeout tracking + this->last_connected_ = App.get_loop_component_start_time(); // Set warning status if reboot timeout is enabled if (this->reboot_timeout_ != 0) { this->status_set_warning(); @@ -168,22 +162,14 @@ void APIServer::loop() { // Process clients and remove disconnected ones in a single pass // Check network connectivity once for all clients - const uint32_t now = App.get_loop_component_start_time(); - if (network::is_connected()) { - // Network is up - track this for grace period - this->network_last_connected_ = now; - } else { - // Network is down - check if grace period has expired - // This allows brief disconnections during WiFi roaming without dropping API clients - if (now - this->network_last_connected_ > NETWORK_DISCONNECT_GRACE_MS) { - // Grace period expired - disconnect all clients - for (auto &client : this->clients_) { - client->on_fatal_error(); - ESP_LOGW(TAG, "%s (%s): Network down; disconnect", client->client_info_.name.c_str(), - client->client_info_.peername.c_str()); - } - // Continue to process and clean up the clients below + if (!network::is_connected()) { + // Network is down - disconnect all clients + for (auto &client : this->clients_) { + client->on_fatal_error(); + ESP_LOGW(TAG, "%s (%s): Network down; disconnect", client->client_info_.name.c_str(), + client->client_info_.peername.c_str()); } + // Continue to process and clean up the clients below } size_t client_index = 0; diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index ab7040a740..96c56fd08a 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -253,7 +253,6 @@ class APIServer : public Component, // 4-byte aligned types uint32_t reboot_timeout_{300000}; uint32_t last_connected_{0}; - uint32_t network_last_connected_{0}; // Track when network was last connected (for roaming grace period) // Vectors and strings (12 bytes each on 32-bit) std::vector> clients_; diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 1c744648bb..335112a6f9 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -242,7 +242,11 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { if (!this->wifi_mode_(true, {})) return false; - this->wifi_disconnect_(); + // Skip disconnect for roaming - let the SDK handle the transition + // This preserves TCP connections during the brief AP switch + if (!this->roaming_connect_active_) { + this->wifi_disconnect_(); + } struct station_config conf {}; memset(&conf, 0, sizeof(conf));