ESPHome  2024.12.2
ble.cpp
Go to the documentation of this file.
1 #ifdef USE_ESP32
2 
3 #include "ble.h"
4 
5 #ifdef USE_ESP32_VARIANT_ESP32C6
6 #include "const_esp32c6.h"
7 #endif // USE_ESP32_VARIANT_ESP32C6
8 
10 #include "esphome/core/log.h"
11 
12 #include <esp_bt.h>
13 #include <esp_bt_device.h>
14 #include <esp_bt_main.h>
15 #include <esp_gap_ble_api.h>
16 #include <freertos/FreeRTOS.h>
17 #include <freertos/FreeRTOSConfig.h>
18 #include <freertos/task.h>
19 #include <nvs_flash.h>
20 
21 #ifdef USE_ARDUINO
22 #include <esp32-hal-bt.h>
23 #endif
24 
25 namespace esphome {
26 namespace esp32_ble {
27 
28 static const char *const TAG = "esp32_ble";
29 
30 static RAMAllocator<BLEEvent> EVENT_ALLOCATOR( // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
32 
34  global_ble = this;
35  ESP_LOGCONFIG(TAG, "Setting up BLE...");
36 
37  if (!ble_pre_setup_()) {
38  ESP_LOGE(TAG, "BLE could not be prepared for configuration");
39  this->mark_failed();
40  return;
41  }
42 
44  if (this->enable_on_boot_) {
45  this->enable();
46  }
47 }
48 
51  return;
52 
54 }
55 
58  return;
59 
61 }
62 
64 
66  this->advertising_init_();
67  if (!this->is_active())
68  return;
69  this->advertising_->start();
70 }
71 
72 void ESP32BLE::advertising_set_service_data(const std::vector<uint8_t> &data) {
73  this->advertising_init_();
74  this->advertising_->set_service_data(data);
75  this->advertising_start();
76 }
77 
78 void ESP32BLE::advertising_set_manufacturer_data(const std::vector<uint8_t> &data) {
79  this->advertising_init_();
81  this->advertising_start();
82 }
83 
84 void ESP32BLE::advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback) {
85  this->advertising_init_();
86  this->advertising_->register_raw_advertisement_callback(std::move(callback));
87 }
88 
90  this->advertising_init_();
91  this->advertising_->add_service_uuid(uuid);
92  this->advertising_start();
93 }
94 
96  this->advertising_init_();
97  this->advertising_->remove_service_uuid(uuid);
98  this->advertising_start();
99 }
100 
102  esp_err_t err = nvs_flash_init();
103  if (err != ESP_OK) {
104  ESP_LOGE(TAG, "nvs_flash_init failed: %d", err);
105  return false;
106  }
107  return true;
108 }
109 
111  if (this->advertising_ != nullptr)
112  return;
113  this->advertising_ = new BLEAdvertising(this->advertising_cycle_time_); // NOLINT(cppcoreguidelines-owning-memory)
114 
115  this->advertising_->set_scan_response(true);
117 }
118 
120  esp_err_t err;
121 #ifdef USE_ARDUINO
122  if (!btStart()) {
123  ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status());
124  return false;
125  }
126 #else
127  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
128  // start bt controller
129  if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
130 #ifdef USE_ESP32_VARIANT_ESP32C6
131  esp_bt_controller_config_t cfg = BT_CONTROLLER_CONFIG;
132 #else
133  esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
134 #endif
135  err = esp_bt_controller_init(&cfg);
136  if (err != ESP_OK) {
137  ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err));
138  return false;
139  }
140  while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE)
141  ;
142  }
143  if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
144  err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
145  if (err != ESP_OK) {
146  ESP_LOGE(TAG, "esp_bt_controller_enable failed: %s", esp_err_to_name(err));
147  return false;
148  }
149  }
150  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
151  ESP_LOGE(TAG, "esp bt controller enable failed");
152  return false;
153  }
154  }
155 #endif
156 
157  esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
158 
159  err = esp_bluedroid_init();
160  if (err != ESP_OK) {
161  ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", err);
162  return false;
163  }
164  err = esp_bluedroid_enable();
165  if (err != ESP_OK) {
166  ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err);
167  return false;
168  }
169 
170  if (!this->gap_event_handlers_.empty()) {
171  err = esp_ble_gap_register_callback(ESP32BLE::gap_event_handler);
172  if (err != ESP_OK) {
173  ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", err);
174  return false;
175  }
176  }
177 
178  if (!this->gatts_event_handlers_.empty()) {
179  err = esp_ble_gatts_register_callback(ESP32BLE::gatts_event_handler);
180  if (err != ESP_OK) {
181  ESP_LOGE(TAG, "esp_ble_gatts_register_callback failed: %d", err);
182  return false;
183  }
184  }
185 
186  if (!this->gattc_event_handlers_.empty()) {
187  err = esp_ble_gattc_register_callback(ESP32BLE::gattc_event_handler);
188  if (err != ESP_OK) {
189  ESP_LOGE(TAG, "esp_ble_gattc_register_callback failed: %d", err);
190  return false;
191  }
192  }
193 
194  std::string name;
195  if (this->name_.has_value()) {
196  name = this->name_.value();
198  name += "-" + get_mac_address().substr(6);
199  }
200  } else {
201  name = App.get_name();
202  if (name.length() > 20) {
204  name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address
205  } else {
206  name = name.substr(0, 20);
207  }
208  }
209  }
210 
211  err = esp_ble_gap_set_device_name(name.c_str());
212  if (err != ESP_OK) {
213  ESP_LOGE(TAG, "esp_ble_gap_set_device_name failed: %d", err);
214  return false;
215  }
216 
217  err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &(this->io_cap_), sizeof(uint8_t));
218  if (err != ESP_OK) {
219  ESP_LOGE(TAG, "esp_ble_gap_set_security_param failed: %d", err);
220  return false;
221  }
222 
223  // BLE takes some time to be fully set up, 200ms should be more than enough
224  delay(200); // NOLINT
225 
226  return true;
227 }
228 
230  esp_err_t err = esp_bluedroid_disable();
231  if (err != ESP_OK) {
232  ESP_LOGE(TAG, "esp_bluedroid_disable failed: %d", err);
233  return false;
234  }
235  err = esp_bluedroid_deinit();
236  if (err != ESP_OK) {
237  ESP_LOGE(TAG, "esp_bluedroid_deinit failed: %d", err);
238  return false;
239  }
240 
241 #ifdef USE_ARDUINO
242  if (!btStop()) {
243  ESP_LOGE(TAG, "btStop failed: %d", esp_bt_controller_get_status());
244  return false;
245  }
246 #else
247  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
248  // stop bt controller
249  if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
250  err = esp_bt_controller_disable();
251  if (err != ESP_OK) {
252  ESP_LOGE(TAG, "esp_bt_controller_disable failed: %s", esp_err_to_name(err));
253  return false;
254  }
255  while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED)
256  ;
257  }
258  if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
259  err = esp_bt_controller_deinit();
260  if (err != ESP_OK) {
261  ESP_LOGE(TAG, "esp_bt_controller_deinit failed: %s", esp_err_to_name(err));
262  return false;
263  }
264  }
265  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
266  ESP_LOGE(TAG, "esp bt controller disable failed");
267  return false;
268  }
269  }
270 #endif
271  return true;
272 }
273 
275  switch (this->state_) {
278  return;
280  ESP_LOGD(TAG, "Disabling BLE...");
281 
282  for (auto *ble_event_handler : this->ble_status_event_handlers_) {
283  ble_event_handler->ble_before_disabled_event_handler();
284  }
285 
286  if (!ble_dismantle_()) {
287  ESP_LOGE(TAG, "BLE could not be dismantled");
288  this->mark_failed();
289  return;
290  }
292  return;
293  }
295  ESP_LOGD(TAG, "Enabling BLE...");
297 
298  if (!ble_setup_()) {
299  ESP_LOGE(TAG, "BLE could not be set up");
300  this->mark_failed();
301  return;
302  }
303 
305  return;
306  }
308  break;
309  }
310 
311  BLEEvent *ble_event = this->ble_events_.pop();
312  while (ble_event != nullptr) {
313  switch (ble_event->type_) {
314  case BLEEvent::GATTS:
315  this->real_gatts_event_handler_(ble_event->event_.gatts.gatts_event, ble_event->event_.gatts.gatts_if,
316  &ble_event->event_.gatts.gatts_param);
317  break;
318  case BLEEvent::GATTC:
319  this->real_gattc_event_handler_(ble_event->event_.gattc.gattc_event, ble_event->event_.gattc.gattc_if,
320  &ble_event->event_.gattc.gattc_param);
321  break;
322  case BLEEvent::GAP:
323  this->real_gap_event_handler_(ble_event->event_.gap.gap_event, &ble_event->event_.gap.gap_param);
324  break;
325  default:
326  break;
327  }
328  ble_event->~BLEEvent();
329  EVENT_ALLOCATOR.deallocate(ble_event, 1);
330  ble_event = this->ble_events_.pop();
331  }
332  if (this->advertising_ != nullptr) {
333  this->advertising_->loop();
334  }
335 }
336 
337 void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
338  BLEEvent *new_event = EVENT_ALLOCATOR.allocate(1);
339  if (new_event == nullptr) {
340  // Memory too fragmented to allocate new event. Can only drop it until memory comes back
341  return;
342  }
343  new (new_event) BLEEvent(event, param);
344  global_ble->ble_events_.push(new_event);
345 } // NOLINT(clang-analyzer-unix.Malloc)
346 
347 void ESP32BLE::real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
348  ESP_LOGV(TAG, "(BLE) gap_event_handler - %d", event);
349  for (auto *gap_handler : this->gap_event_handlers_) {
350  gap_handler->gap_event_handler(event, param);
351  }
352 }
353 
354 void ESP32BLE::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
355  esp_ble_gatts_cb_param_t *param) {
356  BLEEvent *new_event = EVENT_ALLOCATOR.allocate(1);
357  if (new_event == nullptr) {
358  // Memory too fragmented to allocate new event. Can only drop it until memory comes back
359  return;
360  }
361  new (new_event) BLEEvent(event, gatts_if, param);
362  global_ble->ble_events_.push(new_event);
363 } // NOLINT(clang-analyzer-unix.Malloc)
364 
365 void ESP32BLE::real_gatts_event_handler_(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
366  esp_ble_gatts_cb_param_t *param) {
367  ESP_LOGV(TAG, "(BLE) gatts_event [esp_gatt_if: %d] - %d", gatts_if, event);
368  for (auto *gatts_handler : this->gatts_event_handlers_) {
369  gatts_handler->gatts_event_handler(event, gatts_if, param);
370  }
371 }
372 
373 void ESP32BLE::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
374  esp_ble_gattc_cb_param_t *param) {
375  BLEEvent *new_event = EVENT_ALLOCATOR.allocate(1);
376  if (new_event == nullptr) {
377  // Memory too fragmented to allocate new event. Can only drop it until memory comes back
378  return;
379  }
380  new (new_event) BLEEvent(event, gattc_if, param);
381  global_ble->ble_events_.push(new_event);
382 } // NOLINT(clang-analyzer-unix.Malloc)
383 
384 void ESP32BLE::real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
385  esp_ble_gattc_cb_param_t *param) {
386  ESP_LOGV(TAG, "(BLE) gattc_event [esp_gatt_if: %d] - %d", gattc_if, event);
387  for (auto *gattc_handler : this->gattc_event_handlers_) {
388  gattc_handler->gattc_event_handler(event, gattc_if, param);
389  }
390 }
391 
393 
395  const uint8_t *mac_address = esp_bt_dev_get_address();
396  if (mac_address) {
397  const char *io_capability_s;
398  switch (this->io_cap_) {
399  case ESP_IO_CAP_OUT:
400  io_capability_s = "display_only";
401  break;
402  case ESP_IO_CAP_IO:
403  io_capability_s = "display_yes_no";
404  break;
405  case ESP_IO_CAP_IN:
406  io_capability_s = "keyboard_only";
407  break;
408  case ESP_IO_CAP_NONE:
409  io_capability_s = "none";
410  break;
411  case ESP_IO_CAP_KBDISP:
412  io_capability_s = "keyboard_display";
413  break;
414  default:
415  io_capability_s = "invalid";
416  break;
417  }
418  ESP_LOGCONFIG(TAG, "ESP32 BLE:");
419  ESP_LOGCONFIG(TAG, " MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2],
420  mac_address[3], mac_address[4], mac_address[5]);
421  ESP_LOGCONFIG(TAG, " IO Capability: %s", io_capability_s);
422  } else {
423  ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled");
424  }
425 }
426 
427 uint64_t ble_addr_to_uint64(const esp_bd_addr_t address) {
428  uint64_t u = 0;
429  u |= uint64_t(address[0] & 0xFF) << 40;
430  u |= uint64_t(address[1] & 0xFF) << 32;
431  u |= uint64_t(address[2] & 0xFF) << 24;
432  u |= uint64_t(address[3] & 0xFF) << 16;
433  u |= uint64_t(address[4] & 0xFF) << 8;
434  u |= uint64_t(address[5] & 0xFF) << 0;
435  return u;
436 }
437 
438 ESP32BLE *global_ble = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
439 
440 } // namespace esp32_ble
441 } // namespace esphome
442 
443 #endif
value_type const & value() const
Definition: optional.h:89
const char * name
Definition: stm32flash.h:78
uint64_t ble_addr_to_uint64(const esp_bd_addr_t address)
Definition: ble.cpp:427
void set_min_preferred_interval(uint16_t interval)
ESP32BLE * global_ble
Definition: ble.cpp:438
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:354
void set_service_data(const std::vector< uint8_t > &data)
struct esphome::esp32_ble::BLEEvent::@77::gap_event gap
void advertising_remove_service_uuid(ESPBTUUID uuid)
Definition: ble.cpp:95
T * allocate(size_t n)
Definition: helpers.h:690
std::vector< GAPEventHandler * > gap_event_handlers_
Definition: ble.h:124
std::vector< GATTcEventHandler * > gattc_event_handlers_
Definition: ble.h:125
struct esphome::esp32_ble::BLEEvent::@77::gattc_event gattc
bool has_value() const
Definition: optional.h:87
Queue< BLEEvent > ble_events_
Definition: ble.h:130
void set_manufacturer_data(const std::vector< uint8_t > &data)
uint32_t advertising_cycle_time_
Definition: ble.h:133
std::vector< GATTsEventHandler * > gatts_event_handlers_
Definition: ble.h:126
void register_raw_advertisement_callback(std::function< void(bool)> &&callback)
union esphome::esp32_ble::BLEEvent::@77 event_
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
Definition: ble.cpp:337
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:373
optional< std::string > name_
Definition: ble.h:135
BLEComponentState state_
Definition: ble.h:128
void real_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:384
float get_setup_priority() const override
Definition: ble.cpp:392
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Definition: helpers.cpp:723
Nothing has been initialized yet.
Definition: ble.h:44
void real_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:365
void advertising_register_raw_advertisement_callback(std::function< void(bool)> &&callback)
Definition: ble.cpp:84
void setup() override
Definition: ble.cpp:33
void advertising_set_service_data(const std::vector< uint8_t > &data)
Definition: ble.cpp:72
Application App
Global storage of Application pointer - only one Application can exist.
std::vector< BLEStatusEventHandler * > ble_status_event_handlers_
Definition: ble.h:127
enum esphome::esp32_ble::BLEEvent::ble_event_t type_
const std::string & get_name() const
Get the name of this Application set by pre_setup().
Definition: application.h:202
void remove_service_uuid(ESPBTUUID uuid)
void deallocate(T *p, size_t n)
Definition: helpers.h:709
bool is_name_add_mac_suffix_enabled() const
Definition: application.h:213
void dump_config() override
Definition: ble.cpp:394
void loop() override
Definition: ble.cpp:274
void advertising_set_manufacturer_data(const std::vector< uint8_t > &data)
Definition: ble.cpp:78
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
esp_ble_io_cap_t io_cap_
Definition: ble.h:132
void real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
Definition: ble.cpp:347
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
uint8_t address
Definition: bl0906.h:211
BLE should be disabled on next loop.
Definition: ble.h:46
struct esphome::esp32_ble::BLEEvent::@77::gatts_event gatts
BLE should be enabled on next loop.
Definition: ble.h:50
An STL allocator that uses SPI or internal RAM.
Definition: helpers.h:675
void advertising_add_service_uuid(ESPBTUUID uuid)
Definition: ble.cpp:89
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26
BLEAdvertising * advertising_
Definition: ble.h:131
void set_scan_response(bool scan_response)