From 53e0af18fb20e494ac5695f57d99307a722b25cf Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 27 Nov 2022 14:28:02 -1000 Subject: [PATCH] Make parse_characteristics and parse_descriptors lazy to reduce memory pressure (#4063) --- .../components/bluetooth_proxy/bluetooth_proxy.cpp | 11 +++++++++++ .../esp32_ble_client/ble_characteristic.cpp | 5 +++++ .../components/esp32_ble_client/ble_characteristic.h | 1 + .../components/esp32_ble_client/ble_client_base.cpp | 10 +++++++++- esphome/components/esp32_ble_client/ble_service.cpp | 4 +++- esphome/components/esp32_ble_client/ble_service.h | 1 + 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index 7798bb1e85..834901fbdc 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -72,11 +72,15 @@ void BluetoothProxy::loop() { api::BluetoothGATTService service_resp; service_resp.uuid = {service->uuid.get_128bit_high(), service->uuid.get_128bit_low()}; service_resp.handle = service->start_handle; + if (!service->parsed) + service->parse_characteristics(); for (auto &characteristic : service->characteristics) { api::BluetoothGATTCharacteristic characteristic_resp; characteristic_resp.uuid = {characteristic->uuid.get_128bit_high(), characteristic->uuid.get_128bit_low()}; characteristic_resp.handle = characteristic->handle; characteristic_resp.properties = characteristic->properties; + if (!characteristic->parsed) + characteristic->parse_descriptors(); for (auto &descriptor : characteristic->descriptors) { api::BluetoothGATTDescriptor descriptor_resp; descriptor_resp.uuid = {descriptor->uuid.get_128bit_high(), descriptor->uuid.get_128bit_low()}; @@ -87,6 +91,13 @@ void BluetoothProxy::loop() { } resp.services.push_back(std::move(service_resp)); api::global_api_server->send_bluetooth_gatt_services(resp); + // Descriptors are rarely used and can be quite large so we clear them + // after sending them to save memory. If something actually needs them + // it can parse them again. + for (auto &characteristic : service->characteristics) { + characteristic->parsed = false; + characteristic->descriptors.clear(); + } connection->send_service_++; } } diff --git a/esphome/components/esp32_ble_client/ble_characteristic.cpp b/esphome/components/esp32_ble_client/ble_characteristic.cpp index fbc9ba16dc..ce27628c77 100644 --- a/esphome/components/esp32_ble_client/ble_characteristic.cpp +++ b/esphome/components/esp32_ble_client/ble_characteristic.cpp @@ -17,6 +17,7 @@ BLECharacteristic::~BLECharacteristic() { } void BLECharacteristic::parse_descriptors() { + this->parsed = true; uint16_t offset = 0; esp_gattc_descr_elem_t result; @@ -49,6 +50,8 @@ void BLECharacteristic::parse_descriptors() { } BLEDescriptor *BLECharacteristic::get_descriptor(espbt::ESPBTUUID uuid) { + if (!this->parsed) + this->parse_descriptors(); for (auto &desc : this->descriptors) { if (desc->uuid == uuid) return desc; @@ -59,6 +62,8 @@ BLEDescriptor *BLECharacteristic::get_descriptor(uint16_t uuid) { return this->get_descriptor(espbt::ESPBTUUID::from_uint16(uuid)); } BLEDescriptor *BLECharacteristic::get_descriptor_by_handle(uint16_t handle) { + if (!this->parsed) + this->parse_descriptors(); for (auto &desc : this->descriptors) { if (desc->handle == handle) return desc; diff --git a/esphome/components/esp32_ble_client/ble_characteristic.h b/esphome/components/esp32_ble_client/ble_characteristic.h index d56516f1fd..746ed600d8 100644 --- a/esphome/components/esp32_ble_client/ble_characteristic.h +++ b/esphome/components/esp32_ble_client/ble_characteristic.h @@ -18,6 +18,7 @@ class BLEService; class BLECharacteristic { public: ~BLECharacteristic(); + bool parsed = false; espbt::ESPBTUUID uuid; uint16_t handle; esp_gatt_char_prop_t properties; diff --git a/esphome/components/esp32_ble_client/ble_client_base.cpp b/esphome/components/esp32_ble_client/ble_client_base.cpp index 964ff29771..23a55727e4 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.cpp +++ b/esphome/components/esp32_ble_client/ble_client_base.cpp @@ -135,6 +135,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ for (auto &svc : this->services_) delete svc; // NOLINT(cppcoreguidelines-owning-memory) this->services_.clear(); + esp_ble_gattc_cache_clean(this->remote_bda_); this->set_state(espbt::ClientState::IDLE); break; } @@ -154,7 +155,6 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ svc->uuid.to_string().c_str()); ESP_LOGI(TAG, "[%d] [%s] start_handle: 0x%x end_handle: 0x%x", this->connection_index_, this->address_str_.c_str(), svc->start_handle, svc->end_handle); - svc->parse_characteristics(); } this->set_state(espbt::ClientState::CONNECTED); this->state_ = espbt::ClientState::ESTABLISHED; @@ -287,6 +287,8 @@ BLECharacteristic *BLEClientBase::get_characteristic(uint16_t service, uint16_t BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) { for (auto *svc : this->services_) { + if (!svc->parsed) + svc->parse_characteristics(); for (auto *chr : svc->characteristics) { if (chr->handle == handle) return chr; @@ -298,6 +300,8 @@ BLECharacteristic *BLEClientBase::get_characteristic(uint16_t handle) { BLEDescriptor *BLEClientBase::get_config_descriptor(uint16_t handle) { auto *chr = this->get_characteristic(handle); if (chr != nullptr) { + if (!chr->parsed) + chr->parse_descriptors(); for (auto &desc : chr->descriptors) { if (desc->uuid.get_uuid().uuid.uuid16 == 0x2902) return desc; @@ -323,7 +327,11 @@ BLEDescriptor *BLEClientBase::get_descriptor(uint16_t service, uint16_t chr, uin BLEDescriptor *BLEClientBase::get_descriptor(uint16_t handle) { for (auto *svc : this->services_) { + if (!svc->parsed) + svc->parse_characteristics(); for (auto *chr : svc->characteristics) { + if (!chr->parsed) + chr->parse_descriptors(); for (auto *desc : chr->descriptors) { if (desc->handle == handle) return desc; diff --git a/esphome/components/esp32_ble_client/ble_service.cpp b/esphome/components/esp32_ble_client/ble_service.cpp index 2f8a55f928..3c95dad684 100644 --- a/esphome/components/esp32_ble_client/ble_service.cpp +++ b/esphome/components/esp32_ble_client/ble_service.cpp @@ -11,6 +11,8 @@ namespace esp32_ble_client { static const char *const TAG = "esp32_ble_client"; BLECharacteristic *BLEService::get_characteristic(espbt::ESPBTUUID uuid) { + if (!this->parsed) + this->parse_characteristics(); for (auto &chr : this->characteristics) { if (chr->uuid == uuid) return chr; @@ -28,6 +30,7 @@ BLEService::~BLEService() { } void BLEService::parse_characteristics() { + this->parsed = true; uint16_t offset = 0; esp_gattc_char_elem_t result; @@ -57,7 +60,6 @@ void BLEService::parse_characteristics() { ESP_LOGI(TAG, "[%d] [%s] characteristic %s, handle 0x%x, properties 0x%x", this->client->get_connection_index(), this->client->address_str().c_str(), characteristic->uuid.to_string().c_str(), characteristic->handle, characteristic->properties); - characteristic->parse_descriptors(); offset++; } } diff --git a/esphome/components/esp32_ble_client/ble_service.h b/esphome/components/esp32_ble_client/ble_service.h index 7b072f5fae..1b1e86611f 100644 --- a/esphome/components/esp32_ble_client/ble_service.h +++ b/esphome/components/esp32_ble_client/ble_service.h @@ -18,6 +18,7 @@ class BLEClientBase; class BLEService { public: ~BLEService(); + bool parsed = false; espbt::ESPBTUUID uuid; uint16_t start_handle; uint16_t end_handle;