ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
espnow_component.h
Go to the documentation of this file.
1#pragma once
2
6
7#if defined(USE_ESP32) || defined(USE_ESP8266)
8
11#include "espnow_packet.h"
12#include "espnow_types.h"
13
14#if defined(USE_WIFI) && defined(USE_WIFI_CONNECT_STATE_LISTENERS)
16#endif
17
18#include <array>
19#include <map>
20#include <memory>
21#include <string>
22#include <vector>
23
24namespace esphome::espnow {
25
26using peer_address_t = std::array<uint8_t, ESP_NOW_ETH_ALEN>;
27
28enum class ESPNowTriggers : uint8_t {
29 TRIGGER_NONE = 0,
30 ON_NEW_PEER = 1,
31 ON_RECEIVE = 2,
32 ON_BROADCAST = 3,
33 ON_SUCCEED = 10,
34 ON_FAILED = 11,
35};
36
37enum ESPNowState : uint8_t {
39 ESPNOW_STATE_OFF = 0,
41 ESPNOW_STATE_DISABLED,
43 ESPNOW_STATE_ENABLED,
44};
45
46struct ESPNowPeer {
47 uint8_t address[ESP_NOW_ETH_ALEN]; // MAC address of the peer
48
49 bool operator==(const ESPNowPeer &other) const { return memcmp(this->address, other.address, ESP_NOW_ETH_ALEN) == 0; }
50 bool operator==(const uint8_t *other) const { return memcmp(this->address, other, ESP_NOW_ETH_ALEN) == 0; }
51};
52
55class ESPNowUnknownPeerHandler {
56 public:
62 virtual bool on_unknown_peer(const ESPNowRecvInfo &info, const uint8_t *data, uint16_t size) = 0;
63};
64
67class ESPNowReceivedPacketHandler {
68 public:
74 virtual bool on_receive(const ESPNowRecvInfo &info, const uint8_t *data, uint16_t size) = 0;
75};
78class ESPNowBroadcastHandler {
79 public:
85 virtual bool on_broadcast(const ESPNowRecvInfo &info, const uint8_t *data, uint16_t size) = 0;
86};
87
88#if defined(USE_WIFI) && defined(USE_WIFI_CONNECT_STATE_LISTENERS)
89class ESPNowComponent final : public Component, public wifi::WiFiConnectStateListener {
90#else
91class ESPNowComponent final : public Component {
92#endif
93 public:
94 ESPNowComponent();
95 void setup() override;
96 void loop() override;
97 void dump_config() override;
98
99 float get_setup_priority() const override { return setup_priority::LATE; }
100
101 // Add a peer to the internal list of peers
102 void add_peer(peer_address_t address) {
103 ESPNowPeer peer;
104 memcpy(peer.address, address.data(), ESP_NOW_ETH_ALEN);
105 this->peers_.push_back(peer);
106 }
107 // Add a peer with the esp_now api and add to the internal list if doesnt exist already
108 esp_err_t add_peer(const uint8_t *peer);
109 // Remove a peer with the esp_now api and remove from the internal list if exists
110 esp_err_t del_peer(const uint8_t *peer);
111 // Action entry points; distinct names because add_peer(peer_address_t) only fills the boot-time list
112 esp_err_t add_peer_from_action(const peer_address_t &address) { return this->add_peer(address.data()); }
113 esp_err_t del_peer_from_action(const peer_address_t &address) { return this->del_peer(address.data()); }
114
115 void set_wifi_channel(uint8_t channel) { this->wifi_channel_ = channel; }
116 void apply_wifi_channel();
117 void set_channel_from_action(uint8_t channel) {
118 if (this->is_wifi_enabled())
119 return;
120 this->set_wifi_channel(channel);
121 this->apply_wifi_channel();
122 }
123 uint8_t get_wifi_channel();
124
125 void set_auto_add_peer(bool value) { this->auto_add_peer_ = value; }
126
127#if defined(USE_WIFI) && defined(USE_WIFI_CONNECT_STATE_LISTENERS)
128 // WiFiConnectStateListener interface: refresh the cached channel after each (re)connect
129 void on_wifi_connect_state(StringRef ssid, std::span<const uint8_t, 6> bssid) override;
130#endif
131
132 void enable();
133 void disable();
134 bool is_disabled() const { return this->state_ == ESPNOW_STATE_DISABLED; };
135 void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
136 bool is_wifi_enabled();
137
147 esp_err_t send(const uint8_t *peer_address, const std::vector<uint8_t> &payload, send_callback_t callback = nullptr) {
148 return this->send(peer_address, payload.data(), payload.size(), std::move(callback));
149 }
150 esp_err_t send(const uint8_t *peer_address, const uint8_t *payload, size_t size, send_callback_t callback = nullptr);
151
152 void register_receive_handler(ESPNowReceivedPacketHandler *handler) { this->receive_handlers_.push_back(handler); }
153 void register_unknown_peer_handler(ESPNowUnknownPeerHandler *handler) {
154 this->unknown_peer_handlers_.push_back(handler);
155 }
156 void register_broadcast_handler(ESPNowBroadcastHandler *handler) { this->broadcast_handlers_.push_back(handler); }
157
158 // Entry points for the radio driver callbacks in espnow_platform_*.cpp; they run outside the main loop and
159 // only queue the event
160 void packet_received(const uint8_t *src_addr, const uint8_t *des_addr, const uint8_t *data, int size, int8_t rssi,
162 void send_reported(const uint8_t *mac_addr, esp_now_send_status_t status);
163
164 protected:
165 void enable_();
166 void send_();
167
168 std::vector<ESPNowUnknownPeerHandler *> unknown_peer_handlers_;
169 std::vector<ESPNowReceivedPacketHandler *> receive_handlers_;
170 std::vector<ESPNowBroadcastHandler *> broadcast_handlers_;
171
172 std::vector<ESPNowPeer> peers_{};
173
174 uint8_t own_address_[ESP_NOW_ETH_ALEN]{0};
175 LockFreeQueue<ESPNowPacket, MAX_ESP_NOW_RECEIVE_QUEUE_SIZE> receive_packet_queue_{};
176 // Pool sized to queue capacity (SIZE-1) because LockFreeQueue<T,N> is a ring
177 // buffer that holds N-1 elements. This guarantees allocate() returns nullptr
178 // before push() can fail, preventing a pool slot leak.
179 EventPool<ESPNowPacket, MAX_ESP_NOW_RECEIVE_QUEUE_SIZE - 1> receive_packet_pool_{};
180
181 LockFreeQueue<ESPNowSendPacket, MAX_ESP_NOW_SEND_QUEUE_SIZE> send_packet_queue_{};
182 // Pool sized to queue capacity (SIZE-1) — see receive_packet_pool_ comment.
183 EventPool<ESPNowSendPacket, MAX_ESP_NOW_SEND_QUEUE_SIZE - 1> send_packet_pool_{};
184 ESPNowSendPacket *current_send_packet_{nullptr}; // Currently sending packet, nullptr if none
185
186 uint8_t wifi_channel_{0};
187 ESPNowState state_{ESPNOW_STATE_OFF};
188
189 bool auto_add_peer_{false};
190 bool enable_on_boot_{true};
191};
192
193extern ESPNowComponent *global_esp_now; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
194
195} // namespace esphome::espnow
196
197#endif // USE_ESP32 || USE_ESP8266
uint8_t address
Definition bl0906.h:4
uint8_t status
Definition bl0942.h:8
void setup()
void loop()
esp_err_t del_peer(const uint8_t *mac)
esp_err_t send(const uint8_t *mac, const uint8_t *data, uint16_t size)
esp_err_t add_peer(const uint8_t *mac)
ESPNowComponent * global_esp_now
bool operator==(const GainTimePair &lhs, const GainTimePair &rhs)
Definition ltr501.cpp:21
bool is_disabled()
Return whether the network is disabled: every configured interface with a disable() lifecycle (modem,...
Definition util.cpp:42
value[LAYOUT.day_index()]
static void uint32_t
uint16_t timestamp
Definition tt21100.cpp:2