ESPHome  2024.9.0
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 
31  global_ble = this;
32  ESP_LOGCONFIG(TAG, "Setting up BLE...");
33 
34  if (!ble_pre_setup_()) {
35  ESP_LOGE(TAG, "BLE could not be prepared for configuration");
36  this->mark_failed();
37  return;
38  }
39 
41  if (this->enable_on_boot_) {
42  this->enable();
43  }
44 }
45 
48  return;
49 
51 }
52 
55  return;
56 
58 }
59 
61 
63  this->advertising_init_();
64  if (!this->is_active())
65  return;
66  this->advertising_->start();
67 }
68 
69 void ESP32BLE::advertising_set_service_data(const std::vector<uint8_t> &data) {
70  this->advertising_init_();
71  this->advertising_->set_service_data(data);
72  this->advertising_start();
73 }
74 
75 void ESP32BLE::advertising_set_manufacturer_data(const std::vector<uint8_t> &data) {
76  this->advertising_init_();
78  this->advertising_start();
79 }
80 
81 void ESP32BLE::advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback) {
82  this->advertising_init_();
83  this->advertising_->register_raw_advertisement_callback(std::move(callback));
84 }
85 
87  this->advertising_init_();
88  this->advertising_->add_service_uuid(uuid);
89  this->advertising_start();
90 }
91 
93  this->advertising_init_();
94  this->advertising_->remove_service_uuid(uuid);
95  this->advertising_start();
96 }
97 
99  esp_err_t err = nvs_flash_init();
100  if (err != ESP_OK) {
101  ESP_LOGE(TAG, "nvs_flash_init failed: %d", err);
102  return false;
103  }
104  return true;
105 }
106 
108  if (this->advertising_ != nullptr)
109  return;
110  this->advertising_ = new BLEAdvertising(this->advertising_cycle_time_); // NOLINT(cppcoreguidelines-owning-memory)
111 
112  this->advertising_->set_scan_response(true);
114 }
115 
117  esp_err_t err;
118 #ifdef USE_ARDUINO
119  if (!btStart()) {
120  ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status());
121  return false;
122  }
123 #else
124  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
125  // start bt controller
126  if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
127 #ifdef USE_ESP32_VARIANT_ESP32C6
128  esp_bt_controller_config_t cfg = BT_CONTROLLER_CONFIG;
129 #else
130  esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
131 #endif
132  err = esp_bt_controller_init(&cfg);
133  if (err != ESP_OK) {
134  ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err));
135  return false;
136  }
137  while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE)
138  ;
139  }
140  if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
141  err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
142  if (err != ESP_OK) {
143  ESP_LOGE(TAG, "esp_bt_controller_enable failed: %s", esp_err_to_name(err));
144  return false;
145  }
146  }
147  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
148  ESP_LOGE(TAG, "esp bt controller enable failed");
149  return false;
150  }
151  }
152 #endif
153 
154  esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
155 
156  err = esp_bluedroid_init();
157  if (err != ESP_OK) {
158  ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", err);
159  return false;
160  }
161  err = esp_bluedroid_enable();
162  if (err != ESP_OK) {
163  ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err);
164  return false;
165  }
166 
167  if (!this->gap_event_handlers_.empty()) {
168  err = esp_ble_gap_register_callback(ESP32BLE::gap_event_handler);
169  if (err != ESP_OK) {
170  ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", err);
171  return false;
172  }
173  }
174 
175  if (!this->gatts_event_handlers_.empty()) {
176  err = esp_ble_gatts_register_callback(ESP32BLE::gatts_event_handler);
177  if (err != ESP_OK) {
178  ESP_LOGE(TAG, "esp_ble_gatts_register_callback failed: %d", err);
179  return false;
180  }
181  }
182 
183  if (!this->gattc_event_handlers_.empty()) {
184  err = esp_ble_gattc_register_callback(ESP32BLE::gattc_event_handler);
185  if (err != ESP_OK) {
186  ESP_LOGE(TAG, "esp_ble_gattc_register_callback failed: %d", err);
187  return false;
188  }
189  }
190 
191  std::string name = App.get_name();
192  if (name.length() > 20) {
194  name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address
195  } else {
196  name = name.substr(0, 20);
197  }
198  }
199 
200  err = esp_ble_gap_set_device_name(name.c_str());
201  if (err != ESP_OK) {
202  ESP_LOGE(TAG, "esp_ble_gap_set_device_name failed: %d", err);
203  return false;
204  }
205 
206  err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &(this->io_cap_), sizeof(uint8_t));
207  if (err != ESP_OK) {
208  ESP_LOGE(TAG, "esp_ble_gap_set_security_param failed: %d", err);
209  return false;
210  }
211 
212  // BLE takes some time to be fully set up, 200ms should be more than enough
213  delay(200); // NOLINT
214 
215  return true;
216 }
217 
219  esp_err_t err = esp_bluedroid_disable();
220  if (err != ESP_OK) {
221  ESP_LOGE(TAG, "esp_bluedroid_disable failed: %d", err);
222  return false;
223  }
224  err = esp_bluedroid_deinit();
225  if (err != ESP_OK) {
226  ESP_LOGE(TAG, "esp_bluedroid_deinit failed: %d", err);
227  return false;
228  }
229 
230 #ifdef USE_ARDUINO
231  if (!btStop()) {
232  ESP_LOGE(TAG, "btStop failed: %d", esp_bt_controller_get_status());
233  return false;
234  }
235 #else
236  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
237  // stop bt controller
238  if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
239  err = esp_bt_controller_disable();
240  if (err != ESP_OK) {
241  ESP_LOGE(TAG, "esp_bt_controller_disable failed: %s", esp_err_to_name(err));
242  return false;
243  }
244  while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED)
245  ;
246  }
247  if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
248  err = esp_bt_controller_deinit();
249  if (err != ESP_OK) {
250  ESP_LOGE(TAG, "esp_bt_controller_deinit failed: %s", esp_err_to_name(err));
251  return false;
252  }
253  }
254  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
255  ESP_LOGE(TAG, "esp bt controller disable failed");
256  return false;
257  }
258  }
259 #endif
260  return true;
261 }
262 
264  switch (this->state_) {
267  return;
269  ESP_LOGD(TAG, "Disabling BLE...");
270 
271  for (auto *ble_event_handler : this->ble_status_event_handlers_) {
272  ble_event_handler->ble_before_disabled_event_handler();
273  }
274 
275  if (!ble_dismantle_()) {
276  ESP_LOGE(TAG, "BLE could not be dismantled");
277  this->mark_failed();
278  return;
279  }
281  return;
282  }
284  ESP_LOGD(TAG, "Enabling BLE...");
286 
287  if (!ble_setup_()) {
288  ESP_LOGE(TAG, "BLE could not be set up");
289  this->mark_failed();
290  return;
291  }
292 
294  return;
295  }
297  break;
298  }
299 
300  BLEEvent *ble_event = this->ble_events_.pop();
301  while (ble_event != nullptr) {
302  switch (ble_event->type_) {
303  case BLEEvent::GATTS:
304  this->real_gatts_event_handler_(ble_event->event_.gatts.gatts_event, ble_event->event_.gatts.gatts_if,
305  &ble_event->event_.gatts.gatts_param);
306  break;
307  case BLEEvent::GATTC:
308  this->real_gattc_event_handler_(ble_event->event_.gattc.gattc_event, ble_event->event_.gattc.gattc_if,
309  &ble_event->event_.gattc.gattc_param);
310  break;
311  case BLEEvent::GAP:
312  this->real_gap_event_handler_(ble_event->event_.gap.gap_event, &ble_event->event_.gap.gap_param);
313  break;
314  default:
315  break;
316  }
317  delete ble_event; // NOLINT(cppcoreguidelines-owning-memory)
318  ble_event = this->ble_events_.pop();
319  }
320  if (this->advertising_ != nullptr) {
321  this->advertising_->loop();
322  }
323 }
324 
325 void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
326  BLEEvent *new_event = new BLEEvent(event, param); // NOLINT(cppcoreguidelines-owning-memory)
327  global_ble->ble_events_.push(new_event);
328 } // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
329 
330 void ESP32BLE::real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
331  ESP_LOGV(TAG, "(BLE) gap_event_handler - %d", event);
332  for (auto *gap_handler : this->gap_event_handlers_) {
333  gap_handler->gap_event_handler(event, param);
334  }
335 }
336 
337 void ESP32BLE::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
338  esp_ble_gatts_cb_param_t *param) {
339  BLEEvent *new_event = new BLEEvent(event, gatts_if, param); // NOLINT(cppcoreguidelines-owning-memory)
340  global_ble->ble_events_.push(new_event);
341 } // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
342 
343 void ESP32BLE::real_gatts_event_handler_(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
344  esp_ble_gatts_cb_param_t *param) {
345  ESP_LOGV(TAG, "(BLE) gatts_event [esp_gatt_if: %d] - %d", gatts_if, event);
346  for (auto *gatts_handler : this->gatts_event_handlers_) {
347  gatts_handler->gatts_event_handler(event, gatts_if, param);
348  }
349 }
350 
351 void ESP32BLE::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
352  esp_ble_gattc_cb_param_t *param) {
353  BLEEvent *new_event = new BLEEvent(event, gattc_if, param); // NOLINT(cppcoreguidelines-owning-memory)
354  global_ble->ble_events_.push(new_event);
355 } // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
356 
357 void ESP32BLE::real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
358  esp_ble_gattc_cb_param_t *param) {
359  ESP_LOGV(TAG, "(BLE) gattc_event [esp_gatt_if: %d] - %d", gattc_if, event);
360  for (auto *gattc_handler : this->gattc_event_handlers_) {
361  gattc_handler->gattc_event_handler(event, gattc_if, param);
362  }
363 }
364 
366 
368  const uint8_t *mac_address = esp_bt_dev_get_address();
369  if (mac_address) {
370  const char *io_capability_s;
371  switch (this->io_cap_) {
372  case ESP_IO_CAP_OUT:
373  io_capability_s = "display_only";
374  break;
375  case ESP_IO_CAP_IO:
376  io_capability_s = "display_yes_no";
377  break;
378  case ESP_IO_CAP_IN:
379  io_capability_s = "keyboard_only";
380  break;
381  case ESP_IO_CAP_NONE:
382  io_capability_s = "none";
383  break;
384  case ESP_IO_CAP_KBDISP:
385  io_capability_s = "keyboard_display";
386  break;
387  default:
388  io_capability_s = "invalid";
389  break;
390  }
391  ESP_LOGCONFIG(TAG, "ESP32 BLE:");
392  ESP_LOGCONFIG(TAG, " MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2],
393  mac_address[3], mac_address[4], mac_address[5]);
394  ESP_LOGCONFIG(TAG, " IO Capability: %s", io_capability_s);
395  } else {
396  ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled");
397  }
398 }
399 
400 uint64_t ble_addr_to_uint64(const esp_bd_addr_t address) {
401  uint64_t u = 0;
402  u |= uint64_t(address[0] & 0xFF) << 40;
403  u |= uint64_t(address[1] & 0xFF) << 32;
404  u |= uint64_t(address[2] & 0xFF) << 24;
405  u |= uint64_t(address[3] & 0xFF) << 16;
406  u |= uint64_t(address[4] & 0xFF) << 8;
407  u |= uint64_t(address[5] & 0xFF) << 0;
408  return u;
409 }
410 
411 ESP32BLE *global_ble = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
412 
413 } // namespace esp32_ble
414 } // namespace esphome
415 
416 #endif
const char * name
Definition: stm32flash.h:78
uint64_t ble_addr_to_uint64(const esp_bd_addr_t address)
Definition: ble.cpp:400
void set_min_preferred_interval(uint16_t interval)
ESP32BLE * global_ble
Definition: ble.cpp:411
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:337
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:92
std::vector< GAPEventHandler * > gap_event_handlers_
Definition: ble.h:123
std::vector< GATTcEventHandler * > gattc_event_handlers_
Definition: ble.h:124
struct esphome::esp32_ble::BLEEvent::@77::gattc_event gattc
Queue< BLEEvent > ble_events_
Definition: ble.h:129
void set_manufacturer_data(const std::vector< uint8_t > &data)
uint32_t advertising_cycle_time_
Definition: ble.h:132
std::vector< GATTsEventHandler * > gatts_event_handlers_
Definition: ble.h:125
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:325
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:351
BLEComponentState state_
Definition: ble.h:127
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:357
float get_setup_priority() const override
Definition: ble.cpp:365
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:343
void advertising_register_raw_advertisement_callback(std::function< void(bool)> &&callback)
Definition: ble.cpp:81
void setup() override
Definition: ble.cpp:30
void advertising_set_service_data(const std::vector< uint8_t > &data)
Definition: ble.cpp:69
Application App
Global storage of Application pointer - only one Application can exist.
std::vector< BLEStatusEventHandler * > ble_status_event_handlers_
Definition: ble.h:126
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)
bool is_name_add_mac_suffix_enabled() const
Definition: application.h:213
void dump_config() override
Definition: ble.cpp:367
void loop() override
Definition: ble.cpp:263
void advertising_set_manufacturer_data(const std::vector< uint8_t > &data)
Definition: ble.cpp:75
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
esp_ble_io_cap_t io_cap_
Definition: ble.h:131
void real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
Definition: ble.cpp:330
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
void advertising_add_service_uuid(ESPBTUUID uuid)
Definition: ble.cpp:86
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26
BLEAdvertising * advertising_
Definition: ble.h:130
void set_scan_response(bool scan_response)