16#include <esp_random.h>
27static constexpr const char *TAG =
"espnow";
29static const esp_err_t CONFIG_ESPNOW_WAKE_WINDOW = 50;
30static const esp_err_t CONFIG_ESPNOW_WAKE_INTERVAL = 100;
34static const LogString *espnow_error_to_str(esp_err_t error) {
36 case ESP_ERR_ESPNOW_FAILED:
37 return LOG_STR(
"ESPNow is in fail mode");
38 case ESP_ERR_ESPNOW_OWN_ADDRESS:
39 return LOG_STR(
"Message to your self");
40 case ESP_ERR_ESPNOW_DATA_SIZE:
41 return LOG_STR(
"Data size to large");
42 case ESP_ERR_ESPNOW_PEER_NOT_SET:
43 return LOG_STR(
"Peer address not set");
44 case ESP_ERR_ESPNOW_PEER_NOT_PAIRED:
45 return LOG_STR(
"Peer address not paired");
46 case ESP_ERR_ESPNOW_NOT_INIT:
47 return LOG_STR(
"Not init");
48 case ESP_ERR_ESPNOW_ARG:
49 return LOG_STR(
"Invalid argument");
50 case ESP_ERR_ESPNOW_INTERNAL:
51 return LOG_STR(
"Internal Error");
52 case ESP_ERR_ESPNOW_NO_MEM:
53 return LOG_STR(
"Our of memory");
54 case ESP_ERR_ESPNOW_NOT_FOUND:
55 return LOG_STR(
"Peer not found");
56 case ESP_ERR_ESPNOW_IF:
57 return LOG_STR(
"Interface does not match");
60 case ESP_NOW_SEND_FAIL:
61 return LOG_STR(
"Failed");
63 return LOG_STR(
"Unknown Error");
68 if (peer ==
nullptr || peer[0] == 0) {
70 }
else if (memcmp(peer, ESPNOW_BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0) {
72 }
else if (memcmp(peer, ESPNOW_MULTICAST_ADDR, ESP_NOW_ETH_ALEN) == 0) {
79#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
87 if (packet ==
nullptr) {
94#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
105#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
113 if (packet ==
nullptr) {
127#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
135 uint32_t version = 0;
136 esp_now_get_version(&version);
138 ESP_LOGCONFIG(TAG,
"espnow:");
140 ESP_LOGCONFIG(TAG,
" Disabled");
145 " Version: v%" PRIu32
"\n"
146 " Wi-Fi channel: %d",
149 ESP_LOGCONFIG(TAG,
" Wi-Fi enabled: %s", YESNO(this->
is_wifi_enabled()));
165 ESP_ERROR_CHECK(esp_netif_init());
179 ESP_LOGD(TAG,
"Enabling");
187 esp_event_loop_create_default();
189 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
191 ESP_ERROR_CHECK(esp_wifi_init(&cfg));
192 ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
193 ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
194 ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
195 ESP_ERROR_CHECK(esp_wifi_start());
196 ESP_ERROR_CHECK(esp_wifi_disconnect());
202 esp_err_t err = esp_now_init();
204 ESP_LOGE(TAG,
"esp_now_init failed: %s", esp_err_to_name(err));
211 ESP_LOGE(TAG,
"esp_now_register_recv_cb failed: %s", esp_err_to_name(err));
218 ESP_LOGE(TAG,
"esp_now_register_recv_cb failed: %s", esp_err_to_name(err));
226 esp_now_set_wake_window(CONFIG_ESPNOW_WAKE_WINDOW);
227 esp_wifi_connectionless_module_set_wake_interval(CONFIG_ESPNOW_WAKE_INTERVAL);
232 for (
auto peer : this->
peers_) {
241 ESP_LOGD(TAG,
"Disabling");
244 esp_now_unregister_recv_cb();
245 esp_now_unregister_send_cb();
247 esp_err_t err = esp_now_deinit();
249 ESP_LOGE(TAG,
"esp_now_deinit failed! 0x%x", err);
255 ESP_LOGE(TAG,
"Cannot set channel when ESPNOW disabled");
261 ESP_LOGE(TAG,
"Cannot set channel when Wi-Fi enabled");
267 esp_wifi_set_promiscuous(
true);
268 esp_wifi_set_channel(this->
wifi_channel_, WIFI_SECOND_CHAN_NONE);
269 esp_wifi_set_promiscuous(
false);
277 ESP_LOGI(TAG,
"Wifi Channel is changed from %d to %d.", this->
wifi_channel_, new_channel);
284 while (packet !=
nullptr) {
285 switch (packet->
type_) {
288 if (!esp_now_is_peer_exist(info.
src_addr)) {
289 bool handled =
false;
301 if (esp_now_is_peer_exist(info.
src_addr)) {
302#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
308 if (memcmp(info.
des_addr, ESPNOW_BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0) {
323#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
325 LOG_STR_ARG(espnow_error_to_str(packet->
packet_.
sent.status)));
349 if (received_dropped > 0) {
350 ESP_LOGW(TAG,
"Dropped %u received packets due to buffer overflow", received_dropped);
355 if (send_dropped > 0) {
356 ESP_LOGW(TAG,
"Dropped %u send packets due to buffer overflow", send_dropped);
361 wifi_second_chan_t dummy;
369 return ESP_ERR_ESPNOW_NOT_INIT;
371 return ESP_ERR_ESPNOW_FAILED;
372 }
else if (peer_address == 0ULL) {
373 return ESP_ERR_ESPNOW_PEER_NOT_SET;
374 }
else if (memcmp(peer_address, this->
own_address_, ESP_NOW_ETH_ALEN) == 0) {
375 return ESP_ERR_ESPNOW_OWN_ADDRESS;
376 }
else if (size > ESP_NOW_MAX_DATA_LEN) {
377 return ESP_ERR_ESPNOW_DATA_SIZE;
378 }
else if (!esp_now_is_peer_exist(peer_address)) {
379 if (memcmp(peer_address, ESPNOW_BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0 || this->
auto_add_peer_) {
380 esp_err_t err = this->
add_peer(peer_address);
385 return ESP_ERR_ESPNOW_PEER_NOT_PAIRED;
390 if (packet ==
nullptr) {
392 ESP_LOGE(TAG,
"Failed to allocate send packet from pool");
394 return ESP_ERR_ESPNOW_NO_MEM;
397 packet->
load_data(peer_address, payload, size, callback);
405 if (packet ==
nullptr) {
413 LOG_STR_ARG(espnow_error_to_str(err)));
426 return ESP_ERR_ESPNOW_NOT_INIT;
429 if (memcmp(peer, this->
own_address_, ESP_NOW_ETH_ALEN) == 0) {
431 return ESP_ERR_INVALID_MAC;
434 if (!esp_now_is_peer_exist(peer)) {
435 esp_now_peer_info_t peer_info = {};
436 memset(&peer_info, 0,
sizeof(esp_now_peer_info_t));
437 peer_info.ifidx = WIFI_IF_STA;
438 memcpy(peer_info.peer_addr, peer, ESP_NOW_ETH_ALEN);
439 esp_err_t err = esp_now_add_peer(&peer_info);
443 LOG_STR_ARG(espnow_error_to_str(err)));
449 for (
auto &it : this->
peers_) {
457 memcpy(new_peer.
address, peer, ESP_NOW_ETH_ALEN);
458 this->peers_.push_back(new_peer);
466 return ESP_ERR_ESPNOW_NOT_INIT;
468 if (esp_now_is_peer_exist(peer)) {
469 esp_err_t err = esp_now_del_peer(peer);
472 LOG_STR_ARG(espnow_error_to_str(err)));
477 for (
auto it = this->
peers_.begin(); it != this->peers_.end(); ++it) {
void wake_loop_threadsafe()
Wake the main event loop from a FreeRTOS task Thread-safe, can be called from task context to immedia...
virtual void mark_failed()
Mark this component as failed.
void status_momentary_warning(const char *name, uint32_t length=5000)
Set warning status flag and automatically clear it after a timeout.
ESPNowSendPacket * current_send_packet_
esp_err_t send(const uint8_t *peer_address, const std::vector< uint8_t > &payload, const send_callback_t &callback=nullptr)
Queue a packet to be sent to a specific peer address.
LockFreeQueue< ESPNowSendPacket, MAX_ESP_NOW_SEND_QUEUE_SIZE > send_packet_queue_
void add_peer(peer_address_t address)
std::vector< ESPNowUnknownPeerHandler * > unknown_peer_handlers_
void apply_wifi_channel()
EventPool< ESPNowSendPacket, MAX_ESP_NOW_SEND_QUEUE_SIZE > send_packet_pool_
std::vector< ESPNowPeer > peers_
friend void on_send_report(const esp_now_send_info_t *info, esp_now_send_status_t status)
std::vector< ESPNowBroadcastedHandler * > broadcasted_handlers_
friend void on_data_received(const esp_now_recv_info_t *info, const uint8_t *data, int size)
EventPool< ESPNowPacket, MAX_ESP_NOW_RECEIVE_QUEUE_SIZE > receive_packet_pool_
esp_err_t del_peer(const uint8_t *peer)
void dump_config() override
std::vector< ESPNowReceivedPacketHandler * > received_handlers_
LockFreeQueue< ESPNowPacket, MAX_ESP_NOW_RECEIVE_QUEUE_SIZE > receive_packet_queue_
uint8_t get_wifi_channel()
uint8_t own_address_[ESP_NOW_ETH_ALEN]
void load_sent_data(const uint8_t *mac_addr, esp_now_send_status_t status)
struct esphome::espnow::ESPNowPacket::@85::received_data receive
void load_received_data(const esp_now_recv_info_t *info, const uint8_t *data, int size)
union esphome::espnow::ESPNowPacket::@85 packet_
esp_now_packet_type_t type_
const ESPNowRecvInfo & get_receive_info() const
struct esphome::espnow::ESPNowPacket::@85::sent_data sent
void load_data(const uint8_t *peer_address, const uint8_t *payload, size_t size, const send_callback_t &callback)
send_callback_t callback_
uint8_t address_[ESP_NOW_ETH_ALEN]
uint8_t data_[ESP_NOW_MAX_DATA_LEN]
int32_t get_wifi_channel()
@ ESPNOW_STATE_ENABLED
ESPNOW is enabled.
@ ESPNOW_STATE_OFF
Nothing has been initialized yet.
@ ESPNOW_STATE_DISABLED
ESPNOW is disabled.
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
void esp_now_send_status_t status
std::function< void(esp_err_t)> send_callback_t
std::string peer_str(uint8_t *peer)
WiFiComponent * global_wifi_component
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
std::string format_mac_address_pretty(const uint8_t *mac)
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Application App
Global storage of Application pointer - only one Application can exist.
uint8_t address[ESP_NOW_ETH_ALEN]
uint8_t des_addr[ESP_NOW_ETH_ALEN]
Destination address of ESPNOW packet.
uint8_t src_addr[ESP_NOW_ETH_ALEN]
Source address of ESPNOW packet.