From 7e4d09dbd89fb07522825f315f62584299cc82de Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 7 Aug 2025 16:24:26 -1000 Subject: [PATCH] [bluetooth_proxy] Optimize connection loop to reduce CPU usage (#10133) --- .../bluetooth_proxy/bluetooth_connection.cpp | 21 ++++++++++++++----- .../bluetooth_proxy/bluetooth_connection.h | 2 +- .../bluetooth_proxy/bluetooth_proxy.cpp | 5 ++--- .../bluetooth_proxy/bluetooth_proxy.h | 1 + 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index fd77f9bd5b..b16b894188 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -107,13 +107,24 @@ void BluetoothConnection::set_address(uint64_t address) { void BluetoothConnection::loop() { BLEClientBase::loop(); - // Early return if no active connection or not in service discovery phase - if (this->address_ == 0 || this->send_service_ < 0 || this->send_service_ > this->service_count_) { + // Early return if no active connection + if (this->address_ == 0) { return; } - // Handle service discovery - this->send_service_for_discovery_(); + // Handle service discovery if in valid range + if (this->send_service_ >= 0 && this->send_service_ <= this->service_count_) { + this->send_service_for_discovery_(); + } + + // Check if we should disable the loop + // - For V3_WITH_CACHE: Services are never sent, disable after INIT state + // - For other connections: Disable only after service discovery is complete + // (send_service_ == DONE_SENDING_SERVICES, which is only set after services are sent) + if (this->state_ != espbt::ClientState::INIT && (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE || + this->send_service_ == DONE_SENDING_SERVICES)) { + this->disable_loop(); + } } void BluetoothConnection::reset_connection_(esp_err_t reason) { @@ -127,7 +138,7 @@ void BluetoothConnection::reset_connection_(esp_err_t reason) { // to detect incomplete service discovery rather than relying on us to // tell them about a partial list. this->set_address(0); - this->send_service_ = DONE_SENDING_SERVICES; + this->send_service_ = INIT_SENDING_SERVICES; this->proxy_->send_connections_free(); } diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.h b/esphome/components/bluetooth_proxy/bluetooth_connection.h index 7feb3c80bc..a975d25d91 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.h +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.h @@ -44,7 +44,7 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase { BluetoothProxy *proxy_; // Group 2: 2-byte types - int16_t send_service_{-2}; // Needs to handle negative values and service count + int16_t send_service_{-3}; // -3 = INIT_SENDING_SERVICES, -2 = DONE_SENDING_SERVICES, >=0 = service index // Group 3: 1-byte types bool seen_mtu_or_services_{false}; diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index 1986ea90d5..04b85fc3f0 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -192,7 +192,7 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese for (uint8_t i = 0; i < this->connection_count_; i++) { auto *connection = this->connections_[i]; if (connection->get_address() == 0) { - connection->send_service_ = DONE_SENDING_SERVICES; + connection->send_service_ = INIT_SENDING_SERVICES; connection->set_address(address); // All connections must start at INIT // We only set the state if we allocate the connection @@ -373,8 +373,7 @@ void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetSer this->send_gatt_services_done(msg.address); return; } - if (connection->send_service_ == - DONE_SENDING_SERVICES) // Only start sending services if we're not already sending them + if (connection->send_service_ == INIT_SENDING_SERVICES) // Start sending services if not started yet connection->send_service_ = 0; } diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.h b/esphome/components/bluetooth_proxy/bluetooth_proxy.h index 4f22a179d6..21695d9819 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.h +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.h @@ -23,6 +23,7 @@ namespace esphome::bluetooth_proxy { static const esp_err_t ESP_GATT_NOT_CONNECTED = -1; static const int DONE_SENDING_SERVICES = -2; +static const int INIT_SENDING_SERVICES = -3; using namespace esp32_ble_client;