mirror of
https://github.com/esphome/esphome.git
synced 2026-09-18 18:48:39 +00:00
[esp32_ble_tracker] Hold COEX_PREFER_BT for the lifetime of any active connection
count_client_states_() only tracks transient states (CONNECTING, DISCOVERED, DISCONNECTING). When a connection settles into CONNECTED/ESTABLISHED, all counted states go to zero, and loop() reverts coex from PREFER_BT back to BALANCE while the connection is still live. Sustained WiFi traffic then crowds out the BT radio's ability to receive the peer's GATT response, causing esp_ble_gattc_write_char_descr to time out at ~20s with a host-synthesized status=0x85 (commonly reported as status=133). Fix: count CONNECTED + ESTABLISHED clients as "active" and gate the coex revert on the active count. Coex now stays at PREFER_BT for the entire lifetime of any active connection and only returns to BALANCE when all connections are torn down. Validated end-to-end: aioesphomeapi-driven write_descriptor on a Yale BETA211123 lock at LOG_LEVEL_VERBOSE (heavy WiFi traffic, the bug-triggering condition) — pre-patch: 19s hang then status=133. Post-patch: 228ms SUCCESS. Verified live on an M5 Atom Lite running as a bluetooth_proxy with host BlueZ stopped (M5 as the only path): lock ops succeed cleanly with zero status=133 errors. A multi-day production soak window will be added to the PR body before merge.
This commit is contained in:
@@ -166,8 +166,9 @@ void ESP32BLETracker::loop() {
|
||||
ClientStateCounts counts = this->count_client_states_();
|
||||
if (counts != this->client_state_counts_) {
|
||||
this->client_state_counts_ = counts;
|
||||
ESP_LOGD(TAG, "connecting: %d, discovered: %d, disconnecting: %d", this->client_state_counts_.connecting,
|
||||
this->client_state_counts_.discovered, this->client_state_counts_.disconnecting);
|
||||
ESP_LOGD(TAG, "connecting: %d, discovered: %d, disconnecting: %d, active: %d", this->client_state_counts_.connecting,
|
||||
this->client_state_counts_.discovered, this->client_state_counts_.disconnecting,
|
||||
this->client_state_counts_.active);
|
||||
}
|
||||
|
||||
// Scanner failure: reached when set_scanner_state_(FAILED) or scan_set_param_failed_ set
|
||||
@@ -193,7 +194,13 @@ void ESP32BLETracker::loop() {
|
||||
// all clients are idle (their state changes increment version when they finish)
|
||||
if (this->scanner_state_ == ScannerState::IDLE && !counts.connecting && !counts.disconnecting && !counts.discovered) {
|
||||
#ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE
|
||||
this->update_coex_preference_(false);
|
||||
// Only revert to BALANCE when no connections are active. Established connections
|
||||
// continue to need PREFER_BT so the lock's GATT Write Response can reach us while
|
||||
// WiFi traffic (advertisement upload, log streaming) competes for the shared radio.
|
||||
// Reverting too early causes Bluedroid to time out at ~20s and synthesize status=133.
|
||||
if (!counts.active) {
|
||||
this->update_coex_preference_(false);
|
||||
}
|
||||
#endif
|
||||
if (this->scan_continuous_) {
|
||||
this->start_scan_(false); // first = false
|
||||
@@ -701,9 +708,10 @@ void ESP32BLETracker::dump_config() {
|
||||
this->scan_active_ ? "ACTIVE" : "PASSIVE", YESNO(this->scan_continuous_));
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Scanner State: %s\n"
|
||||
" Connecting: %d, discovered: %d, disconnecting: %d",
|
||||
" Connecting: %d, discovered: %d, disconnecting: %d, active: %d",
|
||||
this->scanner_state_to_string_(this->scanner_state_), this->client_state_counts_.connecting,
|
||||
this->client_state_counts_.discovered, this->client_state_counts_.disconnecting);
|
||||
this->client_state_counts_.discovered, this->client_state_counts_.disconnecting,
|
||||
this->client_state_counts_.active);
|
||||
if (this->scan_start_fail_count_) {
|
||||
ESP_LOGCONFIG(TAG, " Scan Start Fail Count: %d", this->scan_start_fail_count_);
|
||||
}
|
||||
|
||||
@@ -160,9 +160,13 @@ struct ClientStateCounts {
|
||||
uint8_t connecting = 0;
|
||||
uint8_t discovered = 0;
|
||||
uint8_t disconnecting = 0;
|
||||
// CONNECTED + ESTABLISHED clients. Tracked so coex stays at PREFER_BT
|
||||
// while active connections may still need to send/receive GATT traffic.
|
||||
uint8_t active = 0;
|
||||
|
||||
bool operator==(const ClientStateCounts &other) const {
|
||||
return connecting == other.connecting && discovered == other.discovered && disconnecting == other.disconnecting;
|
||||
return connecting == other.connecting && discovered == other.discovered && disconnecting == other.disconnecting &&
|
||||
active == other.active;
|
||||
}
|
||||
|
||||
bool operator!=(const ClientStateCounts &other) const { return !(*this == other); }
|
||||
@@ -381,6 +385,10 @@ class ESP32BLETracker : public Component,
|
||||
case ClientState::CONNECTING:
|
||||
counts.connecting++;
|
||||
break;
|
||||
case ClientState::CONNECTED:
|
||||
case ClientState::ESTABLISHED:
|
||||
counts.active++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user