mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'event_emitter_cleanup' into integration
This commit is contained in:
		| @@ -160,7 +160,6 @@ esphome/components/esp_ldo/* @clydebarrow | ||||
| esphome/components/espnow/* @jesserockz | ||||
| esphome/components/ethernet_info/* @gtjadsonsantos | ||||
| esphome/components/event/* @nohat | ||||
| esphome/components/event_emitter/* @Rapsssito | ||||
| esphome/components/exposure_notifications/* @OttoWinter | ||||
| esphome/components/ezo/* @ssieb | ||||
| esphome/components/ezo_pmp/* @carlos-sarmiento | ||||
|   | ||||
| @@ -26,11 +26,12 @@ 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" | ||||
|  | ||||
|  | ||||
| CONF_ADVERTISE = "advertise" | ||||
| CONF_APPEARANCE = "appearance" | ||||
| CONF_BROADCAST = "broadcast" | ||||
| @@ -504,6 +505,7 @@ async def to_code_characteristic(service_var, char_conf): | ||||
|             parse_properties(char_conf), | ||||
|         ), | ||||
|     ) | ||||
|  | ||||
|     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") | ||||
| @@ -583,6 +585,7 @@ async def to_code(config): | ||||
|             [(cg.uint16, "id")], | ||||
|             config[CONF_ON_DISCONNECT], | ||||
|         ) | ||||
|  | ||||
|     cg.add_define("USE_ESP32_BLE_SERVER") | ||||
|     cg.add_define("USE_ESP32_BLE_ADVERTISING") | ||||
|     add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) | ||||
|   | ||||
| @@ -73,7 +73,7 @@ void BLECharacteristic::notify() { | ||||
| void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) { | ||||
|   // 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(BLEDescriptorEvt::VectorEvt::ON_WRITE, [this](const std::vector<uint8_t> &value, uint16_t conn_id) { | ||||
|     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]); | ||||
| @@ -208,8 +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->EventEmitter<BLECharacteristicEvt::EmptyEvt, uint16_t>::emit_(BLECharacteristicEvt::EmptyEvt::ON_READ, | ||||
|                                                                           param->read.conn_id); | ||||
|       if (this->on_read_callback_) { | ||||
|         (*this->on_read_callback_)(param->read.conn_id); | ||||
|       } | ||||
|  | ||||
|       uint16_t max_offset = 22; | ||||
|  | ||||
| @@ -277,8 +278,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt | ||||
|       } | ||||
|  | ||||
|       if (!param->write.is_prep) { | ||||
|         this->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::emit_( | ||||
|             BLECharacteristicEvt::VectorEvt::ON_WRITE, this->value_, param->write.conn_id); | ||||
|         if (this->on_write_callback_) { | ||||
|           (*this->on_write_callback_)(this->value_, param->write.conn_id); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       break; | ||||
| @@ -289,8 +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->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::emit_( | ||||
|             BLECharacteristicEvt::VectorEvt::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); | ||||
|   | ||||
| @@ -2,10 +2,12 @@ | ||||
|  | ||||
| #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 <vector> | ||||
| #include <span> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
|  | ||||
| @@ -22,22 +24,10 @@ namespace esp32_ble_server { | ||||
|  | ||||
| using namespace esp32_ble; | ||||
| using namespace bytebuffer; | ||||
| using namespace event_emitter; | ||||
|  | ||||
| class BLEService; | ||||
|  | ||||
| namespace BLECharacteristicEvt { | ||||
| enum VectorEvt { | ||||
|   ON_WRITE, | ||||
| }; | ||||
|  | ||||
| enum EmptyEvt { | ||||
|   ON_READ, | ||||
| }; | ||||
| }  // namespace BLECharacteristicEvt | ||||
|  | ||||
| class BLECharacteristic : public EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>, | ||||
|                           public EventEmitter<BLECharacteristicEvt::EmptyEvt, uint16_t> { | ||||
| class BLECharacteristic { | ||||
|  public: | ||||
|   BLECharacteristic(ESPBTUUID uuid, uint32_t properties); | ||||
|   ~BLECharacteristic(); | ||||
| @@ -76,6 +66,15 @@ class BLECharacteristic : public EventEmitter<BLECharacteristicEvt::VectorEvt, s | ||||
|   bool is_created(); | ||||
|   bool is_failed(); | ||||
|  | ||||
|   // Direct callback registration - only allocates when callback is set | ||||
|   void on_write(std::function<void(std::span<const uint8_t>, uint16_t)> &&callback) { | ||||
|     this->on_write_callback_ = | ||||
|         std::make_unique<std::function<void(std::span<const uint8_t>, uint16_t)>>(std::move(callback)); | ||||
|   } | ||||
|   void on_read(std::function<void(uint16_t)> &&callback) { | ||||
|     this->on_read_callback_ = std::make_unique<std::function<void(uint16_t)>>(std::move(callback)); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   bool write_event_{false}; | ||||
|   BLEService *service_{}; | ||||
| @@ -98,6 +97,9 @@ class BLECharacteristic : public EventEmitter<BLECharacteristicEvt::VectorEvt, s | ||||
|   void remove_client_from_notify_list_(uint16_t conn_id); | ||||
|   ClientNotificationEntry *find_client_in_notify_list_(uint16_t conn_id); | ||||
|  | ||||
|   std::unique_ptr<std::function<void(std::span<const uint8_t>, uint16_t)>> on_write_callback_; | ||||
|   std::unique_ptr<std::function<void(uint16_t)>> on_read_callback_; | ||||
|  | ||||
|   esp_gatt_perm_t permissions_ = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; | ||||
|  | ||||
|   enum State : uint8_t { | ||||
|   | ||||
| @@ -74,9 +74,10 @@ 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_(BLEDescriptorEvt::VectorEvt::ON_WRITE, | ||||
|                   std::vector<uint8_t>(param->write.value, 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; | ||||
|     } | ||||
|     default: | ||||
|   | ||||
| @@ -1,30 +1,26 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/esp32_ble/ble_uuid.h" | ||||
| #include "esphome/components/event_emitter/event_emitter.h" | ||||
| #include "esphome/components/bytebuffer/bytebuffer.h" | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
|  | ||||
| #include <esp_gatt_defs.h> | ||||
| #include <esp_gatts_api.h> | ||||
| #include <span> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace esp32_ble_server { | ||||
|  | ||||
| using namespace esp32_ble; | ||||
| using namespace bytebuffer; | ||||
| using namespace event_emitter; | ||||
|  | ||||
| class BLECharacteristic; | ||||
|  | ||||
| namespace BLEDescriptorEvt { | ||||
| enum VectorEvt { | ||||
|   ON_WRITE, | ||||
| }; | ||||
| }  // namespace BLEDescriptorEvt | ||||
|  | ||||
| class BLEDescriptor : public EventEmitter<BLEDescriptorEvt::VectorEvt, std::vector<uint8_t>, uint16_t> { | ||||
| // Base class for BLE descriptors | ||||
| class BLEDescriptor { | ||||
|  public: | ||||
|   BLEDescriptor(ESPBTUUID uuid, uint16_t max_len = 100, bool read = true, bool write = true); | ||||
|   virtual ~BLEDescriptor(); | ||||
| @@ -39,6 +35,12 @@ class BLEDescriptor : public EventEmitter<BLEDescriptorEvt::VectorEvt, std::vect | ||||
|   bool is_created() { return this->state_ == CREATED; } | ||||
|   bool is_failed() { return this->state_ == FAILED; } | ||||
|  | ||||
|   // Direct callback registration - only allocates when callback is set | ||||
|   void on_write(std::function<void(std::span<const uint8_t>, uint16_t)> &&callback) { | ||||
|     this->on_write_callback_ = | ||||
|         std::make_unique<std::function<void(std::span<const uint8_t>, uint16_t)>>(std::move(callback)); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   BLECharacteristic *characteristic_{nullptr}; | ||||
|   ESPBTUUID uuid_; | ||||
| @@ -46,6 +48,8 @@ class BLEDescriptor : public EventEmitter<BLEDescriptorEvt::VectorEvt, std::vect | ||||
|  | ||||
|   esp_attr_value_t value_{}; | ||||
|  | ||||
|   std::unique_ptr<std::function<void(std::span<const uint8_t>, uint16_t)>> on_write_callback_; | ||||
|  | ||||
|   esp_gatt_perm_t permissions_{}; | ||||
|  | ||||
|   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: { | ||||
|       ESP_LOGD(TAG, "BLE Client connected"); | ||||
|       this->add_client_(param->connect.conn_id); | ||||
|       this->emit_(BLEServerEvt::EmptyEvt::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_(BLEServerEvt::EmptyEvt::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: { | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
| #include <vector> | ||||
| #include <unordered_map> | ||||
| #include <unordered_set> | ||||
| #include <functional> | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
|  | ||||
| @@ -24,18 +25,8 @@ namespace esp32_ble_server { | ||||
| using namespace esp32_ble; | ||||
| using namespace bytebuffer; | ||||
|  | ||||
| namespace BLEServerEvt { | ||||
| enum EmptyEvt { | ||||
|   ON_CONNECT, | ||||
|   ON_DISCONNECT, | ||||
| }; | ||||
| }  // namespace BLEServerEvt | ||||
|  | ||||
| class BLEServer : public Component, | ||||
|                   public GATTsEventHandler, | ||||
|                   public BLEStatusEventHandler, | ||||
|                   public Parented<ESP32BLE>, | ||||
|                   public EventEmitter<BLEServerEvt::EmptyEvt, uint16_t> { | ||||
| // Base class for BLE server | ||||
| class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented<ESP32BLE> { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void loop() override; | ||||
| @@ -65,6 +56,14 @@ class BLEServer : public Component, | ||||
|  | ||||
|   void ble_before_disabled_event_handler() override; | ||||
|  | ||||
|   // Direct callback registration - only allocates when callback is set | ||||
|   void on_connect(std::function<void(uint16_t)> &&callback) { | ||||
|     this->on_connect_callback_ = std::make_unique<std::function<void(uint16_t)>>(std::move(callback)); | ||||
|   } | ||||
|   void on_disconnect(std::function<void(uint16_t)> &&callback) { | ||||
|     this->on_disconnect_callback_ = std::make_unique<std::function<void(uint16_t)>>(std::move(callback)); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   struct ServiceEntry { | ||||
|     ESPBTUUID uuid; | ||||
| @@ -77,6 +76,9 @@ class BLEServer : public Component, | ||||
|   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::unique_ptr<std::function<void(uint16_t)>> on_connect_callback_; | ||||
|   std::unique_ptr<std::function<void(uint16_t)>> on_disconnect_callback_; | ||||
|  | ||||
|   std::vector<uint8_t> manufacturer_data_{}; | ||||
|   esp_gatt_if_t gatts_if_{0}; | ||||
|   bool registered_{false}; | ||||
|   | ||||
| @@ -14,9 +14,10 @@ Trigger<std::vector<uint8_t>, uint16_t> *BLETriggers::create_characteristic_on_w | ||||
|     BLECharacteristic *characteristic) { | ||||
|   Trigger<std::vector<uint8_t>, uint16_t> *on_write_trigger =  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|       new Trigger<std::vector<uint8_t>, uint16_t>(); | ||||
|   characteristic->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::on( | ||||
|       BLECharacteristicEvt::VectorEvt::ON_WRITE, | ||||
|       [on_write_trigger](const std::vector<uint8_t> &data, uint16_t id) { on_write_trigger->trigger(data, id); }); | ||||
|   characteristic->on_write([on_write_trigger](std::span<const uint8_t> data, uint16_t id) { | ||||
|     // Convert span to vector for trigger | ||||
|     on_write_trigger->trigger(std::vector<uint8_t>(data.begin(), data.end()), id); | ||||
|   }); | ||||
|   return on_write_trigger; | ||||
| } | ||||
| #endif | ||||
| @@ -25,9 +26,10 @@ Trigger<std::vector<uint8_t>, uint16_t> *BLETriggers::create_characteristic_on_w | ||||
| Trigger<std::vector<uint8_t>, uint16_t> *BLETriggers::create_descriptor_on_write_trigger(BLEDescriptor *descriptor) { | ||||
|   Trigger<std::vector<uint8_t>, uint16_t> *on_write_trigger =  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|       new Trigger<std::vector<uint8_t>, uint16_t>(); | ||||
|   descriptor->on( | ||||
|       BLEDescriptorEvt::VectorEvt::ON_WRITE, | ||||
|       [on_write_trigger](const std::vector<uint8_t> &data, uint16_t id) { on_write_trigger->trigger(data, id); }); | ||||
|   descriptor->on_write([on_write_trigger](std::span<const uint8_t> data, uint16_t id) { | ||||
|     // Convert span to vector for trigger | ||||
|     on_write_trigger->trigger(std::vector<uint8_t>(data.begin(), data.end()), id); | ||||
|   }); | ||||
|   return on_write_trigger; | ||||
| } | ||||
| #endif | ||||
| @@ -35,8 +37,7 @@ Trigger<std::vector<uint8_t>, uint16_t> *BLETriggers::create_descriptor_on_write | ||||
| #ifdef USE_ESP32_BLE_SERVER_ON_CONNECT | ||||
| Trigger<uint16_t> *BLETriggers::create_server_on_connect_trigger(BLEServer *server) { | ||||
|   Trigger<uint16_t> *on_connect_trigger = new Trigger<uint16_t>();  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|   server->on(BLEServerEvt::EmptyEvt::ON_CONNECT, | ||||
|              [on_connect_trigger](uint16_t conn_id) { on_connect_trigger->trigger(conn_id); }); | ||||
|   server->on_connect([on_connect_trigger](uint16_t conn_id) { on_connect_trigger->trigger(conn_id); }); | ||||
|   return on_connect_trigger; | ||||
| } | ||||
| #endif | ||||
| @@ -44,38 +45,22 @@ Trigger<uint16_t> *BLETriggers::create_server_on_connect_trigger(BLEServer *serv | ||||
| #ifdef USE_ESP32_BLE_SERVER_ON_DISCONNECT | ||||
| Trigger<uint16_t> *BLETriggers::create_server_on_disconnect_trigger(BLEServer *server) { | ||||
|   Trigger<uint16_t> *on_disconnect_trigger = new Trigger<uint16_t>();  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|   server->on(BLEServerEvt::EmptyEvt::ON_DISCONNECT, | ||||
|              [on_disconnect_trigger](uint16_t conn_id) { on_disconnect_trigger->trigger(conn_id); }); | ||||
|   server->on_disconnect([on_disconnect_trigger](uint16_t conn_id) { on_disconnect_trigger->trigger(conn_id); }); | ||||
|   return on_disconnect_trigger; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_ESP32_BLE_SERVER_SET_VALUE_ACTION | ||||
| void BLECharacteristicSetValueActionManager::set_listener(BLECharacteristic *characteristic, | ||||
|                                                           EventEmitterListenerID listener_id, | ||||
|                                                           const std::function<void()> &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->EventEmitter<BLECharacteristicEvt::EmptyEvt, uint16_t>::off(BLECharacteristicEvt::EmptyEvt::ON_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_( | ||||
|   | ||||
| @@ -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 <vector> | ||||
| @@ -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,38 +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 | ||||
| class BLECharacteristicSetValueActionManager | ||||
|     : public EventEmitter<BLECharacteristicSetValueActionEvt, BLECharacteristic *> { | ||||
| 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<void()> &pre_notify_listener); | ||||
|   EventEmitterListenerID get_listener(BLECharacteristic *characteristic) { | ||||
|   void set_listener(BLECharacteristic *characteristic, const std::function<void()> &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<void()> pre_notify_listener; | ||||
|   }; | ||||
|   std::vector<ListenerEntry> listeners_; | ||||
|  | ||||
| @@ -87,24 +73,22 @@ template<typename... Ts> class BLECharacteristicSetValueAction : public Action<T | ||||
|   void set_buffer(ByteBuffer buffer) { this->set_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_->EventEmitter<BLECharacteristicEvt::EmptyEvt, uint16_t>::on( | ||||
|         BLECharacteristicEvt::EmptyEvt::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...)); | ||||
|         }); | ||||
|     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 | ||||
|  | ||||
|   | ||||
| @@ -38,8 +38,7 @@ void ESP32ImprovComponent::setup() { | ||||
|     }); | ||||
|   } | ||||
| #endif | ||||
|   global_ble_server->on(BLEServerEvt::EmptyEvt::ON_DISCONNECT, | ||||
|                         [this](uint16_t conn_id) { this->set_error_(improv::ERROR_NONE); }); | ||||
|   global_ble_server->on_disconnect([this](uint16_t conn_id) { this->set_error_(improv::ERROR_NONE); }); | ||||
|  | ||||
|   // Start with loop disabled - will be enabled by start() when needed | ||||
|   this->disable_loop(); | ||||
| @@ -57,12 +56,11 @@ void ESP32ImprovComponent::setup_characteristics() { | ||||
|   this->error_->add_descriptor(error_descriptor); | ||||
|  | ||||
|   this->rpc_ = this->service_->create_characteristic(improv::RPC_COMMAND_UUID, BLECharacteristic::PROPERTY_WRITE); | ||||
|   this->rpc_->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::on( | ||||
|       BLECharacteristicEvt::VectorEvt::ON_WRITE, [this](const std::vector<uint8_t> &data, uint16_t id) { | ||||
|         if (!data.empty()) { | ||||
|           this->incoming_data_.insert(this->incoming_data_.end(), data.begin(), data.end()); | ||||
|         } | ||||
|       }); | ||||
|   this->rpc_->on_write([this](std::span<const uint8_t> data, uint16_t id) { | ||||
|     if (!data.empty()) { | ||||
|       this->incoming_data_.insert(this->incoming_data_.end(), data.begin(), data.end()); | ||||
|     } | ||||
|   }); | ||||
|   BLEDescriptor *rpc_descriptor = new BLE2902(); | ||||
|   this->rpc_->add_descriptor(rpc_descriptor); | ||||
|  | ||||
|   | ||||
| @@ -1,5 +0,0 @@ | ||||
| CODEOWNERS = ["@Rapsssito"] | ||||
|  | ||||
| # Allows event_emitter to be configured in yaml, to allow use of the C++ api. | ||||
|  | ||||
| CONFIG_SCHEMA = {} | ||||
| @@ -1,117 +0,0 @@ | ||||
| #pragma once | ||||
| #include <vector> | ||||
| #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. | ||||
| template<typename EvtType, typename... Args> class EventEmitter { | ||||
|  public: | ||||
|   EventEmitterListenerID on(EvtType event, std::function<void(Args...)> listener) { | ||||
|     EventEmitterListenerID listener_id = this->get_next_id_(); | ||||
|  | ||||
|     // Find or create event entry | ||||
|     EventEntry *entry = this->find_or_create_event_(event); | ||||
|     entry->listeners.push_back({listener_id, listener}); | ||||
|  | ||||
|     return listener_id; | ||||
|   } | ||||
|  | ||||
|   void off(EvtType event, EventEmitterListenerID id) { | ||||
|     EventEntry *entry = this->find_event_(event); | ||||
|     if (entry == nullptr) | ||||
|       return; | ||||
|  | ||||
|     // Remove listener with given id | ||||
|     for (auto it = entry->listeners.begin(); it != entry->listeners.end(); ++it) { | ||||
|       if (it->id == id) { | ||||
|         // Swap with last and pop for efficient removal | ||||
|         *it = entry->listeners.back(); | ||||
|         entry->listeners.pop_back(); | ||||
|  | ||||
|         // Remove event entry if no more listeners | ||||
|         if (entry->listeners.empty()) { | ||||
|           this->remove_event_(event); | ||||
|         } | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   void emit_(EvtType event, Args... args) { | ||||
|     EventEntry *entry = this->find_event_(event); | ||||
|     if (entry == nullptr) | ||||
|       return; | ||||
|  | ||||
|     // Call all listeners for this event | ||||
|     for (const auto &listener : entry->listeners) { | ||||
|       listener.callback(args...); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   struct Listener { | ||||
|     EventEmitterListenerID id; | ||||
|     std::function<void(Args...)> callback; | ||||
|   }; | ||||
|  | ||||
|   struct EventEntry { | ||||
|     EvtType event; | ||||
|     std::vector<Listener> listeners; | ||||
|   }; | ||||
|  | ||||
|   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_; | ||||
|   } | ||||
|  | ||||
|   EventEntry *find_event_(EvtType event) { | ||||
|     for (auto &entry : this->events_) { | ||||
|       if (entry.event == event) { | ||||
|         return &entry; | ||||
|       } | ||||
|     } | ||||
|     return nullptr; | ||||
|   } | ||||
|  | ||||
|   EventEntry *find_or_create_event_(EvtType event) { | ||||
|     EventEntry *entry = this->find_event_(event); | ||||
|     if (entry != nullptr) | ||||
|       return entry; | ||||
|  | ||||
|     // Create new event entry | ||||
|     this->events_.push_back({event, {}}); | ||||
|     return &this->events_.back(); | ||||
|   } | ||||
|  | ||||
|   void remove_event_(EvtType event) { | ||||
|     for (auto it = this->events_.begin(); it != this->events_.end(); ++it) { | ||||
|       if (it->event == event) { | ||||
|         // Swap with last and pop | ||||
|         *it = this->events_.back(); | ||||
|         this->events_.pop_back(); | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   std::vector<EventEntry> events_; | ||||
|   EventEmitterListenerID current_id_ = 0; | ||||
| }; | ||||
|  | ||||
| }  // namespace event_emitter | ||||
| }  // namespace esphome | ||||
		Reference in New Issue
	
	Block a user