diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index b63f7ccde9..3c5c2bd438 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -73,9 +73,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga resp.address = this->address_; resp.handle = param->read.handle; resp.data.reserve(param->read.value_len); - for (uint16_t i = 0; i < param->read.value_len; i++) { - resp.data.push_back(param->read.value[i]); - } + // Use bulk insert instead of individual push_backs + resp.data.insert(resp.data.end(), param->read.value, param->read.value + param->read.value_len); this->proxy_->get_api_connection()->send_bluetooth_gatt_read_response(resp); break; } @@ -127,9 +126,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga resp.address = this->address_; resp.handle = param->notify.handle; resp.data.reserve(param->notify.value_len); - for (uint16_t i = 0; i < param->notify.value_len; i++) { - resp.data.push_back(param->notify.value[i]); - } + // Use bulk insert instead of individual push_backs + resp.data.insert(resp.data.end(), param->notify.value, param->notify.value + param->notify.value_len); this->proxy_->get_api_connection()->send_bluetooth_gatt_notify_data_response(resp); break; } diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index e40f4e5dcc..9c8bd4009f 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -56,6 +56,9 @@ bool BluetoothProxy::parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_p return false; api::BluetoothLERawAdvertisementsResponse resp; + // Pre-allocate the advertisements vector to avoid reallocations + resp.advertisements.reserve(count); + for (size_t i = 0; i < count; i++) { auto &result = advertisements[i]; api::BluetoothLERawAdvertisement adv; @@ -65,9 +68,8 @@ bool BluetoothProxy::parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_p uint8_t length = result.adv_data_len + result.scan_rsp_len; adv.data.reserve(length); - for (uint16_t i = 0; i < length; i++) { - adv.data.push_back(result.ble_adv[i]); - } + // 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)); @@ -85,21 +87,34 @@ void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &devi if (!device.get_name().empty()) resp.name = device.get_name(); resp.rssi = device.get_rssi(); - for (auto uuid : device.get_service_uuids()) { + + // Pre-allocate vectors based on known sizes + auto service_uuids = device.get_service_uuids(); + resp.service_uuids.reserve(service_uuids.size()); + for (auto uuid : service_uuids) { resp.service_uuids.push_back(uuid.to_string()); } - for (auto &data : device.get_service_datas()) { + + // Pre-allocate service data vector + auto service_datas = device.get_service_datas(); + resp.service_data.reserve(service_datas.size()); + for (auto &data : service_datas) { api::BluetoothServiceData service_data; service_data.uuid = data.uuid.to_string(); service_data.data.assign(data.data.begin(), data.data.end()); resp.service_data.push_back(std::move(service_data)); } - for (auto &data : device.get_manufacturer_datas()) { + + // Pre-allocate manufacturer data vector + auto manufacturer_datas = device.get_manufacturer_datas(); + resp.manufacturer_data.reserve(manufacturer_datas.size()); + for (auto &data : manufacturer_datas) { api::BluetoothServiceData manufacturer_data; manufacturer_data.uuid = data.uuid.to_string(); manufacturer_data.data.assign(data.data.begin(), data.data.end()); resp.manufacturer_data.push_back(std::move(manufacturer_data)); } + this->api_connection_->send_bluetooth_le_advertisement(resp); } @@ -161,11 +176,27 @@ void BluetoothProxy::loop() { } api::BluetoothGATTGetServicesResponse resp; resp.address = connection->get_address(); + resp.services.reserve(1); // Always one service per response in this implementation api::BluetoothGATTService service_resp; service_resp.uuid = get_128bit_uuid_vec(service_result.uuid); service_resp.handle = service_result.start_handle; uint16_t char_offset = 0; esp_gattc_char_elem_t char_result; + // Get the number of characteristics directly with one call + uint16_t total_char_count = 0; + esp_gatt_status_t char_count_status = esp_ble_gattc_get_attr_count( + connection->get_gattc_if(), connection->get_conn_id(), ESP_GATT_DB_CHARACTERISTIC, + service_result.start_handle, service_result.end_handle, 0, &total_char_count); + + if (char_count_status == ESP_GATT_OK && total_char_count > 0) { + // Only reserve if we successfully got a count + service_resp.characteristics.reserve(total_char_count); + } else if (char_count_status != ESP_GATT_OK) { + ESP_LOGW(TAG, "[%d] [%s] Error getting characteristic count, status=%d", connection->get_connection_index(), + connection->address_str().c_str(), char_count_status); + } + + // Now process characteristics while (true) { // characteristics uint16_t char_count = 1; esp_gatt_status_t char_status = esp_ble_gattc_get_all_char( @@ -187,6 +218,23 @@ void BluetoothProxy::loop() { characteristic_resp.handle = char_result.char_handle; characteristic_resp.properties = char_result.properties; char_offset++; + + // Get the number of descriptors directly with one call + uint16_t total_desc_count = 0; + esp_gatt_status_t desc_count_status = + esp_ble_gattc_get_attr_count(connection->get_gattc_if(), connection->get_conn_id(), ESP_GATT_DB_DESCRIPTOR, + char_result.char_handle, service_result.end_handle, 0, &total_desc_count); + + if (desc_count_status == ESP_GATT_OK && total_desc_count > 0) { + // Only reserve if we successfully got a count + characteristic_resp.descriptors.reserve(total_desc_count); + } else if (desc_count_status != ESP_GATT_OK) { + ESP_LOGW(TAG, "[%d] [%s] Error getting descriptor count for char handle %d, status=%d", + connection->get_connection_index(), connection->address_str().c_str(), char_result.char_handle, + desc_count_status); + } + + // Now process descriptors uint16_t desc_offset = 0; esp_gattc_descr_elem_t desc_result; while (true) { // descriptors