From 3a24d0b03bfbd316e93ba660fe292b9600d7e5d1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 9 Aug 2026 10:22:35 -0500 Subject: [PATCH] Reset the search latches per connection attempt The latches were cleared only in set_idle_(), but the stack-down branch in loop() reaches IDLE through set_state() without it, so after a ble.disable/enable cycle the next connection's discover_services() would complete immediately from the previous connection's latched result and HA would cache an authoritative empty service list. tracker_connect_() now resets the latch alongside the two per-attempt flags it already clears, and delivery consumes the whole latch so a re-discovery on a live link issues a real search instead of re-reporting the first result. --- .../bluetooth_connection_bluedroid.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp index 851749f845..ee9fc9f675 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp +++ b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp @@ -119,6 +119,13 @@ void BluedroidGattClient::tracker_connect_() { ESP_LOGI(TAG, "[%d] 0x%02x Connecting", this->connection_index_, this->remote_addr_type_); this->services_released_ = false; this->seen_mtu_ = false; + // Per-attempt reset: the stack-down path in loop() reaches IDLE through + // set_state() without set_idle_(), and a stale done latch would complete + // this connection's discovery with the previous connection's result. + this->search_prestarted_ = false; + this->search_done_ = false; + this->search_requested_ = false; + this->search_status_ = 0; this->enable_loop(); this->set_state(ClientState::CONNECTING); if (this->connection_type_ == ConnectionType::V3_WITHOUT_CACHE) { @@ -501,11 +508,15 @@ int BluedroidGattClient::handle_search_cmpl_() { } // Reports a completed search once its consumer has asked for it; the -// pre-started search must stay silent until then. +// pre-started search must stay silent until then. Delivery consumes the +// whole latch, so a later discover_services() on the same connection issues +// a real search instead of re-reporting this result. void BluedroidGattClient::deliver_pending_search_() { if (!this->search_requested_ || !this->search_done_) return; this->search_requested_ = false; + this->search_prestarted_ = false; + this->search_done_ = false; this->listener_->on_service_discovery_done(this->search_status_); }