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