10 #include <nvs_flash.h> 11 #include <freertos/FreeRTOSConfig.h> 12 #include <esp_bt_main.h> 14 #include <freertos/FreeRTOS.h> 15 #include <freertos/task.h> 16 #include <esp_gap_ble_api.h> 17 #include <esp_bt_defs.h> 24 #include <esp32-hal-bt.h> 31 namespace esp32_ble_tracker {
33 static const char *
const TAG =
"esp32_ble_tracker";
39 u |= uint64_t(address[0] & 0xFF) << 40;
40 u |= uint64_t(address[1] & 0xFF) << 32;
41 u |= uint64_t(address[2] & 0xFF) << 24;
42 u |= uint64_t(address[3] & 0xFF) << 16;
43 u |= uint64_t(address[4] & 0xFF) << 8;
44 u |= uint64_t(address[5] & 0xFF) << 0;
51 global_esp32_ble_tracker =
this;
72 ESP_LOGW(TAG,
"Cannot start scan!");
79 while (ble_event !=
nullptr) {
80 if (ble_event->
type_) {
93 int disconnecting = 0;
94 for (
auto *client : this->
clients_) {
95 switch (client->state()) {
113 bool promote_to_connecting = discovered && !searching && !connecting;
121 ESP_LOGW(TAG,
"Too many BLE events to process. Some devices may not show up.");
123 for (
size_t i = 0; i < index; i++) {
129 if (listener->parse_device(device))
133 for (
auto *client : this->clients_) {
134 if (client->parse_device(device)) {
137 promote_to_connecting =
true;
164 if (!connecting && !disconnecting && xSemaphoreTake(this->
scan_end_lock_, 0L)) {
180 ESP_LOGE(TAG,
"ESP-IDF BLE scan could not restart after 255 attempts, rebooting to restore BLE stack...");
186 ESP_LOGD(TAG,
"Stopping scan after failure...");
187 esp_ble_gap_stop_scanning();
205 if (promote_to_connecting) {
206 for (
auto *client : this->clients_) {
216 ESP_LOGD(TAG,
"Pausing scan to make connection...");
217 esp_ble_gap_stop_scanning();
230 ESP_LOGW(TAG,
"Scan requested when a scan is already in progress. Ignoring.");
235 ESP_LOGD(TAG,
"Stopping scan.");
237 esp_ble_gap_stop_scanning();
243 esp_err_t err = nvs_flash_init();
245 ESP_LOGE(TAG,
"nvs_flash_init failed: %d", err);
251 ESP_LOGE(TAG,
"btStart failed: %d", esp_bt_controller_get_status());
255 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
257 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
258 esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
259 err = esp_bt_controller_init(&cfg);
261 ESP_LOGE(TAG,
"esp_bt_controller_init failed: %s", esp_err_to_name(err));
264 while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE)
267 if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
268 err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
270 ESP_LOGE(TAG,
"esp_bt_controller_enable failed: %s", esp_err_to_name(err));
274 if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
275 ESP_LOGE(TAG,
"esp bt controller enable failed");
281 esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
283 err = esp_bluedroid_init();
285 ESP_LOGE(TAG,
"esp_bluedroid_init failed: %d", err);
288 err = esp_bluedroid_enable();
290 ESP_LOGE(TAG,
"esp_bluedroid_enable failed: %d", err);
295 ESP_LOGE(TAG,
"esp_ble_gap_register_callback failed: %d", err);
300 ESP_LOGE(TAG,
"esp_ble_gattc_register_callback failed: %d", err);
305 esp_ble_gap_set_device_name(
"");
307 esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;
308 err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap,
sizeof(uint8_t));
310 ESP_LOGE(TAG,
"esp_ble_gap_set_security_param failed: %d", err);
323 ESP_LOGE(TAG,
"start_scan called without holding scan_end_lock_");
327 ESP_LOGD(TAG,
"Starting scan...");
330 listener->on_scan_end();
335 this->
scan_params_.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
336 this->
scan_params_.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
344 ESP_LOGE(TAG,
"ESP-IDF BLE scan never terminated, rebooting to restore BLE stack...");
352 ESP_LOGE(TAG,
"end_of_scan_ called without holding the scan_end_lock_");
356 ESP_LOGD(TAG,
"End of scan.");
363 listener->on_scan_end();
373 global_esp32_ble_tracker->
ble_events_.push(gap_event);
378 case ESP_GAP_BLE_SCAN_RESULT_EVT:
381 case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
384 case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
387 case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
393 for (
auto *client : this->
clients_) {
394 client->gap_event_handler(event, param);
404 if (param.status == ESP_BT_STATUS_SUCCESS) {
417 if (param.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
424 }
else if (param.search_evt == ESP_GAP_SEARCH_INQ_CMPL_EVT) {
430 esp_ble_gattc_cb_param_t *param) {
432 global_esp32_ble_tracker->
ble_events_.push(gattc_event);
436 esp_ble_gattc_cb_param_t *param) {
437 for (
auto *client : this->
clients_) {
438 client->gattc_event_handler(event, gattc_if, param);
445 ret.
uuid_.len = ESP_UUID_LEN_16;
446 ret.
uuid_.uuid.uuid16 = uuid;
451 ret.
uuid_.len = ESP_UUID_LEN_32;
452 ret.
uuid_.uuid.uuid32 = uuid;
457 ret.
uuid_.len = ESP_UUID_LEN_128;
458 for (
size_t i = 0; i < ESP_UUID_LEN_128; i++)
459 ret.
uuid_.uuid.uuid128[i] = data[i];
464 if (data.length() == 4) {
465 ret.
uuid_.len = ESP_UUID_LEN_16;
466 ret.
uuid_.uuid.uuid16 = 0;
467 for (
int i = 0; i < data.length();) {
468 uint8_t msb = data.c_str()[i];
469 uint8_t lsb = data.c_str()[i + 1];
475 ret.
uuid_.uuid.uuid16 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << (2 - i) * 4;
478 }
else if (data.length() == 8) {
479 ret.
uuid_.len = ESP_UUID_LEN_32;
480 ret.
uuid_.uuid.uuid32 = 0;
481 for (
int i = 0; i < data.length();) {
482 uint8_t msb = data.c_str()[i];
483 uint8_t lsb = data.c_str()[i + 1];
489 ret.
uuid_.uuid.uuid32 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << (6 - i) * 4;
492 }
else if (data.length() == 16) {
494 ret.
uuid_.len = ESP_UUID_LEN_128;
495 memcpy(ret.
uuid_.uuid.uuid128, (uint8_t *) data.data(), 16);
496 }
else if (data.length() == 36) {
499 ret.
uuid_.len = ESP_UUID_LEN_128;
501 for (
int i = 0; i < data.length();) {
502 if (data.c_str()[i] ==
'-')
504 uint8_t msb = data.c_str()[i];
505 uint8_t lsb = data.c_str()[i + 1];
511 ret.
uuid_.uuid.uuid128[15 - n++] = ((msb & 0x0F) << 4) | (lsb & 0x0F);
515 ESP_LOGE(TAG,
"ERROR: UUID value not 2, 4, 16 or 36 bytes - %s", data.c_str());
521 ret.
uuid_.len = uuid.len;
522 if (uuid.len == ESP_UUID_LEN_16) {
523 ret.
uuid_.uuid.uuid16 = uuid.uuid.uuid16;
524 }
else if (uuid.len == ESP_UUID_LEN_32) {
525 ret.
uuid_.uuid.uuid32 = uuid.uuid.uuid32;
526 }
else if (uuid.len == ESP_UUID_LEN_128) {
527 memcpy(ret.
uuid_.uuid.uuid128, uuid.uuid.uuid128, ESP_UUID_LEN_128);
532 if (this->
uuid_.len == ESP_UUID_LEN_128) {
535 uint8_t data[] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
537 if (this->
uuid_.len == ESP_UUID_LEN_32) {
538 uuid32 = this->
uuid_.uuid.uuid32;
540 uuid32 = this->
uuid_.uuid.uuid16;
542 for (uint8_t i = 0; i < this->
uuid_.len; i++) {
543 data[12 + i] = ((uuid32 >> i * 8) & 0xFF);
548 if (this->
uuid_.len == ESP_UUID_LEN_16) {
549 return (this->
uuid_.uuid.uuid16 >> 8) == data2 && (this->
uuid_.uuid.uuid16 & 0xFF) == data1;
550 }
else if (this->
uuid_.len == ESP_UUID_LEN_32) {
551 for (uint8_t i = 0; i < 3; i++) {
552 bool a = ((this->
uuid_.uuid.uuid32 >> i * 8) & 0xFF) == data1;
553 bool b = ((this->
uuid_.uuid.uuid32 >> (i + 1) * 8) & 0xFF) == data2;
558 for (uint8_t i = 0; i < 15; i++) {
559 if (this->
uuid_.uuid.uuid128[i] == data1 && this->uuid_.uuid.uuid128[i + 1] == data2)
567 switch (this->
uuid_.len) {
568 case ESP_UUID_LEN_16:
569 if (uuid.
uuid_.uuid.uuid16 == this->uuid_.uuid.uuid16) {
573 case ESP_UUID_LEN_32:
574 if (uuid.
uuid_.uuid.uuid32 == this->uuid_.uuid.uuid32) {
578 case ESP_UUID_LEN_128:
579 for (
int i = 0; i < ESP_UUID_LEN_128; i++) {
580 if (uuid.
uuid_.uuid.uuid128[i] != this->uuid_.uuid.uuid128[i]) {
594 switch (this->
uuid_.len) {
595 case ESP_UUID_LEN_16:
596 return str_snprintf(
"0x%02X%02X", 6, this->
uuid_.uuid.uuid16 >> 8, this->uuid_.uuid.uuid16 & 0xff);
597 case ESP_UUID_LEN_32:
599 (this->uuid_.uuid.uuid32 >> 16 & 0xff), (this->uuid_.uuid.uuid32 >> 8 & 0xff),
600 this->uuid_.uuid.uuid32 & 0xff);
602 case ESP_UUID_LEN_128:
604 for (int8_t i = 15; i >= 0; i--) {
606 if (i == 6 || i == 8 || i == 10 || i == 12)
616 return ((uint64_t) uuid.uuid.uuid128[15] << 56) | ((uint64_t) uuid.uuid.uuid128[14] << 48) |
617 ((uint64_t) uuid.uuid.uuid128[13] << 40) | ((uint64_t) uuid.uuid.uuid128[12] << 32) |
618 ((uint64_t) uuid.uuid.uuid128[11] << 24) | ((uint64_t) uuid.uuid.uuid128[10] << 16) |
619 ((uint64_t) uuid.uuid.uuid128[9] << 8) | ((uint64_t) uuid.uuid.uuid128[8]);
623 return ((uint64_t) uuid.uuid.uuid128[7] << 56) | ((uint64_t) uuid.uuid.uuid128[6] << 48) |
624 ((uint64_t) uuid.uuid.uuid128[5] << 40) | ((uint64_t) uuid.uuid.uuid128[4] << 32) |
625 ((uint64_t) uuid.uuid.uuid128[3] << 24) | ((uint64_t) uuid.uuid.uuid128[2] << 16) |
626 ((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0]);
634 if (data.
data.size() != 23)
640 this->scan_result_ = param;
641 for (uint8_t i = 0; i < ESP_BD_ADDR_LEN; i++)
642 this->address_[i] = param.bda[i];
643 this->address_type_ = param.ble_addr_type;
644 this->rssi_ = param.rssi;
645 this->parse_adv_(param);
647 #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE 648 ESP_LOGVV(TAG,
"Parse Result:");
649 const char *address_type =
"";
650 switch (this->address_type_) {
651 case BLE_ADDR_TYPE_PUBLIC:
652 address_type =
"PUBLIC";
654 case BLE_ADDR_TYPE_RANDOM:
655 address_type =
"RANDOM";
657 case BLE_ADDR_TYPE_RPA_PUBLIC:
658 address_type =
"RPA_PUBLIC";
660 case BLE_ADDR_TYPE_RPA_RANDOM:
661 address_type =
"RPA_RANDOM";
664 ESP_LOGVV(TAG,
" Address: %02X:%02X:%02X:%02X:%02X:%02X (%s)", this->address_[0], this->address_[1],
665 this->address_[2], this->address_[3], this->address_[4], this->address_[5], address_type);
667 ESP_LOGVV(TAG,
" RSSI: %d", this->rssi_);
668 ESP_LOGVV(TAG,
" Name: '%s'", this->name_.c_str());
669 for (
auto &it : this->tx_powers_) {
670 ESP_LOGVV(TAG,
" TX Power: %d", it);
672 if (this->appearance_.has_value()) {
673 ESP_LOGVV(TAG,
" Appearance: %u", *this->appearance_);
675 if (this->ad_flag_.has_value()) {
676 ESP_LOGVV(TAG,
" Ad Flag: %u", *this->ad_flag_);
678 for (
auto &uuid : this->service_uuids_) {
679 ESP_LOGVV(TAG,
" Service UUID: %s", uuid.to_string().c_str());
681 for (
auto &data : this->manufacturer_datas_) {
683 if (this->get_ibeacon().has_value()) {
684 auto ibeacon = this->get_ibeacon().value();
685 ESP_LOGVV(TAG,
" iBeacon data:");
686 ESP_LOGVV(TAG,
" UUID: %s", ibeacon.get_uuid().to_string().c_str());
687 ESP_LOGVV(TAG,
" Major: %u", ibeacon.get_major());
688 ESP_LOGVV(TAG,
" Minor: %u", ibeacon.get_minor());
689 ESP_LOGVV(TAG,
" TXPower: %d", ibeacon.get_signal_power());
692 for (
auto &data : this->service_datas_) {
693 ESP_LOGVV(TAG,
" Service data:");
694 ESP_LOGVV(TAG,
" UUID: %s", data.uuid.to_string().c_str());
698 ESP_LOGVV(TAG,
"Adv data: %s",
format_hex_pretty(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str());
703 const uint8_t *payload = param.ble_adv;
704 uint8_t
len = param.adv_data_len + param.scan_rsp_len;
706 while (offset + 2 < len) {
707 const uint8_t field_length = payload[offset++];
708 if (field_length == 0) {
713 const uint8_t record_type = payload[offset++];
714 const uint8_t *record = &payload[offset];
715 const uint8_t record_length = field_length - 1;
716 offset += record_length;
724 switch (record_type) {
725 case ESP_BLE_AD_TYPE_NAME_SHORT:
726 case ESP_BLE_AD_TYPE_NAME_CMPL: {
733 if (record_length > this->name_.length()) {
734 this->name_ = std::string(reinterpret_cast<const char *>(record), record_length);
738 case ESP_BLE_AD_TYPE_TX_PWR: {
742 this->tx_powers_.push_back(*payload);
745 case ESP_BLE_AD_TYPE_APPEARANCE: {
751 this->appearance_ = *
reinterpret_cast<const uint16_t *
>(record);
754 case ESP_BLE_AD_TYPE_FLAG: {
760 this->ad_flag_ = *record;
767 case ESP_BLE_AD_TYPE_16SRV_CMPL:
768 case ESP_BLE_AD_TYPE_16SRV_PART: {
770 for (uint8_t i = 0; i < record_length / 2; i++) {
771 this->service_uuids_.push_back(
ESPBTUUID::from_uint16(*reinterpret_cast<const uint16_t *>(record + 2 * i)));
775 case ESP_BLE_AD_TYPE_32SRV_CMPL:
776 case ESP_BLE_AD_TYPE_32SRV_PART: {
778 for (uint8_t i = 0; i < record_length / 4; i++) {
779 this->service_uuids_.push_back(
ESPBTUUID::from_uint32(*reinterpret_cast<const uint32_t *>(record + 4 * i)));
783 case ESP_BLE_AD_TYPE_128SRV_CMPL:
784 case ESP_BLE_AD_TYPE_128SRV_PART: {
789 case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: {
795 if (record_length < 2) {
796 ESP_LOGV(TAG,
"Record length too small for ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE");
801 data.data.assign(record + 2UL, record + record_length);
802 this->manufacturer_datas_.push_back(data);
809 case ESP_BLE_AD_TYPE_SERVICE_DATA: {
813 if (record_length < 2) {
814 ESP_LOGV(TAG,
"Record length too small for ESP_BLE_AD_TYPE_SERVICE_DATA");
819 data.data.assign(record + 2UL, record + record_length);
820 this->service_datas_.push_back(data);
823 case ESP_BLE_AD_TYPE_32SERVICE_DATA: {
827 if (record_length < 4) {
828 ESP_LOGV(TAG,
"Record length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA");
833 data.data.assign(record + 4UL, record + record_length);
834 this->service_datas_.push_back(data);
837 case ESP_BLE_AD_TYPE_128SERVICE_DATA: {
841 if (record_length < 16) {
842 ESP_LOGV(TAG,
"Record length too small for ESP_BLE_AD_TYPE_128SERVICE_DATA");
847 data.data.assign(record + 16UL, record + record_length);
848 this->service_datas_.push_back(data);
851 case ESP_BLE_AD_TYPE_INT_RANGE:
855 ESP_LOGV(TAG,
"Unhandled type: advType: 0x%02x", record_type);
863 snprintf(mac,
sizeof(mac),
"%02X:%02X:%02X:%02X:%02X:%02X", this->address_[0], this->address_[1], this->address_[2],
864 this->address_[3], this->address_[4], this->address_[5]);
870 ESP_LOGCONFIG(TAG,
"BLE Tracker:");
871 ESP_LOGCONFIG(TAG,
" Scan Duration: %u s", this->scan_duration_);
872 ESP_LOGCONFIG(TAG,
" Scan Interval: %.1f ms", this->scan_interval_ * 0.625f);
873 ESP_LOGCONFIG(TAG,
" Scan Window: %.1f ms", this->scan_window_ * 0.625f);
874 ESP_LOGCONFIG(TAG,
" Scan Type: %s", this->scan_active_ ?
"ACTIVE" :
"PASSIVE");
875 ESP_LOGCONFIG(TAG,
" Continuous Scanning: %s", this->scan_continuous_ ?
"True" :
"False");
880 for (
auto &disc : this->already_discovered_) {
884 this->already_discovered_.push_back(address);
888 const char *address_type_s;
890 case BLE_ADDR_TYPE_PUBLIC:
891 address_type_s =
"PUBLIC";
893 case BLE_ADDR_TYPE_RANDOM:
894 address_type_s =
"RANDOM";
896 case BLE_ADDR_TYPE_RPA_PUBLIC:
897 address_type_s =
"RPA_PUBLIC";
899 case BLE_ADDR_TYPE_RPA_RANDOM:
900 address_type_s =
"RPA_RANDOM";
903 address_type_s =
"UNKNOWN";
907 ESP_LOGD(TAG,
" Address Type: %s", address_type_s);
909 ESP_LOGD(TAG,
" Name: '%s'", device.
get_name().c_str());
912 ESP_LOGD(TAG,
" TX Power: %d", tx_power);
ESPBTUUID as_128bit() const
void real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
void end_of_scan_()
Called when a scan ends.
std::string to_string() const
esp_bt_status_t scan_start_failed_
std::string format_hex_pretty(const uint8_t *data, size_t length)
Format the byte array data of length len in pretty-printed, human-readable hex.
bool cancel_timeout(const std::string &name)
Cancel a timeout function.
void setup() override
Setup the FreeRTOS task and the Bluetooth stack.
void start_scan_(bool first)
Start a single scan by setting up the parameters and doing some esp-idf calls.
esp_ble_gap_cb_param_t::ble_scan_result_evt_param scan_result_buffer_[16]
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m)
void add_on_state_callback(std::function< void(OTAState, float, uint8_t)> &&callback)
const std::vector< int8_t > & get_tx_powers() const
std::string address_str() const
esp_bt_status_t scan_set_param_failed_
esp_ble_scan_params_t scan_params_
A structure holding the ESP BLE scan parameters.
static ESPBTUUID from_raw(const uint8_t *data)
SemaphoreHandle_t scan_end_lock_
void real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
void register_client(ESPBTClient *client)
ESP32BLETracker * global_esp32_ble_tracker
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
Callback that will handle all GAP events and redistribute them to other callbacks.
void dump_config() override
struct esphome::esp32_ble_tracker::BLEEvent::@61::gattc_event gattc
Application App
Global storage of Application pointer - only one Application can exist.
Queue< BLEEvent > ble_events_
esp_ble_addr_type_t get_address_type() const
union esphome::esp32_ble_tracker::BLEEvent::@61 event_
void gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t::ble_scan_param_cmpl_evt_param ¶m)
Called when a ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT event is received.
uint64_t address_uint64() const
OTAComponent * global_ota_component
esp_bt_uuid_t get_uuid() const
bool contains(uint8_t data1, uint8_t data2) const
uint64_t get_128bit_high() const
struct esphome::esp32_ble_tracker::BLEEvent::@61::gap_event gap
static void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
Callback that will handle all GATTC events and redistribute them to other callbacks.
uint8_t scan_start_fail_count_
SemaphoreHandle_t scan_result_lock_
uint32_t scan_duration_
The interval in seconds to perform scans.
std::vector< uint64_t > already_discovered_
Vector of addresses that have already been printed in print_bt_device_info.
virtual void mark_failed()
Mark this component as failed.
void gap_scan_result_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m)
Called when a ESP_GAP_BLE_SCAN_RESULT_EVT event is received.
uint64_t ble_addr_to_uint64(const esp_bd_addr_t address)
static ESPBTUUID from_uint16(uint16_t uuid)
static ESPBTUUID from_uint32(uint32_t uuid)
void print_bt_device_info(const ESPBTDevice &device)
const std::string & get_name() const
static bool ble_setup()
The FreeRTOS task managing the bluetooth interface.
bool operator==(const ESPBTUUID &uuid) const
std::string str_snprintf(const char *fmt, size_t len,...)
float get_setup_priority() const override
size_t scan_result_index_
uint64_t get_128bit_low() const
void gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param ¶m)
Called when a ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT event is received.
static optional< ESPBLEiBeacon > from_manufacturer_data(const ServiceData &data)
std::vector< ESPBTDeviceListener * > listeners_
std::vector< ESPBTClient * > clients_
Client parameters.
void parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m)
void gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param ¶m)
Called when a ESP_GAP_BLE_SCAN_START_COMPLETE_EVT event is received.
void IRAM_ATTR HOT delay(uint32_t ms)
static ESPBTUUID from_uuid(esp_bt_uuid_t uuid)