mirror of
https://github.com/esphome/esphome.git
synced 2024-11-22 06:58:11 +01: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:
parent
ff8b904097
commit
d5aeb32ca6
17 changed files with 446 additions and 104 deletions
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue