1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-10 23:32:23 +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:
Rodrigo Martín
2023-11-06 03:54:39 +01:00
committed by GitHub
parent ff8b904097
commit d5aeb32ca6
17 changed files with 446 additions and 104 deletions

View File

@@ -6,7 +6,7 @@ from esphome.core import CORE
from esphome.components.esp32 import add_idf_sdkconfig_option
AUTO_LOAD = ["esp32_ble"]
CODEOWNERS = ["@jesserockz", "@clydebarrow"]
CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"]
CONFLICTS_WITH = ["esp32_ble_beacon"]
DEPENDENCIES = ["esp32"]
@@ -41,6 +41,7 @@ async def to_code(config):
parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID])
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_manufacturer(config[CONF_MANUFACTURER]))

View File

@@ -11,6 +11,13 @@ namespace esp32_ble_server {
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) {
this->set_value_lock_ = xSemaphoreCreateBinary();
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::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) {
this->service_ = service;
esp_attr_control_t control;

View File

@@ -25,6 +25,7 @@ class BLEService;
class BLECharacteristic {
public:
BLECharacteristic(ESPBTUUID uuid, uint32_t properties);
~BLECharacteristic();
void set_value(const uint8_t *data, size_t length);
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 add_descriptor(BLEDescriptor *descriptor);
void remove_descriptor(BLEDescriptor *descriptor);
BLEService *get_service() { return this->service_; }
ESPBTUUID get_uuid() { return this->uuid_; }

View File

@@ -30,13 +30,13 @@ void BLEServer::setup() {
ESP_LOGE(TAG, "BLE Server was marked failed by ESP32BLE");
return;
}
ESP_LOGD(TAG, "Setting up BLE Server...");
global_ble_server = this;
}
void BLEServer::loop() {
if (!this->parent_->is_active()) {
return;
}
switch (this->state_) {
case RUNNING:
return;
@@ -53,10 +53,16 @@ void BLEServer::loop() {
}
case REGISTERING: {
if (this->registered_) {
this->device_information_service_ = this->create_service(DEVICE_INFORMATION_SERVICE_UUID);
this->create_device_characteristics_();
// 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->state_ = STARTING_SERVICE;
}
break;
@@ -67,7 +73,6 @@ void BLEServer::loop() {
}
if (this->device_information_service_->is_running()) {
this->state_ = RUNNING;
this->can_proceed_ = true;
this->restart_advertising_();
ESP_LOGD(TAG, "BLE server setup successfully");
} 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_() {
if (this->state_ == RUNNING) {
esp32_ble::global_ble->get_advertising()->set_manufacturer_data(this->manufacturer_data_);
esp32_ble::global_ble->get_advertising()->start();
if (this->is_running()) {
this->parent_->advertising_set_manufacturer_data(this->manufacturer_data_);
}
}
@@ -107,24 +115,36 @@ bool BLEServer::create_device_characteristics_() {
return true;
}
std::shared_ptr<BLEService> BLEServer::create_service(const uint8_t *uuid, bool advertise) {
return this->create_service(ESPBTUUID::from_raw(uuid), advertise);
}
std::shared_ptr<BLEService> BLEServer::create_service(uint16_t uuid, bool advertise) {
return this->create_service(ESPBTUUID::from_uint16(uuid), advertise);
}
std::shared_ptr<BLEService> BLEServer::create_service(const std::string &uuid, bool advertise) {
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);
void BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles, uint8_t inst_id) {
ESP_LOGV(TAG, "Creating BLE service - %s", uuid.to_string().c_str());
// If the service already exists, do nothing
BLEService *service = this->get_service(uuid);
if (service != nullptr) {
ESP_LOGW(TAG, "BLE service %s already exists", uuid.to_string().c_str());
return;
}
service = new BLEService(uuid, num_handles, inst_id, advertise); // NOLINT(cppcoreguidelines-owning-memory)
this->services_.emplace(uuid.to_string(), service);
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;
}
@@ -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");
if (this->remove_client_(param->disconnect.conn_id))
this->connected_clients_--;
esp32_ble::global_ble->get_advertising()->start();
this->parent_->advertising_start();
for (auto *component : this->service_components_) {
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;
}
for (const auto &service : this->services_) {
service->gatts_event_handler(event, gatts_if, param);
for (const auto &pair : this->services_) {
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; }
void BLEServer::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE Server:"); }

View File

@@ -11,9 +11,9 @@
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
#include <map>
#include <memory>
#include <vector>
#include <unordered_map>
#ifdef USE_ESP32
@@ -33,15 +33,16 @@ class BLEServiceComponent {
virtual void stop();
};
class BLEServer : public Component, public GATTsEventHandler, public Parented<ESP32BLE> {
class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented<ESP32BLE> {
public:
void setup() override;
void loop() override;
void dump_config() override;
float get_setup_priority() const override;
bool can_proceed() override { return this->can_proceed_; }
bool can_proceed() override;
void teardown();
bool is_running();
void set_manufacturer(const std::string &manufacturer) { this->manufacturer_ = manufacturer; }
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_();
}
std::shared_ptr<BLEService> create_service(const uint8_t *uuid, bool advertise = false);
std::shared_ptr<BLEService> create_service(uint16_t uuid, bool advertise = false);
std::shared_ptr<BLEService> create_service(const std::string &uuid, bool advertise = false);
std::shared_ptr<BLEService> create_service(ESPBTUUID uuid, bool advertise = false, uint16_t num_handles = 15,
uint8_t inst_id = 0);
void create_service(ESPBTUUID uuid, bool advertise = false, uint16_t num_handles = 15, uint8_t inst_id = 0);
void remove_service(ESPBTUUID uuid);
BLEService *get_service(ESPBTUUID uuid);
esp_gatt_if_t get_gatts_if() { return this->gatts_if_; }
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,
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); }
protected:
bool create_device_characteristics_();
void restart_advertising_();
void add_client_(uint16_t conn_id, void *client) {
this->clients_.insert(std::pair<uint16_t, void *>(conn_id, client));
}
void add_client_(uint16_t conn_id, void *client) { this->clients_.emplace(conn_id, client); }
bool remove_client_(uint16_t conn_id) { return this->clients_.erase(conn_id) > 0; }
bool can_proceed_{false};
std::string manufacturer_;
optional<std::string> model_;
std::vector<uint8_t> manufacturer_data_;
@@ -83,10 +80,9 @@ class BLEServer : public Component, public GATTsEventHandler, public Parented<ES
bool registered_{false};
uint32_t connected_clients_{0};
std::map<uint16_t, void *> clients_;
std::vector<std::shared_ptr<BLEService>> services_;
std::shared_ptr<BLEService> device_information_service_;
std::unordered_map<uint16_t, void *> clients_;
std::unordered_map<std::string, BLEService *> services_;
BLEService *device_information_service_;
std::vector<BLEServiceComponent *> service_components_;

View File

@@ -9,8 +9,8 @@ namespace esp32_ble_server {
static const char *const TAG = "esp32_ble_server.service";
BLEService::BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id)
: uuid_(uuid), num_handles_(num_handles), inst_id_(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), advertise_(advertise) {}
BLEService::~BLEService() {
for (auto &chr : this->characteristics_)
@@ -58,6 +58,20 @@ void BLEService::do_create(BLEServer *server) {
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_() {
if (this->created_characteristic_count_ >= this->characteristics_.size() &&
(this->last_created_characteristic_ == nullptr || this->last_created_characteristic_->is_created()))
@@ -75,24 +89,34 @@ bool BLEService::do_create_characteristics_() {
void BLEService::start() {
if (this->do_create_characteristics_())
return;
should_start_ = true;
esp_err_t err = esp_ble_gatts_start_service(this->handle_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ble_gatts_start_service failed: %d", err);
return;
}
if (this->advertise_)
esp32_ble::global_ble->advertising_add_service_uuid(this->uuid_);
this->running_state_ = STARTING;
}
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_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err);
return;
}
esp32_ble::global_ble->get_advertising()->remove_service_uuid(this->uuid_);
esp32_ble::global_ble->get_advertising()->start();
this->running_state_ = STOPPING;
if (this->advertise_)
esp32_ble::global_ble->advertising_remove_service_uuid(this->uuid_);
}
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->handle_ = param->create.service_handle;
this->init_state_ = CREATED;
if (this->should_start_)
this->start();
}
break;
}
case ESP_GATTS_DELETE_EVT:
if (param->del.service_handle == this->handle_) {
this->init_state_ = DELETED;
}
break;
case ESP_GATTS_START_EVT: {
if (param->start.service_handle == this->handle_) {
this->running_state_ = RUNNING;

View File

@@ -22,7 +22,7 @@ using namespace esp32_ble;
class BLEService {
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();
BLECharacteristic *get_characteristic(ESPBTUUID uuid);
BLECharacteristic *get_characteristic(uint16_t uuid);
@@ -38,6 +38,7 @@ class BLEService {
BLEServer *get_server() { return this->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 start();
@@ -48,6 +49,7 @@ class BLEService {
bool is_running() { return this->running_state_ == RUNNING; }
bool is_starting() { return this->running_state_ == STARTING; }
bool is_deleted() { return this->init_state_ == DELETED; }
protected:
std::vector<BLECharacteristic *> characteristics_;
@@ -58,8 +60,11 @@ class BLEService {
uint16_t num_handles_;
uint16_t handle_{0xFFFF};
uint8_t inst_id_;
bool advertise_{false};
bool should_start_{false};
bool do_create_characteristics_();
void stop_();
enum InitState : uint8_t {
FAILED = 0x00,
@@ -67,6 +72,8 @@ class BLEService {
CREATING,
CREATING_DEPENDENTS,
CREATED,
DELETING,
DELETED,
} init_state_{INIT};
enum RunningState : uint8_t {