ESPHome 2025.10.0-dev
Loading...
Searching...
No Matches
event_emitter.h
Go to the documentation of this file.
1#pragma once
2#include <vector>
3#include <functional>
4#include <limits>
5
6#include "esphome/core/log.h"
7
8namespace esphome {
9namespace event_emitter {
10
11using EventEmitterListenerID = uint32_t;
12static constexpr EventEmitterListenerID INVALID_LISTENER_ID = 0;
13
14// EventEmitter class that can emit events with a specific name (it is highly recommended to use an enum class for this)
15// and a list of arguments. Supports multiple listeners for each event.
16template<typename EvtType, typename... Args> class EventEmitter {
17 public:
18 EventEmitterListenerID on(EvtType event, std::function<void(Args...)> listener) {
19 EventEmitterListenerID listener_id = this->get_next_id_();
20
21 // Find or create event entry
22 EventEntry *entry = this->find_or_create_event_(event);
23 entry->listeners.push_back({listener_id, listener});
24
25 return listener_id;
26 }
27
28 void off(EvtType event, EventEmitterListenerID id) {
29 EventEntry *entry = this->find_event_(event);
30 if (entry == nullptr)
31 return;
32
33 // Remove listener with given id
34 for (auto it = entry->listeners.begin(); it != entry->listeners.end(); ++it) {
35 if (it->id == id) {
36 // Swap with last and pop for efficient removal
37 *it = entry->listeners.back();
38 entry->listeners.pop_back();
39
40 // Remove event entry if no more listeners
41 if (entry->listeners.empty()) {
42 this->remove_event_(event);
43 }
44 return;
45 }
46 }
47 }
48
49 protected:
50 void emit_(EvtType event, Args... args) {
51 EventEntry *entry = this->find_event_(event);
52 if (entry == nullptr)
53 return;
54
55 // Call all listeners for this event
56 for (const auto &listener : entry->listeners) {
57 listener.callback(args...);
58 }
59 }
60
61 private:
62 struct Listener {
64 std::function<void(Args...)> callback;
65 };
66
67 struct EventEntry {
68 EvtType event;
69 std::vector<Listener> listeners;
70 };
71
72 EventEmitterListenerID get_next_id_() {
73 // Simple incrementing ID, wrapping around at max
74 EventEmitterListenerID next_id = (this->current_id_ + 1);
75 if (next_id == INVALID_LISTENER_ID) {
76 next_id = 1;
77 }
78 this->current_id_ = next_id;
79 return this->current_id_;
80 }
81
82 EventEntry *find_event_(EvtType event) {
83 for (auto &entry : this->events_) {
84 if (entry.event == event) {
85 return &entry;
86 }
87 }
88 return nullptr;
89 }
90
91 EventEntry *find_or_create_event_(EvtType event) {
92 EventEntry *entry = this->find_event_(event);
93 if (entry != nullptr)
94 return entry;
95
96 // Create new event entry
97 this->events_.push_back({event, {}});
98 return &this->events_.back();
99 }
100
101 void remove_event_(EvtType event) {
102 for (auto it = this->events_.begin(); it != this->events_.end(); ++it) {
103 if (it->event == event) {
104 // Swap with last and pop
105 *it = this->events_.back();
106 this->events_.pop_back();
107 return;
108 }
109 }
110 }
111
112 std::vector<EventEntry> events_;
113 EventEmitterListenerID current_id_ = 0;
114};
115
116} // namespace event_emitter
117} // namespace esphome
EventEmitterListenerID on(EvtType event, std::function< void(Args...)> listener)
void off(EvtType event, EventEmitterListenerID id)
void emit_(EvtType event, Args... args)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7