From f43a598a83f9dc318b4b2fa7503215ef4ac8f174 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 29 Mar 2026 17:55:55 -1000 Subject: [PATCH] [wifi] Avoid redundant SDK calls in WiFi loop on ESP8266 Replace five separate boolean state variables in the ESP8266 WiFi implementation with a single enum state machine, matching the pattern already used by LibreTiny. This eliminates the per-loop call to wifi_station_get_connect_status() by reading cached state from the existing event callback instead. Also use the cached connected_ field (set unconditionally at the top of loop()) in the STA_CONNECTED branch instead of calling is_connected_() a second time. This applies to all platforms. --- esphome/components/wifi/wifi_component.cpp | 3 +- .../wifi/wifi_component_esp8266.cpp | 58 ++++++++++--------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index db20332667..a0489e93d3 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -784,7 +784,8 @@ void WiFiComponent::loop() { } case WIFI_COMPONENT_STATE_STA_CONNECTED: { - if (!this->is_connected_()) { + // Use cached connected_ set unconditionally at the top of loop() + if (!this->connected_) { ESP_LOGW(TAG, "Connection lost; reconnecting"); this->state_ = WIFI_COMPONENT_STATE_STA_CONNECTING; this->retry_connect(); diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 03800cc3a9..f4e67bc322 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -44,11 +44,17 @@ namespace esphome::wifi { static const char *const TAG = "wifi_esp8266"; -static bool s_sta_connected = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static bool s_sta_got_ip = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static bool s_sta_connect_not_found = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static bool s_sta_connect_error = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static bool s_sta_connecting = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +enum class ESP8266WiFiSTAState : uint8_t { + IDLE, // Not connecting + CONNECTING, // Connection in progress + ASSOCIATED, // Associated to AP, waiting for IP + CONNECTED, // Successfully connected with IP + ERROR_NOT_FOUND, // AP not found (probe failed) + ERROR_FAILED, // Connection failed (auth, timeout, etc.) +}; + +static ESP8266WiFiSTAState s_sta_state = + ESP8266WiFiSTAState::IDLE; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) bool WiFiComponent::wifi_mode_(optional sta, optional ap) { uint8_t current_mode = wifi_get_opmode(); @@ -359,11 +365,7 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { // Reset flags, do this _before_ wifi_station_connect as the callback method // may be called from wifi_station_connect - s_sta_connecting = true; - s_sta_connected = false; - s_sta_got_ip = false; - s_sta_connect_error = false; - s_sta_connect_not_found = false; + s_sta_state = ESP8266WiFiSTAState::CONNECTING; ETS_UART_INTR_DISABLE(); ret = wifi_station_connect(); @@ -493,7 +495,7 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { ESP_LOGV(TAG, "Connected ssid='%.*s' bssid=%s channel=%u", it.ssid_len, (const char *) it.ssid, bssid_buf, it.channel); #endif - s_sta_connected = true; + s_sta_state = ESP8266WiFiSTAState::ASSOCIATED; #ifdef USE_WIFI_CONNECT_STATE_LISTENERS // Defer listener notification until state machine reaches STA_CONNECTED // This ensures wifi.connected condition returns true in listener automations @@ -506,16 +508,14 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { if (it.reason == REASON_NO_AP_FOUND) { ESP_LOGW(TAG, "Disconnected ssid='%.*s' reason='Probe Request Unsuccessful'", it.ssid_len, (const char *) it.ssid); - s_sta_connect_not_found = true; + s_sta_state = ESP8266WiFiSTAState::ERROR_NOT_FOUND; } else { char bssid_s[18]; format_mac_addr_upper(it.bssid, bssid_s); ESP_LOGW(TAG, "Disconnected ssid='%.*s' bssid=" LOG_SECRET("%s") " reason='%s'", it.ssid_len, (const char *) it.ssid, bssid_s, LOG_STR_ARG(get_disconnect_reason_str(it.reason))); - s_sta_connect_error = true; + s_sta_state = ESP8266WiFiSTAState::ERROR_FAILED; } - s_sta_connected = false; - s_sta_connecting = false; global_wifi_component->error_from_callback_ = true; #ifdef USE_WIFI_CONNECT_STATE_LISTENERS global_wifi_component->pending_.disconnect = true; @@ -541,7 +541,7 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { mask_buf[network::IP_ADDRESS_BUFFER_SIZE]; ESP_LOGV(TAG, "static_ip=%s gateway=%s netmask=%s", network::IPAddress(&it.ip).str_to(ip_buf), network::IPAddress(&it.gw).str_to(gw_buf), network::IPAddress(&it.mask).str_to(mask_buf)); - s_sta_got_ip = true; + s_sta_state = ESP8266WiFiSTAState::CONNECTED; #ifdef USE_WIFI_IP_STATE_LISTENERS // Defer listener callbacks to main loop - system context has limited stack global_wifi_component->pending_.got_ip = true; @@ -636,16 +636,22 @@ void WiFiComponent::wifi_pre_setup_() { } WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() const { - station_status_t status = wifi_station_get_connect_status(); - if (status == STATION_GOT_IP) - return WiFiSTAConnectStatus::CONNECTED; - if (status == STATION_NO_AP_FOUND) - return WiFiSTAConnectStatus::ERROR_NETWORK_NOT_FOUND; - if (status == STATION_CONNECT_FAIL || status == STATION_WRONG_PASSWORD) - return WiFiSTAConnectStatus::ERROR_CONNECT_FAILED; - if (status == STATION_CONNECTING) - return WiFiSTAConnectStatus::CONNECTING; - return WiFiSTAConnectStatus::IDLE; + // Use cached state from wifi_event_callback() instead of calling + // wifi_station_get_connect_status() which queries the SDK every time + switch (s_sta_state) { + case ESP8266WiFiSTAState::CONNECTED: + return WiFiSTAConnectStatus::CONNECTED; + case ESP8266WiFiSTAState::ERROR_NOT_FOUND: + return WiFiSTAConnectStatus::ERROR_NETWORK_NOT_FOUND; + case ESP8266WiFiSTAState::ERROR_FAILED: + return WiFiSTAConnectStatus::ERROR_CONNECT_FAILED; + case ESP8266WiFiSTAState::CONNECTING: + case ESP8266WiFiSTAState::ASSOCIATED: + return WiFiSTAConnectStatus::CONNECTING; + case ESP8266WiFiSTAState::IDLE: + default: + return WiFiSTAConnectStatus::IDLE; + } } bool WiFiComponent::wifi_scan_start_(bool passive) { // enable STA