From 63e5b31fe53287908906b1b05affd236a0c047d4 Mon Sep 17 00:00:00 2001 From: Rapsssito Date: Sat, 13 Jul 2024 12:56:43 +0200 Subject: [PATCH] Set characteristic value previous to a notify action --- .../ble_server_automations.cpp | 26 ++++++++++++++++--- .../esp32_ble_server/ble_server_automations.h | 26 ++++++++++++++----- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/esphome/components/esp32_ble_server/ble_server_automations.cpp b/esphome/components/esp32_ble_server/ble_server_automations.cpp index e5009ce5f8..66a27660cb 100644 --- a/esphome/components/esp32_ble_server/ble_server_automations.cpp +++ b/esphome/components/esp32_ble_server/ble_server_automations.cpp @@ -19,14 +19,32 @@ Trigger> *BLETriggers::create_on_write_trigger(BLECharacter } void BLECharacteristicSetValueActionManager::set_listener(BLECharacteristic *characteristic, - EventEmitterListenerID listener_id) { + EventEmitterListenerID listener_id, + std::function pre_notify_listener) { // Check if there is already a listener for this characteristic - if (this->listeners_.find(characteristic) != this->listeners_.end()) { + if (this->listeners_.count(characteristic) > 0) { + // Unpack the pair listener_id, pre_notify_listener_id + auto listener_pairs = this->listeners_[characteristic]; + EventEmitterListenerID old_listener_id = listener_pairs.first; + EventEmitterListenerID old_pre_notify_listener_id = listener_pairs.second; // Remove the previous listener characteristic->EventEmitter::off(BLECharacteristicEvt::EmptyEvt::ON_READ, - this->listeners_[characteristic]); + old_listener_id); + // Remove the pre-notify listener + this->off(BLECharacteristicSetValueActionEvt::PRE_NOTIFY, old_pre_notify_listener_id); } - this->listeners_[characteristic] = listener_id; + // 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 pair listener_id, pre_notify_listener_id to the map + this->listeners_[characteristic] = std::make_pair(listener_id, pre_notify_listener_id); } } // namespace esp32_ble_server_automations diff --git a/esphome/components/esp32_ble_server/ble_server_automations.h b/esphome/components/esp32_ble_server/ble_server_automations.h index d37959537e..7d4ccaf2b8 100644 --- a/esphome/components/esp32_ble_server/ble_server_automations.h +++ b/esphome/components/esp32_ble_server/ble_server_automations.h @@ -7,6 +7,7 @@ #include #include +#include #ifdef USE_ESP32 @@ -22,19 +23,24 @@ class BLETriggers { static Trigger> *create_on_write_trigger(BLECharacteristic *characteristic); }; +enum BLECharacteristicSetValueActionEvt { + PRE_NOTIFY, +}; + // Class to make sure only one BLECharacteristicSetValueAction is active at a time -class BLECharacteristicSetValueActionManager { +class BLECharacteristicSetValueActionManager : public EventEmitter { public: // Singleton pattern static BLECharacteristicSetValueActionManager *get_instance() { static BLECharacteristicSetValueActionManager instance; return &instance; } - void set_listener(BLECharacteristic *characteristic, EventEmitterListenerID listener_id); - EventEmitterListenerID get_listener(BLECharacteristic *characteristic) { return this->listeners_[characteristic]; } + void set_listener(BLECharacteristic *characteristic, EventEmitterListenerID listener_id, std::function pre_notify_listener); + EventEmitterListenerID get_listener(BLECharacteristic *characteristic) { return this->listeners_[characteristic].first; } + void emit_pre_notify(BLECharacteristic *characteristic) { this->emit_(BLECharacteristicSetValueActionEvt::PRE_NOTIFY, characteristic); } private: - std::unordered_map listeners_; + std::unordered_map> listeners_; }; template class BLECharacteristicSetValueAction : public Action { @@ -54,7 +60,10 @@ template class BLECharacteristicSetValueAction : public Actionparent_->set_value(this->value_.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_); + BLECharacteristicSetValueActionManager::get_instance()->set_listener( + this->parent_, this->listener_id_, [this, x...]() { + this->parent_->set_value(this->value_.value(x...)); + }); } protected: @@ -65,7 +74,12 @@ template class BLECharacteristicSetValueAction : public Action class BLECharacteristicNotifyAction : public Action { public: BLECharacteristicNotifyAction(BLECharacteristic *characteristic) : parent_(characteristic) {} - void play(Ts... x) override { this->parent_->notify(); } + void play(Ts... x) override { + // Call the pre-notify event + BLECharacteristicSetValueActionManager::get_instance()->emit_pre_notify(this->parent_); + // Notify the characteristic + this->parent_->notify(); + } protected: BLECharacteristic *parent_;