From ae906ada94f1f6367a2de1de851110068b3e7665 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 9 Aug 2026 16:32:37 -0500 Subject: [PATCH] Address review: quiet stack-down teardown, pin bitfield widths - The stack-down settle resets the stream latches directly instead of calling release_services(): the dying stack invalidates its own cache, and the newly checked cache_clean would warn on every OTA or ble.disable with a live connection - static_asserts pin the exactly-sized state bitfields so a future enumerator truncates loudly at compile time --- .../bluetooth_connection/bluetooth_connection_bluedroid.cpp | 5 ++++- .../bluetooth_connection/bluetooth_connection_bluedroid.h | 1 + .../bluetooth_connection/bluetooth_connection_hub.h | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp index b9080287c3..e40e72ee11 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp +++ b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.cpp @@ -49,7 +49,10 @@ void BluedroidGattClient::loop() { // frees its slot, then re-register the app on the next enable. auto down_st = this->state(); if (down_st != ClientState::IDLE && down_st != ClientState::INIT) { - this->release_services(); + // The dying stack invalidates its own cache; a cache_clean would just + // warn against a disabled stack. Reset the stream latches directly. + this->service_total_ = 0; + this->services_released_ = true; this->set_idle_(); this->listener_->on_connection_state(false, 0, ble_device_base::GATT_ERR_NOT_CONNECTED); } diff --git a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.h b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.h index 1d3ffef530..19b89ea5cd 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.h +++ b/esphome/components/bluetooth_connection/bluetooth_connection_bluedroid.h @@ -131,6 +131,7 @@ class BluedroidGattClient final : public esp32_ble_tracker::ESPBTClient, public bool mtu_failed_ : 1 {false}; // Search issued at OPEN_EVT overlaps the MTU exchange; discover_services() // completes from it. Reset by set_idle_(). + static_assert(static_cast(SearchState::REPORT_PENDING) < (1 << 4), "search_state_ bitfield too narrow"); SearchState search_state_ : 4 {SearchState::NONE}; // esp_gatt_status_t of the completed search, held until claimed. uint8_t search_status_{0}; diff --git a/esphome/components/bluetooth_connection/bluetooth_connection_hub.h b/esphome/components/bluetooth_connection/bluetooth_connection_hub.h index 5e8cf02b4c..82d9ae7db4 100644 --- a/esphome/components/bluetooth_connection/bluetooth_connection_hub.h +++ b/esphome/components/bluetooth_connection/bluetooth_connection_hub.h @@ -148,6 +148,9 @@ class BluetoothConnection final : public ble_device_base::GattClientListener { char address_str_[MAC_ADDRESS_PRETTY_BUFFER_SIZE]{}; // Group 5: bit-packed tail; within 2 bytes the 8-aligned object stays 48. + static_assert(static_cast(ClientState::ESTABLISHED) < (1 << 3), "state_ bitfield too narrow"); + static_assert(static_cast(ConnectionType::V3_WITHOUT_CACHE) < (1 << 2), + "connection_type_ bitfield too narrow"); ClientState state_ : 3 {ClientState::IDLE}; bool paired_ : 1 {false}; ConnectionType connection_type_ : 2 {ConnectionType::V1};