diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 7b31a22ed5..8ae6a3f14c 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -730,9 +730,14 @@ void WiFiComponent::restart_adapter() { } void WiFiComponent::loop() { - this->wifi_loop_(); + bool events_processed = this->wifi_loop_(); const uint32_t now = App.get_loop_component_start_time(); - this->update_connected_state_(); + // Connection state can only change when events are processed (ESP-IDF/LibreTiny) + // or polled (ESP8266/Pico W). Skip the expensive wifi_sta_connect_status_() call + // when no events arrived and we're already in steady state. + if (events_processed || this->state_ != WIFI_COMPONENT_STATE_STA_CONNECTED) { + this->update_connected_state_(); + } if (this->has_sta()) { #if defined(USE_WIFI_CONNECT_TRIGGER) || defined(USE_WIFI_DISCONNECT_TRIGGER) diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index a44a9bd617..53fb0728fb 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -662,7 +662,7 @@ class WiFiComponent final : public Component { void connect_soon_(); - void wifi_loop_(); + bool wifi_loop_(); #ifdef USE_ESP8266 void process_pending_callbacks_(); #endif diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index cb53d3ac1b..e56a8df350 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -938,7 +938,10 @@ network::IPAddress WiFiComponent::wifi_gateway_ip_() { return network::IPAddress(&ip.gw); } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return network::IPAddress(dns_getserver(num)); } -void WiFiComponent::wifi_loop_() { this->process_pending_callbacks_(); } +bool WiFiComponent::wifi_loop_() { + this->process_pending_callbacks_(); + return true; +} void WiFiComponent::process_pending_callbacks_() { // Process callbacks deferred from ESP8266 SDK system context (~2KB stack) diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 594f7495c4..42fff8fd1b 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -716,10 +716,10 @@ const char *get_disconnect_reason_str(uint8_t reason) { } } -void WiFiComponent::wifi_loop_() { +bool WiFiComponent::wifi_loop_() { // Fast path: skip dropped count check and pop loop when queue is empty if (this->event_queue_.empty()) - return; + return false; uint16_t dropped = this->event_queue_.get_and_reset_dropped_count(); if (dropped > 0) { @@ -731,6 +731,7 @@ void WiFiComponent::wifi_loop_() { wifi_process_event_(data); delete data; // NOLINT(cppcoreguidelines-owning-memory) } + return true; } // Events are processed from queue in main loop context, but listener notifications // must be deferred until after the state machine transitions (in check_connecting_finished) diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index 946d1ca50d..7ca3549cab 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -777,10 +777,10 @@ int32_t WiFiComponent::get_wifi_channel() { return WiFi.channel(); } network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {WiFi.subnetMask()}; } network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}; } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {WiFi.dnsIP(num)}; } -void WiFiComponent::wifi_loop_() { +bool WiFiComponent::wifi_loop_() { // Fast path: skip dropped count check and pop loop when queue is empty if (this->event_queue_.empty()) - return; + return false; uint16_t dropped = this->event_queue_.get_and_reset_dropped_count(); if (dropped > 0) { @@ -792,6 +792,7 @@ void WiFiComponent::wifi_loop_() { wifi_process_event_(event); delete event; // NOLINT(cppcoreguidelines-owning-memory) } + return true; } } // namespace esphome::wifi diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index 1cfeee3c1b..4e1e0395c0 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -303,7 +303,7 @@ network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { // Connect state listener notifications are deferred until after the state machine // transitions (in check_connecting_finished) so that conditions like wifi.connected // return correct values in automations. -void WiFiComponent::wifi_loop_() { +bool WiFiComponent::wifi_loop_() { // Handle scan completion if (this->state_ == WIFI_COMPONENT_STATE_STA_SCANNING && !cyw43_wifi_scan_active(&cyw43_state)) { this->scan_done_ = true; @@ -365,6 +365,7 @@ void WiFiComponent::wifi_loop_() { #endif } } + return true; } void WiFiComponent::wifi_pre_setup_() {}