mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Inherit esp32_ble_beacon from esp32_ble (#6908)
				
					
				
			Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							172a358d01
						
					
				
				
					commit
					5d5f3276e9
				
			| @@ -7,10 +7,10 @@ from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant | ||||
|  | ||||
| DEPENDENCIES = ["esp32"] | ||||
| CODEOWNERS = ["@jesserockz", "@Rapsssito"] | ||||
| CONFLICTS_WITH = ["esp32_ble_beacon"] | ||||
|  | ||||
| CONF_BLE_ID = "ble_id" | ||||
| CONF_IO_CAPABILITY = "io_capability" | ||||
| CONF_ADVERTISING_CYCLE_TIME = "advertising_cycle_time" | ||||
|  | ||||
| NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2] | ||||
|  | ||||
| @@ -34,6 +34,19 @@ IO_CAPABILITY = { | ||||
|     "display_yes_no": IoCapability.IO_CAP_IO, | ||||
| } | ||||
|  | ||||
| esp_power_level_t = cg.global_ns.enum("esp_power_level_t") | ||||
|  | ||||
| TX_POWER_LEVELS = { | ||||
|     -12: esp_power_level_t.ESP_PWR_LVL_N12, | ||||
|     -9: esp_power_level_t.ESP_PWR_LVL_N9, | ||||
|     -6: esp_power_level_t.ESP_PWR_LVL_N6, | ||||
|     -3: esp_power_level_t.ESP_PWR_LVL_N3, | ||||
|     0: esp_power_level_t.ESP_PWR_LVL_N0, | ||||
|     3: esp_power_level_t.ESP_PWR_LVL_P3, | ||||
|     6: esp_power_level_t.ESP_PWR_LVL_P6, | ||||
|     9: esp_power_level_t.ESP_PWR_LVL_P9, | ||||
| } | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(ESP32BLE), | ||||
| @@ -41,6 +54,9 @@ CONFIG_SCHEMA = cv.Schema( | ||||
|             IO_CAPABILITY, lower=True | ||||
|         ), | ||||
|         cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean, | ||||
|         cv.Optional( | ||||
|             CONF_ADVERTISING_CYCLE_TIME, default="10s" | ||||
|         ): cv.positive_time_period_milliseconds, | ||||
|     } | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
|  | ||||
| @@ -58,6 +74,7 @@ async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT])) | ||||
|     cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY])) | ||||
|     cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME])) | ||||
|     await cg.register_component(var, config) | ||||
|  | ||||
|     if CORE.using_esp_idf: | ||||
|   | ||||
| @@ -78,6 +78,11 @@ void ESP32BLE::advertising_set_manufacturer_data(const std::vector<uint8_t> &dat | ||||
|   this->advertising_start(); | ||||
| } | ||||
|  | ||||
| void ESP32BLE::advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback) { | ||||
|   this->advertising_init_(); | ||||
|   this->advertising_->register_raw_advertisement_callback(std::move(callback)); | ||||
| } | ||||
|  | ||||
| void ESP32BLE::advertising_add_service_uuid(ESPBTUUID uuid) { | ||||
|   this->advertising_init_(); | ||||
|   this->advertising_->add_service_uuid(uuid); | ||||
| @@ -102,7 +107,7 @@ bool ESP32BLE::ble_pre_setup_() { | ||||
| void ESP32BLE::advertising_init_() { | ||||
|   if (this->advertising_ != nullptr) | ||||
|     return; | ||||
|   this->advertising_ = new BLEAdvertising();  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|   this->advertising_ = new BLEAdvertising(this->advertising_cycle_time_);  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|  | ||||
|   this->advertising_->set_scan_response(true); | ||||
|   this->advertising_->set_min_preferred_interval(0x06); | ||||
| @@ -312,6 +317,9 @@ void ESP32BLE::loop() { | ||||
|     delete ble_event;  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|     ble_event = this->ble_events_.pop(); | ||||
|   } | ||||
|   if (this->advertising_ != nullptr) { | ||||
|     this->advertising_->loop(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { | ||||
|   | ||||
| @@ -3,6 +3,8 @@ | ||||
| #include "ble_advertising.h" | ||||
| #include "ble_uuid.h" | ||||
|  | ||||
| #include <functional> | ||||
|  | ||||
| #include "esphome/core/automation.h" | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/defines.h" | ||||
| @@ -76,6 +78,11 @@ class ESP32BLE : public Component { | ||||
|  public: | ||||
|   void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; } | ||||
|  | ||||
|   void set_advertising_cycle_time(uint32_t advertising_cycle_time) { | ||||
|     this->advertising_cycle_time_ = advertising_cycle_time; | ||||
|   } | ||||
|   uint32_t get_advertising_cycle_time() const { return this->advertising_cycle_time_; } | ||||
|  | ||||
|   void enable(); | ||||
|   void disable(); | ||||
|   bool is_active(); | ||||
| @@ -89,6 +96,7 @@ class ESP32BLE : public Component { | ||||
|   void advertising_set_manufacturer_data(const std::vector<uint8_t> &data); | ||||
|   void advertising_add_service_uuid(ESPBTUUID uuid); | ||||
|   void advertising_remove_service_uuid(ESPBTUUID uuid); | ||||
|   void advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback); | ||||
|  | ||||
|   void register_gap_event_handler(GAPEventHandler *handler) { this->gap_event_handlers_.push_back(handler); } | ||||
|   void register_gattc_event_handler(GATTcEventHandler *handler) { this->gattc_event_handlers_.push_back(handler); } | ||||
| @@ -121,6 +129,7 @@ class ESP32BLE : public Component { | ||||
|   Queue<BLEEvent> ble_events_; | ||||
|   BLEAdvertising *advertising_; | ||||
|   esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE}; | ||||
|   uint32_t advertising_cycle_time_; | ||||
|   bool enable_on_boot_; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -10,9 +10,9 @@ | ||||
| namespace esphome { | ||||
| namespace esp32_ble { | ||||
|  | ||||
| static const char *const TAG = "esp32_ble"; | ||||
| static const char *const TAG = "esp32_ble.advertising"; | ||||
|  | ||||
| BLEAdvertising::BLEAdvertising() { | ||||
| BLEAdvertising::BLEAdvertising(uint32_t advertising_cycle_time) : advertising_cycle_time_(advertising_cycle_time) { | ||||
|   this->advertising_data_.set_scan_rsp = false; | ||||
|   this->advertising_data_.include_name = true; | ||||
|   this->advertising_data_.include_txpower = true; | ||||
| @@ -64,7 +64,7 @@ void BLEAdvertising::set_manufacturer_data(const std::vector<uint8_t> &data) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void BLEAdvertising::start() { | ||||
| esp_err_t BLEAdvertising::services_advertisement_() { | ||||
|   int num_services = this->advertising_uuids_.size(); | ||||
|   if (num_services == 0) { | ||||
|     this->advertising_data_.service_uuid_len = 0; | ||||
| @@ -87,8 +87,8 @@ void BLEAdvertising::start() { | ||||
|   this->advertising_data_.include_txpower = !this->scan_response_; | ||||
|   err = esp_ble_gap_config_adv_data(&this->advertising_data_); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Advertising): %d", err); | ||||
|     return; | ||||
|     ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Advertising): %s", esp_err_to_name(err)); | ||||
|     return err; | ||||
|   } | ||||
|  | ||||
|   if (this->scan_response_) { | ||||
| @@ -101,8 +101,8 @@ void BLEAdvertising::start() { | ||||
|     this->scan_response_data_.flag = 0; | ||||
|     err = esp_ble_gap_config_adv_data(&this->scan_response_data_); | ||||
|     if (err != ESP_OK) { | ||||
|       ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %d", err); | ||||
|       return; | ||||
|       ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %s", esp_err_to_name(err)); | ||||
|       return err; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -113,8 +113,18 @@ void BLEAdvertising::start() { | ||||
|  | ||||
|   err = esp_ble_gap_start_advertising(&this->advertising_params_); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %d", err); | ||||
|     return; | ||||
|     ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %s", esp_err_to_name(err)); | ||||
|     return err; | ||||
|   } | ||||
|  | ||||
|   return ESP_OK; | ||||
| } | ||||
|  | ||||
| void BLEAdvertising::start() { | ||||
|   if (this->current_adv_index_ == -1) { | ||||
|     this->services_advertisement_(); | ||||
|   } else { | ||||
|     this->raw_advertisements_callbacks_[this->current_adv_index_](true); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -124,6 +134,29 @@ void BLEAdvertising::stop() { | ||||
|     ESP_LOGE(TAG, "esp_ble_gap_stop_advertising failed: %d", err); | ||||
|     return; | ||||
|   } | ||||
|   if (this->current_adv_index_ != -1) { | ||||
|     this->raw_advertisements_callbacks_[this->current_adv_index_](false); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void BLEAdvertising::loop() { | ||||
|   if (this->raw_advertisements_callbacks_.empty()) { | ||||
|     return; | ||||
|   } | ||||
|   const uint32_t now = millis(); | ||||
|   if (now - this->last_advertisement_time_ > this->advertising_cycle_time_) { | ||||
|     this->stop(); | ||||
|     this->current_adv_index_ += 1; | ||||
|     if (this->current_adv_index_ >= this->raw_advertisements_callbacks_.size()) { | ||||
|       this->current_adv_index_ = -1; | ||||
|     } | ||||
|     this->start(); | ||||
|     this->last_advertisement_time_ = now; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void BLEAdvertising::register_raw_advertisement_callback(std::function<void(bool)> &&callback) { | ||||
|   this->raw_advertisements_callbacks_.push_back(std::move(callback)); | ||||
| } | ||||
|  | ||||
| }  // namespace esp32_ble | ||||
|   | ||||
| @@ -1,20 +1,31 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <functional> | ||||
| #include <vector> | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
|  | ||||
| #include <esp_bt.h> | ||||
| #include <esp_gap_ble_api.h> | ||||
| #include <esp_gatts_api.h> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace esp32_ble { | ||||
|  | ||||
| using raw_adv_data_t = struct { | ||||
|   uint8_t *data; | ||||
|   size_t length; | ||||
|   esp_power_level_t power_level; | ||||
| }; | ||||
|  | ||||
| class ESPBTUUID; | ||||
|  | ||||
| class BLEAdvertising { | ||||
|  public: | ||||
|   BLEAdvertising(); | ||||
|   BLEAdvertising(uint32_t advertising_cycle_time); | ||||
|  | ||||
|   void loop(); | ||||
|  | ||||
|   void add_service_uuid(ESPBTUUID uuid); | ||||
|   void remove_service_uuid(ESPBTUUID uuid); | ||||
| @@ -22,16 +33,25 @@ class BLEAdvertising { | ||||
|   void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; } | ||||
|   void set_manufacturer_data(const std::vector<uint8_t> &data); | ||||
|   void set_service_data(const std::vector<uint8_t> &data); | ||||
|   void register_raw_advertisement_callback(std::function<void(bool)> &&callback); | ||||
|  | ||||
|   void start(); | ||||
|   void stop(); | ||||
|  | ||||
|  protected: | ||||
|   esp_err_t services_advertisement_(); | ||||
|  | ||||
|   bool scan_response_; | ||||
|   esp_ble_adv_data_t advertising_data_; | ||||
|   esp_ble_adv_data_t scan_response_data_; | ||||
|   esp_ble_adv_params_t advertising_params_; | ||||
|   std::vector<ESPBTUUID> advertising_uuids_; | ||||
|  | ||||
|   std::vector<std::function<void(bool)>> raw_advertisements_callbacks_; | ||||
|  | ||||
|   const uint32_t advertising_cycle_time_; | ||||
|   uint32_t last_advertisement_time_{0}; | ||||
|   int8_t current_adv_index_{-1};  // -1 means standard scan response | ||||
| }; | ||||
|  | ||||
| }  // namespace esp32_ble | ||||
|   | ||||
| @@ -1,16 +1,21 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components.esp32_ble import CONF_BLE_ID | ||||
| from esphome.const import CONF_ID, CONF_TYPE, CONF_UUID, CONF_TX_POWER | ||||
| from esphome.core import CORE, TimePeriod | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
| from esphome.components import esp32_ble | ||||
|  | ||||
| AUTO_LOAD = ["esp32_ble"] | ||||
| DEPENDENCIES = ["esp32"] | ||||
| CONFLICTS_WITH = ["esp32_ble_tracker"] | ||||
|  | ||||
| esp32_ble_beacon_ns = cg.esphome_ns.namespace("esp32_ble_beacon") | ||||
| ESP32BLEBeacon = esp32_ble_beacon_ns.class_("ESP32BLEBeacon", cg.Component) | ||||
|  | ||||
| ESP32BLEBeacon = esp32_ble_beacon_ns.class_( | ||||
|     "ESP32BLEBeacon", | ||||
|     cg.Component, | ||||
|     esp32_ble.GAPEventHandler, | ||||
|     cg.Parented.template(esp32_ble.ESP32BLE), | ||||
| ) | ||||
| CONF_MAJOR = "major" | ||||
| CONF_MINOR = "minor" | ||||
| CONF_MIN_INTERVAL = "min_interval" | ||||
| @@ -28,6 +33,7 @@ CONFIG_SCHEMA = cv.All( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(ESP32BLEBeacon), | ||||
|             cv.GenerateID(CONF_BLE_ID): cv.use_id(esp32_ble.ESP32BLE), | ||||
|             cv.Required(CONF_TYPE): cv.one_of("IBEACON", upper=True), | ||||
|             cv.Required(CONF_UUID): cv.uuid, | ||||
|             cv.Optional(CONF_MAJOR, default=10167): cv.uint16_t, | ||||
| @@ -48,7 +54,7 @@ CONFIG_SCHEMA = cv.All( | ||||
|                 min=-128, max=0 | ||||
|             ), | ||||
|             cv.Optional(CONF_TX_POWER, default="3dBm"): cv.All( | ||||
|                 cv.decibel, cv.one_of(-12, -9, -6, -3, 0, 3, 6, 9, int=True) | ||||
|                 cv.decibel, cv.enum(esp32_ble.TX_POWER_LEVELS, int=True) | ||||
|             ), | ||||
|         } | ||||
|     ).extend(cv.COMPONENT_SCHEMA), | ||||
| @@ -62,6 +68,10 @@ async def to_code(config): | ||||
|     uuid = config[CONF_UUID].hex | ||||
|     uuid_arr = [cg.RawExpression(f"0x{uuid[i:i + 2]}") for i in range(0, len(uuid), 2)] | ||||
|     var = cg.new_Pvariable(config[CONF_ID], uuid_arr) | ||||
|  | ||||
|     parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID]) | ||||
|     cg.add(parent.register_gap_event_handler(var)) | ||||
|  | ||||
|     await cg.register_component(var, config) | ||||
|     cg.add(var.set_major(config[CONF_MAJOR])) | ||||
|     cg.add(var.set_minor(config[CONF_MINOR])) | ||||
|   | ||||
| @@ -3,14 +3,16 @@ | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
|  | ||||
| #include <nvs_flash.h> | ||||
| #include <freertos/FreeRTOS.h> | ||||
| #include <esp_bt_main.h> | ||||
| #include <esp_bt.h> | ||||
| #include <freertos/task.h> | ||||
| #include <esp_bt_main.h> | ||||
| #include <esp_gap_ble_api.h> | ||||
| #include <freertos/FreeRTOS.h> | ||||
| #include <freertos/task.h> | ||||
| #include <nvs_flash.h> | ||||
| #include <cstring> | ||||
|  | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| #ifdef USE_ARDUINO | ||||
| #include <esp32-hal-bt.h> | ||||
| @@ -21,20 +23,6 @@ namespace esp32_ble_beacon { | ||||
|  | ||||
| static const char *const TAG = "esp32_ble_beacon"; | ||||
|  | ||||
| // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | ||||
| static esp_ble_adv_params_t ble_adv_params = { | ||||
|     .adv_int_min = 0x20, | ||||
|     .adv_int_max = 0x40, | ||||
|     .adv_type = ADV_TYPE_NONCONN_IND, | ||||
|     .own_addr_type = BLE_ADDR_TYPE_PUBLIC, | ||||
|     .peer_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, | ||||
|     .peer_addr_type = BLE_ADDR_TYPE_PUBLIC, | ||||
|     .channel_map = ADV_CHNL_ALL, | ||||
|     .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, | ||||
| }; | ||||
|  | ||||
| #define ENDIAN_CHANGE_U16(x) ((((x) &0xFF00) >> 8) + (((x) &0xFF) << 8)) | ||||
|  | ||||
| static const esp_ble_ibeacon_head_t IBEACON_COMMON_HEAD = { | ||||
|     .flags = {0x02, 0x01, 0x06}, .length = 0x1A, .type = 0xFF, .company_id = {0x4C, 0x00}, .beacon_type = {0x02, 0x15}}; | ||||
|  | ||||
| @@ -53,117 +41,62 @@ void ESP32BLEBeacon::dump_config() { | ||||
|                 "  UUID: %s, Major: %u, Minor: %u, Min Interval: %ums, Max Interval: %ums, Measured Power: %d" | ||||
|                 ", TX Power: %ddBm", | ||||
|                 uuid, this->major_, this->minor_, this->min_interval_, this->max_interval_, this->measured_power_, | ||||
|                 this->tx_power_); | ||||
|                 (this->tx_power_ * 3) - 12); | ||||
| } | ||||
|  | ||||
| float ESP32BLEBeacon::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; } | ||||
|  | ||||
| void ESP32BLEBeacon::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up ESP32 BLE beacon..."); | ||||
|   global_esp32_ble_beacon = this; | ||||
|   this->ble_adv_params_ = { | ||||
|       .adv_int_min = static_cast<uint16_t>(this->min_interval_ / 0.625f), | ||||
|       .adv_int_max = static_cast<uint16_t>(this->max_interval_ / 0.625f), | ||||
|       .adv_type = ADV_TYPE_NONCONN_IND, | ||||
|       .own_addr_type = BLE_ADDR_TYPE_PUBLIC, | ||||
|       .peer_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, | ||||
|       .peer_addr_type = BLE_ADDR_TYPE_PUBLIC, | ||||
|       .channel_map = ADV_CHNL_ALL, | ||||
|       .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, | ||||
|   }; | ||||
|  | ||||
|   xTaskCreatePinnedToCore(ESP32BLEBeacon::ble_core_task, | ||||
|                           "ble_task",  // name | ||||
|                           10000,       // stack size (in words) | ||||
|                           nullptr,     // input params | ||||
|                           1,           // priority | ||||
|                           nullptr,     // Handle, not needed | ||||
|                           0            // core | ||||
|   ); | ||||
|   global_ble->advertising_register_raw_advertisement_callback([this](bool advertise) { | ||||
|     this->advertising_ = advertise; | ||||
|     if (advertise) { | ||||
|       this->on_advertise_(); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| float ESP32BLEBeacon::get_setup_priority() const { return setup_priority::BLUETOOTH; } | ||||
| void ESP32BLEBeacon::ble_core_task(void *params) { | ||||
|   ble_setup(); | ||||
|  | ||||
|   while (true) { | ||||
|     delay(1000);  // NOLINT | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ESP32BLEBeacon::ble_setup() { | ||||
|   ble_adv_params.adv_int_min = static_cast<uint16_t>(global_esp32_ble_beacon->min_interval_ / 0.625f); | ||||
|   ble_adv_params.adv_int_max = static_cast<uint16_t>(global_esp32_ble_beacon->max_interval_ / 0.625f); | ||||
|  | ||||
|   // Initialize non-volatile storage for the bluetooth controller | ||||
|   esp_err_t err = nvs_flash_init(); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGE(TAG, "nvs_flash_init failed: %d", err); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
| #ifdef USE_ARDUINO | ||||
|   if (!btStart()) { | ||||
|     ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status()); | ||||
|     return; | ||||
|   } | ||||
| #else | ||||
|   if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { | ||||
|     // start bt controller | ||||
|     if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) { | ||||
|       esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); | ||||
|       err = esp_bt_controller_init(&cfg); | ||||
|       if (err != ESP_OK) { | ||||
|         ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err)); | ||||
|         return; | ||||
|       } | ||||
|       while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) | ||||
|         ; | ||||
|     } | ||||
|     if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) { | ||||
|       err = esp_bt_controller_enable(ESP_BT_MODE_BLE); | ||||
|       if (err != ESP_OK) { | ||||
|         ESP_LOGE(TAG, "esp_bt_controller_enable failed: %s", esp_err_to_name(err)); | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|     if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { | ||||
|       ESP_LOGE(TAG, "esp bt controller enable failed"); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); | ||||
|  | ||||
|   err = esp_bluedroid_init(); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", err); | ||||
|     return; | ||||
|   } | ||||
|   err = esp_bluedroid_enable(); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err); | ||||
|     return; | ||||
|   } | ||||
|   err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, | ||||
|                              static_cast<esp_power_level_t>((global_esp32_ble_beacon->tx_power_ + 12) / 3)); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGE(TAG, "esp_ble_tx_power_set failed: %s", esp_err_to_name(err)); | ||||
|     return; | ||||
|   } | ||||
|   err = esp_ble_gap_register_callback(ESP32BLEBeacon::gap_event_handler); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", err); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
| void ESP32BLEBeacon::on_advertise_() { | ||||
|   esp_ble_ibeacon_t ibeacon_adv_data; | ||||
|   memcpy(&ibeacon_adv_data.ibeacon_head, &IBEACON_COMMON_HEAD, sizeof(esp_ble_ibeacon_head_t)); | ||||
|   memcpy(&ibeacon_adv_data.ibeacon_vendor.proximity_uuid, global_esp32_ble_beacon->uuid_.data(), | ||||
|   memcpy(&ibeacon_adv_data.ibeacon_vendor.proximity_uuid, this->uuid_.data(), | ||||
|          sizeof(ibeacon_adv_data.ibeacon_vendor.proximity_uuid)); | ||||
|   ibeacon_adv_data.ibeacon_vendor.minor = ENDIAN_CHANGE_U16(global_esp32_ble_beacon->minor_); | ||||
|   ibeacon_adv_data.ibeacon_vendor.major = ENDIAN_CHANGE_U16(global_esp32_ble_beacon->major_); | ||||
|   ibeacon_adv_data.ibeacon_vendor.measured_power = static_cast<uint8_t>(global_esp32_ble_beacon->measured_power_); | ||||
|   ibeacon_adv_data.ibeacon_vendor.minor = byteswap(this->minor_); | ||||
|   ibeacon_adv_data.ibeacon_vendor.major = byteswap(this->major_); | ||||
|   ibeacon_adv_data.ibeacon_vendor.measured_power = static_cast<uint8_t>(this->measured_power_); | ||||
|  | ||||
|   esp_ble_gap_config_adv_data_raw((uint8_t *) &ibeacon_adv_data, sizeof(ibeacon_adv_data)); | ||||
|   ESP_LOGD(TAG, "Setting BLE TX power"); | ||||
|   esp_err_t err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, this->tx_power_); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGW(TAG, "esp_ble_tx_power_set failed: %s", esp_err_to_name(err)); | ||||
|   } | ||||
|   err = esp_ble_gap_config_adv_data_raw((uint8_t *) &ibeacon_adv_data, sizeof(ibeacon_adv_data)); | ||||
|   if (err != ESP_OK) { | ||||
|     ESP_LOGE(TAG, "esp_ble_gap_config_adv_data_raw failed: %s", esp_err_to_name(err)); | ||||
|     return; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { | ||||
|   if (!this->advertising_) | ||||
|     return; | ||||
|  | ||||
|   esp_err_t err; | ||||
|   switch (event) { | ||||
|     case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: { | ||||
|       err = esp_ble_gap_start_advertising(&ble_adv_params); | ||||
|       err = esp_ble_gap_start_advertising(&this->ble_adv_params_); | ||||
|       if (err != ESP_OK) { | ||||
|         ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %d", err); | ||||
|         ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %s", esp_err_to_name(err)); | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
| @@ -181,6 +114,7 @@ void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap | ||||
|       } else { | ||||
|         ESP_LOGD(TAG, "BLE stopped advertising successfully"); | ||||
|       } | ||||
|       // this->advertising_ = false; | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
| @@ -188,8 +122,6 @@ void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap | ||||
|   } | ||||
| } | ||||
|  | ||||
| ESP32BLEBeacon *global_esp32_ble_beacon = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
|  | ||||
| }  // namespace esp32_ble_beacon | ||||
| }  // namespace esphome | ||||
|  | ||||
|   | ||||
| @@ -1,39 +1,39 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/esp32_ble/ble.h" | ||||
| #include "esphome/core/component.h" | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
|  | ||||
| #include <esp_gap_ble_api.h> | ||||
| #include <esp_bt.h> | ||||
| #include <esp_gap_ble_api.h> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace esp32_ble_beacon { | ||||
|  | ||||
| // NOLINTNEXTLINE(modernize-use-using) | ||||
| typedef struct { | ||||
| using esp_ble_ibeacon_head_t = struct { | ||||
|   uint8_t flags[3]; | ||||
|   uint8_t length; | ||||
|   uint8_t type; | ||||
|   uint8_t company_id[2]; | ||||
|   uint8_t beacon_type[2]; | ||||
| } __attribute__((packed)) esp_ble_ibeacon_head_t; | ||||
| } __attribute__((packed)); | ||||
|  | ||||
| // NOLINTNEXTLINE(modernize-use-using) | ||||
| typedef struct { | ||||
| using esp_ble_ibeacon_vendor_t = struct { | ||||
|   uint8_t proximity_uuid[16]; | ||||
|   uint16_t major; | ||||
|   uint16_t minor; | ||||
|   uint8_t measured_power; | ||||
| } __attribute__((packed)) esp_ble_ibeacon_vendor_t; | ||||
| } __attribute__((packed)); | ||||
|  | ||||
| // NOLINTNEXTLINE(modernize-use-using) | ||||
| typedef struct { | ||||
| using esp_ble_ibeacon_t = struct { | ||||
|   esp_ble_ibeacon_head_t ibeacon_head; | ||||
|   esp_ble_ibeacon_vendor_t ibeacon_vendor; | ||||
| } __attribute__((packed)) esp_ble_ibeacon_t; | ||||
| } __attribute__((packed)); | ||||
|  | ||||
| class ESP32BLEBeacon : public Component { | ||||
| using namespace esp32_ble; | ||||
|  | ||||
| class ESP32BLEBeacon : public Component, public GAPEventHandler, public Parented<ESP32BLE> { | ||||
|  public: | ||||
|   explicit ESP32BLEBeacon(const std::array<uint8_t, 16> &uuid) : uuid_(uuid) {} | ||||
|  | ||||
| @@ -46,12 +46,11 @@ class ESP32BLEBeacon : public Component { | ||||
|   void set_min_interval(uint16_t val) { this->min_interval_ = val; } | ||||
|   void set_max_interval(uint16_t val) { this->max_interval_ = val; } | ||||
|   void set_measured_power(int8_t val) { this->measured_power_ = val; } | ||||
|   void set_tx_power(int8_t val) { this->tx_power_ = val; } | ||||
|   void set_tx_power(esp_power_level_t val) { this->tx_power_ = val; } | ||||
|   void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; | ||||
|  | ||||
|  protected: | ||||
|   static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); | ||||
|   static void ble_core_task(void *params); | ||||
|   static void ble_setup(); | ||||
|   void on_advertise_(); | ||||
|  | ||||
|   std::array<uint8_t, 16> uuid_; | ||||
|   uint16_t major_{}; | ||||
| @@ -59,12 +58,11 @@ class ESP32BLEBeacon : public Component { | ||||
|   uint16_t min_interval_{}; | ||||
|   uint16_t max_interval_{}; | ||||
|   int8_t measured_power_{}; | ||||
|   int8_t tx_power_{}; | ||||
|   esp_power_level_t tx_power_{}; | ||||
|   esp_ble_adv_params_t ble_adv_params_; | ||||
|   bool advertising_{false}; | ||||
| }; | ||||
|  | ||||
| // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | ||||
| extern ESP32BLEBeacon *global_esp32_ble_beacon; | ||||
|  | ||||
| }  // namespace esp32_ble_beacon | ||||
| }  // namespace esphome | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,6 @@ from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
|  | ||||
| AUTO_LOAD = ["esp32_ble"] | ||||
| CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"] | ||||
| CONFLICTS_WITH = ["esp32_ble_beacon"] | ||||
| DEPENDENCIES = ["esp32"] | ||||
|  | ||||
| CONF_MANUFACTURER = "manufacturer" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ from esphome.const import CONF_ID | ||||
|  | ||||
| AUTO_LOAD = ["esp32_ble_server"] | ||||
| CODEOWNERS = ["@jesserockz"] | ||||
| CONFLICTS_WITH = ["esp32_ble_beacon"] | ||||
| DEPENDENCIES = ["wifi", "esp32"] | ||||
|  | ||||
| CONF_AUTHORIZED_DURATION = "authorized_duration" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user