diff --git a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp index a65bb583598..65964f2ec20 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp +++ b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp @@ -70,8 +70,8 @@ void BluedroidGattClient::loop() { this->listener_->on_connection_state(false, 0, ESP_GATT_CONN_TIMEOUT); } } else { - // The loop stays on while a link exists (stack-down watch, pre-started - // search flush); it settles only back at IDLE. + // The loop stays on while a link exists (pre-started search flush); it + // settles only back at IDLE. this->deliver_pending_search_(); if (this->state() == ClientState::IDLE) { this->disable_loop(); diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index e414f32580a..b08aa55ba2e 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -83,32 +83,22 @@ void ESP32BLE::setup() { } } -void ESP32BLE::enable() { this->request_state_(true); } -void ESP32BLE::disable() { this->request_state_(false); } - // Queue the transition for loop(). A pending transition the other way is // cancelled instead, since nothing was torn down or brought up yet; any other // state is already there or on its way. void ESP32BLE::request_state_(bool enable) { - switch (this->state_) { - case BLE_COMPONENT_STATE_DISABLE: - if (enable) - this->state_ = BLE_COMPONENT_STATE_ACTIVE; - break; - case BLE_COMPONENT_STATE_ENABLE: - if (!enable) - this->state_ = BLE_COMPONENT_STATE_DISABLED; - break; - case BLE_COMPONENT_STATE_DISABLED: - if (enable) - this->state_ = BLE_COMPONENT_STATE_ENABLE; - break; - case BLE_COMPONENT_STATE_ACTIVE: - if (!enable) - this->state_ = BLE_COMPONENT_STATE_DISABLE; - break; - default: - break; + if (enable) { + if (this->state_ == BLE_COMPONENT_STATE_DISABLED) { + this->state_ = BLE_COMPONENT_STATE_ENABLE; + } else if (this->state_ == BLE_COMPONENT_STATE_DISABLE) { + this->state_ = BLE_COMPONENT_STATE_ACTIVE; + } + } else { + if (this->state_ == BLE_COMPONENT_STATE_ACTIVE) { + this->state_ = BLE_COMPONENT_STATE_DISABLE; + } else if (this->state_ == BLE_COMPONENT_STATE_ENABLE) { + this->state_ = BLE_COMPONENT_STATE_DISABLED; + } } } diff --git a/esphome/components/esp32_ble/ble.h b/esphome/components/esp32_ble/ble.h index 2b889c5a3c6..fd4fb15ff69 100644 --- a/esphome/components/esp32_ble/ble.h +++ b/esphome/components/esp32_ble/ble.h @@ -102,8 +102,8 @@ class ESP32BLE final : public Component { } uint32_t get_advertising_cycle_time() const { return this->advertising_cycle_time_; } - void enable(); - void disable(); + void enable() { this->request_state_(true); } + void disable() { this->request_state_(false); } ESPHOME_ALWAYS_INLINE bool is_active() { return this->state_ == BLE_COMPONENT_STATE_ACTIVE; } void setup() override; void loop() override; diff --git a/esphome/components/esp32_ble_client/ble_client_base.cpp b/esphome/components/esp32_ble_client/ble_client_base.cpp index e290f9f2ddd..d209dd22cea 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.cpp +++ b/esphome/components/esp32_ble_client/ble_client_base.cpp @@ -134,7 +134,7 @@ void BLEClientBase::connect() { } if (this->gattc_if_ == ESP_GATT_IF_NONE) { // Bluedroid drops an open on an unknown interface without any event. - ESP_LOGW(TAG, "[%d] [%s] Connect rejected, GATT app not registered", this->connection_index_, this->address_str_); + this->log_warning_("Connect rejected, GATT app not registered"); this->set_state(espbt::ClientState::IDLE); return; } @@ -220,7 +220,10 @@ void BLEClientBase::release_services() { #ifndef CONFIG_BT_GATTC_CACHE_NVS_FLASH // Only the cache clean makes the stack's database unsafe to walk. this->services_released_ = true; - esp_ble_gattc_cache_clean(this->remote_bda_); + // A stack on its way down frees its own cache. + if (esp32_ble::global_ble->is_active()) { + esp_ble_gattc_cache_clean(this->remote_bda_); + } #endif } diff --git a/esphome/components/esp32_ble_client/ble_client_base.h b/esphome/components/esp32_ble_client/ble_client_base.h index 01c3de0c8b0..c189fd4d26f 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.h +++ b/esphome/components/esp32_ble_client/ble_client_base.h @@ -156,10 +156,11 @@ class BLEClientBase : public espbt::ESPBTClient, public Component { void log_connection_params_(const char *param_type); void handle_connection_result_(esp_err_t ret); /// Hook called once a connection has been fully torn down (after release_services() and - /// set_idle_()), from both the CLOSE_EVT handler and the DISCONNECTING safety timeout. + /// set_idle_()): CLOSE_EVT, the DISCONNECTING safety timeout, or the BLE stack going down. /// Subclasses with extra per-connection accounting (e.g. bluetooth_proxy slot state) - /// override this to release that state. `reason` is the controller reason code, or - /// ESP_GATT_CONN_TIMEOUT for the safety-timeout path. + /// override this to release that state. `reason` is the controller reason code, + /// ESP_GATT_CONN_TIMEOUT for the safety timeout, or ESP_GATT_CONN_TERMINATE_LOCAL_HOST + /// for the stack going down. virtual void on_disconnect_complete(esp_err_t reason) {} /// Transition to IDLE and reset conn_id — call when the connection is fully dead. void set_idle_() { diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 9e5f424c877..26296eadf0b 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -74,13 +74,12 @@ void ESP32BLETracker::on_ota_global_state(ota::OTAState state, float progress, u void ESP32BLETracker::loop() { if (!this->parent_->is_active()) { - this->ble_was_disabled_ = true; return; - } else if (this->ble_was_disabled_) { + } + if (this->ble_was_disabled_) { this->ble_was_disabled_ = false; - // Start the scan again after a disable. A cancelled disable never stopped - // it, so only start from IDLE. - if (this->scan_continuous_ && this->scanner_state_ == ScannerState::IDLE) { + // First start after boot or after the stack came back. + if (this->scan_continuous_) { this->start_scan(); } } @@ -228,12 +227,13 @@ void ESP32BLETracker::ble_before_disabled_event_handler() { #endif // The stop above never completes (stack torn down, events dropped); settle // here so start_scan_() sees IDLE once the stack is back. - if (this->scanner_state_ != ScannerState::IDLE) { #ifdef ESPHOME_ESP32_BLE_TRACKER_CLIENT_COUNT - this->skip_next_scan_end_ = false; + this->skip_next_scan_end_ = false; #endif + if (this->scanner_state_ != ScannerState::IDLE) { this->cleanup_scan_state_(true); } + this->ble_was_disabled_ = true; } bool ESP32BLETracker::stop_scan_() {