mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'integration' into memory_api
This commit is contained in:
		| @@ -51,11 +51,11 @@ void BLECharacteristic::notify() { | ||||
|  | ||||
|   for (auto &client : this->service_->get_server()->get_clients()) { | ||||
|     size_t length = this->value_.size(); | ||||
|     // If the client is not in the list of clients to notify, skip it | ||||
|     if (this->clients_to_notify_.count(client) == 0) | ||||
|     // Find the client in the list of clients to notify | ||||
|     auto *entry = this->find_client_in_notify_list_(client); | ||||
|     if (entry == nullptr) | ||||
|       continue; | ||||
|     // If the client is in the list of clients to notify, check if it requires an ack (i.e. INDICATE) | ||||
|     bool require_ack = this->clients_to_notify_[client]; | ||||
|     bool require_ack = entry->indicate; | ||||
|     // TODO: Remove this block when INDICATE acknowledgment is supported | ||||
|     if (require_ack) { | ||||
|       ESP_LOGW(TAG, "INDICATE acknowledgment is not yet supported (i.e. it works as a NOTIFY)"); | ||||
| @@ -79,10 +79,11 @@ void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) { | ||||
|       uint16_t cccd = encode_uint16(value[1], value[0]); | ||||
|       bool notify = (cccd & 1) != 0; | ||||
|       bool indicate = (cccd & 2) != 0; | ||||
|       // Remove existing entry if present | ||||
|       this->remove_client_from_notify_list_(conn_id); | ||||
|       // Add new entry if needed | ||||
|       if (notify || indicate) { | ||||
|         this->clients_to_notify_[conn_id] = indicate; | ||||
|       } else { | ||||
|         this->clients_to_notify_.erase(conn_id); | ||||
|         this->clients_to_notify_.push_back({conn_id, indicate}); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| @@ -307,6 +308,30 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt | ||||
|   } | ||||
| } | ||||
|  | ||||
| void BLECharacteristic::remove_client_from_notify_list_(uint16_t conn_id) { | ||||
|   // Since we typically have very few clients (often just 1), we can optimize | ||||
|   // for the common case by swapping with the last element and popping | ||||
|   for (size_t i = 0; i < this->clients_to_notify_.size(); i++) { | ||||
|     if (this->clients_to_notify_[i].conn_id == conn_id) { | ||||
|       // Swap with last element and pop | ||||
|       if (i != this->clients_to_notify_.size() - 1) { | ||||
|         this->clients_to_notify_[i] = this->clients_to_notify_.back(); | ||||
|       } | ||||
|       this->clients_to_notify_.pop_back(); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| BLECharacteristic::ClientNotificationEntry *BLECharacteristic::find_client_in_notify_list_(uint16_t conn_id) { | ||||
|   for (auto &entry : this->clients_to_notify_) { | ||||
|     if (entry.conn_id == conn_id) { | ||||
|       return &entry; | ||||
|     } | ||||
|   } | ||||
|   return nullptr; | ||||
| } | ||||
|  | ||||
| }  // namespace esp32_ble_server | ||||
| }  // namespace esphome | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "esphome/components/bytebuffer/bytebuffer.h" | ||||
|  | ||||
| #include <vector> | ||||
| #include <unordered_map> | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
|  | ||||
| @@ -89,7 +88,15 @@ class BLECharacteristic : public EventEmitter<BLECharacteristicEvt::VectorEvt, s | ||||
|   SemaphoreHandle_t set_value_lock_; | ||||
|  | ||||
|   std::vector<BLEDescriptor *> descriptors_; | ||||
|   std::unordered_map<uint16_t, bool> clients_to_notify_; | ||||
|  | ||||
|   struct ClientNotificationEntry { | ||||
|     uint16_t conn_id; | ||||
|     bool indicate;  // true = indicate, false = notify | ||||
|   }; | ||||
|   std::vector<ClientNotificationEntry> clients_to_notify_; | ||||
|  | ||||
|   void remove_client_from_notify_list_(uint16_t conn_id); | ||||
|   ClientNotificationEntry *find_client_in_notify_list_(uint16_t conn_id); | ||||
|  | ||||
|   esp_gatt_perm_t permissions_ = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; | ||||
|  | ||||
|   | ||||
| @@ -45,17 +45,16 @@ Trigger<uint16_t> *BLETriggers::create_server_on_disconnect_trigger(BLEServer *s | ||||
| void BLECharacteristicSetValueActionManager::set_listener(BLECharacteristic *characteristic, | ||||
|                                                           EventEmitterListenerID listener_id, | ||||
|                                                           const std::function<void()> &pre_notify_listener) { | ||||
|   // Check if there is already a listener for this characteristic | ||||
|   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; | ||||
|   // 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, | ||||
|                                                                                 old_listener_id); | ||||
|                                                                                 existing->listener_id); | ||||
|     // Remove the pre-notify listener | ||||
|     this->off(BLECharacteristicSetValueActionEvt::PRE_NOTIFY, old_pre_notify_listener_id); | ||||
|     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 = | ||||
| @@ -66,8 +65,32 @@ void BLECharacteristicSetValueActionManager::set_listener(BLECharacteristic *cha | ||||
|                    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); | ||||
|   // Save the entry to the vector | ||||
|   this->listeners_.push_back({characteristic, listener_id, pre_notify_listener_id}); | ||||
| } | ||||
|  | ||||
| BLECharacteristicSetValueActionManager::ListenerEntry *BLECharacteristicSetValueActionManager::find_listener_( | ||||
|     BLECharacteristic *characteristic) { | ||||
|   for (auto &entry : this->listeners_) { | ||||
|     if (entry.characteristic == characteristic) { | ||||
|       return &entry; | ||||
|     } | ||||
|   } | ||||
|   return nullptr; | ||||
| } | ||||
|  | ||||
| void BLECharacteristicSetValueActionManager::remove_listener_(BLECharacteristic *characteristic) { | ||||
|   // Since we typically have very few listeners, optimize by swapping with back and popping | ||||
|   for (size_t i = 0; i < this->listeners_.size(); i++) { | ||||
|     if (this->listeners_[i].characteristic == characteristic) { | ||||
|       // Swap with last element and pop | ||||
|       if (i != this->listeners_.size() - 1) { | ||||
|         this->listeners_[i] = this->listeners_.back(); | ||||
|       } | ||||
|       this->listeners_.pop_back(); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace esp32_ble_server_automations | ||||
|   | ||||
| @@ -8,7 +8,6 @@ | ||||
| #include "esphome/core/automation.h" | ||||
|  | ||||
| #include <vector> | ||||
| #include <unordered_map> | ||||
| #include <functional> | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
| @@ -46,14 +45,27 @@ class BLECharacteristicSetValueActionManager | ||||
|   void set_listener(BLECharacteristic *characteristic, EventEmitterListenerID listener_id, | ||||
|                     const std::function<void()> &pre_notify_listener); | ||||
|   EventEmitterListenerID get_listener(BLECharacteristic *characteristic) { | ||||
|     return this->listeners_[characteristic].first; | ||||
|     for (const auto &entry : this->listeners_) { | ||||
|       if (entry.characteristic == characteristic) { | ||||
|         return entry.listener_id; | ||||
|       } | ||||
|     } | ||||
|     return 0; | ||||
|   } | ||||
|   void emit_pre_notify(BLECharacteristic *characteristic) { | ||||
|     this->emit_(BLECharacteristicSetValueActionEvt::PRE_NOTIFY, characteristic); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   std::unordered_map<BLECharacteristic *, std::pair<EventEmitterListenerID, EventEmitterListenerID>> listeners_; | ||||
|   struct ListenerEntry { | ||||
|     BLECharacteristic *characteristic; | ||||
|     EventEmitterListenerID listener_id; | ||||
|     EventEmitterListenerID pre_notify_listener_id; | ||||
|   }; | ||||
|   std::vector<ListenerEntry> listeners_; | ||||
|  | ||||
|   ListenerEntry *find_listener_(BLECharacteristic *characteristic); | ||||
|   void remove_listener_(BLECharacteristic *characteristic); | ||||
| }; | ||||
|  | ||||
| template<typename... Ts> class BLECharacteristicSetValueAction : public Action<Ts...> { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user