ESPHome 2025.12.2
Loading...
Searching...
No Matches
ble.cpp
Go to the documentation of this file.
1#include "ble.h"
2
3#ifdef USE_ESP32
4
7#include "esphome/core/log.h"
8
9#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
10#include <esp_bt.h>
11#else
12extern "C" {
13#include <esp_hosted.h>
14#include <esp_hosted_misc.h>
15#include <esp_hosted_bluedroid.h>
16}
17#endif
18#include <esp_bt_device.h>
19#include <esp_bt_main.h>
20#include <esp_gap_ble_api.h>
21#include <freertos/FreeRTOS.h>
22#include <freertos/FreeRTOSConfig.h>
23#include <freertos/task.h>
24#include <nvs_flash.h>
25
26#ifdef USE_ARDUINO
27#include <esp32-hal-bt.h>
28#endif
29
31
32static const char *const TAG = "esp32_ble";
33
34// GAP event groups for deduplication across gap_event_handler and dispatch_gap_event_
35#define GAP_SCAN_COMPLETE_EVENTS \
36 case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: \
37 case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: \
38 case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT
39
40#define GAP_ADV_COMPLETE_EVENTS \
41 case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: \
42 case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: \
43 case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: \
44 case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: \
45 case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT
46
47#define GAP_SECURITY_EVENTS \
48 case ESP_GAP_BLE_AUTH_CMPL_EVT: \
49 case ESP_GAP_BLE_SEC_REQ_EVT: \
50 case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: \
51 case ESP_GAP_BLE_PASSKEY_REQ_EVT: \
52 case ESP_GAP_BLE_NC_REQ_EVT
53
55 global_ble = this;
56 if (!ble_pre_setup_()) {
57 ESP_LOGE(TAG, "BLE could not be prepared for configuration");
58 this->mark_failed();
59 return;
60 }
61
62 this->state_ = BLE_COMPONENT_STATE_DISABLED;
63 if (this->enable_on_boot_) {
64 this->enable();
65 }
66}
67
69 if (this->state_ != BLE_COMPONENT_STATE_DISABLED)
70 return;
71
72 this->state_ = BLE_COMPONENT_STATE_ENABLE;
73}
74
76 if (this->state_ == BLE_COMPONENT_STATE_DISABLED)
77 return;
78
79 this->state_ = BLE_COMPONENT_STATE_DISABLE;
80}
81
82bool ESP32BLE::is_active() { return this->state_ == BLE_COMPONENT_STATE_ACTIVE; }
83
84#ifdef USE_ESP32_BLE_ADVERTISING
86 this->advertising_init_();
87 if (!this->is_active())
88 return;
89 this->advertising_->start();
90}
91
92void ESP32BLE::advertising_set_service_data(const std::vector<uint8_t> &data) {
93 this->advertising_init_();
94 this->advertising_->set_service_data(data);
95 this->advertising_start();
96}
97
98void ESP32BLE::advertising_set_manufacturer_data(const std::vector<uint8_t> &data) {
99 this->advertising_init_();
100 this->advertising_->set_manufacturer_data(data);
101 this->advertising_start();
102}
103
104void ESP32BLE::advertising_set_service_data_and_name(std::span<const uint8_t> data, bool include_name) {
105 // This method atomically updates both service data and device name inclusion in BLE advertising.
106 // When include_name is true, the device name is included in the advertising packet making it
107 // visible to passive BLE scanners. When false, the name is only visible in scan response
108 // (requires active scanning). This atomic operation ensures we only restart advertising once
109 // when changing both properties, avoiding the brief gap that would occur with separate calls.
110
111 this->advertising_init_();
112
113 if (include_name) {
114 // When including name, clear service data first to avoid packet overflow
115 this->advertising_->set_service_data(std::span<const uint8_t>{});
116 this->advertising_->set_include_name(true);
117 } else {
118 // When including service data, clear name first to avoid packet overflow
119 this->advertising_->set_include_name(false);
120 this->advertising_->set_service_data(data);
121 }
122
123 this->advertising_start();
124}
125
126void ESP32BLE::advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback) {
127 this->advertising_init_();
128 this->advertising_->register_raw_advertisement_callback(std::move(callback));
129}
130
132 this->advertising_init_();
133 this->advertising_->add_service_uuid(uuid);
134 this->advertising_start();
135}
136
138 this->advertising_init_();
139 this->advertising_->remove_service_uuid(uuid);
140 this->advertising_start();
141}
142#endif
143
145 esp_err_t err = nvs_flash_init();
146 if (err != ESP_OK) {
147 ESP_LOGE(TAG, "nvs_flash_init failed: %d", err);
148 return false;
149 }
150 return true;
151}
152
153#ifdef USE_ESP32_BLE_ADVERTISING
155 if (this->advertising_ != nullptr)
156 return;
157 this->advertising_ = new BLEAdvertising(this->advertising_cycle_time_); // NOLINT(cppcoreguidelines-owning-memory)
158
159 this->advertising_->set_scan_response(true);
160 this->advertising_->set_min_preferred_interval(0x06);
161 this->advertising_->set_appearance(this->appearance_);
162}
163#endif
164
166 esp_err_t err;
167#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
168#ifdef USE_ARDUINO
169 if (!btStart()) {
170 ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status());
171 return false;
172 }
173#else
174 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
175 // start bt controller
176 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
177 esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
178 err = esp_bt_controller_init(&cfg);
179 if (err != ESP_OK) {
180 ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err));
181 return false;
182 }
183 while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE)
184 ;
185 }
186 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
187 err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
188 if (err != ESP_OK) {
189 ESP_LOGE(TAG, "esp_bt_controller_enable failed: %s", esp_err_to_name(err));
190 return false;
191 }
192 }
193 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
194 ESP_LOGE(TAG, "esp bt controller enable failed");
195 return false;
196 }
197 }
198#endif
199
200 esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
201#else
202 esp_hosted_connect_to_slave(); // NOLINT
203
204 if (esp_hosted_bt_controller_init() != ESP_OK) {
205 ESP_LOGW(TAG, "esp_hosted_bt_controller_init failed");
206 return false;
207 }
208
209 if (esp_hosted_bt_controller_enable() != ESP_OK) {
210 ESP_LOGW(TAG, "esp_hosted_bt_controller_enable failed");
211 return false;
212 }
213
214 hosted_hci_bluedroid_open();
215
216 esp_bluedroid_hci_driver_operations_t operations = {
217 .send = hosted_hci_bluedroid_send,
218 .check_send_available = hosted_hci_bluedroid_check_send_available,
219 .register_host_callback = hosted_hci_bluedroid_register_host_callback,
220 };
221 esp_bluedroid_attach_hci_driver(&operations);
222#endif
223
224 err = esp_bluedroid_init();
225 if (err != ESP_OK) {
226 ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", err);
227 return false;
228 }
229 err = esp_bluedroid_enable();
230 if (err != ESP_OK) {
231 ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err);
232 return false;
233 }
234
235#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT
236 err = esp_ble_gap_register_callback(ESP32BLE::gap_event_handler);
237 if (err != ESP_OK) {
238 ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", err);
239 return false;
240 }
241#endif
242
243#if defined(USE_ESP32_BLE_SERVER) && defined(ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT)
244 err = esp_ble_gatts_register_callback(ESP32BLE::gatts_event_handler);
245 if (err != ESP_OK) {
246 ESP_LOGE(TAG, "esp_ble_gatts_register_callback failed: %d", err);
247 return false;
248 }
249#endif
250
251#if defined(USE_ESP32_BLE_CLIENT) && defined(ESPHOME_ESP32_BLE_GATTC_EVENT_HANDLER_COUNT)
252 err = esp_ble_gattc_register_callback(ESP32BLE::gattc_event_handler);
253 if (err != ESP_OK) {
254 ESP_LOGE(TAG, "esp_ble_gattc_register_callback failed: %d", err);
255 return false;
256 }
257#endif
258
259 const char *device_name;
260 std::string name_with_suffix;
261
262 if (this->name_ != nullptr) {
264 // MAC address length: 12 hex chars + null terminator
265 constexpr size_t mac_address_len = 13;
266 // MAC address suffix length (last 6 characters of 12-char MAC address string)
267 constexpr size_t mac_address_suffix_len = 6;
268 char mac_addr[mac_address_len];
270 const char *mac_suffix_ptr = mac_addr + mac_address_suffix_len;
271 name_with_suffix =
272 make_name_with_suffix(this->name_, strlen(this->name_), '-', mac_suffix_ptr, mac_address_suffix_len);
273 device_name = name_with_suffix.c_str();
274 } else {
275 device_name = this->name_;
276 }
277 } else {
278 name_with_suffix = App.get_name();
279 if (name_with_suffix.length() > 20) {
281 // Keep first 13 chars and last 7 chars (MAC suffix), remove middle
282 name_with_suffix.erase(13, name_with_suffix.length() - 20);
283 } else {
284 name_with_suffix.resize(20);
285 }
286 }
287 device_name = name_with_suffix.c_str();
288 }
289
290 err = esp_ble_gap_set_device_name(device_name);
291 if (err != ESP_OK) {
292 ESP_LOGE(TAG, "esp_ble_gap_set_device_name failed: %d", err);
293 return false;
294 }
295
296 err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &(this->io_cap_), sizeof(uint8_t));
297 if (err != ESP_OK) {
298 ESP_LOGE(TAG, "esp_ble_gap_set_security_param failed: %d", err);
299 return false;
300 }
301
302 // BLE takes some time to be fully set up, 200ms should be more than enough
303 delay(200); // NOLINT
304
305 return true;
306}
307
309 esp_err_t err = esp_bluedroid_disable();
310 if (err != ESP_OK) {
311 // ESP_ERR_INVALID_STATE means Bluedroid is already disabled, which is fine
312 if (err != ESP_ERR_INVALID_STATE) {
313 ESP_LOGE(TAG, "esp_bluedroid_disable failed: %d", err);
314 return false;
315 }
316 ESP_LOGD(TAG, "Already disabled");
317 }
318 err = esp_bluedroid_deinit();
319 if (err != ESP_OK) {
320 // ESP_ERR_INVALID_STATE means Bluedroid is already deinitialized, which is fine
321 if (err != ESP_ERR_INVALID_STATE) {
322 ESP_LOGE(TAG, "esp_bluedroid_deinit failed: %d", err);
323 return false;
324 }
325 ESP_LOGD(TAG, "Already deinitialized");
326 }
327
328#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
329#ifdef USE_ARDUINO
330 if (!btStop()) {
331 ESP_LOGE(TAG, "btStop failed: %d", esp_bt_controller_get_status());
332 return false;
333 }
334#else
335 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
336 // stop bt controller
337 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
338 err = esp_bt_controller_disable();
339 if (err != ESP_OK) {
340 ESP_LOGE(TAG, "esp_bt_controller_disable failed: %s", esp_err_to_name(err));
341 return false;
342 }
343 while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED)
344 ;
345 }
346 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
347 err = esp_bt_controller_deinit();
348 if (err != ESP_OK) {
349 ESP_LOGE(TAG, "esp_bt_controller_deinit failed: %s", esp_err_to_name(err));
350 return false;
351 }
352 }
353 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
354 ESP_LOGE(TAG, "esp bt controller disable failed");
355 return false;
356 }
357 }
358#endif
359#else
360 if (esp_hosted_bt_controller_disable() != ESP_OK) {
361 ESP_LOGW(TAG, "esp_hosted_bt_controller_disable failed");
362 return false;
363 }
364
365 if (esp_hosted_bt_controller_deinit(false) != ESP_OK) {
366 ESP_LOGW(TAG, "esp_hosted_bt_controller_deinit failed");
367 return false;
368 }
369
370 hosted_hci_bluedroid_close();
371#endif
372 return true;
373}
374
376 switch (this->state_) {
379 return;
381 ESP_LOGD(TAG, "Disabling");
382
383#ifdef ESPHOME_ESP32_BLE_BLE_STATUS_EVENT_HANDLER_COUNT
384 for (auto *ble_event_handler : this->ble_status_event_handlers_) {
385 ble_event_handler->ble_before_disabled_event_handler();
386 }
387#endif
388
389 if (!ble_dismantle_()) {
390 ESP_LOGE(TAG, "Could not be dismantled");
391 this->mark_failed();
392 return;
393 }
394 this->state_ = BLE_COMPONENT_STATE_DISABLED;
395 return;
396 }
398 ESP_LOGD(TAG, "Enabling");
399 this->state_ = BLE_COMPONENT_STATE_OFF;
400
401 if (!ble_setup_()) {
402 ESP_LOGE(TAG, "Could not be set up");
403 this->mark_failed();
404 return;
405 }
406
407 this->state_ = BLE_COMPONENT_STATE_ACTIVE;
408 return;
409 }
411 break;
412 }
413
414 BLEEvent *ble_event = this->ble_events_.pop();
415 while (ble_event != nullptr) {
416 switch (ble_event->type_) {
417#if defined(USE_ESP32_BLE_SERVER) && defined(ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT)
418 case BLEEvent::GATTS: {
419 esp_gatts_cb_event_t event = ble_event->event_.gatts.gatts_event;
420 esp_gatt_if_t gatts_if = ble_event->event_.gatts.gatts_if;
421 esp_ble_gatts_cb_param_t *param = &ble_event->event_.gatts.gatts_param;
422 ESP_LOGV(TAG, "gatts_event [esp_gatt_if: %d] - %d", gatts_if, event);
423 for (auto *gatts_handler : this->gatts_event_handlers_) {
424 gatts_handler->gatts_event_handler(event, gatts_if, param);
425 }
426 break;
427 }
428#endif
429#if defined(USE_ESP32_BLE_CLIENT) && defined(ESPHOME_ESP32_BLE_GATTC_EVENT_HANDLER_COUNT)
430 case BLEEvent::GATTC: {
431 esp_gattc_cb_event_t event = ble_event->event_.gattc.gattc_event;
432 esp_gatt_if_t gattc_if = ble_event->event_.gattc.gattc_if;
433 esp_ble_gattc_cb_param_t *param = &ble_event->event_.gattc.gattc_param;
434 ESP_LOGV(TAG, "gattc_event [esp_gatt_if: %d] - %d", gattc_if, event);
435 for (auto *gattc_handler : this->gattc_event_handlers_) {
436 gattc_handler->gattc_event_handler(event, gattc_if, param);
437 }
438 break;
439 }
440#endif
441 case BLEEvent::GAP: {
442 esp_gap_ble_cb_event_t gap_event = ble_event->event_.gap.gap_event;
443 switch (gap_event) {
444 case ESP_GAP_BLE_SCAN_RESULT_EVT:
445#ifdef ESPHOME_ESP32_BLE_GAP_SCAN_EVENT_HANDLER_COUNT
446 // Use the new scan event handler - no memcpy!
447 for (auto *scan_handler : this->gap_scan_event_handlers_) {
448 scan_handler->gap_scan_event_handler(ble_event->scan_result());
449 }
450#endif
451 break;
452
453 // Scan complete events
454 GAP_SCAN_COMPLETE_EVENTS:
455 // Advertising complete events
456 GAP_ADV_COMPLETE_EVENTS:
457 // RSSI complete event
458 case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
459 // Security events
460 GAP_SECURITY_EVENTS:
461 ESP_LOGV(TAG, "gap_event_handler - %d", gap_event);
462#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT
463 {
464 esp_ble_gap_cb_param_t *param;
465 // clang-format off
466 switch (gap_event) {
467 // All three scan complete events have the same structure with just status
468 // The scan_complete struct matches ESP-IDF's layout exactly, so this reinterpret_cast is safe
469 // This is verified at compile-time by static_assert checks in ble_event.h
470 // The struct already contains our copy of the status (copied in BLEEvent constructor)
471 GAP_SCAN_COMPLETE_EVENTS:
472 param = reinterpret_cast<esp_ble_gap_cb_param_t *>(&ble_event->event_.gap.scan_complete);
473 break;
474
475 // All advertising complete events have the same structure with just status
476 GAP_ADV_COMPLETE_EVENTS:
477 param = reinterpret_cast<esp_ble_gap_cb_param_t *>(&ble_event->event_.gap.adv_complete);
478 break;
479
480 case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
481 param = reinterpret_cast<esp_ble_gap_cb_param_t *>(&ble_event->event_.gap.read_rssi_complete);
482 break;
483
484 GAP_SECURITY_EVENTS:
485 param = reinterpret_cast<esp_ble_gap_cb_param_t *>(&ble_event->event_.gap.security);
486 break;
487
488 default:
489 break;
490 }
491 // clang-format on
492 // Dispatch to all registered handlers
493 for (auto *gap_handler : this->gap_event_handlers_) {
494 gap_handler->gap_event_handler(gap_event, param);
495 }
496 }
497#endif
498 break;
499
500 default:
501 // Unknown/unhandled event
502 ESP_LOGW(TAG, "Unhandled GAP event type in loop: %d", gap_event);
503 break;
504 }
505 break;
506 }
507 default:
508 break;
509 }
510 // Return the event to the pool
511 this->ble_event_pool_.release(ble_event);
512 ble_event = this->ble_events_.pop();
513 }
514#ifdef USE_ESP32_BLE_ADVERTISING
515 if (this->advertising_ != nullptr) {
516 this->advertising_->loop();
517 }
518#endif
519
520 // Log dropped events periodically
521 uint16_t dropped = this->ble_events_.get_and_reset_dropped_count();
522 if (dropped > 0) {
523 ESP_LOGW(TAG, "Dropped %u BLE events due to buffer overflow", dropped);
524 }
525}
526
527// Helper function to load new event data based on type
528void load_ble_event(BLEEvent *event, esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
529 event->load_gap_event(e, p);
530}
531
532#ifdef USE_ESP32_BLE_CLIENT
533void load_ble_event(BLEEvent *event, esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
534 event->load_gattc_event(e, i, p);
535}
536#endif
537
538#ifdef USE_ESP32_BLE_SERVER
539void load_ble_event(BLEEvent *event, esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
540 event->load_gatts_event(e, i, p);
541}
542#endif
543
544template<typename... Args> void enqueue_ble_event(Args... args) {
545 // Allocate an event from the pool
546 BLEEvent *event = global_ble->ble_event_pool_.allocate();
547 if (event == nullptr) {
548 // No events available - queue is full or we're out of memory
549 global_ble->ble_events_.increment_dropped_count();
550 return;
551 }
552
553 // Load new event data (replaces previous event)
554 load_ble_event(event, args...);
555
556 // Push the event to the queue
557 global_ble->ble_events_.push(event);
558 // Push always succeeds because we're the only producer and the pool ensures we never exceed queue size
559}
560
561// Explicit template instantiations for the friend function
562template void enqueue_ble_event(esp_gap_ble_cb_event_t, esp_ble_gap_cb_param_t *);
563#ifdef USE_ESP32_BLE_SERVER
564template void enqueue_ble_event(esp_gatts_cb_event_t, esp_gatt_if_t, esp_ble_gatts_cb_param_t *);
565#endif
566#ifdef USE_ESP32_BLE_CLIENT
567template void enqueue_ble_event(esp_gattc_cb_event_t, esp_gatt_if_t, esp_ble_gattc_cb_param_t *);
568#endif
569
570void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
571 switch (event) {
572 // Queue GAP events that components need to handle
573 // Scanning events - used by esp32_ble_tracker
574 case ESP_GAP_BLE_SCAN_RESULT_EVT:
575 GAP_SCAN_COMPLETE_EVENTS:
576 // Advertising events - used by esp32_ble_beacon and esp32_ble server
577 GAP_ADV_COMPLETE_EVENTS:
578 // Connection events - used by ble_client
579 case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
580 enqueue_ble_event(event, param);
581 return;
582
583 // Security events - used by ble_client and bluetooth_proxy
584 // These are rare but interactive (pairing/bonding), so notify immediately
585 GAP_SECURITY_EVENTS:
586 enqueue_ble_event(event, param);
587 // Wake up main loop to process security event immediately
588#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
590#endif
591 return;
592
593 // Ignore these GAP events as they are not relevant for our use case
594 case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
595 case ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT:
596 case ESP_GAP_BLE_PHY_UPDATE_COMPLETE_EVT: // BLE 5.0 PHY update complete
597 case ESP_GAP_BLE_CHANNEL_SELECT_ALGORITHM_EVT: // BLE 5.0 channel selection algorithm
598 return;
599
600 default:
601 break;
602 }
603 ESP_LOGW(TAG, "Ignoring unexpected GAP event type: %d", event);
604}
605
606#ifdef USE_ESP32_BLE_SERVER
607void ESP32BLE::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
608 esp_ble_gatts_cb_param_t *param) {
609 enqueue_ble_event(event, gatts_if, param);
610 // Wake up main loop to process GATT event immediately
611#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
613#endif
614}
615#endif
616
617#ifdef USE_ESP32_BLE_CLIENT
618void ESP32BLE::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
619 esp_ble_gattc_cb_param_t *param) {
620 enqueue_ble_event(event, gattc_if, param);
621 // Wake up main loop to process GATT event immediately
622#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
624#endif
625}
626#endif
627
629
631 const uint8_t *mac_address = esp_bt_dev_get_address();
632 if (mac_address) {
633 const char *io_capability_s;
634 switch (this->io_cap_) {
635 case ESP_IO_CAP_OUT:
636 io_capability_s = "display_only";
637 break;
638 case ESP_IO_CAP_IO:
639 io_capability_s = "display_yes_no";
640 break;
641 case ESP_IO_CAP_IN:
642 io_capability_s = "keyboard_only";
643 break;
644 case ESP_IO_CAP_NONE:
645 io_capability_s = "none";
646 break;
647 case ESP_IO_CAP_KBDISP:
648 io_capability_s = "keyboard_display";
649 break;
650 default:
651 io_capability_s = "invalid";
652 break;
653 }
654 char mac_s[18];
655 format_mac_addr_upper(mac_address, mac_s);
656 ESP_LOGCONFIG(TAG,
657 "BLE:\n"
658 " MAC address: %s\n"
659 " IO Capability: %s",
660 mac_s, io_capability_s);
661 } else {
662 ESP_LOGCONFIG(TAG, "Bluetooth stack is not enabled");
663 }
664}
665
666uint64_t ble_addr_to_uint64(const esp_bd_addr_t address) {
667 uint64_t u = 0;
668 u |= uint64_t(address[0] & 0xFF) << 40;
669 u |= uint64_t(address[1] & 0xFF) << 32;
670 u |= uint64_t(address[2] & 0xFF) << 24;
671 u |= uint64_t(address[3] & 0xFF) << 16;
672 u |= uint64_t(address[4] & 0xFF) << 8;
673 u |= uint64_t(address[5] & 0xFF) << 0;
674 return u;
675}
676
677ESP32BLE *global_ble = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
678
679} // namespace esphome::esp32_ble
680
681#endif
uint8_t address
Definition bl0906.h:4
void wake_loop_threadsafe()
Wake the main event loop from a FreeRTOS task Thread-safe, can be called from task context to immedia...
bool is_name_add_mac_suffix_enabled() const
const std::string & get_name() const
Get the name of this Application set by pre_setup().
virtual void mark_failed()
Mark this component as failed.
void set_manufacturer_data(const std::vector< uint8_t > &data)
void set_scan_response(bool scan_response)
void set_include_name(bool include_name)
void set_min_preferred_interval(uint16_t interval)
void set_service_data(const std::vector< uint8_t > &data)
void register_raw_advertisement_callback(std::function< void(bool)> &&callback)
void set_appearance(uint16_t appearance)
union esphome::esp32_ble::BLEEvent::@78 event_
struct esphome::esp32_ble::BLEEvent::@78::gatts_event gatts
struct esphome::esp32_ble::BLEEvent::@78::gap_event gap
struct esphome::esp32_ble::BLEEvent::@78::gattc_event gattc
void advertising_set_manufacturer_data(const std::vector< uint8_t > &data)
Definition ble.cpp:98
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
Definition ble.cpp:570
static void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
Definition ble.cpp:618
friend void enqueue_ble_event(Args... args)
Definition ble.cpp:544
void advertising_register_raw_advertisement_callback(std::function< void(bool)> &&callback)
Definition ble.cpp:126
void advertising_set_service_data_and_name(std::span< const uint8_t > data, bool include_name)
Definition ble.cpp:104
void advertising_add_service_uuid(ESPBTUUID uuid)
Definition ble.cpp:131
void dump_config() override
Definition ble.cpp:630
void loop() override
Definition ble.cpp:375
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
Definition ble.cpp:607
void advertising_set_service_data(const std::vector< uint8_t > &data)
Definition ble.cpp:92
float get_setup_priority() const override
Definition ble.cpp:628
void setup() override
Definition ble.cpp:54
void advertising_remove_service_uuid(ESPBTUUID uuid)
Definition ble.cpp:137
ESP32BLE * global_ble
Definition ble.cpp:677
void load_ble_event(BLEEvent *event, esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p)
Definition ble.cpp:528
@ BLE_COMPONENT_STATE_DISABLE
BLE should be disabled on next loop.
Definition ble.h:59
@ BLE_COMPONENT_STATE_OFF
Nothing has been initialized yet.
Definition ble.h:57
@ BLE_COMPONENT_STATE_ENABLE
BLE should be enabled on next loop.
Definition ble.h:63
@ BLE_COMPONENT_STATE_DISABLED
BLE is disabled.
Definition ble.h:61
@ BLE_COMPONENT_STATE_ACTIVE
BLE is active.
Definition ble.h:65
uint64_t ble_addr_to_uint64(const esp_bd_addr_t address)
Definition ble.cpp:666
void enqueue_ble_event(Args... args)
Definition ble.cpp:544
void format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase)
Definition helpers.h:635
void get_mac_address_into_buffer(std::span< char, MAC_ADDRESS_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in lowercase hex notation.
Definition helpers.cpp:663
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:31
Application App
Global storage of Application pointer - only one Application can exist.
std::string make_name_with_suffix(const char *name, size_t name_len, char sep, const char *suffix_ptr, size_t suffix_len)
Optimized string concatenation: name + separator + suffix (const char* overload) Uses a fixed stack b...
Definition helpers.cpp:241