10#ifndef CONFIG_BT_CONTROLLER_DISABLED
16#include <esp_hosted.h>
18#include <eh_host_bt.h>
19#include <esp_hosted_bt_host_stack.h>
21#include <esp_bt_device.h>
22#include <esp_bt_main.h>
23#include <esp_gap_ble_api.h>
24#include <freertos/FreeRTOS.h>
25#include <freertos/FreeRTOSConfig.h>
26#include <freertos/task.h>
38#ifdef CONFIG_BT_CONTROLLER_DISABLED
49static constexpr uint32_t HOSTED_BT_WDT_TIMEOUT_MS = 60000;
53#define GAP_SCAN_COMPLETE_EVENTS \
54 case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: \
55 case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: \
56 case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT
58#define GAP_ADV_COMPLETE_EVENTS \
59 case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: \
60 case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: \
61 case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: \
62 case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: \
63 case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: \
64 case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT
66#define GAP_SECURITY_EVENTS \
67 case ESP_GAP_BLE_AUTH_CMPL_EVT: \
68 case ESP_GAP_BLE_SEC_REQ_EVT: \
69 case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: \
70 case ESP_GAP_BLE_PASSKEY_REQ_EVT: \
71 case ESP_GAP_BLE_NC_REQ_EVT
77 ESP_LOGE(TAG,
"NVS unavailable");
83 if (this->enable_on_boot_) {
107#ifdef USE_ESP32_BLE_ADVERTISING
110 this->advertising_ref_count_++;
115 if (this->advertising_ref_count_ == 0)
117 this->advertising_ref_count_--;
122 if (this->advertising_ ==
nullptr || !this->
is_active())
125 if (this->advertising_ref_count_ == 0) {
126 this->advertising_->
stop();
128 this->advertising_->
start();
184#ifdef USE_ESP32_BLE_ADVERTISING
186 if (this->advertising_ !=
nullptr)
188 this->advertising_ =
new BLEAdvertising(this->advertising_cycle_time_);
198#ifdef CONFIG_BT_CONTROLLER_DISABLED
201#ifndef CONFIG_BT_CONTROLLER_DISABLED
202 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
204 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
205 esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
206 err = esp_bt_controller_init(&cfg);
208 ESP_LOGE(TAG,
"esp_bt_controller_init failed: %s", esp_err_to_name(err));
211 while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE)
214 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
215 err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
217 ESP_LOGE(TAG,
"esp_bt_controller_enable failed: %s", esp_err_to_name(err));
221 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
222 ESP_LOGE(TAG,
"esp bt controller enable failed");
227 esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
229 if (esp_hosted_connect_to_slave() != ESP_OK) {
230 ESP_LOGE(TAG,
"Co-processor transport failed; BLE disabled");
236 esp_hosted_coprocessor_fwver_t fw_ver{};
237 if (esp_hosted_get_coprocessor_fwversion(&fw_ver) != ESP_OK) {
238 ESP_LOGE(TAG,
"Co-processor not responding; BLE disabled. Update its firmware with the esp32_hosted "
242 ESP_LOGD(TAG,
"Co-processor firmware %" PRIu32
".%" PRIu32
".%" PRIu32, fw_ver.major1, fw_ver.minor1, fw_ver.patch1);
245 err = eh_host_bt_controller_init();
246 if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
248 "BT controller init failed; co-processor firmware %" PRIu32
".%" PRIu32
".%" PRIu32
249 " may lack BT support. Update it with the esp32_hosted update component; BLE disabled",
250 fw_ver.major1, fw_ver.minor1, fw_ver.patch1);
253 err = eh_host_bt_controller_enable();
254 if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
255 ESP_LOGE(TAG,
"BT controller enable failed: %s; BLE disabled", esp_err_to_name(err));
259 esp_hosted_bt_host_stack_cfg_t bt_cfg{};
260 bt_cfg.stack = ESP_HOSTED_BT_HOST_STACK_BLUEDROID;
261 bt_cfg.bring_up_controller =
false;
262 if (esp_hosted_bt_host_stack_setup(&bt_cfg) != ESP_OK) {
263 ESP_LOGE(TAG,
"BT host stack setup failed; BLE disabled");
268 err = esp_bluedroid_init();
270 ESP_LOGE(TAG,
"esp_bluedroid_init failed: %d", err);
273 err = esp_bluedroid_enable();
275 ESP_LOGE(TAG,
"esp_bluedroid_enable failed: %d", err);
279#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT
282 ESP_LOGE(TAG,
"esp_ble_gap_register_callback failed: %d", err);
287#if defined(USE_ESP32_BLE_SERVER) && defined(ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT)
290 ESP_LOGE(TAG,
"esp_ble_gatts_register_callback failed: %d", err);
295#if defined(USE_ESP32_BLE_CLIENT) && defined(ESPHOME_ESP32_BLE_GATTC_EVENT_HANDLER_COUNT)
298 ESP_LOGE(TAG,
"esp_ble_gattc_register_callback failed: %d", err);
305 constexpr size_t ble_name_max_len = 21;
306 char name_buffer[ble_name_max_len];
307 const char *device_name;
309 if (this->name_ !=
nullptr) {
312 constexpr size_t mac_address_suffix_len = 6;
313 char mac_addr[MAC_ADDRESS_BUFFER_SIZE];
315 const char *mac_suffix_ptr = mac_addr + mac_address_suffix_len;
317 mac_address_suffix_len);
318 device_name = name_buffer;
320 device_name = this->name_;
324 truncate_name_to(name_buffer,
sizeof(name_buffer), app_name.c_str(), app_name.length(),
326 device_name = name_buffer;
329 err = esp_ble_gap_set_device_name(device_name);
331 ESP_LOGE(TAG,
"esp_ble_gap_set_device_name failed: %d", err);
335 err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &(this->io_cap_),
sizeof(esp_ble_io_cap_t));
337 ESP_LOGE(TAG,
"esp_ble_gap_set_security_param iocap_mode failed: %d", err);
341#ifdef ESPHOME_ESP32_BLE_EXTENDED_AUTH_PARAMS
342 if (this->max_key_size_) {
343 err = esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &(this->max_key_size_),
sizeof(uint8_t));
345 ESP_LOGE(TAG,
"esp_ble_gap_set_security_param max_key_size failed: %d", err);
350 if (this->min_key_size_) {
351 err = esp_ble_gap_set_security_param(ESP_BLE_SM_MIN_KEY_SIZE, &(this->min_key_size_),
sizeof(uint8_t));
353 ESP_LOGE(TAG,
"esp_ble_gap_set_security_param min_key_size failed: %d", err);
358 if (this->auth_req_mode_) {
359 err = esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &(this->auth_req_mode_.value()),
360 sizeof(esp_ble_auth_req_t));
362 ESP_LOGE(TAG,
"esp_ble_gap_set_security_param authen_req_mode failed: %d", err);
375#ifdef CONFIG_BT_CONTROLLER_DISABLED
379 esp_err_t err = esp_bluedroid_disable();
382 if (err != ESP_ERR_INVALID_STATE) {
383 ESP_LOGE(TAG,
"esp_bluedroid_disable failed: %d", err);
386 ESP_LOGD(TAG,
"Already disabled");
388 err = esp_bluedroid_deinit();
391 if (err != ESP_ERR_INVALID_STATE) {
392 ESP_LOGE(TAG,
"esp_bluedroid_deinit failed: %d", err);
395 ESP_LOGD(TAG,
"Already deinitialized");
398#ifndef CONFIG_BT_CONTROLLER_DISABLED
399 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
401 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
402 err = esp_bt_controller_disable();
404 ESP_LOGE(TAG,
"esp_bt_controller_disable failed: %s", esp_err_to_name(err));
407 while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED)
410 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
411 err = esp_bt_controller_deinit();
413 ESP_LOGE(TAG,
"esp_bt_controller_deinit failed: %s", esp_err_to_name(err));
417 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
418 ESP_LOGE(TAG,
"esp bt controller disable failed");
423 if (esp_hosted_bt_host_stack_teardown() != ESP_OK) {
424 ESP_LOGE(TAG,
"esp_hosted_bt_host_stack_teardown failed");
433 this->loop_handle_state_transition_not_active_();
437#ifdef USE_ESP32_BLE_ADVERTISING
438 if (this->advertising_ !=
nullptr) {
439 this->advertising_->
loop();
443 BLEEvent *ble_event = this->ble_events_.pop();
444 if (ble_event ==
nullptr)
448 switch (ble_event->
type_) {
449#if defined(USE_ESP32_BLE_SERVER) && defined(ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT)
451 esp_gatts_cb_event_t
event = ble_event->
event_.
gatts.gatts_event;
452 esp_gatt_if_t gatts_if = ble_event->
event_.
gatts.gatts_if;
453 esp_ble_gatts_cb_param_t *param = &ble_event->
event_.
gatts.gatts_param;
454 ESP_LOGV(TAG,
"gatts_event [esp_gatt_if: %d] - %d", gatts_if, event);
455 this->gatts_event_callbacks_.call(event, gatts_if, param);
459#if defined(USE_ESP32_BLE_CLIENT) && defined(ESPHOME_ESP32_BLE_GATTC_EVENT_HANDLER_COUNT)
461 esp_gattc_cb_event_t
event = ble_event->
event_.
gattc.gattc_event;
462 esp_gatt_if_t gattc_if = ble_event->
event_.
gattc.gattc_if;
463 esp_ble_gattc_cb_param_t *param = &ble_event->
event_.
gattc.gattc_param;
464 ESP_LOGV(TAG,
"gattc_event [esp_gatt_if: %d] - %d", gattc_if, event);
465 this->gattc_event_callbacks_.call(event, gattc_if, param);
470 esp_gap_ble_cb_event_t gap_event = ble_event->
event_.
gap.gap_event;
472 case ESP_GAP_BLE_SCAN_RESULT_EVT:
473#ifdef ESPHOME_ESP32_BLE_GAP_SCAN_EVENT_HANDLER_COUNT
474 this->gap_scan_event_callbacks_.call(ble_event->
scan_result());
479 GAP_SCAN_COMPLETE_EVENTS:
481 GAP_ADV_COMPLETE_EVENTS:
483 case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
486 ESP_LOGV(TAG,
"gap_event_handler - %d", gap_event);
487#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT
489 esp_ble_gap_cb_param_t *param = NULL;
496 GAP_SCAN_COMPLETE_EVENTS:
497 param =
reinterpret_cast<esp_ble_gap_cb_param_t *
>(&ble_event->
event_.
gap.scan_complete);
501 GAP_ADV_COMPLETE_EVENTS:
502 param =
reinterpret_cast<esp_ble_gap_cb_param_t *
>(&ble_event->
event_.
gap.adv_complete);
505 case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
506 param =
reinterpret_cast<esp_ble_gap_cb_param_t *
>(&ble_event->
event_.
gap.read_rssi_complete);
510 param =
reinterpret_cast<esp_ble_gap_cb_param_t *
>(&ble_event->
event_.
gap.security);
518 this->gap_event_callbacks_.call(gap_event, param);
525 ESP_LOGW(TAG,
"Unhandled GAP event type in loop: %d", gap_event);
534 this->ble_event_pool_.release(ble_event);
535 }
while ((ble_event = this->ble_events_.pop()) !=
nullptr);
540 uint16_t dropped = this->ble_events_.get_and_reset_dropped_count();
542 ESP_LOGW(TAG,
"Dropped %u BLE events due to buffer overflow", dropped);
546void ESP32BLE::loop_handle_state_transition_not_active_() {
549 ESP_LOGD(TAG,
"Disabling");
551#ifdef ESPHOME_ESP32_BLE_BLE_STATUS_EVENT_HANDLER_COUNT
552 this->ble_status_event_callbacks_.call();
556 ESP_LOGE(TAG,
"Could not be dismantled");
566 ESP_LOGD(TAG,
"Enabling");
570 ESP_LOGE(TAG,
"Could not be set up");
576#ifdef USE_ESP32_BLE_ADVERTISING
585 event->load_gap_event(e, p);
588#ifdef USE_ESP32_BLE_CLIENT
590 event->load_gattc_event(e, i, p);
594#ifdef USE_ESP32_BLE_SERVER
596 event->load_gatts_event(e, i, p);
603 if (event ==
nullptr) {
605 global_ble->ble_events_.increment_dropped_count();
620#ifdef USE_ESP32_BLE_SERVER
621template void enqueue_ble_event(esp_gatts_cb_event_t, esp_gatt_if_t, esp_ble_gatts_cb_param_t *);
623#ifdef USE_ESP32_BLE_CLIENT
624template void enqueue_ble_event(esp_gattc_cb_event_t, esp_gatt_if_t, esp_ble_gattc_cb_param_t *);
631 case ESP_GAP_BLE_SCAN_RESULT_EVT:
632 GAP_SCAN_COMPLETE_EVENTS:
634 GAP_ADV_COMPLETE_EVENTS:
636 case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
651 case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: {
652 if (param->update_conn_params.status != ESP_BT_STATUS_SUCCESS) {
653 char mac_s[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
655 ESP_LOGW(TAG,
"[%s] Conn param update failed, status=%d", mac_s, param->update_conn_params.status);
657#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
659 char mac_s[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
661 ESP_LOGV(TAG,
"[%s] Conn params updated: interval=%u (x1.25ms) latency=%u timeout=%u (x10ms)", mac_s,
662 param->update_conn_params.conn_int, param->update_conn_params.latency,
663 param->update_conn_params.timeout);
670 case ESP_GAP_BLE_KEY_EVT:
671 case ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT:
672 case ESP_GAP_BLE_PHY_UPDATE_COMPLETE_EVT:
673 case ESP_GAP_BLE_CHANNEL_SELECT_ALGORITHM_EVT:
674 case ESP_GAP_BLE_LOCAL_IR_EVT:
675 case ESP_GAP_BLE_LOCAL_ER_EVT:
681 ESP_LOGW(TAG,
"Ignoring unexpected GAP event type: %d", event);
684#ifdef USE_ESP32_BLE_SERVER
686 esp_ble_gatts_cb_param_t *param) {
693#ifdef USE_ESP32_BLE_CLIENT
695 esp_ble_gattc_cb_param_t *param) {
705 const uint8_t *mac = esp_bt_dev_get_address();
706 if (mac !=
nullptr) {
707 memcpy(
out, mac, MAC_ADDRESS_SIZE);
709 memset(
out, 0, MAC_ADDRESS_SIZE);
716 uint8_t mac_address[MAC_ADDRESS_SIZE];
719 const char *io_capability_s;
720 switch (this->io_cap_) {
722 io_capability_s =
"display_only";
725 io_capability_s =
"display_yes_no";
728 io_capability_s =
"keyboard_only";
730 case ESP_IO_CAP_NONE:
731 io_capability_s =
"none";
733 case ESP_IO_CAP_KBDISP:
734 io_capability_s =
"keyboard_display";
737 io_capability_s =
"invalid";
741 char mac_s[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
746 " IO Capability: %s",
747 mac_s, io_capability_s);
748#ifdef USE_ESP32_BLE_PSRAM
749 ESP_LOGCONFIG(TAG,
" PSRAM BLE allocation: enabled");
752#ifdef ESPHOME_ESP32_BLE_EXTENDED_AUTH_PARAMS
753 const char *auth_req_mode_s =
"<default>";
754 if (this->auth_req_mode_) {
755 switch (this->auth_req_mode_.value()) {
757 auth_req_mode_s =
"no_bond";
760 auth_req_mode_s =
"bond";
763 auth_req_mode_s =
"mitm";
766 auth_req_mode_s =
"bond_mitm";
769 auth_req_mode_s =
"sc_only";
772 auth_req_mode_s =
"sc_bond";
775 auth_req_mode_s =
"sc_mitm";
778 auth_req_mode_s =
"sc_mitm_bond";
783 ESP_LOGCONFIG(TAG,
" Auth Req Mode: %s", auth_req_mode_s);
784 if (this->max_key_size_ && this->min_key_size_) {
785 ESP_LOGCONFIG(TAG,
" Key Size: %u - %u", this->min_key_size_, this->max_key_size_);
786 }
else if (this->max_key_size_) {
787 ESP_LOGCONFIG(TAG,
" Key Size: <default> - %u", this->max_key_size_);
788 }
else if (this->min_key_size_) {
789 ESP_LOGCONFIG(TAG,
" Key Size: %u - <default>", this->min_key_size_);
794 ESP_LOGCONFIG(TAG,
"Bluetooth stack is not enabled");
const StringRef & get_name() const
Get the name of this Application set by pre_setup().
void wake_loop_threadsafe()
Wake the main event loop from another thread or callback.
bool is_name_add_mac_suffix_enabled() const
void mark_failed()
Mark this component as failed.
void set_manufacturer_data(const std::vector< uint8_t > &data)
void add_service_uuid(ESPBTUUID uuid)
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 remove_service_uuid(ESPBTUUID uuid)
void register_raw_advertisement_callback(std::function< void(bool)> &&callback)
void set_appearance(uint16_t appearance)
BLEScanResult scan_result
struct esphome::esp32_ble::BLEEvent::@79::gap_event gap
struct esphome::esp32_ble::BLEEvent::@79::gatts_event gatts
union esphome::esp32_ble::BLEEvent::@79 event_
struct esphome::esp32_ble::BLEEvent::@79::gattc_event gattc
void advertising_set_manufacturer_data(const std::vector< uint8_t > &data)
void get_mac_msb_first(uint8_t out[MAC_ADDRESS_SIZE]) const
Adapter MAC in printable (MSB-first) order; all-zero until the stack is up.
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
static void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
void advertising_start()
Request advertising on behalf of a component.
void advertising_refresh()
Apply the current payload and request count: advertise while requested, otherwise stop.
friend void enqueue_ble_event(Args... args)
void advertising_register_raw_advertisement_callback(std::function< void(bool)> &&callback)
void advertising_set_service_data_and_name(std::span< const uint8_t > data, bool include_name)
void advertising_add_service_uuid(ESPBTUUID uuid)
void dump_config() override
void request_state_(bool enable)
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
void advertising_set_service_data(const std::vector< uint8_t > &data)
ESPHOME_ALWAYS_INLINE bool is_active()
float get_setup_priority() const override
void advertising_stop()
Release a request made with advertising_start(); advertising stops at the last release.
void advertising_remove_service_uuid(ESPBTUUID uuid)
std::vector< uint8_t > & out
void load_ble_event(BLEEvent *event, esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p)
@ BLE_COMPONENT_STATE_DISABLE
BLE should be disabled on next loop.
@ BLE_COMPONENT_STATE_OFF
Nothing has been initialized yet.
@ BLE_COMPONENT_STATE_ENABLE
BLE should be enabled on next loop.
@ BLE_COMPONENT_STATE_DISABLED
BLE is disabled.
@ BLE_COMPONENT_STATE_ACTIVE
BLE is active.
void enqueue_ble_event(Args... args)
ESPHOME_LOG_TAG(TAG, "esp32_ble")
constexpr float BLUETOOTH
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)
Format name + separator + suffix directly into buffer without heap allocation.
size_t truncate_name_to(char *buffer, size_t buffer_size, const char *name, size_t name_len, size_t keep_suffix_len)
Copy a name into a buffer, cutting it when it does not fit.
bool mac_address_is_valid(const uint8_t *mac)
Check if the MAC address is not all zeros or all ones.
ESPPreferences * global_preferences
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.
void HOT delay(uint32_t ms)
Application App
Global storage of Application pointer - only one Application can exist.
char * format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase, colon separators)