diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index f8f913b8e9..bcb4044f94 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -1,5 +1,4 @@ import encodings -from typing import TypeAlias from esphome import automation import esphome.codegen as cg @@ -27,96 +26,11 @@ from esphome.const import ( from esphome.core import CORE from esphome.schema_extractors import SCHEMA_EXTRACT -AUTO_LOAD = ["esp32_ble", "bytebuffer", "event_emitter"] +AUTO_LOAD = ["esp32_ble", "bytebuffer"] CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"] DEPENDENCIES = ["esp32"] DOMAIN = "esp32_ble_server" -# Type aliases -_ListenerAllocation: TypeAlias = tuple[str, int | str, int] # (component, uuid, count) -_ServerListenerAllocation: TypeAlias = tuple[str, int] # (component, count) - -# Event listener allocation tracking - used by components to reserve slots -_LISTENER_ALLOCATIONS: dict[ - str, list[_ListenerAllocation | _ServerListenerAllocation] -] = { - "characteristic_write": [], - "characteristic_read": [], - "descriptor_write": [], - "server_connect": [], - "server_disconnect": [], -} - - -def allocate_characteristic_event_listener( - uuid: int | str, event_type: str, component: str, count: int = 1 -) -> None: - """ - Allocate event listener slots for a characteristic. - - Args: - uuid: The characteristic UUID (int or string) - event_type: "WRITE" or "READ" - component: Name of the component requesting allocation - count: Number of listeners needed (default 1) - """ - if event_type not in ("WRITE", "READ"): - raise ValueError(f"Unknown event_type: {event_type}") - - key = f"characteristic_{event_type.lower()}" - _LISTENER_ALLOCATIONS[key].append((component, uuid, count)) - - -def allocate_descriptor_event_listener( - uuid: int | str, event_type: str, component: str, count: int = 1 -) -> None: - """Allocate event listener slots for a descriptor.""" - if event_type != "WRITE": - raise ValueError(f"Unknown event_type: {event_type}") - - _LISTENER_ALLOCATIONS["descriptor_write"].append((component, uuid, count)) - - -def allocate_server_event_listener( - event_type: str, component: str, count: int = 1 -) -> None: - """Allocate event listener slots for server events.""" - if event_type not in ("CONNECT", "DISCONNECT"): - raise ValueError(f"Unknown event_type: {event_type}") - - key = f"server_{event_type.lower()}" - _LISTENER_ALLOCATIONS[key].append((component, count)) - - -def _sum_allocations_for_uuid(allocation_key: str, uuid: int | str) -> int: - """Helper to sum allocations for a specific UUID.""" - return sum( - count - for comp, alloc_uuid, count in _LISTENER_ALLOCATIONS[allocation_key] - if alloc_uuid == uuid - ) - - -def _get_allocations_for_uuid(uuid: int | str, event_type: str) -> int: - """Get total allocated listeners for a specific UUID and event type.""" - if event_type not in ("WRITE", "READ"): - return 0 - key = f"characteristic_{event_type.lower()}" - return _sum_allocations_for_uuid(key, uuid) - - -def _get_descriptor_allocations_for_uuid(uuid: int | str) -> int: - """Get total allocated listeners for a descriptor UUID.""" - return _sum_allocations_for_uuid("descriptor_write", uuid) - - -def sanitize_uuid_for_identifier(uuid: int | str) -> str: - """Convert UUID to valid C++ identifier.""" - if isinstance(uuid, int): - return f"0x{uuid:04X}" - # For string UUIDs, replace dashes and colons with underscores - return str(uuid).replace("-", "_").replace(":", "_").lower() - CONF_ADVERTISE = "advertise" CONF_APPEARANCE = "appearance" @@ -592,11 +506,6 @@ async def to_code_characteristic(service_var, char_conf): ), ) - # If this characteristic has notify or indicate, it will get a CCCD descriptor (0x2902) - # and ble_characteristic.cpp will register a listener for it - if char_conf.get(CONF_NOTIFY, False) or char_conf.get(CONF_INDICATE, False): - allocate_descriptor_event_listener(0x2902, "WRITE", "esp32_ble_server", 1) - if CONF_ON_WRITE in char_conf: on_write_conf = char_conf[CONF_ON_WRITE] cg.add_define("USE_ESP32_BLE_SERVER_CHARACTERISTIC_ON_WRITE") @@ -677,193 +586,6 @@ async def to_code(config): config[CONF_ON_DISCONNECT], ) - # Generate defines for BLECharacteristicSetValueActionManager - set_value_action_count = sum( - count for comp, count in _LISTENER_ALLOCATIONS["server_connect"] - ) - if set_value_action_count > 0: - cg.add_define("BLE_SET_VALUE_ACTION_MAX_LISTENERS", str(set_value_action_count)) - - # Generate defines and specialized classes for server events - server_connect_count = sum( - count for comp, count in _LISTENER_ALLOCATIONS["server_connect"] - ) - server_disconnect_count = sum( - count for comp, count in _LISTENER_ALLOCATIONS["server_disconnect"] - ) - - if server_connect_count > 0 or server_disconnect_count > 0: - # Generate the specialized BLEServer class with EventEmitter support - cg.add_define( - "BLE_SERVER_CONNECT_MAX_LISTENERS", str(max(server_connect_count, 1)) - ) - cg.add_define( - "BLE_SERVER_DISCONNECT_MAX_LISTENERS", - str(max(server_disconnect_count, 1)), - ) - # TODO: Generate specialized BLEServer class with EventEmitter mixins - - # Generate defines and specialized classes for characteristics - # Group allocations by UUID - char_write_by_uuid: dict[int | str, int] = {} - for comp, uuid, count in _LISTENER_ALLOCATIONS["characteristic_write"]: - char_write_by_uuid[uuid] = char_write_by_uuid.get(uuid, 0) + count - - char_read_by_uuid: dict[int | str, int] = {} - for comp, uuid, count in _LISTENER_ALLOCATIONS["characteristic_read"]: - char_read_by_uuid[uuid] = char_read_by_uuid.get(uuid, 0) + count - - # Generate defines for each UUID - for uuid, count in char_write_by_uuid.items(): - uuid_id = sanitize_uuid_for_identifier(uuid) - cg.add_define(f"BLE_CHAR_{uuid_id}_WRITE_MAX_LISTENERS", str(count)) - - for uuid, count in char_read_by_uuid.items(): - uuid_id = sanitize_uuid_for_identifier(uuid) - cg.add_define(f"BLE_CHAR_{uuid_id}_READ_MAX_LISTENERS", str(count)) - - # Generate defines and specialized classes for descriptors - descriptor_write_by_uuid: dict[int | str, int] = {} - for comp, uuid, count in _LISTENER_ALLOCATIONS["descriptor_write"]: - descriptor_write_by_uuid[uuid] = descriptor_write_by_uuid.get(uuid, 0) + count - - for uuid, count in descriptor_write_by_uuid.items(): - uuid_id = sanitize_uuid_for_identifier(uuid) - cg.add_define(f"BLE_DESC_{uuid_id}_WRITE_MAX_LISTENERS", str(count)) - - # Generate specialized characteristic classes with EventEmitter support - for uuid in set(list(char_write_by_uuid.keys()) + list(char_read_by_uuid.keys())): - uuid_id = sanitize_uuid_for_identifier(uuid) - write_count = char_write_by_uuid.get(uuid, 0) - read_count = char_read_by_uuid.get(uuid, 0) - - # Generate specialized class that inherits from BLECharacteristic and adds EventEmitter support - class_name = f"BLECharacteristic_{uuid_id}" - - # Build the class header with appropriate EventEmitter base classes - base_classes = ["BLECharacteristic"] - template_params = [] - - if write_count > 0: - base_classes.append( - f"EventEmitter, uint16_t>" - ) - template_params.append("write") - if read_count > 0: - base_classes.append( - f"EventEmitter" - ) - template_params.append("read") - - cg.add_global( - cg.RawExpression(f""" -class {class_name} : public {", public ".join(base_classes)} {{ - public: - {class_name}(ESPBTUUID uuid, uint32_t properties, uint16_t max_len = 100) - : BLECharacteristic(uuid, properties, max_len) {{}} - - // Override virtual methods to provide EventEmitter functionality - {"EventEmitterListenerID on_write(std::function, uint16_t)> &&listener) override {" if write_count > 0 else ""} - {" return this->EventEmitter, uint16_t>::on(BLECharacteristicEvt::SpanEvt::ON_WRITE, std::move(listener));" if write_count > 0 else ""} - {"}" if write_count > 0 else ""} - - {"void off_write(EventEmitterListenerID id) override {" if write_count > 0 else ""} - {" this->EventEmitter, uint16_t>::off(BLECharacteristicEvt::SpanEvt::ON_WRITE, id);" if write_count > 0 else ""} - {"}" if write_count > 0 else ""} - - {"EventEmitterListenerID on_read(std::function &&listener) override {" if read_count > 0 else ""} - {" return this->EventEmitter::on(BLECharacteristicEvt::EmptyEvt::ON_READ, std::move(listener));" if read_count > 0 else ""} - {"}" if read_count > 0 else ""} - - {"void off_read(EventEmitterListenerID id) override {" if read_count > 0 else ""} - {" this->EventEmitter::off(BLECharacteristicEvt::EmptyEvt::ON_READ, id);" if read_count > 0 else ""} - {"}" if read_count > 0 else ""} - - protected: - {"void emit_on_write_(std::span value, uint16_t conn_id) override {" if write_count > 0 else ""} - {" this->EventEmitter, uint16_t>::emit_(BLECharacteristicEvt::SpanEvt::ON_WRITE, value, conn_id);" if write_count > 0 else ""} - {"}" if write_count > 0 else ""} - - {"void emit_on_read_(uint16_t conn_id) override {" if read_count > 0 else ""} - {" this->EventEmitter::emit_(BLECharacteristicEvt::EmptyEvt::ON_READ, conn_id);" if read_count > 0 else ""} - {"}" if read_count > 0 else ""} -}}; -""") - ) - - # Generate specialized descriptor classes with EventEmitter support - for uuid, count in descriptor_write_by_uuid.items(): - uuid_id = sanitize_uuid_for_identifier(uuid) - class_name = f"BLEDescriptor_{uuid_id}" - - cg.add_global( - cg.RawExpression(f""" -class {class_name} : public BLEDescriptor, - public EventEmitter, uint16_t> {{ - public: - {class_name}(ESPBTUUID uuid, uint16_t max_len = 100, bool read = true, bool write = true) - : BLEDescriptor(uuid, max_len, read, write) {{}} - - EventEmitterListenerID on_write(std::function, uint16_t)> &&listener) override {{ - return this->EventEmitter, uint16_t>::on(BLEDescriptorEvt::SpanEvt::ON_WRITE, std::move(listener)); - }} - - void off_write(EventEmitterListenerID id) override {{ - this->EventEmitter, uint16_t>::off(BLEDescriptorEvt::SpanEvt::ON_WRITE, id); - }} - - protected: - void emit_on_write_(std::span value, uint16_t conn_id) override {{ - this->EventEmitter, uint16_t>::emit_(BLEDescriptorEvt::SpanEvt::ON_WRITE, value, conn_id); - }} -}}; -""") - ) - - # Generate specialized BLEServer class if needed - if server_connect_count > 0 or server_disconnect_count > 0: - base_classes = ["BLEServer"] - if server_connect_count > 0: - base_classes.append( - "EventEmitter" - ) - if server_disconnect_count > 0: - base_classes.append( - "EventEmitter" - ) - - cg.add_global( - cg.RawExpression(f""" -class BLEServerWithEvents : public {", public ".join(base_classes)} {{ - public: - {"EventEmitterListenerID on_connect(std::function &&listener) override {" if server_connect_count > 0 else ""} - {" return this->EventEmitter::on(BLEServerEvt::EmptyEvt::ON_CONNECT, std::move(listener));" if server_connect_count > 0 else ""} - {"}" if server_connect_count > 0 else ""} - - {"void off_connect(EventEmitterListenerID id) override {" if server_connect_count > 0 else ""} - {" this->EventEmitter::off(BLEServerEvt::EmptyEvt::ON_CONNECT, id);" if server_connect_count > 0 else ""} - {"}" if server_connect_count > 0 else ""} - - {"EventEmitterListenerID on_disconnect(std::function &&listener) override {" if server_disconnect_count > 0 else ""} - {" return this->EventEmitter::on(BLEServerEvt::EmptyEvt::ON_DISCONNECT, std::move(listener));" if server_disconnect_count > 0 else ""} - {"}" if server_disconnect_count > 0 else ""} - - {"void off_disconnect(EventEmitterListenerID id) override {" if server_disconnect_count > 0 else ""} - {" this->EventEmitter::off(BLEServerEvt::EmptyEvt::ON_DISCONNECT, id);" if server_disconnect_count > 0 else ""} - {"}" if server_disconnect_count > 0 else ""} - - protected: - {"void emit_on_connect_(uint16_t conn_id) override {" if server_connect_count > 0 else ""} - {" this->EventEmitter::emit_(BLEServerEvt::EmptyEvt::ON_CONNECT, conn_id);" if server_connect_count > 0 else ""} - {"}" if server_connect_count > 0 else ""} - - {"void emit_on_disconnect_(uint16_t conn_id) override {" if server_disconnect_count > 0 else ""} - {" this->EventEmitter::emit_(BLEServerEvt::EmptyEvt::ON_DISCONNECT, conn_id);" if server_disconnect_count > 0 else ""} - {"}" if server_disconnect_count > 0 else ""} -}}; -""") - ) - cg.add_define("USE_ESP32_BLE_SERVER") cg.add_define("USE_ESP32_BLE_ADVERTISING") add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) diff --git a/esphome/components/esp32_ble_server/ble_characteristic.cpp b/esphome/components/esp32_ble_server/ble_characteristic.cpp index d3fde4ec25..12530b26ec 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.cpp +++ b/esphome/components/esp32_ble_server/ble_characteristic.cpp @@ -208,7 +208,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt if (!param->read.need_rsp) break; // For some reason you can request a read but not want a response - this->emit_on_read_(param->read.conn_id); + if (this->on_read_callback_) { + this->on_read_callback_(param->read.conn_id); + } uint16_t max_offset = 22; @@ -276,7 +278,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt } if (!param->write.is_prep) { - this->emit_on_write_(this->value_, param->write.conn_id); + if (this->on_write_callback_) { + this->on_write_callback_(this->value_, param->write.conn_id); + } } break; @@ -287,7 +291,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt break; this->write_event_ = false; if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { - this->emit_on_write_(this->value_, param->exec_write.conn_id); + if (this->on_write_callback_) { + this->on_write_callback_(this->value_, param->exec_write.conn_id); + } } esp_err_t err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, nullptr); diff --git a/esphome/components/esp32_ble_server/ble_characteristic.h b/esphome/components/esp32_ble_server/ble_characteristic.h index a64610d73f..3404cca55b 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.h +++ b/esphome/components/esp32_ble_server/ble_characteristic.h @@ -2,11 +2,11 @@ #include "ble_descriptor.h" #include "esphome/components/esp32_ble/ble_uuid.h" -#include "esphome/components/event_emitter/event_emitter.h" #include "esphome/components/bytebuffer/bytebuffer.h" #include #include +#include #ifdef USE_ESP32 @@ -23,22 +23,9 @@ namespace esp32_ble_server { using namespace esp32_ble; using namespace bytebuffer; -using namespace event_emitter; class BLEService; -namespace BLECharacteristicEvt { -enum SpanEvt { - ON_WRITE, -}; - -enum EmptyEvt { - ON_READ, -}; -} // namespace BLECharacteristicEvt - -// Base class for BLE characteristics -// Specialized classes with EventEmitter support are generated per-UUID in the build process class BLECharacteristic { public: BLECharacteristic(ESPBTUUID uuid, uint32_t properties); @@ -78,19 +65,13 @@ class BLECharacteristic { bool is_created(); bool is_failed(); - // Event listener registration - overridden by generated specialized classes - virtual EventEmitterListenerID on_write(std::function, uint16_t)> &&listener) { - return INVALID_LISTENER_ID; + // Direct callback registration + void on_write(std::function, uint16_t)> &&callback) { + this->on_write_callback_ = std::move(callback); } - virtual EventEmitterListenerID on_read(std::function &&listener) { return INVALID_LISTENER_ID; } - virtual void off_write(EventEmitterListenerID id) {} - virtual void off_read(EventEmitterListenerID id) {} + void on_read(std::function &&callback) { this->on_read_callback_ = std::move(callback); } protected: - // Virtual methods for emitting events - overridden by generated specialized classes - virtual void emit_on_write_(std::span value, uint16_t conn_id) {} - virtual void emit_on_read_(uint16_t conn_id) {} - bool write_event_{false}; BLEService *service_{}; ESPBTUUID uuid_; @@ -112,6 +93,9 @@ class BLECharacteristic { void remove_client_from_notify_list_(uint16_t conn_id); ClientNotificationEntry *find_client_in_notify_list_(uint16_t conn_id); + std::function, uint16_t)> on_write_callback_{nullptr}; + std::function on_read_callback_{nullptr}; + esp_gatt_perm_t permissions_ = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; enum State : uint8_t { diff --git a/esphome/components/esp32_ble_server/ble_descriptor.cpp b/esphome/components/esp32_ble_server/ble_descriptor.cpp index dbfa8bc632..1182a83b82 100644 --- a/esphome/components/esp32_ble_server/ble_descriptor.cpp +++ b/esphome/components/esp32_ble_server/ble_descriptor.cpp @@ -74,7 +74,9 @@ void BLEDescriptor::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_ break; this->value_.attr_len = param->write.len; memcpy(this->value_.attr_value, param->write.value, param->write.len); - this->emit_on_write_(std::span(param->write.value, param->write.len), param->write.conn_id); + if (this->on_write_callback_) { + this->on_write_callback_(std::span(param->write.value, param->write.len), param->write.conn_id); + } break; } default: diff --git a/esphome/components/esp32_ble_server/ble_descriptor.h b/esphome/components/esp32_ble_server/ble_descriptor.h index af1cbfd18d..00138d306d 100644 --- a/esphome/components/esp32_ble_server/ble_descriptor.h +++ b/esphome/components/esp32_ble_server/ble_descriptor.h @@ -19,14 +19,7 @@ using namespace event_emitter; class BLECharacteristic; -namespace BLEDescriptorEvt { -enum SpanEvt { - ON_WRITE, -}; -} // namespace BLEDescriptorEvt - // Base class for BLE descriptors -// Specialized classes with EventEmitter support are generated per-UUID in the build process class BLEDescriptor { public: BLEDescriptor(ESPBTUUID uuid, uint16_t max_len = 100, bool read = true, bool write = true); @@ -42,22 +35,20 @@ class BLEDescriptor { bool is_created() { return this->state_ == CREATED; } bool is_failed() { return this->state_ == FAILED; } - // Event listener registration - overridden by generated specialized classes if needed - virtual EventEmitterListenerID on_write(std::function, uint16_t)> &&listener) { - return INVALID_LISTENER_ID; + // Direct callback registration + void on_write(std::function, uint16_t)> &&callback) { + this->on_write_callback_ = std::move(callback); } - virtual void off_write(EventEmitterListenerID id) {} protected: - // Virtual method for emitting events - overridden by generated specialized classes - virtual void emit_on_write_(std::span value, uint16_t conn_id) {} - BLECharacteristic *characteristic_{nullptr}; ESPBTUUID uuid_; uint16_t handle_{0xFFFF}; esp_attr_value_t value_{}; + std::function, uint16_t)> on_write_callback_{nullptr}; + esp_gatt_perm_t permissions_{}; enum State : uint8_t { diff --git a/esphome/components/esp32_ble_server/ble_server.cpp b/esphome/components/esp32_ble_server/ble_server.cpp index d73c343b4d..0f993cad02 100644 --- a/esphome/components/esp32_ble_server/ble_server.cpp +++ b/esphome/components/esp32_ble_server/ble_server.cpp @@ -153,14 +153,18 @@ void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t ga case ESP_GATTS_CONNECT_EVT: { ESP_LOGD(TAG, "BLE Client connected"); this->add_client_(param->connect.conn_id); - this->emit_on_connect_(param->connect.conn_id); + if (this->on_connect_callback_) { + this->on_connect_callback_(param->connect.conn_id); + } break; } case ESP_GATTS_DISCONNECT_EVT: { ESP_LOGD(TAG, "BLE Client disconnected"); this->remove_client_(param->disconnect.conn_id); this->parent_->advertising_start(); - this->emit_on_disconnect_(param->disconnect.conn_id); + if (this->on_disconnect_callback_) { + this->on_disconnect_callback_(param->disconnect.conn_id); + } break; } case ESP_GATTS_REG_EVT: { diff --git a/esphome/components/esp32_ble_server/ble_server.h b/esphome/components/esp32_ble_server/ble_server.h index e3181a945d..8bb9429856 100644 --- a/esphome/components/esp32_ble_server/ble_server.h +++ b/esphome/components/esp32_ble_server/ble_server.h @@ -24,15 +24,7 @@ namespace esp32_ble_server { using namespace esp32_ble; using namespace bytebuffer; -namespace BLEServerEvt { -enum EmptyEvt { - ON_CONNECT, - ON_DISCONNECT, -}; -} // namespace BLEServerEvt - // Base class for BLE server -// Note: Only one BLEServer instance exists per build, so we can use fixed defines class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented { public: void setup() override; @@ -63,16 +55,11 @@ class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEv void ble_before_disabled_event_handler() override; - // Event listener registration - overridden by generated specialized classes if needed - virtual EventEmitterListenerID on_connect(std::function &&listener) { return INVALID_LISTENER_ID; } - virtual EventEmitterListenerID on_disconnect(std::function &&listener) { return INVALID_LISTENER_ID; } - virtual void off_connect(EventEmitterListenerID id) {} - virtual void off_disconnect(EventEmitterListenerID id) {} + // Direct callback registration + void on_connect(std::function &&callback) { this->on_connect_callback_ = std::move(callback); } + void on_disconnect(std::function &&callback) { this->on_disconnect_callback_ = std::move(callback); } protected: - // Virtual methods for emitting events - virtual void emit_on_connect_(uint16_t conn_id) {} - virtual void emit_on_disconnect_(uint16_t conn_id) {} struct ServiceEntry { ESPBTUUID uuid; uint8_t inst_id; @@ -84,6 +71,9 @@ class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEv void add_client_(uint16_t conn_id) { this->clients_.insert(conn_id); } void remove_client_(uint16_t conn_id) { this->clients_.erase(conn_id); } + std::function on_connect_callback_{nullptr}; + std::function on_disconnect_callback_{nullptr}; + std::vector manufacturer_data_{}; esp_gatt_if_t gatts_if_{0}; bool registered_{false}; diff --git a/esphome/components/esp32_ble_server/ble_server_automations.cpp b/esphome/components/esp32_ble_server/ble_server_automations.cpp index afa958a4a0..0761de994a 100644 --- a/esphome/components/esp32_ble_server/ble_server_automations.cpp +++ b/esphome/components/esp32_ble_server/ble_server_automations.cpp @@ -52,29 +52,15 @@ Trigger *BLETriggers::create_server_on_disconnect_trigger(BLEServer *s #ifdef USE_ESP32_BLE_SERVER_SET_VALUE_ACTION void BLECharacteristicSetValueActionManager::set_listener(BLECharacteristic *characteristic, - EventEmitterListenerID listener_id, const std::function &pre_notify_listener) { // Find and remove existing listener for this characteristic auto *existing = this->find_listener_(characteristic); if (existing != nullptr) { - // Remove the previous listener - characteristic->off_read(existing->listener_id); - // Remove the pre-notify listener - this->off(BLECharacteristicSetValueActionEvt::PRE_NOTIFY, existing->pre_notify_listener_id); // Remove from vector this->remove_listener_(characteristic); } - // Create a new listener for the pre-notify event - EventEmitterListenerID pre_notify_listener_id = - this->on(BLECharacteristicSetValueActionEvt::PRE_NOTIFY, - [pre_notify_listener, characteristic](const BLECharacteristic *evt_characteristic) { - // Only call the pre-notify listener if the characteristic is the one we are interested in - if (characteristic == evt_characteristic) { - pre_notify_listener(); - } - }); // Save the entry to the vector - this->listeners_.push_back({characteristic, listener_id, pre_notify_listener_id}); + this->listeners_.push_back({characteristic, pre_notify_listener}); } BLECharacteristicSetValueActionManager::ListenerEntry *BLECharacteristicSetValueActionManager::find_listener_( diff --git a/esphome/components/esp32_ble_server/ble_server_automations.h b/esphome/components/esp32_ble_server/ble_server_automations.h index 08a3322367..543b1153fc 100644 --- a/esphome/components/esp32_ble_server/ble_server_automations.h +++ b/esphome/components/esp32_ble_server/ble_server_automations.h @@ -4,7 +4,6 @@ #include "ble_characteristic.h" #include "ble_descriptor.h" -#include "esphome/components/event_emitter/event_emitter.h" #include "esphome/core/automation.h" #include @@ -18,10 +17,6 @@ namespace esp32_ble_server { namespace esp32_ble_server_automations { using namespace esp32_ble; -using namespace event_emitter; - -// Invalid listener ID constant - 0 is used as sentinel value in EventEmitter -static constexpr EventEmitterListenerID INVALID_LISTENER_ID = 0; class BLETriggers { public: @@ -41,42 +36,29 @@ class BLETriggers { }; #ifdef USE_ESP32_BLE_SERVER_SET_VALUE_ACTION -enum BLECharacteristicSetValueActionEvt { - PRE_NOTIFY, -}; - // Class to make sure only one BLECharacteristicSetValueAction is active at a time for each characteristic -#ifndef BLE_SET_VALUE_ACTION_MAX_LISTENERS -#define BLE_SET_VALUE_ACTION_MAX_LISTENERS 1 -#endif - -class BLECharacteristicSetValueActionManager - : public EventEmitter { +class BLECharacteristicSetValueActionManager { public: // Singleton pattern static BLECharacteristicSetValueActionManager *get_instance() { static BLECharacteristicSetValueActionManager instance; return &instance; } - void set_listener(BLECharacteristic *characteristic, EventEmitterListenerID listener_id, - const std::function &pre_notify_listener); - EventEmitterListenerID get_listener(BLECharacteristic *characteristic) { + void set_listener(BLECharacteristic *characteristic, const std::function &pre_notify_listener); + bool has_listener(BLECharacteristic *characteristic) { return this->find_listener_(characteristic) != nullptr; } + void emit_pre_notify(BLECharacteristic *characteristic) { for (const auto &entry : this->listeners_) { if (entry.characteristic == characteristic) { - return entry.listener_id; + entry.pre_notify_listener(); + break; } } - return INVALID_LISTENER_ID; - } - void emit_pre_notify(BLECharacteristic *characteristic) { - this->emit_(BLECharacteristicSetValueActionEvt::PRE_NOTIFY, characteristic); } private: struct ListenerEntry { BLECharacteristic *characteristic; - EventEmitterListenerID listener_id; - EventEmitterListenerID pre_notify_listener_id; + std::function pre_notify_listener; }; std::vector listeners_; @@ -91,23 +73,22 @@ template class BLECharacteristicSetValueAction : public Actionset_buffer(buffer.get_data()); } void play(Ts... x) override { // If the listener is already set, do nothing - if (BLECharacteristicSetValueActionManager::get_instance()->get_listener(this->parent_) == this->listener_id_) + if (BLECharacteristicSetValueActionManager::get_instance()->has_listener(this->parent_)) return; // Set initial value this->parent_->set_value(this->buffer_.value(x...)); // Set the listener for read events - this->listener_id_ = this->parent_->on_read([this, x...](uint16_t id) { + this->parent_->on_read([this, x...](uint16_t id) { // Set the value of the characteristic every time it is read this->parent_->set_value(this->buffer_.value(x...)); }); // Set the listener in the global manager so only one BLECharacteristicSetValueAction is set for each characteristic BLECharacteristicSetValueActionManager::get_instance()->set_listener( - this->parent_, this->listener_id_, [this, x...]() { this->parent_->set_value(this->buffer_.value(x...)); }); + this->parent_, [this, x...]() { this->parent_->set_value(this->buffer_.value(x...)); }); } protected: BLECharacteristic *parent_; - EventEmitterListenerID listener_id_; }; #endif // USE_ESP32_BLE_SERVER_SET_VALUE_ACTION diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index 43377326bd..fa33bd947a 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -1,6 +1,6 @@ from esphome import automation import esphome.codegen as cg -from esphome.components import binary_sensor, esp32_ble, esp32_ble_server, output +from esphome.components import binary_sensor, esp32_ble, output from esphome.components.esp32_ble import BTLoggers import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID @@ -98,15 +98,6 @@ async def to_code(config): # Register the loggers this component needs esp32_ble.register_bt_logger(BTLoggers.GATT, BTLoggers.SMP) - # Allocate event listeners for esp32_improv - # Need 1 listener for server disconnect event - esp32_ble_server.allocate_server_event_listener("DISCONNECT", "esp32_improv", 1) - # The RPC characteristic UUID comes from the Improv library (0x00467768-6228-2272-4663-277478268000 + 0x01) - # We need 1 listener for the RPC write event - esp32_ble_server.allocate_characteristic_event_listener( - "00467768-6228-2272-4663-277478268001", "WRITE", "esp32_improv", 1 - ) - var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/event_emitter/__init__.py b/esphome/components/event_emitter/__init__.py deleted file mode 100644 index fcbbf26f02..0000000000 --- a/esphome/components/event_emitter/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -CODEOWNERS = ["@Rapsssito"] - -# Allows event_emitter to be configured in yaml, to allow use of the C++ api. - -CONFIG_SCHEMA = {} diff --git a/esphome/components/event_emitter/event_emitter.h b/esphome/components/event_emitter/event_emitter.h deleted file mode 100644 index e44cac7cc7..0000000000 --- a/esphome/components/event_emitter/event_emitter.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once -#include -#include -#include - -#include "esphome/core/log.h" - -namespace esphome { -namespace event_emitter { - -using EventEmitterListenerID = uint32_t; -static constexpr EventEmitterListenerID INVALID_LISTENER_ID = 0; - -// EventEmitter class that can emit events with a specific name (it is highly recommended to use an enum class for this) -// and a list of arguments. Supports multiple listeners for each event. -// MaxListeners is the compile-time maximum number of listeners per event type. -template class EventEmitter { - public: - EventEmitterListenerID on(EvtType event, std::function listener) { - // Find a free slot in the listeners array - for (auto &entry : this->listeners_) { - if (entry.id == INVALID_LISTENER_ID) { - // Found empty slot - EventEmitterListenerID listener_id = this->get_next_id_(); - entry.id = listener_id; - entry.event = event; - entry.callback = std::move(listener); - return listener_id; - } - } - // No free slots - array is full - return INVALID_LISTENER_ID; - } - - void off(EvtType event, EventEmitterListenerID id) { - // Find and remove listener with given id - for (auto &entry : this->listeners_) { - if (entry.id == id && entry.event == event) { - entry.id = INVALID_LISTENER_ID; - entry.callback = nullptr; - return; - } - } - } - - protected: - void emit_(EvtType event, Args... args) { - // Call all listeners for this event - for (const auto &entry : this->listeners_) { - if (entry.id != INVALID_LISTENER_ID && entry.event == event) { - entry.callback(args...); - } - } - } - - private: - struct ListenerEntry { - EvtType event; - EventEmitterListenerID id{INVALID_LISTENER_ID}; - std::function callback{nullptr}; - }; - - EventEmitterListenerID get_next_id_() { - // Simple incrementing ID, wrapping around at max - EventEmitterListenerID next_id = (this->current_id_ + 1); - if (next_id == INVALID_LISTENER_ID) { - next_id = 1; - } - this->current_id_ = next_id; - return this->current_id_; - } - - std::array listeners_{}; - EventEmitterListenerID current_id_{0}; -}; - -} // namespace event_emitter -} // namespace esphome