[wifi] libretiny: reset the STA state on synchronous connect failure (#18719)

This commit is contained in:
Edvard Filistovič
2026-08-25 01:25:44 +00:00
committed by GitHub
parent 8623b6836d
commit 169c055011
2 changed files with 39 additions and 4 deletions
+8
View File
@@ -951,6 +951,14 @@ class WiFiComponent final : public Component {
// On ESP8266, written from SDK system context (wifi_event_callback) —
// uint8_t writes are atomic on Xtensa LX106 so no synchronization is needed.
uint8_t sta_state_{0};
#endif
#ifdef USE_LIBRETINY
// First attempt since STA-up (re-armed on every STA off->on); the
// pre-attempt teardown is skipped then.
bool lt_first_connect_attempt_{true};
// A self-inflicted disconnect from that teardown is pending; it must not
// consume an ignored-disconnect slot.
bool lt_teardown_event_pending_{false};
#endif
RetryHiddenMode retry_hidden_mode_{RetryHiddenMode::BLIND_RETRY};
RoamingState roaming_state_{RoamingState::IDLE};
@@ -115,6 +115,8 @@ bool WiFiComponent::wifi_mode_(optional<bool> sta, optional<bool> ap) {
if (enable_sta && !current_sta) {
ESP_LOGV(TAG, "Enabling STA");
// Fresh STA stack: skip the pre-attempt teardown again.
this->lt_first_connect_attempt_ = true;
} else if (!enable_sta && current_sta) {
ESP_LOGV(TAG, "Disabling STA");
}
@@ -202,10 +204,21 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
if (!this->wifi_mode_(true, {}))
return false;
String ssid = WiFi.SSID();
if (ssid && strcmp(ssid.c_str(), ap.ssid_.c_str()) != 0) {
WiFi.disconnect();
// Tear down any live session so begin() re-fires its events; skipped on the
// first attempt after STA-up (nothing to tear down, and BK7231N on the older
// Beken SDK did not come back from it). The flag is per-attempt and armed
// only for a live session: an idle disconnect may emit no event, and a stale
// flag would swallow this attempt's first real failure.
this->lt_teardown_event_pending_ = false;
if (!this->lt_first_connect_attempt_) {
const bool was_live = WiFi.status() == WL_CONNECTED;
if (WiFi.disconnect()) {
this->lt_teardown_event_pending_ = was_live;
} else {
ESP_LOGD(TAG, "Pre-connect teardown returned false");
}
}
this->lt_first_connect_attempt_ = false;
#ifdef USE_WIFI_MANUAL_IP
if (!this->wifi_sta_ip_config_(ap.get_manual_ip())) {
@@ -227,7 +240,10 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
ap.get_channel(), // 0 = auto
ap.has_bssid() ? ap.get_bssid().data() : NULL);
if (status != WL_CONNECTED) {
ESP_LOGW(TAG, "esp_wifi_connect failed: %d", status);
ESP_LOGW(TAG, "WiFi.begin failed: %d", status);
// Without this reset the state machine stays at CONNECTING and each retry
// stalls for the full connect timeout (46 s).
this->sta_state_ = static_cast<uint8_t>(LTWiFiSTAState::ERROR_FAILED);
return false;
}
@@ -455,6 +471,9 @@ void WiFiComponent::wifi_process_event_(LTWiFiEvent *event) {
break;
}
case ESPHOME_EVENT_ID_WIFI_STA_CONNECTED: {
// Processed in queue order, so a teardown event still ahead of this
// CONNECTED was already consumed; a leftover flag is stale.
this->lt_teardown_event_pending_ = false;
auto &it = event->data.sta_connected;
char bssid_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
format_mac_addr_upper(it.bssid, bssid_buf);
@@ -482,6 +501,14 @@ void WiFiComponent::wifi_process_event_(LTWiFiEvent *event) {
case ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED: {
auto &it = event->data.sta_disconnected;
// Consume the disconnect our own teardown queued, without spending an
// ignore slot. Ungated on SSID and state: the flag is armed only for this
// attempt's teardown of a live session.
if (this->lt_teardown_event_pending_ && it.reason != WIFI_REASON_NO_AP_FOUND) {
this->lt_teardown_event_pending_ = false;
break;
}
// LibreTiny can send spurious disconnect events with empty ssid/bssid during connection.
// These are typically "Association Leave" events that don't indicate actual failures:
// [W][wifi_lt]: Disconnected ssid='' bssid=00:00:00:00:00:00 reason='Association Leave'