mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	feat: Add ESP32 BLE enable/disable automations (#5616)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -89,9 +89,9 @@ esphome/components/ektf2232/* @jesserockz | |||||||
| esphome/components/emc2101/* @ellull | esphome/components/emc2101/* @ellull | ||||||
| esphome/components/ens210/* @itn3rd77 | esphome/components/ens210/* @itn3rd77 | ||||||
| esphome/components/esp32/* @esphome/core | esphome/components/esp32/* @esphome/core | ||||||
| esphome/components/esp32_ble/* @jesserockz | esphome/components/esp32_ble/* @Rapsssito @jesserockz | ||||||
| esphome/components/esp32_ble_client/* @jesserockz | esphome/components/esp32_ble_client/* @jesserockz | ||||||
| esphome/components/esp32_ble_server/* @clydebarrow @jesserockz | esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz | ||||||
| esphome/components/esp32_camera_web_server/* @ayufan | esphome/components/esp32_camera_web_server/* @ayufan | ||||||
| esphome/components/esp32_can/* @Sympatron | esphome/components/esp32_can/* @Sympatron | ||||||
| esphome/components/esp32_improv/* @jesserockz | esphome/components/esp32_improv/* @jesserockz | ||||||
|   | |||||||
| @@ -1,15 +1,17 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
|  | from esphome import automation | ||||||
| from esphome.const import CONF_ID | from esphome.const import CONF_ID | ||||||
| from esphome.core import CORE | from esphome.core import CORE | ||||||
| from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const | from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant, const | ||||||
|  |  | ||||||
| DEPENDENCIES = ["esp32"] | DEPENDENCIES = ["esp32"] | ||||||
| CODEOWNERS = ["@jesserockz"] | CODEOWNERS = ["@jesserockz", "@Rapsssito"] | ||||||
| CONFLICTS_WITH = ["esp32_ble_beacon"] | CONFLICTS_WITH = ["esp32_ble_beacon"] | ||||||
|  |  | ||||||
| CONF_BLE_ID = "ble_id" | CONF_BLE_ID = "ble_id" | ||||||
| CONF_IO_CAPABILITY = "io_capability" | CONF_IO_CAPABILITY = "io_capability" | ||||||
|  | CONF_ENABLE_ON_BOOT = "enable_on_boot" | ||||||
|  |  | ||||||
| NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2] | NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2] | ||||||
|  |  | ||||||
| @@ -20,6 +22,10 @@ GAPEventHandler = esp32_ble_ns.class_("GAPEventHandler") | |||||||
| GATTcEventHandler = esp32_ble_ns.class_("GATTcEventHandler") | GATTcEventHandler = esp32_ble_ns.class_("GATTcEventHandler") | ||||||
| GATTsEventHandler = esp32_ble_ns.class_("GATTsEventHandler") | GATTsEventHandler = esp32_ble_ns.class_("GATTsEventHandler") | ||||||
|  |  | ||||||
|  | BLEEnabledCondition = esp32_ble_ns.class_("BLEEnabledCondition", automation.Condition) | ||||||
|  | BLEEnableAction = esp32_ble_ns.class_("BLEEnableAction", automation.Action) | ||||||
|  | BLEDisableAction = esp32_ble_ns.class_("BLEDisableAction", automation.Action) | ||||||
|  |  | ||||||
| IoCapability = esp32_ble_ns.enum("IoCapability") | IoCapability = esp32_ble_ns.enum("IoCapability") | ||||||
| IO_CAPABILITY = { | IO_CAPABILITY = { | ||||||
|     "none": IoCapability.IO_CAP_NONE, |     "none": IoCapability.IO_CAP_NONE, | ||||||
| @@ -35,6 +41,7 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
|         cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum( |         cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum( | ||||||
|             IO_CAPABILITY, lower=True |             IO_CAPABILITY, lower=True | ||||||
|         ), |         ), | ||||||
|  |         cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean, | ||||||
|     } |     } | ||||||
| ).extend(cv.COMPONENT_SCHEMA) | ).extend(cv.COMPONENT_SCHEMA) | ||||||
|  |  | ||||||
| @@ -50,9 +57,25 @@ FINAL_VALIDATE_SCHEMA = validate_variant | |||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     await cg.register_component(var, config) |     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_io_capability(config[CONF_IO_CAPABILITY])) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |  | ||||||
|     if CORE.using_esp_idf: |     if CORE.using_esp_idf: | ||||||
|         add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) |         add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) | ||||||
|         add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True) |         add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_condition("ble.enabled", BLEEnabledCondition, cv.Schema({})) | ||||||
|  | async def ble_enabled_to_code(config, condition_id, template_arg, args): | ||||||
|  |     return cg.new_Pvariable(condition_id, template_arg) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action("ble.enable", BLEEnableAction, cv.Schema({})) | ||||||
|  | async def ble_enable_to_code(config, action_id, template_arg, args): | ||||||
|  |     return cg.new_Pvariable(action_id, template_arg) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action("ble.disable", BLEDisableAction, cv.Schema({})) | ||||||
|  | async def ble_disable_to_code(config, action_id, template_arg, args): | ||||||
|  |     return cg.new_Pvariable(action_id, template_arg) | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
| #include <esp_bt.h> | #include <esp_bt.h> | ||||||
| #include <esp_bt_main.h> |  | ||||||
| #include <esp_bt_device.h> | #include <esp_bt_device.h> | ||||||
|  | #include <esp_bt_main.h> | ||||||
| #include <esp_gap_ble_api.h> | #include <esp_gap_ble_api.h> | ||||||
| #include <freertos/FreeRTOS.h> | #include <freertos/FreeRTOS.h> | ||||||
| #include <freertos/FreeRTOSConfig.h> | #include <freertos/FreeRTOSConfig.h> | ||||||
| @@ -26,30 +26,85 @@ void ESP32BLE::setup() { | |||||||
|   global_ble = this; |   global_ble = this; | ||||||
|   ESP_LOGCONFIG(TAG, "Setting up BLE..."); |   ESP_LOGCONFIG(TAG, "Setting up BLE..."); | ||||||
|  |  | ||||||
|   if (!ble_setup_()) { |   if (!ble_pre_setup_()) { | ||||||
|     ESP_LOGE(TAG, "BLE could not be set up"); |     ESP_LOGE(TAG, "BLE could not be prepared for configuration"); | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| #ifdef USE_ESP32_BLE_SERVER |   this->state_ = BLE_COMPONENT_STATE_DISABLED; | ||||||
|   this->advertising_ = new BLEAdvertising();  // NOLINT(cppcoreguidelines-owning-memory) |   if (this->enable_on_boot_) { | ||||||
|  |     this->enable(); | ||||||
|   this->advertising_->set_scan_response(true); |   } | ||||||
|   this->advertising_->set_min_preferred_interval(0x06); |  | ||||||
|   this->advertising_->start(); |  | ||||||
| #endif  // USE_ESP32_BLE_SERVER |  | ||||||
|  |  | ||||||
|   ESP_LOGD(TAG, "BLE setup complete"); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool ESP32BLE::ble_setup_() { | void ESP32BLE::enable() { | ||||||
|  |   if (this->state_ != BLE_COMPONENT_STATE_DISABLED) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   this->state_ = BLE_COMPONENT_STATE_ENABLE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESP32BLE::disable() { | ||||||
|  |   if (this->state_ == BLE_COMPONENT_STATE_DISABLED) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   this->state_ = BLE_COMPONENT_STATE_DISABLE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ESP32BLE::is_active() { return this->state_ == BLE_COMPONENT_STATE_ACTIVE; } | ||||||
|  |  | ||||||
|  | void ESP32BLE::advertising_start() { | ||||||
|  |   this->advertising_init_(); | ||||||
|  |   if (!this->is_active()) | ||||||
|  |     return; | ||||||
|  |   this->advertising_->start(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESP32BLE::advertising_set_service_data(const std::vector<uint8_t> &data) { | ||||||
|  |   this->advertising_init_(); | ||||||
|  |   this->advertising_->set_service_data(data); | ||||||
|  |   this->advertising_start(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESP32BLE::advertising_set_manufacturer_data(const std::vector<uint8_t> &data) { | ||||||
|  |   this->advertising_init_(); | ||||||
|  |   this->advertising_->set_manufacturer_data(data); | ||||||
|  |   this->advertising_start(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESP32BLE::advertising_add_service_uuid(ESPBTUUID uuid) { | ||||||
|  |   this->advertising_init_(); | ||||||
|  |   this->advertising_->add_service_uuid(uuid); | ||||||
|  |   this->advertising_start(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESP32BLE::advertising_remove_service_uuid(ESPBTUUID uuid) { | ||||||
|  |   this->advertising_init_(); | ||||||
|  |   this->advertising_->remove_service_uuid(uuid); | ||||||
|  |   this->advertising_start(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ESP32BLE::ble_pre_setup_() { | ||||||
|   esp_err_t err = nvs_flash_init(); |   esp_err_t err = nvs_flash_init(); | ||||||
|   if (err != ESP_OK) { |   if (err != ESP_OK) { | ||||||
|     ESP_LOGE(TAG, "nvs_flash_init failed: %d", err); |     ESP_LOGE(TAG, "nvs_flash_init failed: %d", err); | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESP32BLE::advertising_init_() { | ||||||
|  |   if (this->advertising_ != nullptr) | ||||||
|  |     return; | ||||||
|  |   this->advertising_ = new BLEAdvertising();  // NOLINT(cppcoreguidelines-owning-memory) | ||||||
|  |  | ||||||
|  |   this->advertising_->set_scan_response(true); | ||||||
|  |   this->advertising_->set_min_preferred_interval(0x06); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ESP32BLE::ble_setup_() { | ||||||
|  |   esp_err_t err; | ||||||
| #ifdef USE_ARDUINO | #ifdef USE_ARDUINO | ||||||
|   if (!btStart()) { |   if (!btStart()) { | ||||||
|     ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status()); |     ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status()); | ||||||
| @@ -146,7 +201,88 @@ bool ESP32BLE::ble_setup_() { | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool ESP32BLE::ble_dismantle_() { | ||||||
|  |   esp_err_t err = esp_bluedroid_disable(); | ||||||
|  |   if (err != ESP_OK) { | ||||||
|  |     ESP_LOGE(TAG, "esp_bluedroid_disable failed: %d", err); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   err = esp_bluedroid_deinit(); | ||||||
|  |   if (err != ESP_OK) { | ||||||
|  |     ESP_LOGE(TAG, "esp_bluedroid_deinit failed: %d", err); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #ifdef USE_ARDUINO | ||||||
|  |   if (!btStop()) { | ||||||
|  |     ESP_LOGE(TAG, "btStop failed: %d", esp_bt_controller_get_status()); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | #else | ||||||
|  |   if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) { | ||||||
|  |     // stop bt controller | ||||||
|  |     if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) { | ||||||
|  |       err = esp_bt_controller_disable(); | ||||||
|  |       if (err != ESP_OK) { | ||||||
|  |         ESP_LOGE(TAG, "esp_bt_controller_disable failed: %s", esp_err_to_name(err)); | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |       while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) | ||||||
|  |         ; | ||||||
|  |     } | ||||||
|  |     if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) { | ||||||
|  |       err = esp_bt_controller_deinit(); | ||||||
|  |       if (err != ESP_OK) { | ||||||
|  |         ESP_LOGE(TAG, "esp_bt_controller_deinit failed: %s", esp_err_to_name(err)); | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) { | ||||||
|  |       ESP_LOGE(TAG, "esp bt controller disable failed"); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
| void ESP32BLE::loop() { | void ESP32BLE::loop() { | ||||||
|  |   switch (this->state_) { | ||||||
|  |     case BLE_COMPONENT_STATE_OFF: | ||||||
|  |     case BLE_COMPONENT_STATE_DISABLED: | ||||||
|  |       return; | ||||||
|  |     case BLE_COMPONENT_STATE_DISABLE: { | ||||||
|  |       ESP_LOGD(TAG, "Disabling BLE..."); | ||||||
|  |  | ||||||
|  |       for (auto *ble_event_handler : this->ble_status_event_handlers_) { | ||||||
|  |         ble_event_handler->ble_before_disabled_event_handler(); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (!ble_dismantle_()) { | ||||||
|  |         ESP_LOGE(TAG, "BLE could not be dismantled"); | ||||||
|  |         this->mark_failed(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       this->state_ = BLE_COMPONENT_STATE_DISABLED; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     case BLE_COMPONENT_STATE_ENABLE: { | ||||||
|  |       ESP_LOGD(TAG, "Enabling BLE..."); | ||||||
|  |       this->state_ = BLE_COMPONENT_STATE_OFF; | ||||||
|  |  | ||||||
|  |       if (!ble_setup_()) { | ||||||
|  |         ESP_LOGE(TAG, "BLE could not be set up"); | ||||||
|  |         this->mark_failed(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       this->state_ = BLE_COMPONENT_STATE_ACTIVE; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     case BLE_COMPONENT_STATE_ACTIVE: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   BLEEvent *ble_event = this->ble_events_.pop(); |   BLEEvent *ble_event = this->ble_events_.pop(); | ||||||
|   while (ble_event != nullptr) { |   while (ble_event != nullptr) { | ||||||
|     switch (ble_event->type_) { |     switch (ble_event->type_) { | ||||||
|   | |||||||
| @@ -1,19 +1,21 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "ble_advertising.h" | #include "ble_advertising.h" | ||||||
|  | #include "ble_uuid.h" | ||||||
|  |  | ||||||
|  | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/defines.h" | #include "esphome/core/defines.h" | ||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
|  |  | ||||||
| #include "queue.h" |  | ||||||
| #include "ble_event.h" | #include "ble_event.h" | ||||||
|  | #include "queue.h" | ||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
| #include <esp_gap_ble_api.h> | #include <esp_gap_ble_api.h> | ||||||
| #include <esp_gatts_api.h> |  | ||||||
| #include <esp_gattc_api.h> | #include <esp_gattc_api.h> | ||||||
|  | #include <esp_gatts_api.h> | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace esp32_ble { | namespace esp32_ble { | ||||||
| @@ -35,6 +37,19 @@ enum IoCapability { | |||||||
|   IO_CAP_KBDISP = ESP_IO_CAP_KBDISP, |   IO_CAP_KBDISP = ESP_IO_CAP_KBDISP, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum BLEComponentState { | ||||||
|  |   /** Nothing has been initialized yet. */ | ||||||
|  |   BLE_COMPONENT_STATE_OFF = 0, | ||||||
|  |   /** BLE should be disabled on next loop. */ | ||||||
|  |   BLE_COMPONENT_STATE_DISABLE, | ||||||
|  |   /** BLE is disabled. */ | ||||||
|  |   BLE_COMPONENT_STATE_DISABLED, | ||||||
|  |   /** BLE should be enabled on next loop. */ | ||||||
|  |   BLE_COMPONENT_STATE_ENABLE, | ||||||
|  |   /** BLE is active. */ | ||||||
|  |   BLE_COMPONENT_STATE_ACTIVE, | ||||||
|  | }; | ||||||
|  |  | ||||||
| class GAPEventHandler { | class GAPEventHandler { | ||||||
|  public: |  public: | ||||||
|   virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0; |   virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0; | ||||||
| @@ -52,20 +67,36 @@ class GATTsEventHandler { | |||||||
|                                    esp_ble_gatts_cb_param_t *param) = 0; |                                    esp_ble_gatts_cb_param_t *param) = 0; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | class BLEStatusEventHandler { | ||||||
|  |  public: | ||||||
|  |   virtual void ble_before_disabled_event_handler() = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
| class ESP32BLE : public Component { | class ESP32BLE : public Component { | ||||||
|  public: |  public: | ||||||
|   void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; } |   void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; } | ||||||
|  |  | ||||||
|  |   void enable(); | ||||||
|  |   void disable(); | ||||||
|  |   bool is_active(); | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   void loop() override; |   void loop() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|   float get_setup_priority() const override; |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|   BLEAdvertising *get_advertising() { return this->advertising_; } |   void advertising_start(); | ||||||
|  |   void advertising_set_service_data(const std::vector<uint8_t> &data); | ||||||
|  |   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 register_gap_event_handler(GAPEventHandler *handler) { this->gap_event_handlers_.push_back(handler); } |   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); } |   void register_gattc_event_handler(GATTcEventHandler *handler) { this->gattc_event_handlers_.push_back(handler); } | ||||||
|   void register_gatts_event_handler(GATTsEventHandler *handler) { this->gatts_event_handlers_.push_back(handler); } |   void register_gatts_event_handler(GATTsEventHandler *handler) { this->gatts_event_handlers_.push_back(handler); } | ||||||
|  |   void register_ble_status_event_handler(BLEStatusEventHandler *handler) { | ||||||
|  |     this->ble_status_event_handlers_.push_back(handler); | ||||||
|  |   } | ||||||
|  |   void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); |   static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); | ||||||
| @@ -77,19 +108,40 @@ class ESP32BLE : public Component { | |||||||
|   void real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); |   void real_gap_event_handler_(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); | ||||||
|  |  | ||||||
|   bool ble_setup_(); |   bool ble_setup_(); | ||||||
|  |   bool ble_dismantle_(); | ||||||
|  |   bool ble_pre_setup_(); | ||||||
|  |   void advertising_init_(); | ||||||
|  |  | ||||||
|   std::vector<GAPEventHandler *> gap_event_handlers_; |   std::vector<GAPEventHandler *> gap_event_handlers_; | ||||||
|   std::vector<GATTcEventHandler *> gattc_event_handlers_; |   std::vector<GATTcEventHandler *> gattc_event_handlers_; | ||||||
|   std::vector<GATTsEventHandler *> gatts_event_handlers_; |   std::vector<GATTsEventHandler *> gatts_event_handlers_; | ||||||
|  |   std::vector<BLEStatusEventHandler *> ble_status_event_handlers_; | ||||||
|  |   BLEComponentState state_{BLE_COMPONENT_STATE_OFF}; | ||||||
|  |  | ||||||
|   Queue<BLEEvent> ble_events_; |   Queue<BLEEvent> ble_events_; | ||||||
|   BLEAdvertising *advertising_; |   BLEAdvertising *advertising_; | ||||||
|   esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE}; |   esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE}; | ||||||
|  |   bool enable_on_boot_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
| extern ESP32BLE *global_ble; | extern ESP32BLE *global_ble; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class BLEEnabledCondition : public Condition<Ts...> { | ||||||
|  |  public: | ||||||
|  |   bool check(Ts... x) override { return global_ble->is_active(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class BLEEnableAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { global_ble->enable(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class BLEDisableAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { global_ble->disable(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
| }  // namespace esp32_ble | }  // namespace esp32_ble | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ from esphome.core import CORE | |||||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | from esphome.components.esp32 import add_idf_sdkconfig_option | ||||||
|  |  | ||||||
| AUTO_LOAD = ["esp32_ble"] | AUTO_LOAD = ["esp32_ble"] | ||||||
| CODEOWNERS = ["@jesserockz", "@clydebarrow"] | CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"] | ||||||
| CONFLICTS_WITH = ["esp32_ble_beacon"] | CONFLICTS_WITH = ["esp32_ble_beacon"] | ||||||
| DEPENDENCIES = ["esp32"] | DEPENDENCIES = ["esp32"] | ||||||
|  |  | ||||||
| @@ -41,6 +41,7 @@ async def to_code(config): | |||||||
|  |  | ||||||
|     parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID]) |     parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID]) | ||||||
|     cg.add(parent.register_gatts_event_handler(var)) |     cg.add(parent.register_gatts_event_handler(var)) | ||||||
|  |     cg.add(parent.register_ble_status_event_handler(var)) | ||||||
|     cg.add(var.set_parent(parent)) |     cg.add(var.set_parent(parent)) | ||||||
|  |  | ||||||
|     cg.add(var.set_manufacturer(config[CONF_MANUFACTURER])) |     cg.add(var.set_manufacturer(config[CONF_MANUFACTURER])) | ||||||
|   | |||||||
| @@ -11,6 +11,13 @@ namespace esp32_ble_server { | |||||||
|  |  | ||||||
| static const char *const TAG = "esp32_ble_server.characteristic"; | static const char *const TAG = "esp32_ble_server.characteristic"; | ||||||
|  |  | ||||||
|  | BLECharacteristic::~BLECharacteristic() { | ||||||
|  |   for (auto *descriptor : this->descriptors_) { | ||||||
|  |     delete descriptor;  // NOLINT(cppcoreguidelines-owning-memory) | ||||||
|  |   } | ||||||
|  |   vSemaphoreDelete(this->set_value_lock_); | ||||||
|  | } | ||||||
|  |  | ||||||
| BLECharacteristic::BLECharacteristic(const ESPBTUUID uuid, uint32_t properties) : uuid_(uuid) { | BLECharacteristic::BLECharacteristic(const ESPBTUUID uuid, uint32_t properties) : uuid_(uuid) { | ||||||
|   this->set_value_lock_ = xSemaphoreCreateBinary(); |   this->set_value_lock_ = xSemaphoreCreateBinary(); | ||||||
|   xSemaphoreGive(this->set_value_lock_); |   xSemaphoreGive(this->set_value_lock_); | ||||||
| @@ -98,6 +105,11 @@ void BLECharacteristic::notify(bool notification) { | |||||||
|  |  | ||||||
| void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) { this->descriptors_.push_back(descriptor); } | void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) { this->descriptors_.push_back(descriptor); } | ||||||
|  |  | ||||||
|  | void BLECharacteristic::remove_descriptor(BLEDescriptor *descriptor) { | ||||||
|  |   this->descriptors_.erase(std::remove(this->descriptors_.begin(), this->descriptors_.end(), descriptor), | ||||||
|  |                            this->descriptors_.end()); | ||||||
|  | } | ||||||
|  |  | ||||||
| void BLECharacteristic::do_create(BLEService *service) { | void BLECharacteristic::do_create(BLEService *service) { | ||||||
|   this->service_ = service; |   this->service_ = service; | ||||||
|   esp_attr_control_t control; |   esp_attr_control_t control; | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ class BLEService; | |||||||
| class BLECharacteristic { | class BLECharacteristic { | ||||||
|  public: |  public: | ||||||
|   BLECharacteristic(ESPBTUUID uuid, uint32_t properties); |   BLECharacteristic(ESPBTUUID uuid, uint32_t properties); | ||||||
|  |   ~BLECharacteristic(); | ||||||
|  |  | ||||||
|   void set_value(const uint8_t *data, size_t length); |   void set_value(const uint8_t *data, size_t length); | ||||||
|   void set_value(std::vector<uint8_t> value); |   void set_value(std::vector<uint8_t> value); | ||||||
| @@ -52,6 +53,7 @@ class BLECharacteristic { | |||||||
|   void on_write(const std::function<void(const std::vector<uint8_t> &)> &&func) { this->on_write_ = func; } |   void on_write(const std::function<void(const std::vector<uint8_t> &)> &&func) { this->on_write_ = func; } | ||||||
|  |  | ||||||
|   void add_descriptor(BLEDescriptor *descriptor); |   void add_descriptor(BLEDescriptor *descriptor); | ||||||
|  |   void remove_descriptor(BLEDescriptor *descriptor); | ||||||
|  |  | ||||||
|   BLEService *get_service() { return this->service_; } |   BLEService *get_service() { return this->service_; } | ||||||
|   ESPBTUUID get_uuid() { return this->uuid_; } |   ESPBTUUID get_uuid() { return this->uuid_; } | ||||||
|   | |||||||
| @@ -30,13 +30,13 @@ void BLEServer::setup() { | |||||||
|     ESP_LOGE(TAG, "BLE Server was marked failed by ESP32BLE"); |     ESP_LOGE(TAG, "BLE Server was marked failed by ESP32BLE"); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   ESP_LOGD(TAG, "Setting up BLE Server..."); |  | ||||||
|  |  | ||||||
|   global_ble_server = this; |   global_ble_server = this; | ||||||
| } | } | ||||||
|  |  | ||||||
| void BLEServer::loop() { | void BLEServer::loop() { | ||||||
|  |   if (!this->parent_->is_active()) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|   switch (this->state_) { |   switch (this->state_) { | ||||||
|     case RUNNING: |     case RUNNING: | ||||||
|       return; |       return; | ||||||
| @@ -53,10 +53,16 @@ void BLEServer::loop() { | |||||||
|     } |     } | ||||||
|     case REGISTERING: { |     case REGISTERING: { | ||||||
|       if (this->registered_) { |       if (this->registered_) { | ||||||
|         this->device_information_service_ = this->create_service(DEVICE_INFORMATION_SERVICE_UUID); |         // Create all services previously created | ||||||
|  |         for (auto &pair : this->services_) { | ||||||
|  |           pair.second->do_create(this); | ||||||
|  |         } | ||||||
|  |         if (this->device_information_service_ == nullptr) { | ||||||
|  |           this->create_service(ESPBTUUID::from_uint16(DEVICE_INFORMATION_SERVICE_UUID)); | ||||||
|  |           this->device_information_service_ = | ||||||
|  |               this->get_service(ESPBTUUID::from_uint16(DEVICE_INFORMATION_SERVICE_UUID)); | ||||||
|           this->create_device_characteristics_(); |           this->create_device_characteristics_(); | ||||||
|  |         } | ||||||
|         this->state_ = STARTING_SERVICE; |         this->state_ = STARTING_SERVICE; | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
| @@ -67,7 +73,6 @@ void BLEServer::loop() { | |||||||
|       } |       } | ||||||
|       if (this->device_information_service_->is_running()) { |       if (this->device_information_service_->is_running()) { | ||||||
|         this->state_ = RUNNING; |         this->state_ = RUNNING; | ||||||
|         this->can_proceed_ = true; |  | ||||||
|         this->restart_advertising_(); |         this->restart_advertising_(); | ||||||
|         ESP_LOGD(TAG, "BLE server setup successfully"); |         ESP_LOGD(TAG, "BLE server setup successfully"); | ||||||
|       } else if (!this->device_information_service_->is_starting()) { |       } else if (!this->device_information_service_->is_starting()) { | ||||||
| @@ -78,10 +83,13 @@ void BLEServer::loop() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool BLEServer::is_running() { return this->parent_->is_active() && this->state_ == RUNNING; } | ||||||
|  |  | ||||||
|  | bool BLEServer::can_proceed() { return this->is_running() || !this->parent_->is_active(); } | ||||||
|  |  | ||||||
| void BLEServer::restart_advertising_() { | void BLEServer::restart_advertising_() { | ||||||
|   if (this->state_ == RUNNING) { |   if (this->is_running()) { | ||||||
|     esp32_ble::global_ble->get_advertising()->set_manufacturer_data(this->manufacturer_data_); |     this->parent_->advertising_set_manufacturer_data(this->manufacturer_data_); | ||||||
|     esp32_ble::global_ble->get_advertising()->start(); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -107,24 +115,36 @@ bool BLEServer::create_device_characteristics_() { | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| std::shared_ptr<BLEService> BLEServer::create_service(const uint8_t *uuid, bool advertise) { | void BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles, uint8_t inst_id) { | ||||||
|   return this->create_service(ESPBTUUID::from_raw(uuid), advertise); |   ESP_LOGV(TAG, "Creating BLE service - %s", uuid.to_string().c_str()); | ||||||
| } |   // If the service already exists, do nothing | ||||||
| std::shared_ptr<BLEService> BLEServer::create_service(uint16_t uuid, bool advertise) { |   BLEService *service = this->get_service(uuid); | ||||||
|   return this->create_service(ESPBTUUID::from_uint16(uuid), advertise); |   if (service != nullptr) { | ||||||
| } |     ESP_LOGW(TAG, "BLE service %s already exists", uuid.to_string().c_str()); | ||||||
| std::shared_ptr<BLEService> BLEServer::create_service(const std::string &uuid, bool advertise) { |     return; | ||||||
|   return this->create_service(ESPBTUUID::from_raw(uuid), advertise); |  | ||||||
| } |  | ||||||
| std::shared_ptr<BLEService> BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles, |  | ||||||
|                                                       uint8_t inst_id) { |  | ||||||
|   ESP_LOGV(TAG, "Creating service - %s", uuid.to_string().c_str()); |  | ||||||
|   std::shared_ptr<BLEService> service = std::make_shared<BLEService>(uuid, num_handles, inst_id); |  | ||||||
|   this->services_.emplace_back(service); |  | ||||||
|   if (advertise) { |  | ||||||
|     esp32_ble::global_ble->get_advertising()->add_service_uuid(uuid); |  | ||||||
|   } |   } | ||||||
|  |   service = new BLEService(uuid, num_handles, inst_id, advertise);  // NOLINT(cppcoreguidelines-owning-memory) | ||||||
|  |   this->services_.emplace(uuid.to_string(), service); | ||||||
|   service->do_create(this); |   service->do_create(this); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void BLEServer::remove_service(ESPBTUUID uuid) { | ||||||
|  |   ESP_LOGV(TAG, "Removing BLE service - %s", uuid.to_string().c_str()); | ||||||
|  |   BLEService *service = this->get_service(uuid); | ||||||
|  |   if (service == nullptr) { | ||||||
|  |     ESP_LOGW(TAG, "BLE service %s not found", uuid.to_string().c_str()); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   service->do_delete(); | ||||||
|  |   delete service;  // NOLINT(cppcoreguidelines-owning-memory) | ||||||
|  |   this->services_.erase(uuid.to_string()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | BLEService *BLEServer::get_service(ESPBTUUID uuid) { | ||||||
|  |   BLEService *service = nullptr; | ||||||
|  |   if (this->services_.count(uuid.to_string()) > 0) { | ||||||
|  |     service = this->services_.at(uuid.to_string()); | ||||||
|  |   } | ||||||
|   return service; |   return service; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -144,7 +164,7 @@ void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t ga | |||||||
|       ESP_LOGD(TAG, "BLE Client disconnected"); |       ESP_LOGD(TAG, "BLE Client disconnected"); | ||||||
|       if (this->remove_client_(param->disconnect.conn_id)) |       if (this->remove_client_(param->disconnect.conn_id)) | ||||||
|         this->connected_clients_--; |         this->connected_clients_--; | ||||||
|       esp32_ble::global_ble->get_advertising()->start(); |       this->parent_->advertising_start(); | ||||||
|       for (auto *component : this->service_components_) { |       for (auto *component : this->service_components_) { | ||||||
|         component->on_client_disconnect(); |         component->on_client_disconnect(); | ||||||
|       } |       } | ||||||
| @@ -159,11 +179,22 @@ void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t ga | |||||||
|       break; |       break; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   for (const auto &service : this->services_) { |   for (const auto &pair : this->services_) { | ||||||
|     service->gatts_event_handler(event, gatts_if, param); |     pair.second->gatts_event_handler(event, gatts_if, param); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void BLEServer::ble_before_disabled_event_handler() { | ||||||
|  |   // Delete all clients | ||||||
|  |   this->clients_.clear(); | ||||||
|  |   // Delete all services | ||||||
|  |   for (auto &pair : this->services_) { | ||||||
|  |     pair.second->do_delete(); | ||||||
|  |   } | ||||||
|  |   this->registered_ = false; | ||||||
|  |   this->state_ = INIT; | ||||||
|  | } | ||||||
|  |  | ||||||
| float BLEServer::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH + 10; } | float BLEServer::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH + 10; } | ||||||
|  |  | ||||||
| void BLEServer::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE Server:"); } | void BLEServer::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE Server:"); } | ||||||
|   | |||||||
| @@ -11,9 +11,9 @@ | |||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| #include "esphome/core/preferences.h" | #include "esphome/core/preferences.h" | ||||||
|  |  | ||||||
| #include <map> |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <unordered_map> | ||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
| @@ -33,15 +33,16 @@ class BLEServiceComponent { | |||||||
|   virtual void stop(); |   virtual void stop(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class BLEServer : public Component, public GATTsEventHandler, public Parented<ESP32BLE> { | class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented<ESP32BLE> { | ||||||
|  public: |  public: | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   void loop() override; |   void loop() override; | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|   float get_setup_priority() const override; |   float get_setup_priority() const override; | ||||||
|   bool can_proceed() override { return this->can_proceed_; } |   bool can_proceed() override; | ||||||
|  |  | ||||||
|   void teardown(); |   void teardown(); | ||||||
|  |   bool is_running(); | ||||||
|  |  | ||||||
|   void set_manufacturer(const std::string &manufacturer) { this->manufacturer_ = manufacturer; } |   void set_manufacturer(const std::string &manufacturer) { this->manufacturer_ = manufacturer; } | ||||||
|   void set_model(const std::string &model) { this->model_ = model; } |   void set_model(const std::string &model) { this->model_ = model; } | ||||||
| @@ -50,32 +51,28 @@ class BLEServer : public Component, public GATTsEventHandler, public Parented<ES | |||||||
|     this->restart_advertising_(); |     this->restart_advertising_(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   std::shared_ptr<BLEService> create_service(const uint8_t *uuid, bool advertise = false); |   void create_service(ESPBTUUID uuid, bool advertise = false, uint16_t num_handles = 15, uint8_t inst_id = 0); | ||||||
|   std::shared_ptr<BLEService> create_service(uint16_t uuid, bool advertise = false); |   void remove_service(ESPBTUUID uuid); | ||||||
|   std::shared_ptr<BLEService> create_service(const std::string &uuid, bool advertise = false); |   BLEService *get_service(ESPBTUUID uuid); | ||||||
|   std::shared_ptr<BLEService> create_service(ESPBTUUID uuid, bool advertise = false, uint16_t num_handles = 15, |  | ||||||
|                                              uint8_t inst_id = 0); |  | ||||||
|  |  | ||||||
|   esp_gatt_if_t get_gatts_if() { return this->gatts_if_; } |   esp_gatt_if_t get_gatts_if() { return this->gatts_if_; } | ||||||
|   uint32_t get_connected_client_count() { return this->connected_clients_; } |   uint32_t get_connected_client_count() { return this->connected_clients_; } | ||||||
|   const std::map<uint16_t, void *> &get_clients() { return this->clients_; } |   const std::unordered_map<uint16_t, void *> &get_clients() { return this->clients_; } | ||||||
|  |  | ||||||
|   void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, |   void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, | ||||||
|                            esp_ble_gatts_cb_param_t *param) override; |                            esp_ble_gatts_cb_param_t *param) override; | ||||||
|  |  | ||||||
|  |   void ble_before_disabled_event_handler() override; | ||||||
|  |  | ||||||
|   void register_service_component(BLEServiceComponent *component) { this->service_components_.push_back(component); } |   void register_service_component(BLEServiceComponent *component) { this->service_components_.push_back(component); } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   bool create_device_characteristics_(); |   bool create_device_characteristics_(); | ||||||
|   void restart_advertising_(); |   void restart_advertising_(); | ||||||
|  |  | ||||||
|   void add_client_(uint16_t conn_id, void *client) { |   void add_client_(uint16_t conn_id, void *client) { this->clients_.emplace(conn_id, client); } | ||||||
|     this->clients_.insert(std::pair<uint16_t, void *>(conn_id, client)); |  | ||||||
|   } |  | ||||||
|   bool remove_client_(uint16_t conn_id) { return this->clients_.erase(conn_id) > 0; } |   bool remove_client_(uint16_t conn_id) { return this->clients_.erase(conn_id) > 0; } | ||||||
|  |  | ||||||
|   bool can_proceed_{false}; |  | ||||||
|  |  | ||||||
|   std::string manufacturer_; |   std::string manufacturer_; | ||||||
|   optional<std::string> model_; |   optional<std::string> model_; | ||||||
|   std::vector<uint8_t> manufacturer_data_; |   std::vector<uint8_t> manufacturer_data_; | ||||||
| @@ -83,10 +80,9 @@ class BLEServer : public Component, public GATTsEventHandler, public Parented<ES | |||||||
|   bool registered_{false}; |   bool registered_{false}; | ||||||
|  |  | ||||||
|   uint32_t connected_clients_{0}; |   uint32_t connected_clients_{0}; | ||||||
|   std::map<uint16_t, void *> clients_; |   std::unordered_map<uint16_t, void *> clients_; | ||||||
|  |   std::unordered_map<std::string, BLEService *> services_; | ||||||
|   std::vector<std::shared_ptr<BLEService>> services_; |   BLEService *device_information_service_; | ||||||
|   std::shared_ptr<BLEService> device_information_service_; |  | ||||||
|  |  | ||||||
|   std::vector<BLEServiceComponent *> service_components_; |   std::vector<BLEServiceComponent *> service_components_; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,8 +9,8 @@ namespace esp32_ble_server { | |||||||
|  |  | ||||||
| static const char *const TAG = "esp32_ble_server.service"; | static const char *const TAG = "esp32_ble_server.service"; | ||||||
|  |  | ||||||
| BLEService::BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id) | BLEService::BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id, bool advertise) | ||||||
|     : uuid_(uuid), num_handles_(num_handles), inst_id_(inst_id) {} |     : uuid_(uuid), num_handles_(num_handles), inst_id_(inst_id), advertise_(advertise) {} | ||||||
|  |  | ||||||
| BLEService::~BLEService() { | BLEService::~BLEService() { | ||||||
|   for (auto &chr : this->characteristics_) |   for (auto &chr : this->characteristics_) | ||||||
| @@ -58,6 +58,20 @@ void BLEService::do_create(BLEServer *server) { | |||||||
|   this->init_state_ = CREATING; |   this->init_state_ = CREATING; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void BLEService::do_delete() { | ||||||
|  |   if (this->init_state_ == DELETING || this->init_state_ == DELETED) | ||||||
|  |     return; | ||||||
|  |   this->init_state_ = DELETING; | ||||||
|  |   this->created_characteristic_count_ = 0; | ||||||
|  |   this->last_created_characteristic_ = nullptr; | ||||||
|  |   this->stop_(); | ||||||
|  |   esp_err_t err = esp_ble_gatts_delete_service(this->handle_); | ||||||
|  |   if (err != ESP_OK) { | ||||||
|  |     ESP_LOGE(TAG, "esp_ble_gatts_delete_service failed: %d", err); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| bool BLEService::do_create_characteristics_() { | bool BLEService::do_create_characteristics_() { | ||||||
|   if (this->created_characteristic_count_ >= this->characteristics_.size() && |   if (this->created_characteristic_count_ >= this->characteristics_.size() && | ||||||
|       (this->last_created_characteristic_ == nullptr || this->last_created_characteristic_->is_created())) |       (this->last_created_characteristic_ == nullptr || this->last_created_characteristic_->is_created())) | ||||||
| @@ -75,24 +89,34 @@ bool BLEService::do_create_characteristics_() { | |||||||
| void BLEService::start() { | void BLEService::start() { | ||||||
|   if (this->do_create_characteristics_()) |   if (this->do_create_characteristics_()) | ||||||
|     return; |     return; | ||||||
|  |   should_start_ = true; | ||||||
|  |  | ||||||
|   esp_err_t err = esp_ble_gatts_start_service(this->handle_); |   esp_err_t err = esp_ble_gatts_start_service(this->handle_); | ||||||
|   if (err != ESP_OK) { |   if (err != ESP_OK) { | ||||||
|     ESP_LOGE(TAG, "esp_ble_gatts_start_service failed: %d", err); |     ESP_LOGE(TAG, "esp_ble_gatts_start_service failed: %d", err); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |   if (this->advertise_) | ||||||
|  |     esp32_ble::global_ble->advertising_add_service_uuid(this->uuid_); | ||||||
|   this->running_state_ = STARTING; |   this->running_state_ = STARTING; | ||||||
| } | } | ||||||
|  |  | ||||||
| void BLEService::stop() { | void BLEService::stop() { | ||||||
|  |   should_start_ = false; | ||||||
|  |   this->stop_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void BLEService::stop_() { | ||||||
|  |   if (this->running_state_ == STOPPING || this->running_state_ == STOPPED) | ||||||
|  |     return; | ||||||
|  |   this->running_state_ = STOPPING; | ||||||
|   esp_err_t err = esp_ble_gatts_stop_service(this->handle_); |   esp_err_t err = esp_ble_gatts_stop_service(this->handle_); | ||||||
|   if (err != ESP_OK) { |   if (err != ESP_OK) { | ||||||
|     ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err); |     ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   esp32_ble::global_ble->get_advertising()->remove_service_uuid(this->uuid_); |   if (this->advertise_) | ||||||
|   esp32_ble::global_ble->get_advertising()->start(); |     esp32_ble::global_ble->advertising_remove_service_uuid(this->uuid_); | ||||||
|   this->running_state_ = STOPPING; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool BLEService::is_created() { return this->init_state_ == CREATED; } | bool BLEService::is_created() { return this->init_state_ == CREATED; } | ||||||
| @@ -116,9 +140,16 @@ void BLEService::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t g | |||||||
|           this->inst_id_ == param->create.service_id.id.inst_id) { |           this->inst_id_ == param->create.service_id.id.inst_id) { | ||||||
|         this->handle_ = param->create.service_handle; |         this->handle_ = param->create.service_handle; | ||||||
|         this->init_state_ = CREATED; |         this->init_state_ = CREATED; | ||||||
|  |         if (this->should_start_) | ||||||
|  |           this->start(); | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|  |     case ESP_GATTS_DELETE_EVT: | ||||||
|  |       if (param->del.service_handle == this->handle_) { | ||||||
|  |         this->init_state_ = DELETED; | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|     case ESP_GATTS_START_EVT: { |     case ESP_GATTS_START_EVT: { | ||||||
|       if (param->start.service_handle == this->handle_) { |       if (param->start.service_handle == this->handle_) { | ||||||
|         this->running_state_ = RUNNING; |         this->running_state_ = RUNNING; | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ using namespace esp32_ble; | |||||||
|  |  | ||||||
| class BLEService { | class BLEService { | ||||||
|  public: |  public: | ||||||
|   BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id); |   BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id, bool advertise); | ||||||
|   ~BLEService(); |   ~BLEService(); | ||||||
|   BLECharacteristic *get_characteristic(ESPBTUUID uuid); |   BLECharacteristic *get_characteristic(ESPBTUUID uuid); | ||||||
|   BLECharacteristic *get_characteristic(uint16_t uuid); |   BLECharacteristic *get_characteristic(uint16_t uuid); | ||||||
| @@ -38,6 +38,7 @@ class BLEService { | |||||||
|   BLEServer *get_server() { return this->server_; } |   BLEServer *get_server() { return this->server_; } | ||||||
|  |  | ||||||
|   void do_create(BLEServer *server); |   void do_create(BLEServer *server); | ||||||
|  |   void do_delete(); | ||||||
|   void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); |   void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); | ||||||
|  |  | ||||||
|   void start(); |   void start(); | ||||||
| @@ -48,6 +49,7 @@ class BLEService { | |||||||
|  |  | ||||||
|   bool is_running() { return this->running_state_ == RUNNING; } |   bool is_running() { return this->running_state_ == RUNNING; } | ||||||
|   bool is_starting() { return this->running_state_ == STARTING; } |   bool is_starting() { return this->running_state_ == STARTING; } | ||||||
|  |   bool is_deleted() { return this->init_state_ == DELETED; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   std::vector<BLECharacteristic *> characteristics_; |   std::vector<BLECharacteristic *> characteristics_; | ||||||
| @@ -58,8 +60,11 @@ class BLEService { | |||||||
|   uint16_t num_handles_; |   uint16_t num_handles_; | ||||||
|   uint16_t handle_{0xFFFF}; |   uint16_t handle_{0xFFFF}; | ||||||
|   uint8_t inst_id_; |   uint8_t inst_id_; | ||||||
|  |   bool advertise_{false}; | ||||||
|  |   bool should_start_{false}; | ||||||
|  |  | ||||||
|   bool do_create_characteristics_(); |   bool do_create_characteristics_(); | ||||||
|  |   void stop_(); | ||||||
|  |  | ||||||
|   enum InitState : uint8_t { |   enum InitState : uint8_t { | ||||||
|     FAILED = 0x00, |     FAILED = 0x00, | ||||||
| @@ -67,6 +72,8 @@ class BLEService { | |||||||
|     CREATING, |     CREATING, | ||||||
|     CREATING_DEPENDENTS, |     CREATING_DEPENDENTS, | ||||||
|     CREATED, |     CREATED, | ||||||
|  |     DELETING, | ||||||
|  |     DELETED, | ||||||
|   } init_state_{INIT}; |   } init_state_{INIT}; | ||||||
|  |  | ||||||
|   enum RunningState : uint8_t { |   enum RunningState : uint8_t { | ||||||
|   | |||||||
| @@ -212,6 +212,7 @@ async def to_code(config): | |||||||
|     parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID]) |     parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID]) | ||||||
|     cg.add(parent.register_gap_event_handler(var)) |     cg.add(parent.register_gap_event_handler(var)) | ||||||
|     cg.add(parent.register_gattc_event_handler(var)) |     cg.add(parent.register_gattc_event_handler(var)) | ||||||
|  |     cg.add(parent.register_ble_status_event_handler(var)) | ||||||
|     cg.add(var.set_parent(parent)) |     cg.add(var.set_parent(parent)) | ||||||
|  |  | ||||||
|     params = config[CONF_SCAN_PARAMETERS] |     params = config[CONF_SCAN_PARAMETERS] | ||||||
|   | |||||||
| @@ -64,17 +64,19 @@ void ESP32BLETracker::setup() { | |||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   if (this->scan_continuous_) { |  | ||||||
|     if (xSemaphoreTake(this->scan_end_lock_, 0L)) { |  | ||||||
|       this->start_scan_(true); |  | ||||||
|     } else { |  | ||||||
|       ESP_LOGW(TAG, "Cannot start scan!"); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void ESP32BLETracker::loop() { | void ESP32BLETracker::loop() { | ||||||
|  |   if (!this->parent_->is_active()) { | ||||||
|  |     this->ble_was_disabled_ = true; | ||||||
|  |     return; | ||||||
|  |   } else if (this->ble_was_disabled_) { | ||||||
|  |     this->ble_was_disabled_ = false; | ||||||
|  |     // If the BLE stack was disabled, we need to start the scan again. | ||||||
|  |     if (this->scan_continuous_) { | ||||||
|  |       this->start_scan(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|   int connecting = 0; |   int connecting = 0; | ||||||
|   int discovered = 0; |   int discovered = 0; | ||||||
|   int searching = 0; |   int searching = 0; | ||||||
| @@ -182,8 +184,7 @@ void ESP32BLETracker::loop() { | |||||||
|         xSemaphoreGive(this->scan_end_lock_); |         xSemaphoreGive(this->scan_end_lock_); | ||||||
|       } else { |       } else { | ||||||
|         ESP_LOGD(TAG, "Stopping scan after failure..."); |         ESP_LOGD(TAG, "Stopping scan after failure..."); | ||||||
|         esp_ble_gap_stop_scanning(); |         this->stop_scan_(); | ||||||
|         this->cancel_timeout("scan"); |  | ||||||
|       } |       } | ||||||
|       if (this->scan_start_failed_) { |       if (this->scan_start_failed_) { | ||||||
|         ESP_LOGE(TAG, "Scan start failed: %d", this->scan_start_failed_); |         ESP_LOGE(TAG, "Scan start failed: %d", this->scan_start_failed_); | ||||||
| @@ -212,8 +213,7 @@ void ESP32BLETracker::loop() { | |||||||
|           client->set_state(ClientState::READY_TO_CONNECT); |           client->set_state(ClientState::READY_TO_CONNECT); | ||||||
|         } else { |         } else { | ||||||
|           ESP_LOGD(TAG, "Pausing scan to make connection..."); |           ESP_LOGD(TAG, "Pausing scan to make connection..."); | ||||||
|           esp_ble_gap_stop_scanning(); |           this->stop_scan_(); | ||||||
|           this->cancel_timeout("scan"); |  | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
| @@ -232,11 +232,31 @@ void ESP32BLETracker::start_scan() { | |||||||
| void ESP32BLETracker::stop_scan() { | void ESP32BLETracker::stop_scan() { | ||||||
|   ESP_LOGD(TAG, "Stopping scan."); |   ESP_LOGD(TAG, "Stopping scan."); | ||||||
|   this->scan_continuous_ = false; |   this->scan_continuous_ = false; | ||||||
|   esp_ble_gap_stop_scanning(); |   this->stop_scan_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESP32BLETracker::ble_before_disabled_event_handler() { | ||||||
|  |   this->stop_scan_(); | ||||||
|  |   xSemaphoreGive(this->scan_end_lock_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESP32BLETracker::stop_scan_() { | ||||||
|   this->cancel_timeout("scan"); |   this->cancel_timeout("scan"); | ||||||
|  |   if (this->scanner_idle_) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   esp_err_t err = esp_ble_gap_stop_scanning(); | ||||||
|  |   if (err != ESP_OK) { | ||||||
|  |     ESP_LOGE(TAG, "esp_ble_gap_stop_scanning failed: %d", err); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void ESP32BLETracker::start_scan_(bool first) { | void ESP32BLETracker::start_scan_(bool first) { | ||||||
|  |   if (!this->parent_->is_active()) { | ||||||
|  |     ESP_LOGW(TAG, "Cannot start scan while ESP32BLE is disabled."); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|   // The lock must be held when calling this function. |   // The lock must be held when calling this function. | ||||||
|   if (xSemaphoreTake(this->scan_end_lock_, 0L)) { |   if (xSemaphoreTake(this->scan_end_lock_, 0L)) { | ||||||
|     ESP_LOGE(TAG, "start_scan called without holding scan_end_lock_"); |     ESP_LOGE(TAG, "start_scan called without holding scan_end_lock_"); | ||||||
| @@ -249,15 +269,23 @@ void ESP32BLETracker::start_scan_(bool first) { | |||||||
|       listener->on_scan_end(); |       listener->on_scan_end(); | ||||||
|   } |   } | ||||||
|   this->already_discovered_.clear(); |   this->already_discovered_.clear(); | ||||||
|   this->scanner_idle_ = false; |  | ||||||
|   this->scan_params_.scan_type = this->scan_active_ ? BLE_SCAN_TYPE_ACTIVE : BLE_SCAN_TYPE_PASSIVE; |   this->scan_params_.scan_type = this->scan_active_ ? BLE_SCAN_TYPE_ACTIVE : BLE_SCAN_TYPE_PASSIVE; | ||||||
|   this->scan_params_.own_addr_type = BLE_ADDR_TYPE_PUBLIC; |   this->scan_params_.own_addr_type = BLE_ADDR_TYPE_PUBLIC; | ||||||
|   this->scan_params_.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL; |   this->scan_params_.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL; | ||||||
|   this->scan_params_.scan_interval = this->scan_interval_; |   this->scan_params_.scan_interval = this->scan_interval_; | ||||||
|   this->scan_params_.scan_window = this->scan_window_; |   this->scan_params_.scan_window = this->scan_window_; | ||||||
|  |  | ||||||
|   esp_ble_gap_set_scan_params(&this->scan_params_); |   esp_err_t err = esp_ble_gap_set_scan_params(&this->scan_params_); | ||||||
|   esp_ble_gap_start_scanning(this->scan_duration_); |   if (err != ESP_OK) { | ||||||
|  |     ESP_LOGE(TAG, "esp_ble_gap_set_scan_params failed: %d", err); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   err = esp_ble_gap_start_scanning(this->scan_duration_); | ||||||
|  |   if (err != ESP_OK) { | ||||||
|  |     ESP_LOGE(TAG, "esp_ble_gap_start_scanning failed: %d", err); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   this->scanner_idle_ = false; | ||||||
|  |  | ||||||
|   this->set_timeout("scan", this->scan_duration_ * 2000, []() { |   this->set_timeout("scan", this->scan_duration_ * 2000, []() { | ||||||
|     ESP_LOGE(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack..."); |     ESP_LOGE(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack..."); | ||||||
|   | |||||||
| @@ -177,7 +177,11 @@ class ESPBTClient : public ESPBTDeviceListener { | |||||||
|   ClientState state_; |   ClientState state_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class ESP32BLETracker : public Component, public GAPEventHandler, public GATTcEventHandler, public Parented<ESP32BLE> { | class ESP32BLETracker : public Component, | ||||||
|  |                         public GAPEventHandler, | ||||||
|  |                         public GATTcEventHandler, | ||||||
|  |                         public BLEStatusEventHandler, | ||||||
|  |                         public Parented<ESP32BLE> { | ||||||
|  public: |  public: | ||||||
|   void set_scan_duration(uint32_t scan_duration) { scan_duration_ = scan_duration; } |   void set_scan_duration(uint32_t scan_duration) { scan_duration_ = scan_duration; } | ||||||
|   void set_scan_interval(uint32_t scan_interval) { scan_interval_ = scan_interval; } |   void set_scan_interval(uint32_t scan_interval) { scan_interval_ = scan_interval; } | ||||||
| @@ -204,8 +208,10 @@ class ESP32BLETracker : public Component, public GAPEventHandler, public GATTcEv | |||||||
|   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, |   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | ||||||
|                            esp_ble_gattc_cb_param_t *param) override; |                            esp_ble_gattc_cb_param_t *param) override; | ||||||
|   void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; |   void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; | ||||||
|  |   void ble_before_disabled_event_handler() override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|  |   void stop_scan_(); | ||||||
|   /// Start a single scan by setting up the parameters and doing some esp-idf calls. |   /// Start a single scan by setting up the parameters and doing some esp-idf calls. | ||||||
|   void start_scan_(bool first); |   void start_scan_(bool first); | ||||||
|   /// Called when a scan ends |   /// Called when a scan ends | ||||||
| @@ -236,6 +242,7 @@ class ESP32BLETracker : public Component, public GAPEventHandler, public GATTcEv | |||||||
|   bool scan_continuous_; |   bool scan_continuous_; | ||||||
|   bool scan_active_; |   bool scan_active_; | ||||||
|   bool scanner_idle_; |   bool scanner_idle_; | ||||||
|  |   bool ble_was_disabled_{true}; | ||||||
|   bool raw_advertisements_{false}; |   bool raw_advertisements_{false}; | ||||||
|   bool parse_advertisements_{false}; |   bool parse_advertisements_{false}; | ||||||
|   SemaphoreHandle_t scan_result_lock_; |   SemaphoreHandle_t scan_result_lock_; | ||||||
|   | |||||||
| @@ -16,9 +16,6 @@ static const char *const ESPHOME_MY_LINK = "https://my.home-assistant.io/redirec | |||||||
| ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; } | ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; } | ||||||
|  |  | ||||||
| void ESP32ImprovComponent::setup() { | void ESP32ImprovComponent::setup() { | ||||||
|   this->service_ = global_ble_server->create_service(improv::SERVICE_UUID, true); |  | ||||||
|   this->setup_characteristics(); |  | ||||||
|  |  | ||||||
| #ifdef USE_BINARY_SENSOR | #ifdef USE_BINARY_SENSOR | ||||||
|   if (this->authorizer_ != nullptr) { |   if (this->authorizer_ != nullptr) { | ||||||
|     this->authorizer_->add_on_state_callback([this](bool state) { |     this->authorizer_->add_on_state_callback([this](bool state) { | ||||||
| @@ -70,6 +67,19 @@ void ESP32ImprovComponent::setup_characteristics() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void ESP32ImprovComponent::loop() { | void ESP32ImprovComponent::loop() { | ||||||
|  |   if (!global_ble_server->is_running()) { | ||||||
|  |     this->state_ = improv::STATE_STOPPED; | ||||||
|  |     this->incoming_data_.clear(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (this->service_ == nullptr) { | ||||||
|  |     // Setup the service | ||||||
|  |     ESP_LOGD(TAG, "Creating Improv service"); | ||||||
|  |     global_ble_server->create_service(ESPBTUUID::from_raw(improv::SERVICE_UUID), true); | ||||||
|  |     this->service_ = global_ble_server->get_service(ESPBTUUID::from_raw(improv::SERVICE_UUID)); | ||||||
|  |     this->setup_characteristics(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   if (!this->incoming_data_.empty()) |   if (!this->incoming_data_.empty()) | ||||||
|     this->process_incoming_data_(); |     this->process_incoming_data_(); | ||||||
|   uint32_t now = millis(); |   uint32_t now = millis(); | ||||||
| @@ -80,11 +90,10 @@ void ESP32ImprovComponent::loop() { | |||||||
|  |  | ||||||
|       if (this->service_->is_created() && this->should_start_ && this->setup_complete_) { |       if (this->service_->is_created() && this->should_start_ && this->setup_complete_) { | ||||||
|         if (this->service_->is_running()) { |         if (this->service_->is_running()) { | ||||||
|           esp32_ble::global_ble->get_advertising()->start(); |           esp32_ble::global_ble->advertising_start(); | ||||||
|  |  | ||||||
|           this->set_state_(improv::STATE_AWAITING_AUTHORIZATION); |           this->set_state_(improv::STATE_AWAITING_AUTHORIZATION); | ||||||
|           this->set_error_(improv::ERROR_NONE); |           this->set_error_(improv::ERROR_NONE); | ||||||
|           this->should_start_ = false; |  | ||||||
|           ESP_LOGD(TAG, "Service started!"); |           ESP_LOGD(TAG, "Service started!"); | ||||||
|         } else { |         } else { | ||||||
|           this->service_->start(); |           this->service_->start(); | ||||||
| @@ -138,10 +147,7 @@ void ESP32ImprovComponent::loop() { | |||||||
| #endif | #endif | ||||||
|         std::vector<uint8_t> data = improv::build_rpc_response(improv::WIFI_SETTINGS, urls); |         std::vector<uint8_t> data = improv::build_rpc_response(improv::WIFI_SETTINGS, urls); | ||||||
|         this->send_response_(data); |         this->send_response_(data); | ||||||
|         this->set_timeout("end-service", 1000, [this] { |         this->stop(); | ||||||
|           this->service_->stop(); |  | ||||||
|           this->set_state_(improv::STATE_STOPPED); |  | ||||||
|         }); |  | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
| @@ -206,8 +212,7 @@ void ESP32ImprovComponent::set_state_(improv::State state) { | |||||||
|   service_data[6] = 0x00;  // Reserved |   service_data[6] = 0x00;  // Reserved | ||||||
|   service_data[7] = 0x00;  // Reserved |   service_data[7] = 0x00;  // Reserved | ||||||
|  |  | ||||||
|   esp32_ble::global_ble->get_advertising()->set_service_data(service_data); |   esp32_ble::global_ble->advertising_set_service_data(service_data); | ||||||
|   esp32_ble::global_ble->get_advertising()->start(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void ESP32ImprovComponent::set_error_(improv::Error error) { | void ESP32ImprovComponent::set_error_(improv::Error error) { | ||||||
| @@ -237,7 +242,10 @@ void ESP32ImprovComponent::start() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void ESP32ImprovComponent::stop() { | void ESP32ImprovComponent::stop() { | ||||||
|  |   this->should_start_ = false; | ||||||
|   this->set_timeout("end-service", 1000, [this] { |   this->set_timeout("end-service", 1000, [this] { | ||||||
|  |     if (this->state_ == improv::STATE_STOPPED || this->service_ == nullptr) | ||||||
|  |       return; | ||||||
|     this->service_->stop(); |     this->service_->stop(); | ||||||
|     this->set_state_(improv::STATE_STOPPED); |     this->set_state_(improv::STATE_STOPPED); | ||||||
|   }); |   }); | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { | |||||||
|   std::vector<uint8_t> incoming_data_; |   std::vector<uint8_t> incoming_data_; | ||||||
|   wifi::WiFiAP connecting_sta_; |   wifi::WiFiAP connecting_sta_; | ||||||
|  |  | ||||||
|   std::shared_ptr<BLEService> service_; |   BLEService *service_ = nullptr; | ||||||
|   BLECharacteristic *status_; |   BLECharacteristic *status_; | ||||||
|   BLECharacteristic *error_; |   BLECharacteristic *error_; | ||||||
|   BLECharacteristic *rpc_; |   BLECharacteristic *rpc_; | ||||||
|   | |||||||
| @@ -104,6 +104,12 @@ binary_sensor: | |||||||
|     on_release: |     on_release: | ||||||
|       then: |       then: | ||||||
|         - switch.turn_off: Led0 |         - switch.turn_off: Led0 | ||||||
|  |         - if: | ||||||
|  |             condition: ble.enabled | ||||||
|  |             then: | ||||||
|  |               - ble.disable: | ||||||
|  |             else: | ||||||
|  |               - ble.enable: | ||||||
|  |  | ||||||
|   - platform: tm1638 |   - platform: tm1638 | ||||||
|     id: Button1 |     id: Button1 | ||||||
| @@ -273,6 +279,7 @@ output: | |||||||
| demo: | demo: | ||||||
|  |  | ||||||
| esp32_ble: | esp32_ble: | ||||||
|  |   enable_on_boot: false | ||||||
|  |  | ||||||
| esp32_ble_server: | esp32_ble_server: | ||||||
|   manufacturer: ESPHome |   manufacturer: ESPHome | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user