From 4925f6648b126587e801c81d0e9060712dba6634 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 9 Aug 2026 17:05:01 -0500 Subject: [PATCH] Address review: retry-latch hygiene on subscriber change, parity note - Both retry latches clear on subscribe/unsubscribe: a new subscriber must not receive a connected=false for an address from the previous session (it resyncs through its own subscribe requests) - The app-register failure path states its BLEClientBase parity so the no-retry behavior reads as deliberate --- .../bluetooth_connection/bluetooth_connection_bluedroid.cpp | 2 ++ esphome/components/bluetooth_proxy/bluetooth_proxy.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp index e62ec103d3..f24d261c57 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp +++ b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp @@ -58,6 +58,8 @@ void BluedroidGattClient::loop() { } auto st = this->state(); if (st == ClientState::INIT) { + // Parity with BLEClientBase: a failed registration marks the slot + // failed and idles it without retry. auto ret = esp_ble_gattc_app_register(this->app_id); if (ret) { ESP_LOGE(TAG, "gattc app register failed: app_id=%d code=%d", this->app_id, ret); diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index c5281c5b4f..14e5c66c68 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -620,6 +620,9 @@ void BluetoothProxy::subscribe_api_connection(api::APIConnection *api_connection api_connection->get_peername_to(new_peername), this->api_connection_->get_name(), this->api_connection_->get_peername_to(old_peername)); } + // Stale retry latches belong to the previous subscriber's session. + this->connections_free_pending_ = false; + this->pending_disconnection_address_ = 0; this->api_connection_ = api_connection; #ifdef USE_BLE_SCANNER_STATE_CALLBACK // get_scanner_state() is part of the push-hub surface (see BLEHubContract). @@ -635,6 +638,8 @@ void BluetoothProxy::unsubscribe_api_connection(api::APIConnection *api_connecti return; } this->api_connection_ = nullptr; + this->connections_free_pending_ = false; + this->pending_disconnection_address_ = 0; } void BluetoothProxy::send_device_connection(uint64_t address, bool connected, uint16_t mtu, conn_err_t error) {