From 9b50ed3589a2f9cd322d43ebbbec256dd44984e1 Mon Sep 17 00:00:00 2001 From: kbx81 Date: Mon, 24 Nov 2025 16:09:12 -0600 Subject: [PATCH] conditionally compile callbacks --- esphome/components/wifi/__init__.py | 14 ++++++++++++++ esphome/components/wifi/wifi_component.h | 4 ++++ esphome/components/wifi/wifi_component_esp8266.cpp | 8 ++++++++ esphome/components/wifi/wifi_component_esp_idf.cpp | 10 ++++++++++ .../components/wifi/wifi_component_libretiny.cpp | 10 ++++++++++ esphome/components/wifi/wifi_component_pico_w.cpp | 8 ++++++++ esphome/components/wifi_info/text_sensor.py | 13 +++++++++++++ esphome/core/defines.h | 1 + 8 files changed, 68 insertions(+) diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index 8a5e5329f1..16db3a990b 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -608,6 +608,7 @@ 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_CALLBACKS_KEY = "wifi_callbacks" def request_wifi_scan_results(): @@ -633,6 +634,17 @@ def enable_runtime_power_save_control(): CORE.data[RUNTIME_POWER_SAVE_KEY] = True +def request_wifi_callbacks(): + """Request that WiFi callbacks be compiled in. + + 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_on_ip_state_callback(), add_on_wifi_scan_state_callback(), + and add_on_wifi_connect_state_callback() APIs. + """ + CORE.data[WIFI_CALLBACKS_KEY] = True + + @coroutine_with_priority(CoroPriority.FINAL) async def final_step(): """Final code generation step to configure optional WiFi features.""" @@ -642,6 +654,8 @@ 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_CALLBACKS_KEY, False): + cg.add_define("USE_WIFI_CALLBACKS") @automation.register_action( diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index 8bfeb36c70..b6b956a12d 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -369,6 +369,7 @@ class WiFiComponent : public Component { int32_t get_wifi_channel(); +#ifdef USE_WIFI_CALLBACKS /// Add a callback that will be called on configuration changes (IP change, SSID change, etc.) /// @param callback The callback to be called; template arguments are: /// - IP addresses @@ -387,6 +388,7 @@ class WiFiComponent : public Component { void add_on_wifi_connect_state_callback(std::function &&callback) { this->wifi_connect_state_callback_.add(std::move(callback)); } +#endif // USE_WIFI_CALLBACKS #ifdef USE_WIFI_RUNTIME_POWER_SAVE /** Request high-performance mode (no power saving) for improved WiFi latency. @@ -544,9 +546,11 @@ class WiFiComponent : public Component { WiFiAP ap_; #endif optional output_power_; +#ifdef USE_WIFI_CALLBACKS CallbackManager ip_state_callback_; CallbackManager &)> wifi_scan_state_callback_; CallbackManager wifi_connect_state_callback_; +#endif // USE_WIFI_CALLBACKS 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 28dc597620..540ad3a585 100644 --- a/esphome/components/wifi/wifi_component_esp8266.cpp +++ b/esphome/components/wifi/wifi_component_esp8266.cpp @@ -513,8 +513,10 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { ESP_LOGV(TAG, "Connected ssid='%s' bssid=%s channel=%u", buf, format_mac_address_pretty(it.bssid).c_str(), it.channel); s_sta_connected = true; +#ifdef USE_WIFI_CALLBACKS global_wifi_component->wifi_connect_state_callback_.call(global_wifi_component->wifi_ssid(), global_wifi_component->wifi_bssid()); +#endif break; } case EVENT_STAMODE_DISCONNECTED: { @@ -534,7 +536,9 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { } s_sta_connected = false; s_sta_connecting = false; +#ifdef USE_WIFI_CALLBACKS global_wifi_component->wifi_connect_state_callback_.call("", bssid_t({0, 0, 0, 0, 0, 0})); +#endif break; } case EVENT_STAMODE_AUTHMODE_CHANGE: { @@ -557,9 +561,11 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) { ESP_LOGV(TAG, "static_ip=%s gateway=%s netmask=%s", format_ip_addr(it.ip).c_str(), format_ip_addr(it.gw).c_str(), format_ip_addr(it.mask).c_str()); s_sta_got_ip = true; +#ifdef USE_WIFI_CALLBACKS global_wifi_component->ip_state_callback_.call(global_wifi_component->wifi_sta_ip_addresses(), global_wifi_component->get_dns_address(0), global_wifi_component->get_dns_address(1)); +#endif break; } case EVENT_STAMODE_DHCP_TIMEOUT: { @@ -734,7 +740,9 @@ void WiFiComponent::wifi_scan_done_callback_(void *arg, STATUS status) { it->is_hidden != 0); } this->scan_done_ = true; +#ifdef USE_WIFI_CALLBACKS global_wifi_component->wifi_scan_state_callback_.call(global_wifi_component->scan_result_); +#endif } #ifdef USE_WIFI_AP diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 3bc37deb41..c20c96ced0 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -727,7 +727,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); s_sta_connected = true; +#ifdef USE_WIFI_CALLBACKS this->wifi_connect_state_callback_.call(this->wifi_ssid(), this->wifi_bssid()); +#endif } else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_DISCONNECTED) { const auto &it = data->data.sta_disconnected; @@ -751,7 +753,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { s_sta_connected = false; s_sta_connecting = false; error_from_callback_ = true; +#ifdef USE_WIFI_CALLBACKS this->wifi_connect_state_callback_.call("", bssid_t({0, 0, 0, 0, 0, 0})); +#endif } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_GOT_IP) { const auto &it = data->data.ip_got_ip; @@ -760,14 +764,18 @@ 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_CALLBACKS this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); +#endif #if USE_NETWORK_IPV6 } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_GOT_IP6) { 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_CALLBACKS this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); +#endif #endif /* USE_NETWORK_IPV6 */ } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_LOST_IP) { @@ -807,7 +815,9 @@ 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_CALLBACKS this->wifi_scan_state_callback_.call(this->scan_result_); +#endif } else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_START) { ESP_LOGV(TAG, "AP start"); diff --git a/esphome/components/wifi/wifi_component_libretiny.cpp b/esphome/components/wifi/wifi_component_libretiny.cpp index bf1d7a5408..04d0d4fa85 100644 --- a/esphome/components/wifi/wifi_component_libretiny.cpp +++ b/esphome/components/wifi/wifi_component_libretiny.cpp @@ -287,7 +287,9 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ buf[it.ssid_len] = '\0'; ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf, format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode)); +#ifdef USE_WIFI_CALLBACKS this->wifi_connect_state_callback_.call(this->wifi_ssid(), this->wifi_bssid()); +#endif break; } case ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED: { @@ -313,7 +315,9 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ } s_sta_connecting = false; +#ifdef USE_WIFI_CALLBACKS this->wifi_connect_state_callback_.call("", bssid_t({0, 0, 0, 0, 0, 0})); +#endif break; } case ESPHOME_EVENT_ID_WIFI_STA_AUTHMODE_CHANGE: { @@ -335,13 +339,17 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_ ESP_LOGV(TAG, "static_ip=%s gateway=%s", format_ip4_addr(WiFi.localIP()).c_str(), format_ip4_addr(WiFi.gatewayIP()).c_str()); s_sta_connecting = false; +#ifdef USE_WIFI_CALLBACKS this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); +#endif break; } case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: { // auto it = info.got_ip.ip_info; ESP_LOGV(TAG, "Got IPv6"); +#ifdef USE_WIFI_CALLBACKS this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); +#endif break; } case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: { @@ -435,7 +443,9 @@ void WiFiComponent::wifi_scan_done_callback_() { } WiFi.scanDelete(); this->scan_done_ = true; +#ifdef USE_WIFI_CALLBACKS this->wifi_scan_state_callback_.call(this->scan_result_); +#endif } #ifdef USE_WIFI_AP diff --git a/esphome/components/wifi/wifi_component_pico_w.cpp b/esphome/components/wifi/wifi_component_pico_w.cpp index 2cc7bd2567..326883c0c4 100644 --- a/esphome/components/wifi/wifi_component_pico_w.cpp +++ b/esphome/components/wifi/wifi_component_pico_w.cpp @@ -225,7 +225,9 @@ 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_CALLBACKS this->wifi_scan_state_callback_.call(this->scan_result_); +#endif } // Poll for connection state changes @@ -239,13 +241,17 @@ void WiFiComponent::wifi_loop_() { // Just connected s_sta_was_connected = true; ESP_LOGV(TAG, "Connected"); +#ifdef USE_WIFI_CALLBACKS this->wifi_connect_state_callback_.call(this->wifi_ssid(), this->wifi_bssid()); +#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_CALLBACKS this->wifi_connect_state_callback_.call("", bssid_t({0, 0, 0, 0, 0, 0})); +#endif } // Detect IP address changes (only when connected) @@ -261,7 +267,9 @@ void WiFiComponent::wifi_loop_() { // Just got IP address s_sta_had_ip = true; ESP_LOGV(TAG, "Got IP address"); +#ifdef USE_WIFI_CALLBACKS this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1)); +#endif } } } diff --git a/esphome/components/wifi_info/text_sensor.py b/esphome/components/wifi_info/text_sensor.py index be402cfb7b..50fe31d151 100644 --- a/esphome/components/wifi_info/text_sensor.py +++ b/esphome/components/wifi_info/text_sensor.py @@ -70,6 +70,19 @@ async def setup_conf(config, key): async def to_code(config): + # Request WiFi callbacks for any sensor that needs them + if any( + key in config + for key in ( + CONF_SSID, + CONF_BSSID, + CONF_IP_ADDRESS, + CONF_DNS_ADDRESS, + CONF_SCAN_RESULTS, + ) + ): + wifi.request_wifi_callbacks() + await setup_conf(config, CONF_SSID) await setup_conf(config, CONF_BSSID) await setup_conf(config, CONF_MAC_ADDRESS) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 4b24c395b9..1373ea6366 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -210,6 +210,7 @@ #define USE_WEBSERVER_SORTING #define USE_WIFI_11KV_SUPPORT #define USE_WIFI_FAST_CONNECT +#define USE_WIFI_CALLBACKS #define USE_WIFI_RUNTIME_POWER_SAVE #define USB_HOST_MAX_REQUESTS 16