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