ESPHome 2026.10.0-dev
Loading...
Searching...
No Matches
espnow_component.h
Go to the documentation of this file.
1#pragma once
2
6
7#ifdef USE_ESP32
8
11#include "espnow_packet.h"
12
13#if defined(USE_WIFI) && defined(USE_WIFI_CONNECT_STATE_LISTENERS)
15#endif
16
17#include <esp_idf_version.h>
18
19#include <esp_mac.h>
20#include <esp_now.h>
21
22#include <array>
23#include <map>
24#include <memory>
25#include <string>
26#include <vector>
27
28namespace esphome::espnow {
29
30// Maximum size of the ESPNow event queue - must be power of 2 for lock-free queue
31static constexpr size_t MAX_ESP_NOW_SEND_QUEUE_SIZE = 16;
32static constexpr size_t MAX_ESP_NOW_RECEIVE_QUEUE_SIZE = 16;
33
34using peer_address_t = std::array<uint8_t, ESP_NOW_ETH_ALEN>;
35
36enum class ESPNowTriggers : uint8_t {
37 TRIGGER_NONE = 0,
38 ON_NEW_PEER = 1,
39 ON_RECEIVE = 2,
40 ON_BROADCAST = 3,
41 ON_SUCCEED = 10,
42 ON_FAILED = 11,
43};
44
45enum ESPNowState : uint8_t {
47 ESPNOW_STATE_OFF = 0,
49 ESPNOW_STATE_DISABLED,
51 ESPNOW_STATE_ENABLED,
52};
53
54struct ESPNowPeer {
55 uint8_t address[ESP_NOW_ETH_ALEN]; // MAC address of the peer
56
57 bool operator==(const ESPNowPeer &other) const { return memcmp(this->address, other.address, ESP_NOW_ETH_ALEN) == 0; }
58 bool operator==(const uint8_t *other) const { return memcmp(this->address, other, ESP_NOW_ETH_ALEN) == 0; }
59};
60
63class ESPNowUnknownPeerHandler {
64 public:
70 virtual bool on_unknown_peer(const ESPNowRecvInfo &info, const uint8_t *data, uint16_t size) = 0;
71};
72
75class ESPNowReceivedPacketHandler {
76 public:
82 virtual bool on_receive(const ESPNowRecvInfo &info, const uint8_t *data, uint16_t size) = 0;
83};
86class ESPNowBroadcastHandler {
87 public:
93 virtual bool on_broadcast(const ESPNowRecvInfo &info, const uint8_t *data, uint16_t size) = 0;
94};
95
96#if defined(USE_WIFI) && defined(USE_WIFI_CONNECT_STATE_LISTENERS)
97class ESPNowComponent final : public Component, public wifi::WiFiConnectStateListener {
98#else
99class ESPNowComponent final : public Component {
100#endif
101 public:
102 ESPNowComponent();
103 void setup() override;
104 void loop() override;
105 void dump_config() override;
106
107 float get_setup_priority() const override { return setup_priority::LATE; }
108
109 // Add a peer to the internal list of peers
110 void add_peer(peer_address_t address) {
111 ESPNowPeer peer;
112 memcpy(peer.address, address.data(), ESP_NOW_ETH_ALEN);
113 this->peers_.push_back(peer);
114 }
115 // Add a peer with the esp_now api and add to the internal list if doesnt exist already
116 esp_err_t add_peer(const uint8_t *peer);
117 // Remove a peer with the esp_now api and remove from the internal list if exists
118 esp_err_t del_peer(const uint8_t *peer);
119
120 void set_wifi_channel(uint8_t channel) { this->wifi_channel_ = channel; }
121 void apply_wifi_channel();
122 uint8_t get_wifi_channel();
123
124 void set_auto_add_peer(bool value) { this->auto_add_peer_ = value; }
125
126#if defined(USE_WIFI) && defined(USE_WIFI_CONNECT_STATE_LISTENERS)
127 // WiFiConnectStateListener interface: refresh the cached channel after each (re)connect
128 void on_wifi_connect_state(StringRef ssid, std::span<const uint8_t, 6> bssid) override;
129#endif
130
131 void enable();
132 void disable();
133 bool is_disabled() const { return this->state_ == ESPNOW_STATE_DISABLED; };
134 void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
135 bool is_wifi_enabled();
136
146 esp_err_t send(const uint8_t *peer_address, const std::vector<uint8_t> &payload,
147 const send_callback_t &callback = nullptr) {
148 return this->send(peer_address, payload.data(), payload.size(), callback);
149 }
150 esp_err_t send(const uint8_t *peer_address, const uint8_t *payload, size_t size,
151 const send_callback_t &callback = nullptr);
152
153 void register_receive_handler(ESPNowReceivedPacketHandler *handler) { this->receive_handlers_.push_back(handler); }
154 void register_unknown_peer_handler(ESPNowUnknownPeerHandler *handler) {
155 this->unknown_peer_handlers_.push_back(handler);
156 }
157 void register_broadcast_handler(ESPNowBroadcastHandler *handler) { this->broadcast_handlers_.push_back(handler); }
158
159 protected:
160 friend void on_data_received(const esp_now_recv_info_t *info, const uint8_t *data, int size);
161#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
162 friend void on_send_report(const esp_now_send_info_t *info, esp_now_send_status_t status);
163#else
164 friend void on_send_report(const uint8_t *mac_addr, esp_now_send_status_t status);
165#endif
166
167 void enable_();
168 void send_();
169
170 std::vector<ESPNowUnknownPeerHandler *> unknown_peer_handlers_;
171 std::vector<ESPNowReceivedPacketHandler *> receive_handlers_;
172 std::vector<ESPNowBroadcastHandler *> broadcast_handlers_;
173
174 std::vector<ESPNowPeer> peers_{};
175
176 uint8_t own_address_[ESP_NOW_ETH_ALEN]{0};
177 LockFreeQueue<ESPNowPacket, MAX_ESP_NOW_RECEIVE_QUEUE_SIZE> receive_packet_queue_{};
178 // Pool sized to queue capacity (SIZE-1) because LockFreeQueue<T,N> is a ring
179 // buffer that holds N-1 elements. This guarantees allocate() returns nullptr
180 // before push() can fail, preventing a pool slot leak.
181 EventPool<ESPNowPacket, MAX_ESP_NOW_RECEIVE_QUEUE_SIZE - 1> receive_packet_pool_{};
182
183 LockFreeQueue<ESPNowSendPacket, MAX_ESP_NOW_SEND_QUEUE_SIZE> send_packet_queue_{};
184 // Pool sized to queue capacity (SIZE-1) — see receive_packet_pool_ comment.
185 EventPool<ESPNowSendPacket, MAX_ESP_NOW_SEND_QUEUE_SIZE - 1> send_packet_pool_{};
186 ESPNowSendPacket *current_send_packet_{nullptr}; // Currently sending packet, nullptr if none
187
188 uint8_t wifi_channel_{0};
189 ESPNowState state_{ESPNOW_STATE_OFF};
190
191 bool auto_add_peer_{false};
192 bool enable_on_boot_{true};
193};
194
195extern ESPNowComponent *global_esp_now; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
196
197} // namespace esphome::espnow
198
199#endif // USE_ESP32
uint8_t address
Definition bl0906.h:4
uint8_t status
Definition bl0942.h:8
void setup()
void loop()
void on_send_report(const esp_now_send_info_t *info, esp_now_send_status_t status) void on_send_report(const uint8_t *mac_addr
void on_data_received(const esp_now_recv_info_t *info, const uint8_t *data, int size)
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:12