mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[wifi] Fix wifi.connected condition returning false in connect state listener automations (#13733)
This commit is contained in:
@@ -1464,6 +1464,12 @@ void WiFiComponent::check_connecting_finished(uint32_t now) {
|
|||||||
|
|
||||||
this->release_scan_results_();
|
this->release_scan_results_();
|
||||||
|
|
||||||
|
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
|
// Notify listeners now that state machine has reached STA_CONNECTED
|
||||||
|
// This ensures wifi.connected condition returns true in listener automations
|
||||||
|
this->notify_connect_state_listeners_();
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2183,6 +2189,21 @@ void WiFiComponent::release_scan_results_() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
|
void WiFiComponent::notify_connect_state_listeners_() {
|
||||||
|
if (!this->pending_.connect_state)
|
||||||
|
return;
|
||||||
|
this->pending_.connect_state = false;
|
||||||
|
// Get current SSID and BSSID from the WiFi driver
|
||||||
|
char ssid_buf[SSID_BUFFER_SIZE];
|
||||||
|
const char *ssid = this->wifi_ssid_to(ssid_buf);
|
||||||
|
bssid_t bssid = this->wifi_bssid();
|
||||||
|
for (auto *listener : this->connect_state_listeners_) {
|
||||||
|
listener->on_wifi_connect_state(StringRef(ssid, strlen(ssid)), bssid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
|
|
||||||
void WiFiComponent::check_roaming_(uint32_t now) {
|
void WiFiComponent::check_roaming_(uint32_t now) {
|
||||||
// Guard: not for hidden networks (may not appear in scan)
|
// Guard: not for hidden networks (may not appear in scan)
|
||||||
const WiFiAP *selected = this->get_selected_sta_();
|
const WiFiAP *selected = this->get_selected_sta_();
|
||||||
|
|||||||
@@ -632,6 +632,11 @@ class WiFiComponent : public Component {
|
|||||||
/// Free scan results memory unless a component needs them
|
/// Free scan results memory unless a component needs them
|
||||||
void release_scan_results_();
|
void release_scan_results_();
|
||||||
|
|
||||||
|
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
|
/// Notify connect state listeners (called after state machine reaches STA_CONNECTED)
|
||||||
|
void notify_connect_state_listeners_();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
static void wifi_event_callback(System_Event_t *event);
|
static void wifi_event_callback(System_Event_t *event);
|
||||||
void wifi_scan_done_callback_(void *arg, STATUS status);
|
void wifi_scan_done_callback_(void *arg, STATUS status);
|
||||||
@@ -739,6 +744,16 @@ class WiFiComponent : public Component {
|
|||||||
SemaphoreHandle_t high_performance_semaphore_{nullptr};
|
SemaphoreHandle_t high_performance_semaphore_{nullptr};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
|
// Pending listener notifications deferred until state machine reaches appropriate state.
|
||||||
|
// Listeners are notified after state transitions complete so conditions like
|
||||||
|
// wifi.connected return correct values in automations.
|
||||||
|
// Uses bitfields to minimize memory; more flags may be added as needed.
|
||||||
|
struct {
|
||||||
|
bool connect_state : 1; // Notify connect state listeners after STA_CONNECTED
|
||||||
|
} pending_{};
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WIFI_CONNECT_TRIGGER
|
#ifdef USE_WIFI_CONNECT_TRIGGER
|
||||||
Trigger<> connect_trigger_;
|
Trigger<> connect_trigger_;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -500,6 +500,10 @@ const LogString *get_disconnect_reason_str(uint8_t reason) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This callback runs in ESP8266 system context with limited stack (~2KB).
|
||||||
|
// All listener notifications should be deferred to wifi_loop_() via pending_ flags
|
||||||
|
// to avoid stack overflow. Currently only connect_state is deferred; disconnect,
|
||||||
|
// IP, and scan listeners still run in this context and should be migrated.
|
||||||
void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||||
switch (event->event) {
|
switch (event->event) {
|
||||||
case EVENT_STAMODE_CONNECTED: {
|
case EVENT_STAMODE_CONNECTED: {
|
||||||
@@ -512,9 +516,9 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
|||||||
#endif
|
#endif
|
||||||
s_sta_connected = true;
|
s_sta_connected = true;
|
||||||
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
for (auto *listener : global_wifi_component->connect_state_listeners_) {
|
// Defer listener notification until state machine reaches STA_CONNECTED
|
||||||
listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid);
|
// This ensures wifi.connected condition returns true in listener automations
|
||||||
}
|
global_wifi_component->pending_.connect_state = true;
|
||||||
#endif
|
#endif
|
||||||
// For static IP configurations, GOT_IP event may not fire, so notify IP listeners here
|
// For static IP configurations, GOT_IP event may not fire, so notify IP listeners here
|
||||||
#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP)
|
#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP)
|
||||||
|
|||||||
@@ -710,6 +710,9 @@ void WiFiComponent::wifi_loop_() {
|
|||||||
delete data; // NOLINT(cppcoreguidelines-owning-memory)
|
delete data; // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 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)
|
||||||
|
// so that conditions like wifi.connected return correct values in automations.
|
||||||
void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_START) {
|
if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_START) {
|
||||||
@@ -743,9 +746,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
|||||||
#endif
|
#endif
|
||||||
s_sta_connected = true;
|
s_sta_connected = true;
|
||||||
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
for (auto *listener : this->connect_state_listeners_) {
|
// Defer listener notification until state machine reaches STA_CONNECTED
|
||||||
listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid);
|
// This ensures wifi.connected condition returns true in listener automations
|
||||||
}
|
this->pending_.connect_state = true;
|
||||||
#endif
|
#endif
|
||||||
// For static IP configurations, GOT_IP event may not fire, so notify IP listeners here
|
// For static IP configurations, GOT_IP event may not fire, so notify IP listeners here
|
||||||
#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP)
|
#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP)
|
||||||
|
|||||||
@@ -423,7 +423,10 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process a single event from the queue - runs in main loop context
|
// Process a single event from the queue - runs in main loop context.
|
||||||
|
// Listener notifications must be 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_process_event_(LTWiFiEvent *event) {
|
void WiFiComponent::wifi_process_event_(LTWiFiEvent *event) {
|
||||||
switch (event->event_id) {
|
switch (event->event_id) {
|
||||||
case ESPHOME_EVENT_ID_WIFI_READY: {
|
case ESPHOME_EVENT_ID_WIFI_READY: {
|
||||||
@@ -456,9 +459,9 @@ void WiFiComponent::wifi_process_event_(LTWiFiEvent *event) {
|
|||||||
// This matches ESP32 IDF behavior where s_sta_connected is set but
|
// This matches ESP32 IDF behavior where s_sta_connected is set but
|
||||||
// wifi_sta_connect_status_() also checks got_ipv4_address_
|
// wifi_sta_connect_status_() also checks got_ipv4_address_
|
||||||
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
for (auto *listener : this->connect_state_listeners_) {
|
// Defer listener notification until state machine reaches STA_CONNECTED
|
||||||
listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid);
|
// This ensures wifi.connected condition returns true in listener automations
|
||||||
}
|
this->pending_.connect_state = true;
|
||||||
#endif
|
#endif
|
||||||
// For static IP configurations, GOT_IP event may not fire, so set connected state here
|
// For static IP configurations, GOT_IP event may not fire, so set connected state here
|
||||||
#ifdef USE_WIFI_MANUAL_IP
|
#ifdef USE_WIFI_MANUAL_IP
|
||||||
|
|||||||
@@ -252,6 +252,10 @@ network::IPAddress WiFiComponent::wifi_dns_ip_(int num) {
|
|||||||
return network::IPAddress(dns_ip);
|
return network::IPAddress(dns_ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pico W uses polling for connection state detection.
|
||||||
|
// 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_() {
|
void WiFiComponent::wifi_loop_() {
|
||||||
// Handle scan completion
|
// Handle scan completion
|
||||||
if (this->state_ == WIFI_COMPONENT_STATE_STA_SCANNING && !cyw43_wifi_scan_active(&cyw43_state)) {
|
if (this->state_ == WIFI_COMPONENT_STATE_STA_SCANNING && !cyw43_wifi_scan_active(&cyw43_state)) {
|
||||||
@@ -278,11 +282,9 @@ void WiFiComponent::wifi_loop_() {
|
|||||||
s_sta_was_connected = true;
|
s_sta_was_connected = true;
|
||||||
ESP_LOGV(TAG, "Connected");
|
ESP_LOGV(TAG, "Connected");
|
||||||
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
|
||||||
String ssid = WiFi.SSID();
|
// Defer listener notification until state machine reaches STA_CONNECTED
|
||||||
bssid_t bssid = this->wifi_bssid();
|
// This ensures wifi.connected condition returns true in listener automations
|
||||||
for (auto *listener : this->connect_state_listeners_) {
|
this->pending_.connect_state = true;
|
||||||
listener->on_wifi_connect_state(StringRef(ssid.c_str(), ssid.length()), bssid);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
// For static IP configurations, notify IP listeners immediately as the IP is already configured
|
// For static IP configurations, notify IP listeners immediately as the IP is already configured
|
||||||
#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP)
|
#if defined(USE_WIFI_IP_STATE_LISTENERS) && defined(USE_WIFI_MANUAL_IP)
|
||||||
|
|||||||
Reference in New Issue
Block a user