From 8c772b4dd413ac84c24be9d3726b94ea8c95f7f2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 10 Sep 2026 07:39:51 -0500 Subject: [PATCH] [esp32_ble] Drop queued events and settle the scanner when the stack is dismantled Events the old stack queued while going down were replayed after the next ble.enable against a fresh stack that hands out the same interface ids, and the scanner relied on that replay to leave STOPPING. Drain the queue after the teardown and put the scanner back to IDLE from the before-disabled handler, since no completion can arrive anymore. --- esphome/components/esp32_ble/ble.cpp | 8 ++++++++ .../components/esp32_ble_tracker/esp32_ble_tracker.cpp | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index fc95760cf8..15c370d3e2 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -580,6 +580,14 @@ void ESP32BLE::loop_handle_state_transition_not_active_() { this->mark_failed(); return; } + // Whatever the old stack queued while going down (close events for the + // links it tore down, scan completions) must not replay against the next + // stack, which hands out the same interface ids. + BLEEvent *ble_event; + while ((ble_event = this->ble_events_.pop()) != nullptr) { + this->ble_event_pool_.release(ble_event); + } + this->ble_events_.get_and_reset_dropped_count(); this->state_ = BLE_COMPONENT_STATE_DISABLED; } else if (this->state_ == BLE_COMPONENT_STATE_ENABLE) { ESP_LOGD(TAG, "Enabling"); diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index b3c905c8d8..7ae2ce568d 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -225,6 +225,15 @@ void ESP32BLETracker::ble_before_disabled_event_handler() { client->ble_before_disabled_event_handler(); } #endif + // The stop above never completes: the stack is torn down and its queued + // events are dropped, so settle the scanner here. start_scan_() refuses + // anything but 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; +#endif + this->cleanup_scan_state_(true); + } } bool ESP32BLETracker::stop_scan_() {