From 47ee2f4ad904e9b5968593b479533bc9aa976a3b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 13 Jan 2026 16:20:39 -1000 Subject: [PATCH] [wifi] Use StaticVector for WiFi listeners with per-type compile-time sizing (#13197) --- esphome/components/wifi/__init__.py | 56 +++++++++++++++---- esphome/components/wifi/wifi_component.h | 40 ++++++++++--- .../wifi/wifi_component_esp8266.cpp | 14 ++--- .../wifi/wifi_component_esp_idf.cpp | 16 +++--- .../wifi/wifi_component_libretiny.cpp | 16 +++--- .../components/wifi/wifi_component_pico_w.cpp | 14 ++--- esphome/components/wifi_info/text_sensor.py | 34 +++++------ .../wifi_info/wifi_info_text_sensor.cpp | 22 ++++++-- .../wifi_info/wifi_info_text_sensor.h | 10 +++- esphome/components/wifi_signal/sensor.py | 2 +- .../wifi_signal/wifi_signal_sensor.h | 6 +- esphome/core/defines.h | 9 ++- 12 files changed, 161 insertions(+), 78 deletions(-) diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 26aec29b6d..98266eb589 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -624,7 +624,11 @@ async def wifi_disable_to_code(config, action_id, template_arg, args): KEEP_SCAN_RESULTS_KEY = "wifi_keep_scan_results" RUNTIME_POWER_SAVE_KEY = "wifi_runtime_power_save" -WIFI_LISTENERS_KEY = "wifi_listeners" +# Keys for listener counts +IP_STATE_LISTENERS_KEY = "wifi_ip_state_listeners" +SCAN_RESULTS_LISTENERS_KEY = "wifi_scan_results_listeners" +CONNECT_STATE_LISTENERS_KEY = "wifi_connect_state_listeners" +POWER_SAVE_LISTENERS_KEY = "wifi_power_save_listeners" def request_wifi_scan_results(): @@ -650,15 +654,28 @@ def enable_runtime_power_save_control(): CORE.data[RUNTIME_POWER_SAVE_KEY] = True -def request_wifi_listeners() -> None: - """Request that WiFi state listeners be compiled in. +def request_wifi_ip_state_listener() -> None: + """Request an IP state listener slot.""" + CORE.data[IP_STATE_LISTENERS_KEY] = CORE.data.get(IP_STATE_LISTENERS_KEY, 0) + 1 - Components that need to be notified about WiFi state changes (IP address changes, - scan results, connection state) should call this function during their code generation. - This enables the add_ip_state_listener(), add_scan_results_listener(), - and add_connect_state_listener() APIs. - """ - CORE.data[WIFI_LISTENERS_KEY] = True + +def request_wifi_scan_results_listener() -> None: + """Request a scan results listener slot.""" + CORE.data[SCAN_RESULTS_LISTENERS_KEY] = ( + CORE.data.get(SCAN_RESULTS_LISTENERS_KEY, 0) + 1 + ) + + +def request_wifi_connect_state_listener() -> None: + """Request a connect state listener slot.""" + CORE.data[CONNECT_STATE_LISTENERS_KEY] = ( + CORE.data.get(CONNECT_STATE_LISTENERS_KEY, 0) + 1 + ) + + +def request_wifi_power_save_listener() -> None: + """Request a power save listener slot.""" + CORE.data[POWER_SAVE_LISTENERS_KEY] = CORE.data.get(POWER_SAVE_LISTENERS_KEY, 0) + 1 @coroutine_with_priority(CoroPriority.FINAL) @@ -670,8 +687,25 @@ async def final_step(): ) if CORE.data.get(RUNTIME_POWER_SAVE_KEY, False): cg.add_define("USE_WIFI_RUNTIME_POWER_SAVE") - if CORE.data.get(WIFI_LISTENERS_KEY, False): - cg.add_define("USE_WIFI_LISTENERS") + + # Generate listener defines - each listener type has its own #ifdef + ip_state_count = CORE.data.get(IP_STATE_LISTENERS_KEY, 0) + scan_results_count = CORE.data.get(SCAN_RESULTS_LISTENERS_KEY, 0) + connect_state_count = CORE.data.get(CONNECT_STATE_LISTENERS_KEY, 0) + power_save_count = CORE.data.get(POWER_SAVE_LISTENERS_KEY, 0) + + if ip_state_count: + cg.add_define("USE_WIFI_IP_STATE_LISTENERS") + cg.add_define("ESPHOME_WIFI_IP_STATE_LISTENERS", ip_state_count) + if scan_results_count: + cg.add_define("USE_WIFI_SCAN_RESULTS_LISTENERS") + cg.add_define("ESPHOME_WIFI_SCAN_RESULTS_LISTENERS", scan_results_count) + if connect_state_count: + cg.add_define("USE_WIFI_CONNECT_STATE_LISTENERS") + cg.add_define("ESPHOME_WIFI_CONNECT_STATE_LISTENERS", connect_state_count) + if power_save_count: + cg.add_define("USE_WIFI_POWER_SAVE_LISTENERS") + cg.add_define("ESPHOME_WIFI_POWER_SAVE_LISTENERS", power_save_count) @automation.register_action( diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index b4c4a622d5..dfc91fb5da 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -275,6 +275,9 @@ struct LTWiFiEvent; * * Components can implement this interface to receive IP address updates * without the overhead of std::function callbacks. + * + * @note Components must call wifi.request_wifi_ip_state_listener() in their + * Python to_code() to register for this listener type. */ class WiFiIPStateListener { public: @@ -286,6 +289,9 @@ class WiFiIPStateListener { * * Components can implement this interface to receive scan results * without the overhead of std::function callbacks. + * + * @note Components must call wifi.request_wifi_scan_results_listener() in their + * Python to_code() to register for this listener type. */ class WiFiScanResultsListener { public: @@ -296,6 +302,9 @@ class WiFiScanResultsListener { * * Components can implement this interface to receive connection updates * without the overhead of std::function callbacks. + * + * @note Components must call wifi.request_wifi_connect_state_listener() in their + * Python to_code() to register for this listener type. */ class WiFiConnectStateListener { public: @@ -306,6 +315,9 @@ class WiFiConnectStateListener { * * Components can implement this interface to receive power save mode updates * without the overhead of std::function callbacks. + * + * @note Components must call wifi.request_wifi_power_save_listener() in their + * Python to_code() to register for this listener type. */ class WiFiPowerSaveListener { public: @@ -444,26 +456,32 @@ class WiFiComponent : public Component { int32_t get_wifi_channel(); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS /** Add a listener for IP state changes. * Listener receives: IP addresses, DNS address 1, DNS address 2 */ void add_ip_state_listener(WiFiIPStateListener *listener) { this->ip_state_listeners_.push_back(listener); } +#endif // USE_WIFI_IP_STATE_LISTENERS +#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS /// Add a listener for WiFi scan results void add_scan_results_listener(WiFiScanResultsListener *listener) { this->scan_results_listeners_.push_back(listener); } +#endif // USE_WIFI_SCAN_RESULTS_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS /** Add a listener for WiFi connection state changes. * Listener receives: SSID, BSSID */ void add_connect_state_listener(WiFiConnectStateListener *listener) { this->connect_state_listeners_.push_back(listener); } +#endif // USE_WIFI_CONNECT_STATE_LISTENERS +#ifdef USE_WIFI_POWER_SAVE_LISTENERS /** Add a listener for WiFi power save mode changes. * Listener receives: WiFiPowerSaveMode */ void add_power_save_listener(WiFiPowerSaveListener *listener) { this->power_save_listeners_.push_back(listener); } -#endif // USE_WIFI_LISTENERS +#endif // USE_WIFI_POWER_SAVE_LISTENERS #ifdef USE_WIFI_RUNTIME_POWER_SAVE /** Request high-performance mode (no power saving) for improved WiFi latency. @@ -628,12 +646,18 @@ class WiFiComponent : public Component { WiFiAP ap_; #endif float output_power_{NAN}; -#ifdef USE_WIFI_LISTENERS - std::vector ip_state_listeners_; - std::vector scan_results_listeners_; - std::vector connect_state_listeners_; - std::vector power_save_listeners_; -#endif // USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS + StaticVector ip_state_listeners_; +#endif +#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS + StaticVector scan_results_listeners_; +#endif +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS + StaticVector connect_state_listeners_; +#endif +#ifdef USE_WIFI_POWER_SAVE_LISTENERS + StaticVector power_save_listeners_; +#endif ESPPreferenceObject pref_; #ifdef USE_WIFI_FAST_CONNECT ESPPreferenceObject fast_connect_pref_; diff --git a/esphome/components/wifi/wifi_component_esp8266.cpp b/esphome/components/wifi/wifi_component_esp8266.cpp index 61c4584d09..6fb5dd5769 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -105,7 +105,7 @@ bool WiFiComponent::wifi_apply_power_save_() { } wifi_fpm_auto_sleep_set_in_null_mode(1); bool success = wifi_set_sleep_type(power_save); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_POWER_SAVE_LISTENERS if (success) { for (auto *listener : this->power_save_listeners_) { listener->on_wifi_power_save(this->power_save_); @@ -511,12 +511,13 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { it.channel); #endif s_sta_connected = true; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS for (auto *listener : global_wifi_component->connect_state_listeners_) { listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid); } +#endif // For static IP configurations, GOT_IP event may not fire, so notify IP listeners here -#ifdef USE_WIFI_MANUAL_IP +#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP) if (const WiFiAP *config = global_wifi_component->get_selected_sta_(); config && config->get_manual_ip().has_value()) { for (auto *listener : global_wifi_component->ip_state_listeners_) { @@ -524,7 +525,6 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { global_wifi_component->get_dns_address(0), global_wifi_component->get_dns_address(1)); } } -#endif #endif break; } @@ -547,7 +547,7 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { // This ensures is_connected() returns false during listener callbacks, // which is critical for proper reconnection logic (e.g., roaming). global_wifi_component->error_from_callback_ = true; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS // Notify listeners AFTER setting error flag so they see correct state static constexpr uint8_t EMPTY_BSSID[6] = {}; for (auto *listener : global_wifi_component->connect_state_listeners_) { @@ -578,7 +578,7 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { 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; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS for (auto *listener : global_wifi_component->ip_state_listeners_) { listener->on_ip_state(global_wifi_component->wifi_sta_ip_addresses(), global_wifi_component->get_dns_address(0), global_wifi_component->get_dns_address(1)); @@ -771,7 +771,7 @@ void WiFiComponent::wifi_scan_done_callback_(void *arg, STATUS status) { it->is_hidden != 0); } this->scan_done_ = true; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS for (auto *listener : global_wifi_component->scan_results_listeners_) { listener->on_wifi_scan_results(global_wifi_component->scan_result_); } diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 820725ed31..848ec3e11c 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -281,7 +281,7 @@ bool WiFiComponent::wifi_apply_power_save_() { break; } bool success = esp_wifi_set_ps(power_save) == ESP_OK; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_POWER_SAVE_LISTENERS if (success) { for (auto *listener : this->power_save_listeners_) { listener->on_wifi_power_save(this->power_save_); @@ -741,18 +741,18 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { (const char *) it.ssid, bssid_buf, it.channel, get_auth_mode_str(it.authmode)); #endif s_sta_connected = true; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS for (auto *listener : this->connect_state_listeners_) { listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid); } +#endif // For static IP configurations, GOT_IP event may not fire, so notify IP listeners here -#ifdef USE_WIFI_MANUAL_IP +#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP) if (const WiFiAP *config = this->get_selected_sta_(); config && config->get_manual_ip().has_value()) { for (auto *listener : this->ip_state_listeners_) { listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); } } -#endif #endif } else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_DISCONNECTED) { @@ -774,7 +774,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { s_sta_connected = false; s_sta_connecting = false; error_from_callback_ = true; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS static constexpr uint8_t EMPTY_BSSID[6] = {}; for (auto *listener : this->connect_state_listeners_) { listener->on_wifi_connect_state(StringRef(), EMPTY_BSSID); @@ -788,7 +788,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { #endif /* USE_NETWORK_IPV6 */ ESP_LOGV(TAG, "static_ip=" IPSTR " gateway=" IPSTR, IP2STR(&it.ip_info.ip), IP2STR(&it.ip_info.gw)); this->got_ipv4_address_ = true; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS for (auto *listener : this->ip_state_listeners_) { listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); } @@ -799,7 +799,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { const auto &it = data->data.ip_got_ip6; ESP_LOGV(TAG, "IPv6 address=" IPV6STR, IPV62STR(it.ip6_info.ip)); this->num_ipv6_addresses_++; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS for (auto *listener : this->ip_state_listeners_) { listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); } @@ -843,7 +843,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { scan_result_.emplace_back(bssid, ssid, record.primary, record.rssi, record.authmode != WIFI_AUTH_OPEN, ssid.empty()); } -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS for (auto *listener : this->scan_results_listeners_) { listener->on_wifi_scan_results(this->scan_result_); } diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index c5b6a8ad96..162ed4e835 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -144,7 +144,7 @@ bool WiFiComponent::wifi_sta_pre_setup_() { } bool WiFiComponent::wifi_apply_power_save_() { bool success = WiFi.setSleep(this->power_save_ != WIFI_POWER_SAVE_NONE); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_POWER_SAVE_LISTENERS if (success) { for (auto *listener : this->power_save_listeners_) { listener->on_wifi_power_save(this->power_save_); @@ -455,19 +455,19 @@ void WiFiComponent::wifi_process_event_(LTWiFiEvent *event) { // Note: We don't set CONNECTED state here yet - wait for GOT_IP // This matches ESP32 IDF behavior where s_sta_connected is set but // wifi_sta_connect_status_() also checks got_ipv4_address_ -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS for (auto *listener : this->connect_state_listeners_) { listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid); } +#endif // For static IP configurations, GOT_IP event may not fire, so notify IP listeners here -#ifdef USE_WIFI_MANUAL_IP +#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP) if (const WiFiAP *config = this->get_selected_sta_(); config && config->get_manual_ip().has_value()) { s_sta_state = LTWiFiSTAState::CONNECTED; for (auto *listener : this->ip_state_listeners_) { listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); } } -#endif #endif break; } @@ -521,7 +521,7 @@ void WiFiComponent::wifi_process_event_(LTWiFiEvent *event) { this->error_from_callback_ = true; } -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS static constexpr uint8_t EMPTY_BSSID[6] = {}; for (auto *listener : this->connect_state_listeners_) { listener->on_wifi_connect_state(StringRef(), EMPTY_BSSID); @@ -547,7 +547,7 @@ void WiFiComponent::wifi_process_event_(LTWiFiEvent *event) { ESP_LOGV(TAG, "static_ip=%s gateway=%s", network::IPAddress(WiFi.localIP()).str_to(ip_buf), network::IPAddress(WiFi.gatewayIP()).str_to(gw_buf)); s_sta_state = LTWiFiSTAState::CONNECTED; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS for (auto *listener : this->ip_state_listeners_) { listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); } @@ -556,7 +556,7 @@ void WiFiComponent::wifi_process_event_(LTWiFiEvent *event) { } case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: { ESP_LOGV(TAG, "Got IPv6"); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS for (auto *listener : this->ip_state_listeners_) { listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); } @@ -677,7 +677,7 @@ void WiFiComponent::wifi_scan_done_callback_() { ssid.length() == 0); } WiFi.scanDelete(); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS for (auto *listener : this->scan_results_listeners_) { listener->on_wifi_scan_results(this->scan_result_); } diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index 1aa737ff4a..29ac096d94 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -55,7 +55,7 @@ bool WiFiComponent::wifi_apply_power_save_() { } int ret = cyw43_wifi_pm(&cyw43_state, pm); bool success = ret == 0; -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_POWER_SAVE_LISTENERS if (success) { for (auto *listener : this->power_save_listeners_) { listener->on_wifi_power_save(this->power_save_); @@ -245,7 +245,7 @@ void WiFiComponent::wifi_loop_() { if (this->state_ == WIFI_COMPONENT_STATE_STA_SCANNING && !cyw43_wifi_scan_active(&cyw43_state)) { this->scan_done_ = true; ESP_LOGV(TAG, "Scan done"); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS for (auto *listener : this->scan_results_listeners_) { listener->on_wifi_scan_results(this->scan_result_); } @@ -263,28 +263,28 @@ void WiFiComponent::wifi_loop_() { // Just connected s_sta_was_connected = true; ESP_LOGV(TAG, "Connected"); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS String ssid = WiFi.SSID(); bssid_t bssid = this->wifi_bssid(); for (auto *listener : this->connect_state_listeners_) { listener->on_wifi_connect_state(StringRef(ssid.c_str(), ssid.length()), bssid); } +#endif // For static IP configurations, notify IP listeners immediately as the IP is already configured -#ifdef USE_WIFI_MANUAL_IP +#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP) if (const WiFiAP *config = this->get_selected_sta_(); config && config->get_manual_ip().has_value()) { s_sta_had_ip = true; for (auto *listener : this->ip_state_listeners_) { listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); } } -#endif #endif } else if (!is_connected && s_sta_was_connected) { // Just disconnected s_sta_was_connected = false; s_sta_had_ip = false; ESP_LOGV(TAG, "Disconnected"); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS static constexpr uint8_t EMPTY_BSSID[6] = {}; for (auto *listener : this->connect_state_listeners_) { listener->on_wifi_connect_state(StringRef(), EMPTY_BSSID); @@ -305,7 +305,7 @@ void WiFiComponent::wifi_loop_() { // Just got IP address s_sta_had_ip = true; ESP_LOGV(TAG, "Got IP address"); -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS for (auto *listener : this->ip_state_listeners_) { listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); } diff --git a/esphome/components/wifi_info/text_sensor.py b/esphome/components/wifi_info/text_sensor.py index 8a7f192367..9ecb5b7490 100644 --- a/esphome/components/wifi_info/text_sensor.py +++ b/esphome/components/wifi_info/text_sensor.py @@ -69,16 +69,6 @@ CONFIG_SCHEMA = cv.Schema( } ) -# Keys that require WiFi listeners -_NETWORK_INFO_KEYS = { - CONF_SSID, - CONF_BSSID, - CONF_IP_ADDRESS, - CONF_DNS_ADDRESS, - CONF_SCAN_RESULTS, - CONF_POWER_SAVE_MODE, -} - async def setup_conf(config, key): if key in config: @@ -88,16 +78,28 @@ async def setup_conf(config, key): async def to_code(config): - # Request WiFi listeners for any sensor that needs them - if _NETWORK_INFO_KEYS.intersection(config): - wifi.request_wifi_listeners() + # Request specific WiFi listeners based on which sensors are configured + # SSID and BSSID use WiFiConnectStateListener + if CONF_SSID in config or CONF_BSSID in config: + wifi.request_wifi_connect_state_listener() + + # IP address and DNS use WiFiIPStateListener + if CONF_IP_ADDRESS in config or CONF_DNS_ADDRESS in config: + wifi.request_wifi_ip_state_listener() + + # Scan results use WiFiScanResultsListener + if CONF_SCAN_RESULTS in config: + wifi.request_wifi_scan_results_listener() + wifi.request_wifi_scan_results() + + # Power save mode uses WiFiPowerSaveListener + if CONF_POWER_SAVE_MODE in config: + wifi.request_wifi_power_save_listener() await setup_conf(config, CONF_SSID) await setup_conf(config, CONF_BSSID) await setup_conf(config, CONF_MAC_ADDRESS) - if CONF_SCAN_RESULTS in config: - await setup_conf(config, CONF_SCAN_RESULTS) - wifi.request_wifi_scan_results() + await setup_conf(config, CONF_SCAN_RESULTS) await setup_conf(config, CONF_DNS_ADDRESS) await setup_conf(config, CONF_POWER_SAVE_MODE) if conf := config.get(CONF_IP_ADDRESS): diff --git a/esphome/components/wifi_info/wifi_info_text_sensor.cpp b/esphome/components/wifi_info/wifi_info_text_sensor.cpp index 2c0e66eeaf..a63b30b892 100644 --- a/esphome/components/wifi_info/wifi_info_text_sensor.cpp +++ b/esphome/components/wifi_info/wifi_info_text_sensor.cpp @@ -10,9 +10,7 @@ namespace esphome::wifi_info { static const char *const TAG = "wifi_info"; -#ifdef USE_WIFI_LISTENERS - -static constexpr size_t MAX_STATE_LENGTH = 255; +#ifdef USE_WIFI_IP_STATE_LISTENERS /******************** * IPAddressWiFiInfo @@ -58,6 +56,10 @@ void DNSAddressWifiInfo::on_ip_state(const network::IPAddresses &ips, const netw this->publish_state(buf); } +#endif // USE_WIFI_IP_STATE_LISTENERS + +#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS + /********************** * ScanResultsWiFiInfo *********************/ @@ -80,9 +82,9 @@ static char *format_scan_entry(char *buf, const char *ssid, size_t ssid_len, int } void ScanResultsWiFiInfo::on_wifi_scan_results(const wifi::wifi_scan_vector_t &results) { - char buf[MAX_STATE_LENGTH + 1]; + char buf[MAX_STATE_LEN + 1]; char *ptr = buf; - const char *end = buf + MAX_STATE_LENGTH; + const char *end = buf + MAX_STATE_LEN; for (const auto &scan : results) { if (scan.get_is_hidden()) @@ -98,6 +100,10 @@ void ScanResultsWiFiInfo::on_wifi_scan_results(const wifi::wifi_scan_vector_tpublish_state(buf); } +#endif // USE_WIFI_SCAN_RESULTS_LISTENERS + +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS + /*************** * SSIDWiFiInfo **************/ @@ -126,6 +132,10 @@ void BSSIDWiFiInfo::on_wifi_connect_state(StringRef ssid, std::spanpublish_state(buf); } +#endif // USE_WIFI_CONNECT_STATE_LISTENERS + +#ifdef USE_WIFI_POWER_SAVE_LISTENERS + /************************ * PowerSaveModeWiFiInfo ***********************/ @@ -182,7 +192,7 @@ void PowerSaveModeWiFiInfo::on_wifi_power_save(wifi::WiFiPowerSaveMode mode) { this->publish_state(mode_str); } -#endif +#endif // USE_WIFI_POWER_SAVE_LISTENERS /********************* * MacAddressWifiInfo diff --git a/esphome/components/wifi_info/wifi_info_text_sensor.h b/esphome/components/wifi_info/wifi_info_text_sensor.h index 6beb1372f5..8ef35a5f5d 100644 --- a/esphome/components/wifi_info/wifi_info_text_sensor.h +++ b/esphome/components/wifi_info/wifi_info_text_sensor.h @@ -11,7 +11,7 @@ namespace esphome::wifi_info { -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_IP_STATE_LISTENERS class IPAddressWiFiInfo final : public Component, public text_sensor::TextSensor, public wifi::WiFiIPStateListener { public: void setup() override; @@ -35,7 +35,9 @@ class DNSAddressWifiInfo final : public Component, public text_sensor::TextSenso void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1, const network::IPAddress &dns2) override; }; +#endif // USE_WIFI_IP_STATE_LISTENERS +#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS class ScanResultsWiFiInfo final : public Component, public text_sensor::TextSensor, public wifi::WiFiScanResultsListener { @@ -47,7 +49,9 @@ class ScanResultsWiFiInfo final : public Component, // WiFiScanResultsListener interface void on_wifi_scan_results(const wifi::wifi_scan_vector_t &results) override; }; +#endif // USE_WIFI_SCAN_RESULTS_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS class SSIDWiFiInfo final : public Component, public text_sensor::TextSensor, public wifi::WiFiConnectStateListener { public: void setup() override; @@ -65,7 +69,9 @@ class BSSIDWiFiInfo final : public Component, public text_sensor::TextSensor, pu // WiFiConnectStateListener interface void on_wifi_connect_state(StringRef ssid, std::span bssid) override; }; +#endif // USE_WIFI_CONNECT_STATE_LISTENERS +#ifdef USE_WIFI_POWER_SAVE_LISTENERS class PowerSaveModeWiFiInfo final : public Component, public text_sensor::TextSensor, public wifi::WiFiPowerSaveListener { @@ -76,7 +82,7 @@ class PowerSaveModeWiFiInfo final : public Component, // WiFiPowerSaveListener interface void on_wifi_power_save(wifi::WiFiPowerSaveMode mode) override; }; -#endif +#endif // USE_WIFI_POWER_SAVE_LISTENERS class MacAddressWifiInfo final : public Component, public text_sensor::TextSensor { public: diff --git a/esphome/components/wifi_signal/sensor.py b/esphome/components/wifi_signal/sensor.py index 82cb90c745..075cfd96c6 100644 --- a/esphome/components/wifi_signal/sensor.py +++ b/esphome/components/wifi_signal/sensor.py @@ -25,6 +25,6 @@ CONFIG_SCHEMA = sensor.sensor_schema( async def to_code(config): - wifi.request_wifi_listeners() + wifi.request_wifi_connect_state_listener() var = await sensor.new_sensor(config) await cg.register_component(var, config) diff --git a/esphome/components/wifi_signal/wifi_signal_sensor.h b/esphome/components/wifi_signal/wifi_signal_sensor.h index 2e1f8cbb2b..9ff4cc54a0 100644 --- a/esphome/components/wifi_signal/wifi_signal_sensor.h +++ b/esphome/components/wifi_signal/wifi_signal_sensor.h @@ -9,13 +9,13 @@ #include namespace esphome::wifi_signal { -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS class WiFiSignalSensor : public sensor::Sensor, public PollingComponent, public wifi::WiFiConnectStateListener { #else class WiFiSignalSensor : public sensor::Sensor, public PollingComponent { #endif public: -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS void setup() override { wifi::global_wifi_component->add_connect_state_listener(this); } #endif void update() override { @@ -28,7 +28,7 @@ class WiFiSignalSensor : public sensor::Sensor, public PollingComponent { float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } -#ifdef USE_WIFI_LISTENERS +#ifdef USE_WIFI_CONNECT_STATE_LISTENERS // WiFiConnectStateListener interface - update RSSI immediately on connect void on_wifi_connect_state(StringRef ssid, std::span bssid) override { this->update(); } #endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 3cc48c6008..673397fa31 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -222,7 +222,14 @@ #define USE_CAPTIVE_PORTAL_GZIP #define USE_WIFI_11KV_SUPPORT #define USE_WIFI_FAST_CONNECT -#define USE_WIFI_LISTENERS +#define USE_WIFI_IP_STATE_LISTENERS +#define USE_WIFI_SCAN_RESULTS_LISTENERS +#define USE_WIFI_CONNECT_STATE_LISTENERS +#define USE_WIFI_POWER_SAVE_LISTENERS +#define ESPHOME_WIFI_IP_STATE_LISTENERS 2 +#define ESPHOME_WIFI_SCAN_RESULTS_LISTENERS 2 +#define ESPHOME_WIFI_CONNECT_STATE_LISTENERS 2 +#define ESPHOME_WIFI_POWER_SAVE_LISTENERS 2 #define USE_WIFI_RUNTIME_POWER_SAVE #define USB_HOST_MAX_REQUESTS 16