ESPHome 2025.6.0
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
bluetooth_proxy.cpp
Go to the documentation of this file.
1#include "bluetooth_proxy.h"
2
3#include "esphome/core/log.h"
6
7#ifdef USE_ESP32
8
9namespace esphome {
10namespace bluetooth_proxy {
11
12static const char *const TAG = "bluetooth_proxy";
13static const int DONE_SENDING_SERVICES = -2;
14
15std::vector<uint64_t> get_128bit_uuid_vec(esp_bt_uuid_t uuid_source) {
16 esp_bt_uuid_t uuid = espbt::ESPBTUUID::from_uuid(uuid_source).as_128bit().get_uuid();
17 return std::vector<uint64_t>{((uint64_t) uuid.uuid.uuid128[15] << 56) | ((uint64_t) uuid.uuid.uuid128[14] << 48) |
18 ((uint64_t) uuid.uuid.uuid128[13] << 40) | ((uint64_t) uuid.uuid.uuid128[12] << 32) |
19 ((uint64_t) uuid.uuid.uuid128[11] << 24) | ((uint64_t) uuid.uuid.uuid128[10] << 16) |
20 ((uint64_t) uuid.uuid.uuid128[9] << 8) | ((uint64_t) uuid.uuid.uuid128[8]),
21 ((uint64_t) uuid.uuid.uuid128[7] << 56) | ((uint64_t) uuid.uuid.uuid128[6] << 48) |
22 ((uint64_t) uuid.uuid.uuid128[5] << 40) | ((uint64_t) uuid.uuid.uuid128[4] << 32) |
23 ((uint64_t) uuid.uuid.uuid128[3] << 24) | ((uint64_t) uuid.uuid.uuid128[2] << 16) |
24 ((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0])};
25}
26
28
31 if (this->api_connection_ != nullptr) {
33 }
34 });
35}
36
44
46 if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || this->raw_advertisements_)
47 return false;
48
49 ESP_LOGV(TAG, "Proxying packet from %s - %s. RSSI: %d dB", device.get_name().c_str(), device.address_str().c_str(),
50 device.get_rssi());
51 this->send_api_packet_(device);
52 return true;
53}
54
55static constexpr size_t FLUSH_BATCH_SIZE = 8;
56static std::vector<api::BluetoothLERawAdvertisement> &get_batch_buffer() {
57 static std::vector<api::BluetoothLERawAdvertisement> batch_buffer;
58 return batch_buffer;
59}
60
61bool BluetoothProxy::parse_devices(const esp32_ble::BLEScanResult *scan_results, size_t count) {
62 if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || !this->raw_advertisements_)
63 return false;
64
65 // Get the batch buffer reference
66 auto &batch_buffer = get_batch_buffer();
67
68 // Reserve additional capacity if needed
69 size_t new_size = batch_buffer.size() + count;
70 if (batch_buffer.capacity() < new_size) {
71 batch_buffer.reserve(new_size);
72 }
73
74 // Add new advertisements to the batch buffer
75 for (size_t i = 0; i < count; i++) {
76 auto &result = scan_results[i];
77 uint8_t length = result.adv_data_len + result.scan_rsp_len;
78
79 batch_buffer.emplace_back();
80 auto &adv = batch_buffer.back();
81 adv.address = esp32_ble::ble_addr_to_uint64(result.bda);
82 adv.rssi = result.rssi;
83 adv.address_type = result.ble_addr_type;
84 adv.data.assign(&result.ble_adv[0], &result.ble_adv[length]);
85
86 ESP_LOGV(TAG, "Queuing raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", result.bda[0],
87 result.bda[1], result.bda[2], result.bda[3], result.bda[4], result.bda[5], length, result.rssi);
88 }
89
90 // Only send if we've accumulated a good batch size to maximize batching efficiency
91 // https://github.com/esphome/backlog/issues/21
92 if (batch_buffer.size() >= FLUSH_BATCH_SIZE) {
94 }
95
96 return true;
97}
98
100 auto &batch_buffer = get_batch_buffer();
101 if (batch_buffer.empty() || !api::global_api_server->is_connected() || this->api_connection_ == nullptr)
102 return;
103
105 resp.advertisements.swap(batch_buffer);
106 this->api_connection_->send_message(resp);
107}
108
111 resp.address = device.address_uint64();
112 resp.address_type = device.get_address_type();
113 if (!device.get_name().empty())
114 resp.name = device.get_name();
115 resp.rssi = device.get_rssi();
116
117 // Pre-allocate vectors based on known sizes
118 auto service_uuids = device.get_service_uuids();
119 resp.service_uuids.reserve(service_uuids.size());
120 for (auto &uuid : service_uuids) {
121 resp.service_uuids.emplace_back(uuid.to_string());
122 }
123
124 // Pre-allocate service data vector
125 auto service_datas = device.get_service_datas();
126 resp.service_data.reserve(service_datas.size());
127 for (auto &data : service_datas) {
128 resp.service_data.emplace_back();
129 auto &service_data = resp.service_data.back();
130 service_data.uuid = data.uuid.to_string();
131 service_data.data.assign(data.data.begin(), data.data.end());
132 }
133
134 // Pre-allocate manufacturer data vector
135 auto manufacturer_datas = device.get_manufacturer_datas();
136 resp.manufacturer_data.reserve(manufacturer_datas.size());
137 for (auto &data : manufacturer_datas) {
138 resp.manufacturer_data.emplace_back();
139 auto &manufacturer_data = resp.manufacturer_data.back();
140 manufacturer_data.uuid = data.uuid.to_string();
141 manufacturer_data.data.assign(data.data.begin(), data.data.end());
142 }
143
144 this->api_connection_->send_message(resp);
145}
146
148 ESP_LOGCONFIG(TAG, "Bluetooth Proxy:");
149 ESP_LOGCONFIG(TAG,
150 " Active: %s\n"
151 " Connections: %d\n"
152 " Raw advertisements: %s",
153 YESNO(this->active_), this->connections_.size(), YESNO(this->raw_advertisements_));
154}
155
157 int free = 0;
158 for (auto *connection : this->connections_) {
159 if (connection->address_ == 0) {
160 free++;
161 ESP_LOGV(TAG, "[%d] Free connection", connection->get_connection_index());
162 } else {
163 ESP_LOGV(TAG, "[%d] Used connection by [%s]", connection->get_connection_index(),
164 connection->address_str().c_str());
165 }
166 }
167 return free;
168}
169
171 if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr) {
172 for (auto *connection : this->connections_) {
173 if (connection->get_address() != 0) {
174 connection->disconnect();
175 }
176 }
177 return;
178 }
179
180 // Flush any pending BLE advertisements that have been accumulated but not yet sent
181 if (this->raw_advertisements_) {
182 static uint32_t last_flush_time = 0;
183 uint32_t now = App.get_loop_component_start_time();
184
185 // Flush accumulated advertisements every 100ms
186 if (now - last_flush_time >= 100) {
188 last_flush_time = now;
189 }
190 }
191 for (auto *connection : this->connections_) {
192 if (connection->send_service_ == connection->service_count_) {
193 connection->send_service_ = DONE_SENDING_SERVICES;
194 this->send_gatt_services_done(connection->get_address());
195 if (connection->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
196 connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
197 connection->release_services();
198 }
199 } else if (connection->send_service_ >= 0) {
200 esp_gattc_service_elem_t service_result;
201 uint16_t service_count = 1;
202 esp_gatt_status_t service_status =
203 esp_ble_gattc_get_service(connection->get_gattc_if(), connection->get_conn_id(), nullptr, &service_result,
204 &service_count, connection->send_service_);
205 connection->send_service_++;
206 if (service_status != ESP_GATT_OK) {
207 ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service error at offset=%d, status=%d",
208 connection->get_connection_index(), connection->address_str().c_str(), connection->send_service_ - 1,
209 service_status);
210 continue;
211 }
212 if (service_count == 0) {
213 ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service missing, service_count=%d",
214 connection->get_connection_index(), connection->address_str().c_str(), service_count);
215 continue;
216 }
218 resp.address = connection->get_address();
219 resp.services.reserve(1); // Always one service per response in this implementation
220 api::BluetoothGATTService service_resp;
221 service_resp.uuid = get_128bit_uuid_vec(service_result.uuid);
222 service_resp.handle = service_result.start_handle;
223 uint16_t char_offset = 0;
224 esp_gattc_char_elem_t char_result;
225 // Get the number of characteristics directly with one call
226 uint16_t total_char_count = 0;
227 esp_gatt_status_t char_count_status = esp_ble_gattc_get_attr_count(
228 connection->get_gattc_if(), connection->get_conn_id(), ESP_GATT_DB_CHARACTERISTIC,
229 service_result.start_handle, service_result.end_handle, 0, &total_char_count);
230
231 if (char_count_status == ESP_GATT_OK && total_char_count > 0) {
232 // Only reserve if we successfully got a count
233 service_resp.characteristics.reserve(total_char_count);
234 } else if (char_count_status != ESP_GATT_OK) {
235 ESP_LOGW(TAG, "[%d] [%s] Error getting characteristic count, status=%d", connection->get_connection_index(),
236 connection->address_str().c_str(), char_count_status);
237 }
238
239 // Now process characteristics
240 while (true) { // characteristics
241 uint16_t char_count = 1;
242 esp_gatt_status_t char_status = esp_ble_gattc_get_all_char(
243 connection->get_gattc_if(), connection->get_conn_id(), service_result.start_handle,
244 service_result.end_handle, &char_result, &char_count, char_offset);
245 if (char_status == ESP_GATT_INVALID_OFFSET || char_status == ESP_GATT_NOT_FOUND) {
246 break;
247 }
248 if (char_status != ESP_GATT_OK) {
249 ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_char error, status=%d", connection->get_connection_index(),
250 connection->address_str().c_str(), char_status);
251 break;
252 }
253 if (char_count == 0) {
254 break;
255 }
256 api::BluetoothGATTCharacteristic characteristic_resp;
257 characteristic_resp.uuid = get_128bit_uuid_vec(char_result.uuid);
258 characteristic_resp.handle = char_result.char_handle;
259 characteristic_resp.properties = char_result.properties;
260 char_offset++;
261
262 // Get the number of descriptors directly with one call
263 uint16_t total_desc_count = 0;
264 esp_gatt_status_t desc_count_status =
265 esp_ble_gattc_get_attr_count(connection->get_gattc_if(), connection->get_conn_id(), ESP_GATT_DB_DESCRIPTOR,
266 char_result.char_handle, service_result.end_handle, 0, &total_desc_count);
267
268 if (desc_count_status == ESP_GATT_OK && total_desc_count > 0) {
269 // Only reserve if we successfully got a count
270 characteristic_resp.descriptors.reserve(total_desc_count);
271 } else if (desc_count_status != ESP_GATT_OK) {
272 ESP_LOGW(TAG, "[%d] [%s] Error getting descriptor count for char handle %d, status=%d",
273 connection->get_connection_index(), connection->address_str().c_str(), char_result.char_handle,
274 desc_count_status);
275 }
276
277 // Now process descriptors
278 uint16_t desc_offset = 0;
279 esp_gattc_descr_elem_t desc_result;
280 while (true) { // descriptors
281 uint16_t desc_count = 1;
282 esp_gatt_status_t desc_status =
283 esp_ble_gattc_get_all_descr(connection->get_gattc_if(), connection->get_conn_id(),
284 char_result.char_handle, &desc_result, &desc_count, desc_offset);
285 if (desc_status == ESP_GATT_INVALID_OFFSET || desc_status == ESP_GATT_NOT_FOUND) {
286 break;
287 }
288 if (desc_status != ESP_GATT_OK) {
289 ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_descr error, status=%d", connection->get_connection_index(),
290 connection->address_str().c_str(), desc_status);
291 break;
292 }
293 if (desc_count == 0) {
294 break;
295 }
296 api::BluetoothGATTDescriptor descriptor_resp;
297 descriptor_resp.uuid = get_128bit_uuid_vec(desc_result.uuid);
298 descriptor_resp.handle = desc_result.handle;
299 characteristic_resp.descriptors.push_back(std::move(descriptor_resp));
300 desc_offset++;
301 }
302 service_resp.characteristics.push_back(std::move(characteristic_resp));
303 }
304 resp.services.push_back(std::move(service_resp));
305 this->api_connection_->send_message(resp);
306 }
307 }
308}
309
315
317 for (auto *connection : this->connections_) {
318 if (connection->get_address() == address)
319 return connection;
320 }
321
322 if (!reserve)
323 return nullptr;
324
325 for (auto *connection : this->connections_) {
326 if (connection->get_address() == 0) {
327 connection->send_service_ = DONE_SENDING_SERVICES;
328 connection->set_address(address);
329 // All connections must start at INIT
330 // We only set the state if we allocate the connection
331 // to avoid a race where multiple connection attempts
332 // are made.
333 connection->set_state(espbt::ClientState::INIT);
334 return connection;
335 }
336 }
337
338 return nullptr;
339}
340
342 switch (msg.request_type) {
346 auto *connection = this->get_connection_(msg.address, true);
347 if (connection == nullptr) {
348 ESP_LOGW(TAG, "No free connections available");
349 this->send_device_connection(msg.address, false);
350 return;
351 }
352 if (connection->state() == espbt::ClientState::CONNECTED ||
353 connection->state() == espbt::ClientState::ESTABLISHED) {
354 ESP_LOGW(TAG, "[%d] [%s] Connection already established", connection->get_connection_index(),
355 connection->address_str().c_str());
356 this->send_device_connection(msg.address, true);
357 this->send_connections_free();
358 return;
359 } else if (connection->state() == espbt::ClientState::SEARCHING) {
360 ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already searching for device",
361 connection->get_connection_index(), connection->address_str().c_str());
362 return;
363 } else if (connection->state() == espbt::ClientState::DISCOVERED) {
364 ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device already discovered",
365 connection->get_connection_index(), connection->address_str().c_str());
366 return;
367 } else if (connection->state() == espbt::ClientState::READY_TO_CONNECT) {
368 ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, waiting in line to connect",
369 connection->get_connection_index(), connection->address_str().c_str());
370 return;
371 } else if (connection->state() == espbt::ClientState::CONNECTING) {
372 if (connection->disconnect_pending()) {
373 ESP_LOGW(TAG, "[%d] [%s] Connection request while pending disconnect, cancelling pending disconnect",
374 connection->get_connection_index(), connection->address_str().c_str());
375 connection->cancel_pending_disconnect();
376 return;
377 }
378 ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already connecting", connection->get_connection_index(),
379 connection->address_str().c_str());
380 return;
381 } else if (connection->state() == espbt::ClientState::DISCONNECTING) {
382 ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device is disconnecting",
383 connection->get_connection_index(), connection->address_str().c_str());
384 return;
385 } else if (connection->state() != espbt::ClientState::INIT) {
386 ESP_LOGW(TAG, "[%d] [%s] Connection already in progress", connection->get_connection_index(),
387 connection->address_str().c_str());
388 return;
389 }
391 connection->set_connection_type(espbt::ConnectionType::V3_WITH_CACHE);
392 ESP_LOGI(TAG, "[%d] [%s] Connecting v3 with cache", connection->get_connection_index(),
393 connection->address_str().c_str());
395 connection->set_connection_type(espbt::ConnectionType::V3_WITHOUT_CACHE);
396 ESP_LOGI(TAG, "[%d] [%s] Connecting v3 without cache", connection->get_connection_index(),
397 connection->address_str().c_str());
398 } else {
399 connection->set_connection_type(espbt::ConnectionType::V1);
400 ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str());
401 }
402 if (msg.has_address_type) {
403 uint64_to_bd_addr(msg.address, connection->remote_bda_);
404 connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type));
405 connection->set_state(espbt::ClientState::DISCOVERED);
406 } else {
407 connection->set_state(espbt::ClientState::SEARCHING);
408 }
409 this->send_connections_free();
410 break;
411 }
413 auto *connection = this->get_connection_(msg.address, false);
414 if (connection == nullptr) {
415 this->send_device_connection(msg.address, false);
416 this->send_connections_free();
417 return;
418 }
419 if (connection->state() != espbt::ClientState::IDLE) {
420 connection->disconnect();
421 } else {
422 connection->set_address(0);
423 this->send_device_connection(msg.address, false);
424 this->send_connections_free();
425 }
426 break;
427 }
429 auto *connection = this->get_connection_(msg.address, false);
430 if (connection != nullptr) {
431 if (!connection->is_paired()) {
432 auto err = connection->pair();
433 if (err != ESP_OK) {
434 this->send_device_pairing(msg.address, false, err);
435 }
436 } else {
437 this->send_device_pairing(msg.address, true);
438 }
439 }
440 break;
441 }
443 esp_bd_addr_t address;
445 esp_err_t ret = esp_ble_remove_bond_device(address);
446 this->send_device_pairing(msg.address, ret == ESP_OK, ret);
447 break;
448 }
450 esp_bd_addr_t address;
452 esp_err_t ret = esp_ble_gattc_cache_clean(address);
454 call.address = msg.address;
455 call.success = ret == ESP_OK;
456 call.error = ret;
457
458 this->api_connection_->send_message(call);
459
460 break;
461 }
462 }
463}
464
466 auto *connection = this->get_connection_(msg.address, false);
467 if (connection == nullptr) {
468 ESP_LOGW(TAG, "Cannot read GATT characteristic, not connected");
469 this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
470 return;
471 }
472
473 auto err = connection->read_characteristic(msg.handle);
474 if (err != ESP_OK) {
475 this->send_gatt_error(msg.address, msg.handle, err);
476 }
477}
478
480 auto *connection = this->get_connection_(msg.address, false);
481 if (connection == nullptr) {
482 ESP_LOGW(TAG, "Cannot write GATT characteristic, not connected");
483 this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
484 return;
485 }
486
487 auto err = connection->write_characteristic(msg.handle, msg.data, msg.response);
488 if (err != ESP_OK) {
489 this->send_gatt_error(msg.address, msg.handle, err);
490 }
491}
492
494 auto *connection = this->get_connection_(msg.address, false);
495 if (connection == nullptr) {
496 ESP_LOGW(TAG, "Cannot read GATT descriptor, not connected");
497 this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
498 return;
499 }
500
501 auto err = connection->read_descriptor(msg.handle);
502 if (err != ESP_OK) {
503 this->send_gatt_error(msg.address, msg.handle, err);
504 }
505}
506
508 auto *connection = this->get_connection_(msg.address, false);
509 if (connection == nullptr) {
510 ESP_LOGW(TAG, "Cannot write GATT descriptor, not connected");
511 this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
512 return;
513 }
514
515 auto err = connection->write_descriptor(msg.handle, msg.data, true);
516 if (err != ESP_OK) {
517 this->send_gatt_error(msg.address, msg.handle, err);
518 }
519}
520
522 auto *connection = this->get_connection_(msg.address, false);
523 if (connection == nullptr || !connection->connected()) {
524 ESP_LOGW(TAG, "Cannot get GATT services, not connected");
525 this->send_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED);
526 return;
527 }
528 if (!connection->service_count_) {
529 ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str());
531 return;
532 }
533 if (connection->send_service_ ==
534 DONE_SENDING_SERVICES) // Only start sending services if we're not already sending them
535 connection->send_service_ = 0;
536}
537
539 auto *connection = this->get_connection_(msg.address, false);
540 if (connection == nullptr) {
541 ESP_LOGW(TAG, "Cannot notify GATT characteristic, not connected");
542 this->send_gatt_error(msg.address, msg.handle, ESP_GATT_NOT_CONNECTED);
543 return;
544 }
545
546 auto err = connection->notify_characteristic(msg.handle, msg.enable);
547 if (err != ESP_OK) {
548 this->send_gatt_error(msg.address, msg.handle, err);
549 }
550}
551
553 if (this->api_connection_ != nullptr) {
554 ESP_LOGE(TAG, "Only one API subscription is allowed at a time");
555 return;
556 }
557 this->api_connection_ = api_connection;
560
562}
563
565 if (this->api_connection_ != api_connection) {
566 ESP_LOGV(TAG, "API connection is not subscribed");
567 return;
568 }
569 this->api_connection_ = nullptr;
570 this->raw_advertisements_ = false;
572}
573
574void BluetoothProxy::send_device_connection(uint64_t address, bool connected, uint16_t mtu, esp_err_t error) {
575 if (this->api_connection_ == nullptr)
576 return;
579 call.connected = connected;
580 call.mtu = mtu;
581 call.error = error;
582 this->api_connection_->send_message(call);
583}
585 if (this->api_connection_ == nullptr)
586 return;
590 for (auto *connection : this->connections_) {
591 if (connection->address_ != 0) {
592 call.allocated.push_back(connection->address_);
593 }
594 }
595 this->api_connection_->send_message(call);
596}
597
605
606void BluetoothProxy::send_gatt_error(uint64_t address, uint16_t handle, esp_err_t error) {
607 if (this->api_connection_ == nullptr)
608 return;
611 call.handle = handle;
612 call.error = error;
613 this->api_connection_->send_message(call);
614}
615
616void BluetoothProxy::send_device_pairing(uint64_t address, bool paired, esp_err_t error) {
619 call.paired = paired;
620 call.error = error;
621
622 this->api_connection_->send_message(call);
623}
624
625void BluetoothProxy::send_device_unpairing(uint64_t address, bool success, esp_err_t error) {
628 call.success = success;
629 call.error = error;
630
631 this->api_connection_->send_message(call);
632}
633
635 if (this->parent_->get_scan_active() == active) {
636 return;
637 }
638 ESP_LOGD(TAG, "Setting scanner mode to %s", active ? "active" : "passive");
639 this->parent_->set_scan_active(active);
640 this->parent_->stop_scan();
642 true); // Set this to true to automatically start scanning again when it has cleaned up.
643}
644
645BluetoothProxy *global_bluetooth_proxy = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
646
647} // namespace bluetooth_proxy
648} // namespace esphome
649
650#endif // USE_ESP32
uint8_t address
Definition bl0906.h:4
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
enums::BluetoothDeviceRequestType request_type
Definition api_pb2.h:1848
std::vector< BluetoothGATTDescriptor > descriptors
Definition api_pb2.h:1915
std::vector< uint64_t > uuid
Definition api_pb2.h:1899
std::vector< BluetoothGATTService > services
Definition api_pb2.h:1949
std::vector< uint64_t > uuid
Definition api_pb2.h:1928
std::vector< BluetoothGATTCharacteristic > characteristics
Definition api_pb2.h:1930
std::vector< BluetoothServiceData > service_data
Definition api_pb2.h:1794
std::vector< std::string > service_uuids
Definition api_pb2.h:1793
std::vector< BluetoothServiceData > manufacturer_data
Definition api_pb2.h:1795
std::vector< BluetoothLERawAdvertisement > advertisements
Definition api_pb2.h:1830
enums::BluetoothScannerMode mode
Definition api_pb2.h:2282
enums::BluetoothScannerState state
Definition api_pb2.h:2281
void bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg)
void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg)
esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override
void send_device_connection(uint64_t address, bool connected, uint16_t mtu=0, esp_err_t error=ESP_OK)
void send_device_unpairing(uint64_t address, bool success, esp_err_t error=ESP_OK)
void send_device_pairing(uint64_t address, bool paired, esp_err_t error=ESP_OK)
bool parse_devices(const esp32_ble::BLEScanResult *scan_results, size_t count) override
void bluetooth_device_request(const api::BluetoothDeviceRequest &msg)
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override
void bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg)
void send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerState state)
void subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags)
void send_gatt_error(uint64_t address, uint16_t handle, esp_err_t error)
void unsubscribe_api_connection(api::APIConnection *api_connection)
BluetoothConnection * get_connection_(uint64_t address, bool reserve)
void bluetooth_gatt_read_descriptor(const api::BluetoothGATTReadDescriptorRequest &msg)
void bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg)
std::vector< BluetoothConnection * > connections_
void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg)
static void uint64_to_bd_addr(uint64_t address, esp_bd_addr_t bd_addr)
void send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device)
void add_scanner_state_callback(std::function< void(ScannerState)> &&callback)
esp_ble_addr_type_t get_address_type() const
const std::vector< ServiceData > & get_service_datas() const
const std::vector< ServiceData > & get_manufacturer_datas() const
const std::vector< ESPBTUUID > & get_service_uuids() const
bool state
Definition fan.h:0
@ BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR
Definition api_pb2.h:169
@ BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE
Definition api_pb2.h:170
@ BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT
Definition api_pb2.h:166
@ BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR
Definition api_pb2.h:168
@ BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE
Definition api_pb2.h:171
@ BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE
Definition api_pb2.h:172
@ BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT
Definition api_pb2.h:167
@ BLUETOOTH_SCANNER_MODE_PASSIVE
Definition api_pb2.h:183
@ BLUETOOTH_SCANNER_MODE_ACTIVE
Definition api_pb2.h:184
APIServer * global_api_server
std::vector< uint64_t > get_128bit_uuid_vec(esp_bt_uuid_t uuid_source)
BluetoothProxy * global_bluetooth_proxy
uint64_t ble_addr_to_uint64(const esp_bd_addr_t address)
Definition ble.cpp:467
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
Application App
Global storage of Application pointer - only one Application can exist.
uint16_t length
Definition tt21100.cpp:0