From d95bbfc6c44ecd0cacd692ed2cfc121c9b35a7a7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 13 May 2025 03:00:38 -0500 Subject: [PATCH] its too much --- .../bluetooth_proxy/bluetooth_proxy.cpp | 58 ++++++++++++++++--- .../bluetooth_proxy/bluetooth_proxy.h | 1 + .../esp32_ble_tracker/esp32_ble_tracker.cpp | 6 ++ .../esp32_ble_tracker/esp32_ble_tracker.h | 4 +- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index 9c8bd4009f..26c5eaca4d 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -51,14 +51,19 @@ bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device) return true; } +// Static buffer to store advertisements between batches +static constexpr size_t MAX_BATCH_SIZE = 64; // Larger batch size for more efficient transfers +static std::vector batch_buffer; + bool BluetoothProxy::parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) { if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || !this->raw_advertisements_) return false; - api::BluetoothLERawAdvertisementsResponse resp; - // Pre-allocate the advertisements vector to avoid reallocations - resp.advertisements.reserve(count); + if (batch_buffer.capacity() < MAX_BATCH_SIZE) { + batch_buffer.reserve(MAX_BATCH_SIZE); + } + // Add new advertisements to the batch buffer for (size_t i = 0; i < count; i++) { auto &result = advertisements[i]; api::BluetoothLERawAdvertisement adv; @@ -71,15 +76,36 @@ bool BluetoothProxy::parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_p // Use a bulk insert instead of individual push_backs adv.data.insert(adv.data.end(), &result.ble_adv[0], &result.ble_adv[length]); - resp.advertisements.push_back(std::move(adv)); + batch_buffer.push_back(std::move(adv)); - ESP_LOGV(TAG, "Proxying raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", result.bda[0], + ESP_LOGV(TAG, "Queuing raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", result.bda[0], result.bda[1], result.bda[2], result.bda[3], result.bda[4], result.bda[5], length, result.rssi); } - ESP_LOGV(TAG, "Proxying %d packets", count); - this->api_connection_->send_bluetooth_le_raw_advertisements_response(resp); + + // Only send if we've accumulated a good batch size to maximize batching efficiency + if (batch_buffer.size() >= MAX_BATCH_SIZE) { + this->flush_pending_advertisements(); + } + return true; } + +void BluetoothProxy::flush_pending_advertisements() { + if (batch_buffer.empty() || !api::global_api_server->is_connected() || this->api_connection_ == nullptr) + return; + + api::BluetoothLERawAdvertisementsResponse resp; + resp.advertisements.reserve(batch_buffer.size()); + + // Move all advertisements from the buffer to the response + for (auto &adv : batch_buffer) { + resp.advertisements.push_back(std::move(adv)); + } + + ESP_LOGV(TAG, "Proxying batch of %d packets", resp.advertisements.size()); + this->api_connection_->send_bluetooth_le_raw_advertisements_response(resp); + batch_buffer.clear(); +} void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) { api::BluetoothLEAdvertisementResponse resp; resp.address = device.address_uint64(); @@ -148,6 +174,18 @@ void BluetoothProxy::loop() { } return; } + + // Flush any pending BLE advertisements that have been accumulated but not yet sent + if (this->raw_advertisements_) { + static uint32_t last_flush_time = 0; + uint32_t now = millis(); + + // Flush accumulated advertisements every 100ms + if (now - last_flush_time >= 100) { + this->flush_pending_advertisements(); + last_flush_time = now; + } + } for (auto *connection : this->connections_) { if (connection->send_service_ == connection->service_count_) { connection->send_service_ = DONE_SENDING_SERVICES; @@ -526,6 +564,12 @@ void BluetoothProxy::unsubscribe_api_connection(api::APIConnection *api_connecti ESP_LOGV(TAG, "API connection is not subscribed"); return; } + + // Flush any pending advertisements before unsubscribing + if (this->raw_advertisements_) { + this->flush_pending_advertisements(); + } + this->api_connection_ = nullptr; this->raw_advertisements_ = false; this->parent_->recalculate_advertisement_parser_types(); diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.h b/esphome/components/bluetooth_proxy/bluetooth_proxy.h index de24165fe8..f75e73e796 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.h +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.h @@ -56,6 +56,7 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com void dump_config() override; void setup() override; void loop() override; + void flush_pending_advertisements(); esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override; void register_connection(BluetoothConnection *connection) { diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index be45b177ff..5cc4e6f2da 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -120,9 +120,15 @@ void ESP32BLETracker::loop() { } bool promote_to_connecting = discovered && !searching && !connecting; + static uint32_t last_process_time = 0; + uint32_t now = millis(); + + // Process scan results less frequently to allow more batching - process every 50ms if (this->scanner_state_ == ScannerState::RUNNING && this->scan_result_index_ && // if it looks like we have a scan result we will take the lock + (now - last_process_time >= 50 || this->scan_result_index_ >= ESP32BLETracker::SCAN_RESULT_BUFFER_SIZE / 2) && xSemaphoreTake(this->scan_result_lock_, 5L / portTICK_PERIOD_MS)) { + last_process_time = now; uint32_t index = this->scan_result_index_; if (index >= ESP32BLETracker::SCAN_RESULT_BUFFER_SIZE) { ESP_LOGW(TAG, "Too many BLE events to process. Some devices may not show up."); diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 2e45d9602c..d49318e669 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -288,9 +288,9 @@ class ESP32BLETracker : public Component, SemaphoreHandle_t scan_result_lock_; size_t scan_result_index_{0}; #ifdef USE_PSRAM - const static u_int8_t SCAN_RESULT_BUFFER_SIZE = 32; + const static u_int8_t SCAN_RESULT_BUFFER_SIZE = 128; #else - const static u_int8_t SCAN_RESULT_BUFFER_SIZE = 16; + const static u_int8_t SCAN_RESULT_BUFFER_SIZE = 64; #endif // USE_PSRAM esp_ble_gap_cb_param_t::ble_scan_result_evt_param *scan_result_buffer_; esp_bt_status_t scan_start_failed_{ESP_BT_STATUS_SUCCESS};