mirror of
https://github.com/esphome/esphome.git
synced 2026-02-28 09:54:19 -07:00
[esp32_ble_client] Add 10s safety timeout for DISCONNECTING state
If CLOSE_EVT never arrives after DISCONNECT_EVT, the client gets stuck in DISCONNECTING forever, blocking reconnection and scanner restart. Add a 10s timeout watchdog in loop() that forces IDLE as a recovery path. Introduce set_disconnecting_() helper to ensure the timeout timestamp is always set when entering DISCONNECTING state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@ static constexpr uint16_t MEDIUM_CONN_TIMEOUT = 800; // 800 * 10ms = 8s
|
||||
static constexpr uint16_t FAST_MIN_CONN_INTERVAL = 0x06; // 6 * 1.25ms = 7.5ms (BLE minimum)
|
||||
static constexpr uint16_t FAST_MAX_CONN_INTERVAL = 0x06; // 6 * 1.25ms = 7.5ms
|
||||
static constexpr uint16_t FAST_CONN_TIMEOUT = 1000; // 1000 * 10ms = 10s
|
||||
static constexpr uint32_t DISCONNECTING_TIMEOUT = 10000; // 10s
|
||||
static const esp_bt_uuid_t NOTIFY_DESC_UUID = {
|
||||
.len = ESP_UUID_LEN_16,
|
||||
.uuid =
|
||||
@@ -62,6 +63,11 @@ void BLEClientBase::loop() {
|
||||
// will enable it again when a connection is needed.
|
||||
else if (this->state() == espbt::ClientState::IDLE) {
|
||||
this->disable_loop();
|
||||
} else if (this->state() == espbt::ClientState::DISCONNECTING &&
|
||||
(millis() - this->disconnecting_started_) > DISCONNECTING_TIMEOUT) {
|
||||
ESP_LOGE(TAG, "[%d] [%s] Timeout waiting for CLOSE_EVT after disconnect, forcing IDLE", this->connection_index_,
|
||||
this->address_str_);
|
||||
this->set_idle_();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +184,7 @@ void BLEClientBase::unconditional_disconnect() {
|
||||
this->set_address(0);
|
||||
this->set_state(espbt::ClientState::IDLE);
|
||||
} else {
|
||||
this->set_state(espbt::ClientState::DISCONNECTING);
|
||||
this->set_disconnecting_();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +379,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
// causing the controller to reject the new connection (status=133) or crash
|
||||
// with ASSERT_PARAM in lld_evt.c.
|
||||
this->release_services();
|
||||
this->set_state(espbt::ClientState::DISCONNECTING);
|
||||
this->set_disconnecting_();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,10 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
|
||||
char address_str_[MAC_ADDRESS_PRETTY_BUFFER_SIZE]{};
|
||||
esp_bd_addr_t remote_bda_; // 6 bytes
|
||||
|
||||
// Group 5: 2-byte types
|
||||
// Group 5: 4-byte types
|
||||
uint32_t disconnecting_started_{0};
|
||||
|
||||
// Group 6: 2-byte types
|
||||
uint16_t conn_id_{UNSET_CONN_ID};
|
||||
uint16_t mtu_{23};
|
||||
|
||||
@@ -142,6 +145,11 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
|
||||
this->set_state(espbt::ClientState::IDLE);
|
||||
this->conn_id_ = UNSET_CONN_ID;
|
||||
}
|
||||
/// Transition to DISCONNECTING and start the safety timeout.
|
||||
void set_disconnecting_() {
|
||||
this->disconnecting_started_ = millis();
|
||||
this->set_state(espbt::ClientState::DISCONNECTING);
|
||||
}
|
||||
// Compact error logging helpers to reduce flash usage
|
||||
void log_error_(const char *message);
|
||||
void log_error_(const char *message, int code);
|
||||
|
||||
Reference in New Issue
Block a user