mirror of
https://github.com/esphome/esphome.git
synced 2026-11-15 09:36:04 +00:00
Compare commits
42
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47f8393f68 | ||
|
|
f245927b49 | ||
|
|
bd0aa95dcb | ||
|
|
deb8ff7747 | ||
|
|
a4f10e34d2 | ||
|
|
be7ebd4502 | ||
|
|
db8aabb0a5 | ||
|
|
278c58acaa | ||
|
|
8441f30da4 | ||
|
|
c468be5fe6 | ||
|
|
a1ede4e5c6 | ||
|
|
c277712e47 | ||
|
|
93efaca879 | ||
|
|
b7d59ccf7d | ||
|
|
1bf9d1a7b2 | ||
|
|
70ec155ea2 | ||
|
|
f55557f581 | ||
|
|
cb17035ee4 | ||
|
|
9d30de6f8a | ||
|
|
b78f3df6c1 | ||
|
|
ce9763bea5 | ||
|
|
507f754c78 | ||
|
|
95f297a126 | ||
|
|
e465f754c6 | ||
|
|
a971115a68 | ||
|
|
4e09edb59a | ||
|
|
4e6f994b7c | ||
|
|
ad9027207b | ||
|
|
195d16eb27 | ||
|
|
d05bea3046 | ||
|
|
fab9d004cc | ||
|
|
f976b0c89a | ||
|
|
7479304f75 | ||
|
|
d4ffa31c4a | ||
|
|
93416cb81e | ||
|
|
1296f3bc63 | ||
|
|
2b37efad87 | ||
|
|
e40165dd84 | ||
|
|
91996b4b7c | ||
|
|
21c0d5c464 | ||
|
|
9579244ef3 | ||
|
|
60812d8055 |
No files matched your search
@@ -41,7 +41,7 @@ from esphome.const import (
|
||||
__version__ as ESPHOME_VERSION,
|
||||
)
|
||||
from esphome.core import CORE, ID, MACAddress
|
||||
from esphome.cpp_generator import MockObj, StaticCastExpression
|
||||
from esphome.cpp_generator import MockObj, StaticCastExpression, UnaryOpExpression
|
||||
import esphome.final_validate as fv
|
||||
from esphome.schema_extractors import SCHEMA_EXTRACT
|
||||
from esphome.types import ConfigType, TemplateArgsType
|
||||
@@ -704,7 +704,8 @@ async def to_code_descriptor(descriptor_conf, char_conf, char_var):
|
||||
descriptor_conf[CONF_MAX_LENGTH],
|
||||
descriptor_permissions(descriptor_conf, char_conf),
|
||||
)
|
||||
cg.add(char_var.add_descriptor(desc_var))
|
||||
# Static storage, so the characteristic must not free it
|
||||
cg.add(char_var.add_descriptor(UnaryOpExpression("*", desc_var)))
|
||||
cg.add(desc_var.set_value(value))
|
||||
if (on_write_conf := descriptor_conf.get(CONF_ON_WRITE)) is not None:
|
||||
await _build_on_write_automation(desc_var, on_write_conf)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "ble_server.h"
|
||||
#include "ble_service.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
@@ -13,7 +15,12 @@ ESPHOME_LOG_TAG(TAG, "esp32_ble_server.characteristic");
|
||||
|
||||
BLECharacteristic::~BLECharacteristic() {
|
||||
for (auto *descriptor : this->descriptors_) {
|
||||
delete descriptor; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
if (descriptor->owned_) {
|
||||
delete descriptor; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
} else if (descriptor->characteristic_ == this) {
|
||||
// A caller-owned descriptor outlives this characteristic, and may already belong to another one
|
||||
descriptor->characteristic_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +86,27 @@ void BLECharacteristic::notify() {
|
||||
}
|
||||
}
|
||||
|
||||
void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) {
|
||||
void BLECharacteristic::do_delete() {
|
||||
this->clients_to_notify_.clear();
|
||||
// The stack may reuse the handles, so a deleted characteristic must not match events until it is created again
|
||||
this->handle_ = 0xFFFF;
|
||||
this->state_ = INIT;
|
||||
for (auto *descriptor : this->descriptors_) {
|
||||
descriptor->handle_ = 0xFFFF;
|
||||
descriptor->state_ = BLEDescriptor::INIT;
|
||||
}
|
||||
}
|
||||
|
||||
bool BLECharacteristic::add_descriptor(BLEDescriptor &descriptor) {
|
||||
// Bound until removed or the parent is destroyed
|
||||
if (descriptor.characteristic_ != nullptr) {
|
||||
ESP_LOGE(TAG, "Already added");
|
||||
return false;
|
||||
}
|
||||
descriptor.characteristic_ = this;
|
||||
// If the descriptor is the CCCD descriptor, listen to its write event to know if the client wants to be notified
|
||||
if (descriptor->get_uuid() == ESPBTUUID::from_uint16(ESP_GATT_UUID_CHAR_CLIENT_CONFIG)) {
|
||||
descriptor->on_write([this](std::span<const uint8_t> value, uint16_t conn_id) {
|
||||
if (descriptor.get_uuid() == ESPBTUUID::from_uint16(ESP_GATT_UUID_CHAR_CLIENT_CONFIG)) {
|
||||
descriptor.on_write([this](std::span<const uint8_t> value, uint16_t conn_id) {
|
||||
if (value.size() != 2)
|
||||
return;
|
||||
uint16_t cccd = encode_uint16(value[1], value[0]);
|
||||
@@ -96,16 +120,18 @@ void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) {
|
||||
}
|
||||
});
|
||||
}
|
||||
this->descriptors_.push_back(descriptor);
|
||||
this->descriptors_.push_back(&descriptor);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BLECharacteristic::remove_descriptor(BLEDescriptor *descriptor) {
|
||||
this->descriptors_.erase(std::remove(this->descriptors_.begin(), this->descriptors_.end(), descriptor),
|
||||
this->descriptors_.end());
|
||||
if (std::erase(this->descriptors_, descriptor) == 0)
|
||||
return;
|
||||
descriptor->owned_ = false; // the caller owns it again
|
||||
descriptor->characteristic_ = nullptr;
|
||||
}
|
||||
|
||||
void BLECharacteristic::do_create(BLEService *service) {
|
||||
this->service_ = service;
|
||||
void BLECharacteristic::do_create() {
|
||||
esp_attr_control_t control;
|
||||
control.auto_rsp = ESP_GATT_RSP_BY_APP;
|
||||
|
||||
@@ -116,8 +142,9 @@ void BLECharacteristic::do_create(BLEService *service) {
|
||||
#endif
|
||||
|
||||
esp_bt_uuid_t uuid = this->uuid_.get_uuid();
|
||||
esp_err_t err = esp_ble_gatts_add_char(service->get_handle(), &uuid, static_cast<esp_gatt_perm_t>(this->permissions_),
|
||||
this->properties_, nullptr, &control);
|
||||
esp_err_t err =
|
||||
esp_ble_gatts_add_char(this->service_->get_handle(), &uuid, static_cast<esp_gatt_perm_t>(this->permissions_),
|
||||
this->properties_, nullptr, &control);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gatts_add_char failed: %d", err);
|
||||
@@ -188,11 +215,15 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_ADD_CHAR_EVT: {
|
||||
if (this->uuid_ == ESPBTUUID::from_uuid(param->add_char.char_uuid)) {
|
||||
// Only while creating, in its own service: a late event for a removed service or a same-UUID
|
||||
// characteristic elsewhere must not set the handle or start the descriptors
|
||||
if (this->state_ == CREATING && this->service_ != nullptr &&
|
||||
this->service_->get_handle() == param->add_char.service_handle &&
|
||||
this->uuid_ == ESPBTUUID::from_uuid(param->add_char.char_uuid)) {
|
||||
this->handle_ = param->add_char.attr_handle;
|
||||
|
||||
for (auto *descriptor : this->descriptors_) {
|
||||
descriptor->do_create(this);
|
||||
descriptor->do_create();
|
||||
}
|
||||
|
||||
this->state_ = CREATING_DEPENDENTS;
|
||||
|
||||
@@ -25,6 +25,8 @@ using namespace bytebuffer;
|
||||
class BLEService;
|
||||
|
||||
class BLECharacteristic final {
|
||||
friend class BLEService;
|
||||
|
||||
public:
|
||||
BLECharacteristic(ESPBTUUID uuid, uint32_t properties, esp_gatt_perm_t permissions);
|
||||
~BLECharacteristic();
|
||||
@@ -44,11 +46,18 @@ class BLECharacteristic final {
|
||||
|
||||
void notify();
|
||||
|
||||
void do_create(BLEService *service);
|
||||
void do_delete() { this->clients_to_notify_.clear(); }
|
||||
void do_create();
|
||||
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 add_descriptor(BLEDescriptor *descriptor);
|
||||
/// Takes ownership of a heap-allocated descriptor and frees it with this characteristic.
|
||||
void add_descriptor(BLEDescriptor *descriptor) {
|
||||
if (this->add_descriptor(*descriptor))
|
||||
descriptor->owned_ = true;
|
||||
}
|
||||
/// Adds a descriptor the caller keeps alive (such as a component member); it is never freed here.
|
||||
/// False when it already belongs to a characteristic.
|
||||
bool add_descriptor(BLEDescriptor &descriptor);
|
||||
void remove_descriptor(BLEDescriptor *descriptor);
|
||||
|
||||
BLEService *get_service() { return this->service_; }
|
||||
@@ -106,6 +115,8 @@ class BLECharacteristic final {
|
||||
CREATING_DEPENDENTS,
|
||||
CREATED,
|
||||
} state_{INIT};
|
||||
// Set by BLEService::create_characteristic(), which allocates it; the service frees it
|
||||
bool owned_{false};
|
||||
};
|
||||
|
||||
} // namespace esphome::esp32_ble_server
|
||||
|
||||
@@ -27,8 +27,7 @@ BLEDescriptor::BLEDescriptor(ESPBTUUID uuid, uint16_t max_len, esp_gatt_perm_t p
|
||||
|
||||
BLEDescriptor::~BLEDescriptor() { free(this->value_.attr_value); } // NOLINT
|
||||
|
||||
void BLEDescriptor::do_create(BLECharacteristic *characteristic) {
|
||||
this->characteristic_ = characteristic;
|
||||
void BLEDescriptor::do_create() {
|
||||
esp_attr_control_t control;
|
||||
control.auto_rsp = ESP_GATT_AUTO_RSP;
|
||||
|
||||
@@ -66,7 +65,8 @@ void BLEDescriptor::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_
|
||||
esp_ble_gatts_cb_param_t *param) {
|
||||
switch (event) {
|
||||
case ESP_GATTS_ADD_CHAR_DESCR_EVT: {
|
||||
if (this->characteristic_ != nullptr && this->uuid_ == ESPBTUUID::from_uuid(param->add_char_descr.descr_uuid) &&
|
||||
// Bound by add_descriptor(), so only a descriptor do_create() is creating may claim the event
|
||||
if (this->state_ == CREATING && this->uuid_ == ESPBTUUID::from_uuid(param->add_char_descr.descr_uuid) &&
|
||||
this->characteristic_->get_service()->get_handle() == param->add_char_descr.service_handle &&
|
||||
this->characteristic_ == this->characteristic_->get_service()->get_last_created_characteristic()) {
|
||||
this->handle_ = param->add_char_descr.attr_handle;
|
||||
|
||||
@@ -20,11 +20,13 @@ class BLECharacteristic;
|
||||
|
||||
// Base class for BLE descriptors
|
||||
class BLEDescriptor {
|
||||
friend class BLECharacteristic;
|
||||
|
||||
public:
|
||||
BLEDescriptor(ESPBTUUID uuid, uint16_t max_len = 100, bool read = true, bool write = true);
|
||||
BLEDescriptor(ESPBTUUID uuid, uint16_t max_len, esp_gatt_perm_t permissions);
|
||||
virtual ~BLEDescriptor();
|
||||
void do_create(BLECharacteristic *characteristic);
|
||||
void do_create();
|
||||
ESPBTUUID get_uuid() const { return this->uuid_; }
|
||||
|
||||
void set_value(const uint8_t *data, size_t length);
|
||||
@@ -60,6 +62,8 @@ class BLEDescriptor {
|
||||
CREATING,
|
||||
CREATED,
|
||||
} state_{INIT};
|
||||
// Set when the characteristic took ownership through add_descriptor(BLEDescriptor *) and frees it
|
||||
bool owned_{false};
|
||||
};
|
||||
|
||||
} // namespace esphome::esp32_ble_server
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "ble_server.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "esphome/components/ble_device_base/ble_device.h"
|
||||
#include "esphome/components/esp32_ble/ble.h"
|
||||
#include "esphome/core/log.h"
|
||||
@@ -76,11 +79,11 @@ void BLEServer::loop() {
|
||||
// it is at the top of the GATT table
|
||||
this->device_information_service_->do_create(this);
|
||||
// Create all services previously created
|
||||
for (auto &entry : this->services_) {
|
||||
if (entry.service == this->device_information_service_) {
|
||||
for (auto *service : this->services_) {
|
||||
if (service == this->device_information_service_) {
|
||||
continue;
|
||||
}
|
||||
entry.service->do_create(this);
|
||||
service->do_create(this);
|
||||
}
|
||||
this->state_ = STARTING_SERVICE;
|
||||
}
|
||||
@@ -123,31 +126,52 @@ void BLEServer::release_advertising_() {
|
||||
}
|
||||
|
||||
BLEService *BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles) {
|
||||
// Checked before allocating, so a failure never deletes a service and pulls in its destructor
|
||||
const uint8_t inst_id = this->free_inst_id_(uuid);
|
||||
if (inst_id == INVALID_INST_ID)
|
||||
return nullptr;
|
||||
auto *service = new BLEService(uuid, num_handles, advertise); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
service->owned_ = true;
|
||||
this->register_service_(*service, inst_id);
|
||||
return service;
|
||||
}
|
||||
|
||||
bool BLEServer::add_service(BLEService &service) {
|
||||
// Adding it twice would free or start it twice
|
||||
if (std::ranges::find(this->services_, &service) != this->services_.end()) {
|
||||
ESP_LOGE(TAG, "Already added");
|
||||
return false;
|
||||
}
|
||||
const uint8_t inst_id = this->free_inst_id_(service.get_uuid());
|
||||
if (inst_id == INVALID_INST_ID)
|
||||
return false;
|
||||
this->register_service_(service, inst_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t BLEServer::free_inst_id_(const ESPBTUUID &uuid) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char uuid_buf[esp32_ble::UUID_STR_LEN];
|
||||
uuid.to_str(uuid_buf);
|
||||
ESP_LOGV(TAG, "Creating BLE service - %s", uuid_buf);
|
||||
ESP_LOGV(TAG, "Adding BLE service - %s", uuid_buf);
|
||||
#endif
|
||||
// Calculate the inst_id for the service
|
||||
uint8_t inst_id = 0;
|
||||
for (; inst_id < 0xFF; inst_id++) {
|
||||
if (this->get_service(uuid, inst_id) == nullptr) {
|
||||
break;
|
||||
}
|
||||
for (uint8_t inst_id = 0; inst_id < INVALID_INST_ID; inst_id++) {
|
||||
if (this->get_service(uuid, inst_id) == nullptr)
|
||||
return inst_id;
|
||||
}
|
||||
if (inst_id == 0xFF) {
|
||||
char warn_uuid_buf[esp32_ble::UUID_STR_LEN];
|
||||
uuid.to_str(warn_uuid_buf);
|
||||
ESP_LOGW(TAG, "Could not create BLE service %s, too many instances", warn_uuid_buf);
|
||||
return nullptr;
|
||||
}
|
||||
BLEService *service = // NOLINT(cppcoreguidelines-owning-memory)
|
||||
new BLEService(uuid, num_handles, inst_id, advertise);
|
||||
this->services_.push_back({uuid, inst_id, service});
|
||||
char warn_uuid_buf[esp32_ble::UUID_STR_LEN];
|
||||
uuid.to_str(warn_uuid_buf);
|
||||
ESP_LOGW(TAG, "Could not create BLE service %s, too many instances", warn_uuid_buf);
|
||||
return INVALID_INST_ID;
|
||||
}
|
||||
|
||||
void BLEServer::register_service_(BLEService &service, uint8_t inst_id) {
|
||||
service.inst_id_ = inst_id;
|
||||
BLEService *ptr = &service; // an lvalue reuses the push_back already linked for services_to_start_
|
||||
this->services_.push_back(ptr);
|
||||
if (this->parent_->is_active() && this->registered_) {
|
||||
service->do_create(this);
|
||||
service.do_create(this);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
void BLEServer::remove_service(ESPBTUUID uuid, uint8_t inst_id) {
|
||||
@@ -157,9 +181,13 @@ void BLEServer::remove_service(ESPBTUUID uuid, uint8_t inst_id) {
|
||||
ESP_LOGV(TAG, "Removing BLE service - %s %d", uuid_buf, inst_id);
|
||||
#endif
|
||||
for (auto it = this->services_.begin(); it != this->services_.end(); ++it) {
|
||||
if (it->uuid == uuid && it->inst_id == inst_id) {
|
||||
it->service->do_delete();
|
||||
delete it->service; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
BLEService *service = *it;
|
||||
if (service->get_inst_id() == inst_id && service->get_uuid() == uuid) {
|
||||
service->do_delete();
|
||||
// A service still waiting to start must not stay queued once it is unregistered or freed
|
||||
std::erase(this->services_to_start_, service);
|
||||
if (service->owned_)
|
||||
delete service; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
this->services_.erase(it);
|
||||
return;
|
||||
}
|
||||
@@ -170,9 +198,9 @@ void BLEServer::remove_service(ESPBTUUID uuid, uint8_t inst_id) {
|
||||
}
|
||||
|
||||
BLEService *BLEServer::get_service(ESPBTUUID uuid, uint8_t inst_id) {
|
||||
for (auto &entry : this->services_) {
|
||||
if (entry.uuid == uuid && entry.inst_id == inst_id) {
|
||||
return entry.service;
|
||||
for (auto *service : this->services_) {
|
||||
if (service->get_inst_id() == inst_id && service->get_uuid() == uuid) {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -215,8 +243,17 @@ void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t ga
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto &entry : this->services_) {
|
||||
entry.service->gatts_event_handler(event, gatts_if, param);
|
||||
for (auto *service : this->services_) {
|
||||
service->gatts_event_handler(event, gatts_if, param);
|
||||
}
|
||||
// A service this server asked for but removed while the stack was still creating it is deleted once its handle
|
||||
// arrives; services of other GATT applications are left alone
|
||||
if (event == ESP_GATTS_CREATE_EVT && gatts_if == this->gatts_if_ && param->create.status == ESP_GATT_OK) {
|
||||
for (auto *service : this->services_) {
|
||||
if (service->get_handle() == param->create.service_handle)
|
||||
return;
|
||||
}
|
||||
esp_ble_gatts_delete_service(param->create.service_handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,8 +315,8 @@ void BLEServer::ble_before_disabled_event_handler() {
|
||||
// Delete all clients
|
||||
this->client_count_ = 0;
|
||||
// Delete all services
|
||||
for (auto &entry : this->services_) {
|
||||
entry.service->do_delete();
|
||||
for (auto *service : this->services_) {
|
||||
service->do_delete();
|
||||
}
|
||||
this->registered_ = false;
|
||||
this->state_ = INIT;
|
||||
|
||||
@@ -49,6 +49,10 @@ class BLEServer final : public Component, public Parented<ESP32BLE> {
|
||||
uint8_t get_max_clients() const { return this->max_clients_; }
|
||||
|
||||
BLEService *create_service(ESPBTUUID uuid, bool advertise = false, uint16_t num_handles = 15);
|
||||
/// Adds a service the caller keeps alive (such as a component member); remove_service() never frees it.
|
||||
/// Do not add it again after remove_service(). Returns false when it is already added or the UUID already has
|
||||
/// 255 instances.
|
||||
bool add_service(BLEService &service);
|
||||
void remove_service(ESPBTUUID uuid, uint8_t inst_id = 0);
|
||||
BLEService *get_service(ESPBTUUID uuid, uint8_t inst_id = 0);
|
||||
void enqueue_start_service(BLEService *service) { this->services_to_start_.push_back(service); }
|
||||
@@ -111,12 +115,9 @@ class BLEServer final : public Component, public Parented<ESP32BLE> {
|
||||
std::function<void(uint16_t)> callback;
|
||||
};
|
||||
|
||||
struct ServiceEntry {
|
||||
ESPBTUUID uuid;
|
||||
uint8_t inst_id;
|
||||
BLEService *service;
|
||||
};
|
||||
|
||||
static constexpr uint8_t INVALID_INST_ID = 0xFF;
|
||||
uint8_t free_inst_id_(const ESPBTUUID &uuid);
|
||||
void register_service_(BLEService &service, uint8_t inst_id);
|
||||
void restart_advertising_();
|
||||
void request_advertising_();
|
||||
void release_advertising_();
|
||||
@@ -159,7 +160,7 @@ class BLEServer final : public Component, public Parented<ESP32BLE> {
|
||||
#endif
|
||||
uint8_t client_count_{0};
|
||||
uint8_t max_clients_{1};
|
||||
std::vector<ServiceEntry> services_{};
|
||||
std::vector<BLEService *> services_{};
|
||||
std::vector<BLEService *> services_to_start_{};
|
||||
BLEService *device_information_service_{};
|
||||
|
||||
|
||||
@@ -12,8 +12,25 @@ BLEService::BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id, bo
|
||||
: uuid_(uuid), num_handles_(num_handles), inst_id_(inst_id), advertise_(advertise) {}
|
||||
|
||||
BLEService::~BLEService() {
|
||||
for (auto &chr : this->characteristics_)
|
||||
delete chr; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
for (auto *chr : this->characteristics_) {
|
||||
if (chr->owned_) {
|
||||
delete chr; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
} else if (chr->service_ == this) {
|
||||
// A caller-owned characteristic outlives this service, and may already belong to another one
|
||||
chr->service_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BLEService::add_characteristic(BLECharacteristic &characteristic) {
|
||||
// Bound until the parent is destroyed
|
||||
if (characteristic.service_ != nullptr) {
|
||||
ESP_LOGE(TAG, "Already added");
|
||||
return false;
|
||||
}
|
||||
characteristic.service_ = this;
|
||||
this->characteristics_.push_back(&characteristic);
|
||||
return true;
|
||||
}
|
||||
|
||||
BLECharacteristic *BLEService::get_characteristic(ESPBTUUID uuid) {
|
||||
@@ -39,7 +56,8 @@ BLECharacteristic *BLEService::create_characteristic(ESPBTUUID uuid, esp_gatt_ch
|
||||
esp_gatt_perm_t permissions) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
|
||||
BLECharacteristic *characteristic = new BLECharacteristic(uuid, properties, permissions);
|
||||
this->characteristics_.push_back(characteristic);
|
||||
characteristic->owned_ = true;
|
||||
this->add_characteristic(*characteristic);
|
||||
return characteristic;
|
||||
}
|
||||
|
||||
@@ -69,8 +87,14 @@ void BLEService::do_delete() {
|
||||
// Call all characteristics to delete
|
||||
for (auto *characteristic : this->characteristics_)
|
||||
characteristic->do_delete();
|
||||
// Not created on the stack yet; if a create is in flight, the server deletes it when its handle arrives
|
||||
if (this->handle_ == 0xFFFF) {
|
||||
this->state_ = DELETED;
|
||||
return;
|
||||
}
|
||||
this->stop_();
|
||||
esp_err_t err = esp_ble_gatts_delete_service(this->handle_);
|
||||
this->handle_ = 0xFFFF; // a later add creates it again with a new handle
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gatts_delete_service failed: %d", err);
|
||||
return;
|
||||
@@ -87,7 +111,7 @@ bool BLEService::do_create_characteristics_() {
|
||||
|
||||
auto *characteristic = this->characteristics_[this->created_characteristic_count_++];
|
||||
this->last_created_characteristic_ = characteristic;
|
||||
characteristic->do_create(this);
|
||||
characteristic->do_create();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -140,7 +164,7 @@ void BLEService::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t g
|
||||
esp_ble_gatts_cb_param_t *param) {
|
||||
switch (event) {
|
||||
case ESP_GATTS_CREATE_EVT: {
|
||||
if (this->uuid_ == ESPBTUUID::from_uuid(param->create.service_id.id.uuid) &&
|
||||
if (this->state_ == CREATING && this->uuid_ == ESPBTUUID::from_uuid(param->create.service_id.id.uuid) &&
|
||||
this->inst_id_ == param->create.service_id.id.inst_id) {
|
||||
this->handle_ = param->create.service_handle;
|
||||
this->state_ = CREATED;
|
||||
|
||||
@@ -20,8 +20,12 @@ class BLEServer;
|
||||
using namespace esp32_ble;
|
||||
|
||||
class BLEService final {
|
||||
friend class BLEServer;
|
||||
|
||||
public:
|
||||
BLEService(ESPBTUUID uuid, uint16_t num_handles, uint8_t inst_id, bool advertise);
|
||||
/// The server picks the instance id when the service is added.
|
||||
BLEService(ESPBTUUID uuid, uint16_t num_handles, bool advertise) : BLEService(uuid, num_handles, 0, advertise) {}
|
||||
~BLEService();
|
||||
BLECharacteristic *get_characteristic(ESPBTUUID uuid);
|
||||
BLECharacteristic *get_characteristic(uint16_t uuid);
|
||||
@@ -32,9 +36,11 @@ class BLEService final {
|
||||
esp_gatt_perm_t permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE);
|
||||
BLECharacteristic *create_characteristic(ESPBTUUID uuid, esp_gatt_char_prop_t properties,
|
||||
esp_gatt_perm_t permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE);
|
||||
/// Adds a characteristic the caller keeps alive; it is never freed here. False when it already belongs to a service.
|
||||
bool add_characteristic(BLECharacteristic &characteristic);
|
||||
|
||||
ESPBTUUID get_uuid() { return this->uuid_; }
|
||||
uint8_t get_inst_id() { return this->inst_id_; }
|
||||
const ESPBTUUID &get_uuid() const { return this->uuid_; }
|
||||
uint8_t get_inst_id() const { return this->inst_id_; }
|
||||
BLECharacteristic *get_last_created_characteristic() { return this->last_created_characteristic_; }
|
||||
uint16_t get_handle() { return this->handle_; }
|
||||
|
||||
@@ -57,7 +63,9 @@ class BLEService final {
|
||||
protected:
|
||||
std::vector<BLECharacteristic *> characteristics_;
|
||||
BLECharacteristic *last_created_characteristic_{nullptr};
|
||||
uint32_t created_characteristic_count_{0};
|
||||
uint16_t created_characteristic_count_{0}; // never above num_handles_, so owned_ fits beside it
|
||||
// Set by BLEServer::create_service(), which allocates it; remove_service() frees it
|
||||
bool owned_{false};
|
||||
BLEServer *server_ = nullptr;
|
||||
ESPBTUUID uuid_;
|
||||
uint16_t num_handles_;
|
||||
|
||||
@@ -147,6 +147,17 @@ def test_set_value_constants_share_a_flash_table(
|
||||
assert "ByteBuffer::wrap" not in main_cpp
|
||||
|
||||
|
||||
def test_yaml_descriptors_are_added_by_reference(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
main_cpp = generate_main(component_config_path("set_value.yaml"))
|
||||
|
||||
# Descriptors live in static storage, so the characteristic must not take ownership
|
||||
assert "->add_descriptor((*test_descriptor));" in main_cpp
|
||||
assert "->add_descriptor(test_descriptor);" not in main_cpp
|
||||
|
||||
|
||||
def test_float32_rejects_out_of_range() -> None:
|
||||
for value in (1e40, -1e40):
|
||||
with pytest.raises(cv.Invalid, match="out of range for a float"):
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
esphome:
|
||||
on_boot:
|
||||
- lambda: |-
|
||||
// Objects the caller keeps alive, registered without heap allocation
|
||||
static esp32_ble_server::BLEService battery(esp32_ble::ESPBTUUID::from_uint16(0x180F), 6, false);
|
||||
static esp32_ble_server::BLECharacteristic level(
|
||||
esp32_ble::ESPBTUUID::from_uint16(0x2A19),
|
||||
esp32_ble_server::BLECharacteristic::PROPERTY_READ | esp32_ble_server::BLECharacteristic::PROPERTY_NOTIFY,
|
||||
ESP_GATT_PERM_READ);
|
||||
static esp32_ble_server::BLE2902 level_cccd;
|
||||
level.add_descriptor(level_cccd);
|
||||
battery.add_characteristic(level);
|
||||
if (id(ble_server).add_service(battery))
|
||||
id(ble_server).enqueue_start_service(&battery);
|
||||
|
||||
esp32_ble_server:
|
||||
id: ble_server
|
||||
manufacturer_data: [0x72, 0x4, 0x00, 0x23]
|
||||
|
||||
Reference in new issue
Block a user