mirror of
https://github.com/esphome/esphome.git
synced 2025-10-03 18:42:23 +01:00
wip
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import encodings
|
import encodings
|
||||||
from typing import TypeAlias
|
|
||||||
|
|
||||||
from esphome import automation
|
from esphome import automation
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
@@ -27,96 +26,11 @@ from esphome.const import (
|
|||||||
from esphome.core import CORE
|
from esphome.core import CORE
|
||||||
from esphome.schema_extractors import SCHEMA_EXTRACT
|
from esphome.schema_extractors import SCHEMA_EXTRACT
|
||||||
|
|
||||||
AUTO_LOAD = ["esp32_ble", "bytebuffer", "event_emitter"]
|
AUTO_LOAD = ["esp32_ble", "bytebuffer"]
|
||||||
CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"]
|
CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"]
|
||||||
DEPENDENCIES = ["esp32"]
|
DEPENDENCIES = ["esp32"]
|
||||||
DOMAIN = "esp32_ble_server"
|
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_ADVERTISE = "advertise"
|
||||||
CONF_APPEARANCE = "appearance"
|
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:
|
if CONF_ON_WRITE in char_conf:
|
||||||
on_write_conf = char_conf[CONF_ON_WRITE]
|
on_write_conf = char_conf[CONF_ON_WRITE]
|
||||||
cg.add_define("USE_ESP32_BLE_SERVER_CHARACTERISTIC_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],
|
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<BLECharacteristicEvt::SpanEvt, BLE_CHAR_{uuid_id}_WRITE_MAX_LISTENERS, std::span<const uint8_t>, uint16_t>"
|
|
||||||
)
|
|
||||||
template_params.append("write")
|
|
||||||
if read_count > 0:
|
|
||||||
base_classes.append(
|
|
||||||
f"EventEmitter<BLECharacteristicEvt::EmptyEvt, BLE_CHAR_{uuid_id}_READ_MAX_LISTENERS, uint16_t>"
|
|
||||||
)
|
|
||||||
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<void(std::span<const uint8_t>, uint16_t)> &&listener) override {" if write_count > 0 else ""}
|
|
||||||
{" return this->EventEmitter<BLECharacteristicEvt::SpanEvt, BLE_CHAR_" + uuid_id + "_WRITE_MAX_LISTENERS, std::span<const uint8_t>, 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<BLECharacteristicEvt::SpanEvt, BLE_CHAR_" + uuid_id + "_WRITE_MAX_LISTENERS, std::span<const uint8_t>, uint16_t>::off(BLECharacteristicEvt::SpanEvt::ON_WRITE, id);" if write_count > 0 else ""}
|
|
||||||
{"}" if write_count > 0 else ""}
|
|
||||||
|
|
||||||
{"EventEmitterListenerID on_read(std::function<void(uint16_t)> &&listener) override {" if read_count > 0 else ""}
|
|
||||||
{" return this->EventEmitter<BLECharacteristicEvt::EmptyEvt, BLE_CHAR_" + uuid_id + "_READ_MAX_LISTENERS, uint16_t>::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<BLECharacteristicEvt::EmptyEvt, BLE_CHAR_" + uuid_id + "_READ_MAX_LISTENERS, uint16_t>::off(BLECharacteristicEvt::EmptyEvt::ON_READ, id);" if read_count > 0 else ""}
|
|
||||||
{"}" if read_count > 0 else ""}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
{"void emit_on_write_(std::span<const uint8_t> value, uint16_t conn_id) override {" if write_count > 0 else ""}
|
|
||||||
{" this->EventEmitter<BLECharacteristicEvt::SpanEvt, BLE_CHAR_" + uuid_id + "_WRITE_MAX_LISTENERS, std::span<const uint8_t>, 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<BLECharacteristicEvt::EmptyEvt, BLE_CHAR_" + uuid_id + "_READ_MAX_LISTENERS, uint16_t>::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<BLEDescriptorEvt::SpanEvt, BLE_DESC_{uuid_id}_WRITE_MAX_LISTENERS, std::span<const uint8_t>, 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<void(std::span<const uint8_t>, uint16_t)> &&listener) override {{
|
|
||||||
return this->EventEmitter<BLEDescriptorEvt::SpanEvt, BLE_DESC_{uuid_id}_WRITE_MAX_LISTENERS, std::span<const uint8_t>, uint16_t>::on(BLEDescriptorEvt::SpanEvt::ON_WRITE, std::move(listener));
|
|
||||||
}}
|
|
||||||
|
|
||||||
void off_write(EventEmitterListenerID id) override {{
|
|
||||||
this->EventEmitter<BLEDescriptorEvt::SpanEvt, BLE_DESC_{uuid_id}_WRITE_MAX_LISTENERS, std::span<const uint8_t>, uint16_t>::off(BLEDescriptorEvt::SpanEvt::ON_WRITE, id);
|
|
||||||
}}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void emit_on_write_(std::span<const uint8_t> value, uint16_t conn_id) override {{
|
|
||||||
this->EventEmitter<BLEDescriptorEvt::SpanEvt, BLE_DESC_{uuid_id}_WRITE_MAX_LISTENERS, std::span<const uint8_t>, 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<BLEServerEvt::EmptyEvt, BLE_SERVER_CONNECT_MAX_LISTENERS, uint16_t>"
|
|
||||||
)
|
|
||||||
if server_disconnect_count > 0:
|
|
||||||
base_classes.append(
|
|
||||||
"EventEmitter<BLEServerEvt::EmptyEvt, BLE_SERVER_DISCONNECT_MAX_LISTENERS, uint16_t>"
|
|
||||||
)
|
|
||||||
|
|
||||||
cg.add_global(
|
|
||||||
cg.RawExpression(f"""
|
|
||||||
class BLEServerWithEvents : public {", public ".join(base_classes)} {{
|
|
||||||
public:
|
|
||||||
{"EventEmitterListenerID on_connect(std::function<void(uint16_t)> &&listener) override {" if server_connect_count > 0 else ""}
|
|
||||||
{" return this->EventEmitter<BLEServerEvt::EmptyEvt, BLE_SERVER_CONNECT_MAX_LISTENERS, uint16_t>::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<BLEServerEvt::EmptyEvt, BLE_SERVER_CONNECT_MAX_LISTENERS, uint16_t>::off(BLEServerEvt::EmptyEvt::ON_CONNECT, id);" if server_connect_count > 0 else ""}
|
|
||||||
{"}" if server_connect_count > 0 else ""}
|
|
||||||
|
|
||||||
{"EventEmitterListenerID on_disconnect(std::function<void(uint16_t)> &&listener) override {" if server_disconnect_count > 0 else ""}
|
|
||||||
{" return this->EventEmitter<BLEServerEvt::EmptyEvt, BLE_SERVER_DISCONNECT_MAX_LISTENERS, uint16_t>::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<BLEServerEvt::EmptyEvt, BLE_SERVER_DISCONNECT_MAX_LISTENERS, uint16_t>::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<BLEServerEvt::EmptyEvt, BLE_SERVER_CONNECT_MAX_LISTENERS, uint16_t>::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<BLEServerEvt::EmptyEvt, BLE_SERVER_DISCONNECT_MAX_LISTENERS, uint16_t>::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_SERVER")
|
||||||
cg.add_define("USE_ESP32_BLE_ADVERTISING")
|
cg.add_define("USE_ESP32_BLE_ADVERTISING")
|
||||||
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
||||||
|
@@ -208,7 +208,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
|
|||||||
if (!param->read.need_rsp)
|
if (!param->read.need_rsp)
|
||||||
break; // For some reason you can request a read but not want a response
|
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;
|
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) {
|
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;
|
break;
|
||||||
@@ -287,7 +291,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
|
|||||||
break;
|
break;
|
||||||
this->write_event_ = false;
|
this->write_event_ = false;
|
||||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
|
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_err_t err =
|
||||||
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, nullptr);
|
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, nullptr);
|
||||||
|
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
#include "ble_descriptor.h"
|
#include "ble_descriptor.h"
|
||||||
#include "esphome/components/esp32_ble/ble_uuid.h"
|
#include "esphome/components/esp32_ble/ble_uuid.h"
|
||||||
#include "esphome/components/event_emitter/event_emitter.h"
|
|
||||||
#include "esphome/components/bytebuffer/bytebuffer.h"
|
#include "esphome/components/bytebuffer/bytebuffer.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
@@ -23,22 +23,9 @@ namespace esp32_ble_server {
|
|||||||
|
|
||||||
using namespace esp32_ble;
|
using namespace esp32_ble;
|
||||||
using namespace bytebuffer;
|
using namespace bytebuffer;
|
||||||
using namespace event_emitter;
|
|
||||||
|
|
||||||
class BLEService;
|
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 {
|
class BLECharacteristic {
|
||||||
public:
|
public:
|
||||||
BLECharacteristic(ESPBTUUID uuid, uint32_t properties);
|
BLECharacteristic(ESPBTUUID uuid, uint32_t properties);
|
||||||
@@ -78,19 +65,13 @@ class BLECharacteristic {
|
|||||||
bool is_created();
|
bool is_created();
|
||||||
bool is_failed();
|
bool is_failed();
|
||||||
|
|
||||||
// Event listener registration - overridden by generated specialized classes
|
// Direct callback registration
|
||||||
virtual EventEmitterListenerID on_write(std::function<void(std::span<const uint8_t>, uint16_t)> &&listener) {
|
void on_write(std::function<void(std::span<const uint8_t>, uint16_t)> &&callback) {
|
||||||
return INVALID_LISTENER_ID;
|
this->on_write_callback_ = std::move(callback);
|
||||||
}
|
}
|
||||||
virtual EventEmitterListenerID on_read(std::function<void(uint16_t)> &&listener) { return INVALID_LISTENER_ID; }
|
void on_read(std::function<void(uint16_t)> &&callback) { this->on_read_callback_ = std::move(callback); }
|
||||||
virtual void off_write(EventEmitterListenerID id) {}
|
|
||||||
virtual void off_read(EventEmitterListenerID id) {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Virtual methods for emitting events - overridden by generated specialized classes
|
|
||||||
virtual void emit_on_write_(std::span<const uint8_t> value, uint16_t conn_id) {}
|
|
||||||
virtual void emit_on_read_(uint16_t conn_id) {}
|
|
||||||
|
|
||||||
bool write_event_{false};
|
bool write_event_{false};
|
||||||
BLEService *service_{};
|
BLEService *service_{};
|
||||||
ESPBTUUID uuid_;
|
ESPBTUUID uuid_;
|
||||||
@@ -112,6 +93,9 @@ class BLECharacteristic {
|
|||||||
void remove_client_from_notify_list_(uint16_t conn_id);
|
void remove_client_from_notify_list_(uint16_t conn_id);
|
||||||
ClientNotificationEntry *find_client_in_notify_list_(uint16_t conn_id);
|
ClientNotificationEntry *find_client_in_notify_list_(uint16_t conn_id);
|
||||||
|
|
||||||
|
std::function<void(std::span<const uint8_t>, uint16_t)> on_write_callback_{nullptr};
|
||||||
|
std::function<void(uint16_t)> on_read_callback_{nullptr};
|
||||||
|
|
||||||
esp_gatt_perm_t permissions_ = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
|
esp_gatt_perm_t permissions_ = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
|
||||||
|
|
||||||
enum State : uint8_t {
|
enum State : uint8_t {
|
||||||
|
@@ -74,7 +74,9 @@ void BLEDescriptor::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_
|
|||||||
break;
|
break;
|
||||||
this->value_.attr_len = param->write.len;
|
this->value_.attr_len = param->write.len;
|
||||||
memcpy(this->value_.attr_value, param->write.value, param->write.len);
|
memcpy(this->value_.attr_value, param->write.value, param->write.len);
|
||||||
this->emit_on_write_(std::span<const uint8_t>(param->write.value, param->write.len), param->write.conn_id);
|
if (this->on_write_callback_) {
|
||||||
|
this->on_write_callback_(std::span<const uint8_t>(param->write.value, param->write.len), param->write.conn_id);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@@ -19,14 +19,7 @@ using namespace event_emitter;
|
|||||||
|
|
||||||
class BLECharacteristic;
|
class BLECharacteristic;
|
||||||
|
|
||||||
namespace BLEDescriptorEvt {
|
|
||||||
enum SpanEvt {
|
|
||||||
ON_WRITE,
|
|
||||||
};
|
|
||||||
} // namespace BLEDescriptorEvt
|
|
||||||
|
|
||||||
// Base class for BLE descriptors
|
// Base class for BLE descriptors
|
||||||
// Specialized classes with EventEmitter support are generated per-UUID in the build process
|
|
||||||
class BLEDescriptor {
|
class BLEDescriptor {
|
||||||
public:
|
public:
|
||||||
BLEDescriptor(ESPBTUUID uuid, uint16_t max_len = 100, bool read = true, bool write = true);
|
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_created() { return this->state_ == CREATED; }
|
||||||
bool is_failed() { return this->state_ == FAILED; }
|
bool is_failed() { return this->state_ == FAILED; }
|
||||||
|
|
||||||
// Event listener registration - overridden by generated specialized classes if needed
|
// Direct callback registration
|
||||||
virtual EventEmitterListenerID on_write(std::function<void(std::span<const uint8_t>, uint16_t)> &&listener) {
|
void on_write(std::function<void(std::span<const uint8_t>, uint16_t)> &&callback) {
|
||||||
return INVALID_LISTENER_ID;
|
this->on_write_callback_ = std::move(callback);
|
||||||
}
|
}
|
||||||
virtual void off_write(EventEmitterListenerID id) {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Virtual method for emitting events - overridden by generated specialized classes
|
|
||||||
virtual void emit_on_write_(std::span<const uint8_t> value, uint16_t conn_id) {}
|
|
||||||
|
|
||||||
BLECharacteristic *characteristic_{nullptr};
|
BLECharacteristic *characteristic_{nullptr};
|
||||||
ESPBTUUID uuid_;
|
ESPBTUUID uuid_;
|
||||||
uint16_t handle_{0xFFFF};
|
uint16_t handle_{0xFFFF};
|
||||||
|
|
||||||
esp_attr_value_t value_{};
|
esp_attr_value_t value_{};
|
||||||
|
|
||||||
|
std::function<void(std::span<const uint8_t>, uint16_t)> on_write_callback_{nullptr};
|
||||||
|
|
||||||
esp_gatt_perm_t permissions_{};
|
esp_gatt_perm_t permissions_{};
|
||||||
|
|
||||||
enum State : uint8_t {
|
enum State : uint8_t {
|
||||||
|
@@ -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: {
|
case ESP_GATTS_CONNECT_EVT: {
|
||||||
ESP_LOGD(TAG, "BLE Client connected");
|
ESP_LOGD(TAG, "BLE Client connected");
|
||||||
this->add_client_(param->connect.conn_id);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ESP_GATTS_DISCONNECT_EVT: {
|
case ESP_GATTS_DISCONNECT_EVT: {
|
||||||
ESP_LOGD(TAG, "BLE Client disconnected");
|
ESP_LOGD(TAG, "BLE Client disconnected");
|
||||||
this->remove_client_(param->disconnect.conn_id);
|
this->remove_client_(param->disconnect.conn_id);
|
||||||
this->parent_->advertising_start();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ESP_GATTS_REG_EVT: {
|
case ESP_GATTS_REG_EVT: {
|
||||||
|
@@ -24,15 +24,7 @@ namespace esp32_ble_server {
|
|||||||
using namespace esp32_ble;
|
using namespace esp32_ble;
|
||||||
using namespace bytebuffer;
|
using namespace bytebuffer;
|
||||||
|
|
||||||
namespace BLEServerEvt {
|
|
||||||
enum EmptyEvt {
|
|
||||||
ON_CONNECT,
|
|
||||||
ON_DISCONNECT,
|
|
||||||
};
|
|
||||||
} // namespace BLEServerEvt
|
|
||||||
|
|
||||||
// Base class for BLE server
|
// 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<ESP32BLE> {
|
class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented<ESP32BLE> {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
@@ -63,16 +55,11 @@ class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEv
|
|||||||
|
|
||||||
void ble_before_disabled_event_handler() override;
|
void ble_before_disabled_event_handler() override;
|
||||||
|
|
||||||
// Event listener registration - overridden by generated specialized classes if needed
|
// Direct callback registration
|
||||||
virtual EventEmitterListenerID on_connect(std::function<void(uint16_t)> &&listener) { return INVALID_LISTENER_ID; }
|
void on_connect(std::function<void(uint16_t)> &&callback) { this->on_connect_callback_ = std::move(callback); }
|
||||||
virtual EventEmitterListenerID on_disconnect(std::function<void(uint16_t)> &&listener) { return INVALID_LISTENER_ID; }
|
void on_disconnect(std::function<void(uint16_t)> &&callback) { this->on_disconnect_callback_ = std::move(callback); }
|
||||||
virtual void off_connect(EventEmitterListenerID id) {}
|
|
||||||
virtual void off_disconnect(EventEmitterListenerID id) {}
|
|
||||||
|
|
||||||
protected:
|
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 {
|
struct ServiceEntry {
|
||||||
ESPBTUUID uuid;
|
ESPBTUUID uuid;
|
||||||
uint8_t inst_id;
|
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 add_client_(uint16_t conn_id) { this->clients_.insert(conn_id); }
|
||||||
void remove_client_(uint16_t conn_id) { this->clients_.erase(conn_id); }
|
void remove_client_(uint16_t conn_id) { this->clients_.erase(conn_id); }
|
||||||
|
|
||||||
|
std::function<void(uint16_t)> on_connect_callback_{nullptr};
|
||||||
|
std::function<void(uint16_t)> on_disconnect_callback_{nullptr};
|
||||||
|
|
||||||
std::vector<uint8_t> manufacturer_data_{};
|
std::vector<uint8_t> manufacturer_data_{};
|
||||||
esp_gatt_if_t gatts_if_{0};
|
esp_gatt_if_t gatts_if_{0};
|
||||||
bool registered_{false};
|
bool registered_{false};
|
||||||
|
@@ -52,29 +52,15 @@ Trigger<uint16_t> *BLETriggers::create_server_on_disconnect_trigger(BLEServer *s
|
|||||||
|
|
||||||
#ifdef USE_ESP32_BLE_SERVER_SET_VALUE_ACTION
|
#ifdef USE_ESP32_BLE_SERVER_SET_VALUE_ACTION
|
||||||
void BLECharacteristicSetValueActionManager::set_listener(BLECharacteristic *characteristic,
|
void BLECharacteristicSetValueActionManager::set_listener(BLECharacteristic *characteristic,
|
||||||
EventEmitterListenerID listener_id,
|
|
||||||
const std::function<void()> &pre_notify_listener) {
|
const std::function<void()> &pre_notify_listener) {
|
||||||
// Find and remove existing listener for this characteristic
|
// Find and remove existing listener for this characteristic
|
||||||
auto *existing = this->find_listener_(characteristic);
|
auto *existing = this->find_listener_(characteristic);
|
||||||
if (existing != nullptr) {
|
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
|
// Remove from vector
|
||||||
this->remove_listener_(characteristic);
|
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
|
// 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_(
|
BLECharacteristicSetValueActionManager::ListenerEntry *BLECharacteristicSetValueActionManager::find_listener_(
|
||||||
|
@@ -4,7 +4,6 @@
|
|||||||
#include "ble_characteristic.h"
|
#include "ble_characteristic.h"
|
||||||
#include "ble_descriptor.h"
|
#include "ble_descriptor.h"
|
||||||
|
|
||||||
#include "esphome/components/event_emitter/event_emitter.h"
|
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -18,10 +17,6 @@ namespace esp32_ble_server {
|
|||||||
namespace esp32_ble_server_automations {
|
namespace esp32_ble_server_automations {
|
||||||
|
|
||||||
using namespace esp32_ble;
|
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 {
|
class BLETriggers {
|
||||||
public:
|
public:
|
||||||
@@ -41,42 +36,29 @@ class BLETriggers {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_ESP32_BLE_SERVER_SET_VALUE_ACTION
|
#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
|
// Class to make sure only one BLECharacteristicSetValueAction is active at a time for each characteristic
|
||||||
#ifndef BLE_SET_VALUE_ACTION_MAX_LISTENERS
|
class BLECharacteristicSetValueActionManager {
|
||||||
#define BLE_SET_VALUE_ACTION_MAX_LISTENERS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class BLECharacteristicSetValueActionManager
|
|
||||||
: public EventEmitter<BLECharacteristicSetValueActionEvt, BLE_SET_VALUE_ACTION_MAX_LISTENERS, BLECharacteristic *> {
|
|
||||||
public:
|
public:
|
||||||
// Singleton pattern
|
// Singleton pattern
|
||||||
static BLECharacteristicSetValueActionManager *get_instance() {
|
static BLECharacteristicSetValueActionManager *get_instance() {
|
||||||
static BLECharacteristicSetValueActionManager instance;
|
static BLECharacteristicSetValueActionManager instance;
|
||||||
return &instance;
|
return &instance;
|
||||||
}
|
}
|
||||||
void set_listener(BLECharacteristic *characteristic, EventEmitterListenerID listener_id,
|
void set_listener(BLECharacteristic *characteristic, const std::function<void()> &pre_notify_listener);
|
||||||
const std::function<void()> &pre_notify_listener);
|
bool has_listener(BLECharacteristic *characteristic) { return this->find_listener_(characteristic) != nullptr; }
|
||||||
EventEmitterListenerID get_listener(BLECharacteristic *characteristic) {
|
void emit_pre_notify(BLECharacteristic *characteristic) {
|
||||||
for (const auto &entry : this->listeners_) {
|
for (const auto &entry : this->listeners_) {
|
||||||
if (entry.characteristic == characteristic) {
|
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:
|
private:
|
||||||
struct ListenerEntry {
|
struct ListenerEntry {
|
||||||
BLECharacteristic *characteristic;
|
BLECharacteristic *characteristic;
|
||||||
EventEmitterListenerID listener_id;
|
std::function<void()> pre_notify_listener;
|
||||||
EventEmitterListenerID pre_notify_listener_id;
|
|
||||||
};
|
};
|
||||||
std::vector<ListenerEntry> listeners_;
|
std::vector<ListenerEntry> listeners_;
|
||||||
|
|
||||||
@@ -91,23 +73,22 @@ template<typename... Ts> class BLECharacteristicSetValueAction : public Action<T
|
|||||||
void set_buffer(ByteBuffer buffer) { this->set_buffer(buffer.get_data()); }
|
void set_buffer(ByteBuffer buffer) { this->set_buffer(buffer.get_data()); }
|
||||||
void play(Ts... x) override {
|
void play(Ts... x) override {
|
||||||
// If the listener is already set, do nothing
|
// 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;
|
return;
|
||||||
// Set initial value
|
// Set initial value
|
||||||
this->parent_->set_value(this->buffer_.value(x...));
|
this->parent_->set_value(this->buffer_.value(x...));
|
||||||
// Set the listener for read events
|
// 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
|
// Set the value of the characteristic every time it is read
|
||||||
this->parent_->set_value(this->buffer_.value(x...));
|
this->parent_->set_value(this->buffer_.value(x...));
|
||||||
});
|
});
|
||||||
// Set the listener in the global manager so only one BLECharacteristicSetValueAction is set for each characteristic
|
// Set the listener in the global manager so only one BLECharacteristicSetValueAction is set for each characteristic
|
||||||
BLECharacteristicSetValueActionManager::get_instance()->set_listener(
|
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:
|
protected:
|
||||||
BLECharacteristic *parent_;
|
BLECharacteristic *parent_;
|
||||||
EventEmitterListenerID listener_id_;
|
|
||||||
};
|
};
|
||||||
#endif // USE_ESP32_BLE_SERVER_SET_VALUE_ACTION
|
#endif // USE_ESP32_BLE_SERVER_SET_VALUE_ACTION
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
from esphome import automation
|
from esphome import automation
|
||||||
import esphome.codegen as cg
|
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
|
from esphome.components.esp32_ble import BTLoggers
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID
|
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
|
# Register the loggers this component needs
|
||||||
esp32_ble.register_bt_logger(BTLoggers.GATT, BTLoggers.SMP)
|
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])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
@@ -1,5 +0,0 @@
|
|||||||
CODEOWNERS = ["@Rapsssito"]
|
|
||||||
|
|
||||||
# Allows event_emitter to be configured in yaml, to allow use of the C++ api.
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = {}
|
|
@@ -1,78 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#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<typename EvtType, size_t MaxListeners, typename... Args> class EventEmitter {
|
|
||||||
public:
|
|
||||||
EventEmitterListenerID on(EvtType event, std::function<void(Args...)> 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<void(Args...)> 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<ListenerEntry, MaxListeners> listeners_{};
|
|
||||||
EventEmitterListenerID current_id_{0};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace event_emitter
|
|
||||||
} // namespace esphome
|
|
Reference in New Issue
Block a user