From 2c68fdc977785189de77b2bfa58706d5c23d324d Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:22:37 +0100 Subject: [PATCH 01/37] feat(libs): Add ESP-NOW Arduino library --- CMakeLists.txt | 5 + libraries/ESP_NOW/library.properties | 9 + libraries/ESP_NOW/src/ESP32_NOW.cpp | 387 +++++++++++++++++++++ libraries/ESP_NOW/src/ESP32_NOW.h | 65 ++++ libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 323 +++++++++++++++++ libraries/ESP_NOW/src/ESP32_NOW_Serial.h | 52 +++ 6 files changed, 841 insertions(+) create mode 100755 libraries/ESP_NOW/library.properties create mode 100644 libraries/ESP_NOW/src/ESP32_NOW.cpp create mode 100644 libraries/ESP_NOW/src/ESP32_NOW.h create mode 100644 libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp create mode 100644 libraries/ESP_NOW/src/ESP32_NOW_Serial.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 026990d264e..2346da6b47d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ set(ARDUINO_ALL_LIBRARIES DNSServer EEPROM ESP_I2S + ESP_NOW ESP_SR ESPmDNS Ethernet @@ -126,6 +127,10 @@ set(ARDUINO_LIBRARY_DNSServer_SRCS libraries/DNSServer/src/DNSServer.cpp) set(ARDUINO_LIBRARY_EEPROM_SRCS libraries/EEPROM/src/EEPROM.cpp) set(ARDUINO_LIBRARY_ESP_I2S_SRCS libraries/ESP_I2S/src/ESP_I2S.cpp) + +set(ARDUINO_LIBRARY_ESP_NOW_SRCS + libraries/ESP_NOW/src/ESP32_NOW.cpp + libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp) set(ARDUINO_LIBRARY_ESP_SR_SRCS libraries/ESP_SR/src/ESP_SR.cpp diff --git a/libraries/ESP_NOW/library.properties b/libraries/ESP_NOW/library.properties new file mode 100755 index 00000000000..e07c55d5aa2 --- /dev/null +++ b/libraries/ESP_NOW/library.properties @@ -0,0 +1,9 @@ +name=ESP_NOW +version=1.0.0 +author=me-no-dev +maintainer=P-R-O-C-H-Y +sentence=Library for ESP_NOW +paragraph=Supports ESP32 Arduino platforms. +category=Sensor +url=https://github.com/espressif/arduino-esp32/ +architectures=esp32 \ No newline at end of file diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp new file mode 100644 index 00000000000..e1c37e9c192 --- /dev/null +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -0,0 +1,387 @@ +#include "ESP32_NOW.h" +#include +#include "esp_system.h" +#include "esp32-hal.h" +#include "esp_mac.h" + +static void (*new_cb)(const esp_now_recv_info_t *info, const uint8_t * data, int len, void * arg) = NULL; +static void * new_arg = NULL;// * tx_arg = NULL, * rx_arg = NULL, +static bool _esp_now_has_begun = false; +static ESP_NOW_Peer * _esp_now_peers[ESP_NOW_MAX_TOTAL_PEER_NUM]; + +static esp_err_t _esp_now_add_peer(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk, ESP_NOW_Peer * _peer=NULL){ + log_v(MACSTR, MAC2STR(mac_addr)); + if (esp_now_is_peer_exist(mac_addr)) { + log_e("Peer Already Exists"); + return ESP_ERR_ESPNOW_EXIST; + } + + esp_now_peer_info_t peer; + memset(&peer, 0, sizeof(esp_now_peer_info_t)); + memcpy(peer.peer_addr, mac_addr, ESP_NOW_ETH_ALEN); + peer.channel = channel; + peer.ifidx = iface; + peer.encrypt = lmk != NULL; + if(lmk){ + memcpy(peer.lmk, lmk, ESP_NOW_KEY_LEN); + } + + esp_err_t result = esp_now_add_peer(&peer); + if(result == ESP_OK){ + if(_peer != NULL){ + for(uint8_t i=0; iaddr(), ESP_NOW_ETH_ALEN) == 0){ + _esp_now_peers[i] = NULL; + break; + } + } + return result; +} + +static esp_err_t _esp_now_modify_peer(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk){ + log_v(MACSTR, MAC2STR(mac_addr)); + if (!esp_now_is_peer_exist(mac_addr)) { + log_e("Peer not found"); + return ESP_ERR_ESPNOW_NOT_FOUND; + } + + esp_now_peer_info_t peer; + memset(&peer, 0, sizeof(esp_now_peer_info_t)); + memcpy(peer.peer_addr, mac_addr, ESP_NOW_ETH_ALEN); + peer.channel = channel; + peer.ifidx = iface; + peer.encrypt = lmk != NULL; + if(lmk){ + memcpy(peer.lmk, lmk, ESP_NOW_KEY_LEN); + } + + esp_err_t result = esp_now_mod_peer(&peer); + if (result == ESP_OK) { + return result; + } else if (result == ESP_ERR_ESPNOW_NOT_INIT) { + log_e("ESPNOW Not Init"); + } else if (result == ESP_ERR_ESPNOW_ARG) { + log_e("Invalid Argument"); + } else if (result == ESP_ERR_ESPNOW_FULL) { + log_e("Peer list full"); + } else if (result == ESP_ERR_ESPNOW_NO_MEM) { + log_e("Out of memory"); + } + return result; +} + +static void _esp_now_rx_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len){ + log_v(MACSTR", data lenght : %d", MAC2STR(info->src_addr), len); + log_buf_v(data, len); + if(!esp_now_is_peer_exist(info->src_addr) && new_cb != NULL){ + log_v("Calling new_cb, peer not found."); + new_cb(info, data, len, new_arg); + return; + } + //find the peer and call it's callback + for(uint8_t i=0; isrc_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0){ + _esp_now_peers[i]->_onReceive(data, len); + return; + } + } +} + +static void _esp_now_tx_cb(const uint8_t *mac_addr, esp_now_send_status_t status) { + log_v(MACSTR" : %s", MAC2STR(mac_addr), (status == ESP_NOW_SEND_SUCCESS)?"SUCCESS":"FAILED"); + //find the peer and call it's callback + for(uint8_t i=0; iaddr(), ESP_NOW_ETH_ALEN) == 0){ + _esp_now_peers[i]->_onSent(status == ESP_NOW_SEND_SUCCESS); + return; + } + } +} + +ESP_NOW_Class::ESP_NOW_Class(){} + +ESP_NOW_Class::~ESP_NOW_Class(){} + +bool ESP_NOW_Class::begin(const uint8_t *pmk){ + if(_esp_now_has_begun){ + return true; + } + _esp_now_has_begun = true; + + memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM); + + esp_err_t err = esp_now_init(); + if(err != ESP_OK){ + log_e("esp_now_init failed! 0x%x", err); + _esp_now_has_begun = false; + return false; + } + + if(pmk){ + err = esp_now_set_pmk(pmk); + if(err != ESP_OK){ + log_e("esp_now_set_pmk failed! 0x%x", err); + _esp_now_has_begun = false; + return false; + } + } + + err = esp_now_register_recv_cb(_esp_now_rx_cb); + if(err != ESP_OK){ + log_e("esp_now_register_recv_cb failed! 0x%x", err); + _esp_now_has_begun = false; + return false; + } + + err = esp_now_register_send_cb(_esp_now_tx_cb); + if(err != ESP_OK){ + log_e("esp_now_register_send_cb failed! 0x%x", err); + _esp_now_has_begun = false; + return false; + } + return true; +} + +bool ESP_NOW_Class::end(){ + if(!_esp_now_has_begun){ + return true; + } + //remove all peers? + esp_err_t err = esp_now_deinit(); + if(err != ESP_OK){ + log_e("esp_now_deinit failed! 0x%x", err); + return false; + } + _esp_now_has_begun = false; + memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM); + return true; +} + +int ESP_NOW_Class::getTotalPeerCount(){ + if(!_esp_now_has_begun){ + return -1; + } + esp_now_peer_num_t num; + esp_err_t err = esp_now_get_peer_num(&num); + if(err != ESP_OK){ + log_e("esp_now_get_peer_num failed! 0x%x", err); + return -1; + } + return num.total_num; +} + +int ESP_NOW_Class::getEncryptedPeerCount(){ + if(!_esp_now_has_begun){ + return -1; + } + esp_now_peer_num_t num; + esp_err_t err = esp_now_get_peer_num(&num); + if(err != ESP_OK){ + log_e("esp_now_get_peer_num failed! 0x%x", err); + return -1; + } + return num.encrypt_num; +} + +int ESP_NOW_Class::availableForWrite(){ + return ESP_NOW_MAX_DATA_LEN; +} + +size_t ESP_NOW_Class::write(const uint8_t * data, size_t len){ + if(!_esp_now_has_begun){ + return 0; + } + if(len > ESP_NOW_MAX_DATA_LEN){ + len = ESP_NOW_MAX_DATA_LEN; + } + esp_err_t result = esp_now_send(NULL, data, len); + if (result == ESP_OK) { + return len; + } else if (result == ESP_ERR_ESPNOW_NOT_INIT) { + log_e("ESPNOW not init."); + } else if (result == ESP_ERR_ESPNOW_ARG) { + log_e("Invalid argument"); + } else if (result == ESP_ERR_ESPNOW_INTERNAL) { + log_e("Internal Error"); + } else if (result == ESP_ERR_ESPNOW_NO_MEM) { + log_e("Our of memory"); + } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) { + log_e("Peer not found."); + } else if (result == ESP_ERR_ESPNOW_IF) { + log_e("Interface does not match."); + } + return 0; +} + +void ESP_NOW_Class::onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t * data, int len, void * arg), void * arg){ + new_cb = cb; + new_arg = arg; +} + +ESP_NOW_Class ESP_NOW; + +/* + * + * Inheritable Peer Class + * +*/ + +ESP_NOW_Peer::ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk){ + added = false; + if(mac_addr){ + memcpy(mac, mac_addr,6); + } + chan = channel; + ifc = iface; + encrypt = lmk != NULL; + if(encrypt){ + memcpy(key, lmk, 16); + } +} + +bool ESP_NOW_Peer::add(){ + if(!_esp_now_has_begun){ + return false; + } + if(added){ + return true; + } + if(_esp_now_add_peer(mac, chan, ifc, encrypt?key:NULL, this) != ESP_OK){ + return false; + } + log_v("Peer added - "MACSTR, MAC2STR(mac)); + added = true; + return true; +} + +bool ESP_NOW_Peer::remove(){ + if(!_esp_now_has_begun){ + return false; + } + if(!added){ + return true; + } + log_v("Peer removed - "MACSTR, MAC2STR(mac)); + esp_err_t err = _esp_now_del_peer(mac); + if(err == ESP_OK){ + added = false; + return true; + } + return false; +} + +const uint8_t * ESP_NOW_Peer::addr() const{ + return mac; +} + +bool ESP_NOW_Peer::addr(const uint8_t *mac_addr){ + if(!_esp_now_has_begun || !added){ + memcpy(mac, mac_addr,6); + return true; + } + return false; +} + +uint8_t ESP_NOW_Peer::getChannel() const{ + return chan; +} + +bool ESP_NOW_Peer::setChannel(uint8_t channel){ + chan = channel; + if(!_esp_now_has_begun || !added){ + return true; + } + return _esp_now_modify_peer(mac, chan, ifc, encrypt?key:NULL) == ESP_OK; +} + +wifi_interface_t ESP_NOW_Peer::getInterface() const{ + return ifc; +} + +bool ESP_NOW_Peer::setInterface(wifi_interface_t iface){ + ifc = iface; + if(!_esp_now_has_begun || !added){ + return true; + } + return _esp_now_modify_peer(mac, chan, ifc, encrypt?key:NULL) == ESP_OK; +} + +bool ESP_NOW_Peer::isEncrypted() const{ + return encrypt; +} + +bool ESP_NOW_Peer::setKey(const uint8_t *lmk){ + encrypt = lmk != NULL; + if(encrypt){ + memcpy(key, lmk, 16); + } + if(!_esp_now_has_begun || !added){ + return true; + } + return _esp_now_modify_peer(mac, chan, ifc, encrypt?key:NULL) == ESP_OK; +} + +size_t ESP_NOW_Peer::send(const uint8_t * data, int len){ + log_v(MACSTR", data lenght %d", MAC2STR(mac), len); + if(!_esp_now_has_begun || !added){ + log_e("Peer not added."); + return 0; + } + if(len > ESP_NOW_MAX_DATA_LEN){ + len = ESP_NOW_MAX_DATA_LEN; + } + esp_err_t result = esp_now_send(mac, data, len); + if (result == ESP_OK) { + return len; + } else if (result == ESP_ERR_ESPNOW_NOT_INIT) { + log_e("ESPNOW not init."); + } else if (result == ESP_ERR_ESPNOW_ARG) { + log_e("Invalid argument"); + } else if (result == ESP_ERR_ESPNOW_INTERNAL) { + log_e("Internal Error"); + } else if (result == ESP_ERR_ESPNOW_NO_MEM) { + log_e("Our of memory"); + } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) { + log_e("Peer not found."); + } else if (result == ESP_ERR_ESPNOW_IF) { + log_e("Interface does not match."); + } + return 0; +} + +ESP_NOW_Peer::operator bool() const +{ + return added; +} diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h new file mode 100644 index 00000000000..bbab443def7 --- /dev/null +++ b/libraries/ESP_NOW/src/ESP32_NOW.h @@ -0,0 +1,65 @@ +#pragma once + +#include "esp_wifi_types.h" +#include "Print.h" +#include "esp_now.h" + +class ESP_NOW_Peer { +private: + uint8_t mac[6]; + uint8_t chan; + wifi_interface_t ifc; + bool encrypt; + uint8_t key[16]; + +protected: + bool added; + bool add(); + bool remove(); + size_t send(const uint8_t * data, int len); + +public: + ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel=0, wifi_interface_t iface=WIFI_IF_AP, const uint8_t *lmk=NULL); + virtual ~ESP_NOW_Peer() {} + + const uint8_t * addr() const; + bool addr(const uint8_t *mac_addr); + + uint8_t getChannel() const; + bool setChannel(uint8_t channel); + + wifi_interface_t getInterface() const; + bool setInterface(wifi_interface_t iface); + + bool isEncrypted() const; + bool setKey(const uint8_t *lmk); + + operator bool() const; + + //must be implemented by the upper class + virtual void _onReceive(const uint8_t * data, size_t len) = 0; + virtual void _onSent(bool success) = 0; +}; + +class ESP_NOW_Class : public Print { +public: + ESP_NOW_Class(); + ~ESP_NOW_Class(); + + bool begin(const uint8_t *pmk=NULL /* 16 bytes */); + bool end(); + + int getTotalPeerCount(); + int getEncryptedPeerCount(); + + int availableForWrite(); + size_t write(const uint8_t * data, size_t len); + size_t write(uint8_t data){ return write(&data, 1); } + + void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t * data, int len, void * arg), void * arg); + + //TODO: Add function to set peer rate - esp_now_set_peer_rate_config() +}; + +extern ESP_NOW_Class ESP_NOW; + diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp new file mode 100644 index 00000000000..95f2266699e --- /dev/null +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -0,0 +1,323 @@ +#include "ESP32_NOW_Serial.h" +#include +#include "esp_now.h" +#include "esp_system.h" +#include "esp32-hal.h" +#include "esp_mac.h" + +/* + * + * Serial Port Implementation Class + * +*/ + +ESP_NOW_Serial_Class::ESP_NOW_Serial_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk) +: ESP_NOW_Peer(mac_addr, channel, iface, lmk){ + tx_ring_buf = NULL; + rx_queue = NULL; + rx2_queue = NULL; + tx_sem = NULL; + last_tx_result = false; + queued_size = 0; + queued_buff = NULL; + resend_count = 0; +} + +ESP_NOW_Serial_Class::~ESP_NOW_Serial_Class(){ + +} + +size_t ESP_NOW_Serial_Class::setTxBufferSize(size_t tx_queue_len){ + if(tx_ring_buf){ + if(!tx_queue_len){ + vRingbufferDelete(tx_ring_buf); + tx_ring_buf = NULL; + } + return 0; + } + tx_ring_buf = xRingbufferCreate(tx_queue_len, RINGBUF_TYPE_BYTEBUF); + if(!tx_ring_buf){ + return 0; + } + return tx_queue_len; +} + +size_t ESP_NOW_Serial_Class::setRxBufferSize(size_t rx_queue_len){ + if(rx_queue){ + if(!rx_queue_len){ + vQueueDelete(rx_queue); + rx_queue = NULL; + } + return 0; + } + rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); + if(!rx_queue){ + return 0; + } + return rx_queue_len; +} + +size_t ESP_NOW_Serial_Class::setRx2BufferSize(size_t rx_queue_len){ + if(rx2_queue){ + if(!rx_queue_len){ + vQueueDelete(rx2_queue); + rx_queue = NULL; + } + return 0; + } else if(rx_queue_len){ + rx2_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); + if(!rx2_queue){ + return 0; + } + } + return rx_queue_len; +} + +bool ESP_NOW_Serial_Class::begin(unsigned long baud){ + if(!ESP_NOW.begin() || !add()){ + return false; + } + if(tx_sem == NULL){ + tx_sem = xSemaphoreCreateBinary(); + //xSemaphoreTake(tx_sem, 0); + xSemaphoreGive(tx_sem); + } + setRxBufferSize(1024);//default if not preset + setRx2BufferSize(0);//default if not preset + setTxBufferSize(1024);//default if not preset + return true; +} + +void ESP_NOW_Serial_Class::end(){ + remove(); + setRxBufferSize(0); + setRx2BufferSize(0); + setTxBufferSize(0); + if (tx_sem != NULL) { + vSemaphoreDelete(tx_sem); + tx_sem = NULL; + } +} + +//Stream +int ESP_NOW_Serial_Class::available(void){ + if(rx_queue == NULL){ + return -1; + } + return uxQueueMessagesWaiting(rx_queue); +} + +int ESP_NOW_Serial_Class::peek(void){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c; + if(xQueuePeek(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +int ESP_NOW_Serial_Class::read(void){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + if(xQueueReceive(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +size_t ESP_NOW_Serial_Class::read(uint8_t *buffer, size_t size){ + if(rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + size_t count = 0; + while(count < size && xQueueReceive(rx_queue, &c, 0)){ + buffer[count++] = c; + } + return count; +} + +void ESP_NOW_Serial_Class::flush(){ + if(tx_ring_buf == NULL){ + return; + } + UBaseType_t uxItemsWaiting = 0; + vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting); + if(uxItemsWaiting){ + // Now trigger the ISR to read data from the ring buffer. + if(xSemaphoreTake(tx_sem, 0) == pdTRUE){ + checkForTxData(); + } + } + while(uxItemsWaiting){ + delay(5); + vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting); + } +} +//Upper chars +int ESP_NOW_Serial_Class::available2(void){ + if(rx2_queue == NULL){ + return -1; + } + return uxQueueMessagesWaiting(rx2_queue); +} + +int ESP_NOW_Serial_Class::read2(void){ + if(rx2_queue == NULL){ + return -1; + } + uint8_t c = 0; + if(xQueueReceive(rx2_queue, &c, 0)) { + return c; + } + return -1; +} + +//RX callback +void ESP_NOW_Serial_Class::_onReceive(const uint8_t * data, size_t len){ + if(rx_queue == NULL && rx2_queue == NULL){ + return; + } + log_v(MACSTR", data lenght : %u", MAC2STR(addr()), len); + for(uint32_t i=0; i 0; + } + //log_d(MACSTR ": EMPTY", MAC2STR(addr())); + xSemaphoreGive(tx_sem); + return false; +} + +size_t ESP_NOW_Serial_Class::write(const uint8_t *buffer, size_t size, uint32_t timeout){ + log_v(MACSTR", size %u", MAC2STR(addr()), size); + if(tx_sem == NULL || tx_ring_buf == NULL || !added){ + return 0; + } + size_t space = availableForWrite(); + size_t left = size; + + if(space){ + if(left < space){ + space = left; + } + if(xRingbufferSend(tx_ring_buf, (void*) (buffer), space, 0) == pdTRUE){ + buffer += space; + left -= space; + if(xSemaphoreTake(tx_sem, 0) == pdTRUE){ + if(checkForTxData()){ + if(!left){ + //we are done + return size; + } + } else { + //send failed + return 0; + } + } + } else { + log_e("RingbufferFastSend Failed"); + return 0; + } + } else if(xSemaphoreTake(tx_sem, timeout) == pdTRUE){ + checkForTxData(); + } + // Blocking method, Sending data to ringbuffer, and handle the data in ISR. + if(xRingbufferSend(tx_ring_buf, (void*) (buffer), left, timeout / portTICK_PERIOD_MS) != pdTRUE){ + log_e("RingbufferSend Failed"); + return size - left; + } + // Now trigger the ISR to read data from the ring buffer. + if(xSemaphoreTake(tx_sem, 0) == pdTRUE){ + checkForTxData(); + } + + return size; +} +//TX Done Callback +void ESP_NOW_Serial_Class::_onSent(bool success){ + log_v(MACSTR" : %s", MAC2STR(addr()), success?"OK":"FAIL"); + if(tx_sem == NULL || tx_ring_buf == NULL || !added){ + return; + } + if(success){ + vRingbufferReturnItem(tx_ring_buf, queued_buff); + queued_buff = NULL; + //send next packet? + //log_d(MACSTR ": NEXT", MAC2STR(addr())); + checkForTxData(); + } else { + //send failed + //resend + if(resend_count < 5){ + resend_count++; + //log_d(MACSTR ": RE-SENDING[%u]", MAC2STR(addr()), resend_count); + tryToSend(); + } else { + //resend limit reached + //sucks that we lose the data here + vRingbufferReturnItem(tx_ring_buf, queued_buff); + queued_buff = NULL; + xSemaphoreGive(tx_sem); + end(); + log_e(MACSTR" : RE-SEND_MAX[%u]", MAC2STR(addr()), resend_count); + } + } +} diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.h b/libraries/ESP_NOW/src/ESP32_NOW_Serial.h new file mode 100644 index 00000000000..02e1815c5fe --- /dev/null +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.h @@ -0,0 +1,52 @@ +#pragma once + +#include "esp_wifi_types.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/ringbuf.h" +#include "Stream.h" +#include "ESP32_NOW.h" + +class ESP_NOW_Serial_Class : public Stream, public ESP_NOW_Peer { +private: + RingbufHandle_t tx_ring_buf; + xQueueHandle rx_queue; + xQueueHandle rx2_queue; + xSemaphoreHandle tx_sem; + bool last_tx_result; + size_t queued_size; + uint8_t *queued_buff; + size_t resend_count; + + bool checkForTxData(); + size_t tryToSend(); +public: + ESP_NOW_Serial_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface=WIFI_IF_AP, const uint8_t *lmk=NULL); + ~ESP_NOW_Serial_Class(); + size_t setRxBufferSize(size_t); + size_t setRx2BufferSize(size_t); + size_t setTxBufferSize(size_t); + bool begin(unsigned long baud=0); + void end(); + //Stream + int available(); + int read(); + size_t read(uint8_t *buffer, size_t size); + int peek(); + void flush(); + //Upper chars + int available2(); + int read2(); + //Print + int availableForWrite(); + size_t write(const uint8_t *buffer, size_t size, uint32_t timeout_ms); + size_t write(const uint8_t *buffer, size_t size){ return write(buffer, size, 1000); } + size_t write(uint8_t data){ return write(&data, 1); } + //ESP_NOW_Peer + void _onReceive(const uint8_t * data, size_t len); + void _onSent(bool success); +}; + + From f1a6b90179b4de90151039481d2fa4818d9e88d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:28:10 +0100 Subject: [PATCH 02/37] Update libraries/ESP_NOW/src/ESP32_NOW.cpp Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> --- libraries/ESP_NOW/src/ESP32_NOW.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp index e1c37e9c192..3c3b7ea04dd 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -281,7 +281,7 @@ bool ESP_NOW_Peer::add(){ if(_esp_now_add_peer(mac, chan, ifc, encrypt?key:NULL, this) != ESP_OK){ return false; } - log_v("Peer added - "MACSTR, MAC2STR(mac)); + log_v("Peer added - " MACSTR, MAC2STR(mac)); added = true; return true; } From 26410d96897c2908ced0536cb43ab366c6aac568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:28:22 +0100 Subject: [PATCH 03/37] Update libraries/ESP_NOW/src/ESP32_NOW.cpp Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> --- libraries/ESP_NOW/src/ESP32_NOW.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp index 3c3b7ea04dd..405954563dc 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -293,7 +293,7 @@ bool ESP_NOW_Peer::remove(){ if(!added){ return true; } - log_v("Peer removed - "MACSTR, MAC2STR(mac)); + log_v("Peer removed - " MACSTR, MAC2STR(mac)); esp_err_t err = _esp_now_del_peer(mac); if(err == ESP_OK){ added = false; From 1f34934c3fe4c226aa35ebdf9db26af0fe3976b6 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:22:52 +0100 Subject: [PATCH 04/37] fix(esp-now): Add check if Wifi is started. --- libraries/ESP_NOW/src/ESP32_NOW.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp index 405954563dc..76215057438 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -3,6 +3,7 @@ #include "esp_system.h" #include "esp32-hal.h" #include "esp_mac.h" +#include "esp_wifi.h" static void (*new_cb)(const esp_now_recv_info_t *info, const uint8_t * data, int len, void * arg) = NULL; static void * new_arg = NULL;// * tx_arg = NULL, * rx_arg = NULL, @@ -138,11 +139,18 @@ bool ESP_NOW_Class::begin(const uint8_t *pmk){ if(_esp_now_has_begun){ return true; } + + esp_err_t err = esp_wifi_start(); + if (err != ESP_OK) { + log_e("WiFi not started! 0x%x)", err); + return false; + } + _esp_now_has_begun = true; memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM); - esp_err_t err = esp_now_init(); + err = esp_now_init(); if(err != ESP_OK){ log_e("esp_now_init failed! 0x%x", err); _esp_now_has_begun = false; From c5ed3b1d4b019b542929c08d2533bbfa65bd0589 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 21 Mar 2024 14:19:51 +0200 Subject: [PATCH 05/37] Fix ESP_NOW_Serial --- libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 62 +++------------------- libraries/ESP_NOW/src/ESP32_NOW_Serial.h | 10 +--- 2 files changed, 8 insertions(+), 64 deletions(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index 95f2266699e..39744de975b 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -15,16 +15,14 @@ ESP_NOW_Serial_Class::ESP_NOW_Serial_Class(const uint8_t *mac_addr, uint8_t chan : ESP_NOW_Peer(mac_addr, channel, iface, lmk){ tx_ring_buf = NULL; rx_queue = NULL; - rx2_queue = NULL; tx_sem = NULL; - last_tx_result = false; queued_size = 0; queued_buff = NULL; resend_count = 0; } ESP_NOW_Serial_Class::~ESP_NOW_Serial_Class(){ - + end(); } size_t ESP_NOW_Serial_Class::setTxBufferSize(size_t tx_queue_len){ @@ -57,22 +55,6 @@ size_t ESP_NOW_Serial_Class::setRxBufferSize(size_t rx_queue_len){ return rx_queue_len; } -size_t ESP_NOW_Serial_Class::setRx2BufferSize(size_t rx_queue_len){ - if(rx2_queue){ - if(!rx_queue_len){ - vQueueDelete(rx2_queue); - rx_queue = NULL; - } - return 0; - } else if(rx_queue_len){ - rx2_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); - if(!rx2_queue){ - return 0; - } - } - return rx_queue_len; -} - bool ESP_NOW_Serial_Class::begin(unsigned long baud){ if(!ESP_NOW.begin() || !add()){ return false; @@ -83,7 +65,6 @@ bool ESP_NOW_Serial_Class::begin(unsigned long baud){ xSemaphoreGive(tx_sem); } setRxBufferSize(1024);//default if not preset - setRx2BufferSize(0);//default if not preset setTxBufferSize(1024);//default if not preset return true; } @@ -91,7 +72,6 @@ bool ESP_NOW_Serial_Class::begin(unsigned long baud){ void ESP_NOW_Serial_Class::end(){ remove(); setRxBufferSize(0); - setRx2BufferSize(0); setTxBufferSize(0); if (tx_sem != NULL) { vSemaphoreDelete(tx_sem); @@ -158,47 +138,17 @@ void ESP_NOW_Serial_Class::flush(){ vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting); } } -//Upper chars -int ESP_NOW_Serial_Class::available2(void){ - if(rx2_queue == NULL){ - return -1; - } - return uxQueueMessagesWaiting(rx2_queue); -} - -int ESP_NOW_Serial_Class::read2(void){ - if(rx2_queue == NULL){ - return -1; - } - uint8_t c = 0; - if(xQueueReceive(rx2_queue, &c, 0)) { - return c; - } - return -1; -} //RX callback void ESP_NOW_Serial_Class::_onReceive(const uint8_t * data, size_t len){ - if(rx_queue == NULL && rx2_queue == NULL){ + if(rx_queue == NULL){ return; } - log_v(MACSTR", data lenght : %u", MAC2STR(addr()), len); + log_v(MACSTR ", data lenght : %u", MAC2STR(addr()), len); for(uint32_t i=0; i Date: Thu, 21 Mar 2024 15:13:06 -0300 Subject: [PATCH 06/37] Add ESP NOW Serial Example --- .../ESP_NOW_Serial/ESP_NOW_Serial.ino | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino new file mode 100644 index 00000000000..691c125cf5f --- /dev/null +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino @@ -0,0 +1,104 @@ +/* + ESP-NOW Serial Example - Unicast transmission + Lucas Saavedra Vaz - 2024 + Send data between two ESP32s using the ESP-NOW protocol in one-to-one (unicast) configuration. + Note that different MAC addresses are used for different interfaces. + To properly visualize the data being sent, set the line ending in the Serial Monitor to "Both NL & CR". +*/ + +#include "ESP32_NOW_Serial.h" +#include "MacAddress.h" +#include "WiFi.h" + +#define ESPNOW_WIFI_MODE_STATION 0 +#define ESPNOW_WIFI_CHANNEL 1 + +#if ESPNOW_WIFI_MODE_STATION // ESP-NOW using WiFi Station mode +#define ESPNOW_WIFI_IF WIFI_IF_STA +#define GET_IF_MAC WiFi.macAddress + +// Station mode MAC addresses of the devices in the network +// Device 1 - F4:12:FA:42:B6:E8 +const MacAddress mac1({0xF4, 0x12, 0xFA, 0x42, 0xB6, 0xE8}); +// Device 2 - F4:12:FA:40:64:4C +const MacAddress mac2({0xF4, 0x12, 0xFA, 0x40, 0x64, 0x4C}); +#else // ESP-NOW using WiFi AP mode +#define ESPNOW_WIFI_IF WIFI_IF_AP +#define GET_IF_MAC WiFi.softAPmacAddress + +// AP mode MAC addresses of the devices in the network +// Device 1 - F6:12:FA:42:B6:E8 +const MacAddress mac1({0xF6, 0x12, 0xFA, 0x42, 0xB6, 0xE8}); +// Device 2 - F6:12:FA:40:64:4C +const MacAddress mac2({0xF6, 0x12, 0xFA, 0x40, 0x64, 0x4C}); +#endif + +ESP_NOW_Serial_Class *esp_now_serial; + +void setup() { + MacAddress current_mac; + + Serial.begin(115200); + + Serial.print("WiFi Mode: "); + + #if ESPNOW_WIFI_MODE_STATION + Serial.println("STA"); + WiFi.mode(ESPNOW_WIFI_MODE); + esp_wifi_set_channel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE); + #else + Serial.println("AP"); + WiFi.softAP(WiFi.getHostname(), NULL, ESPNOW_WIFI_CHANNEL, 1); + #endif + + Serial.print("Channel: "); + Serial.println(ESPNOW_WIFI_CHANNEL); + + String mac = GET_IF_MAC(); + Serial.print("MAC Address: "); + current_mac.fromString(mac); + Serial.println(mac); + + WiFi.disconnect(); + + if (current_mac == mac1) + { + Serial.println("I'm the Device 1\n"); + // Pass the MAC address of the other device to the ESP_NOW_Serial_Class + esp_now_serial = new ESP_NOW_Serial_Class(mac2, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF); + } + else if (current_mac == mac2) + { + Serial.println("I'm the Device 2\n"); + // Pass the MAC address of the other device to the ESP_NOW_Serial_Class + esp_now_serial = new ESP_NOW_Serial_Class(mac1, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF); + } + else + { + Serial.println("Unknown MAC address. Please update the mac addresses in the sketch\n"); + while(1); + } + + // Start the ESP-NOW communication + Serial.println("ESP-NOW communication starting..."); + esp_now_serial->begin(115200); + Serial.println("You can now send data between the devices using the Serial Monitor\n"); +} + +void loop() { + while (esp_now_serial->available() > 0) + { + Serial.write(esp_now_serial->read()); + } + + while (Serial.available() && esp_now_serial->availableForWrite()) + { + if (esp_now_serial->write(Serial.read()) <= 0) + { + Serial.println("Failed to send data"); + break; + } + } + + delay(1); +} From e3b6715eaf53f81bfc0bb44bc8c012d3dda2b06a Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:11:18 -0300 Subject: [PATCH 07/37] Add comment --- libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino index 691c125cf5f..de0c1800adb 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino @@ -10,7 +10,10 @@ #include "MacAddress.h" #include "WiFi.h" +// 0: AP mode, 1: Station mode #define ESPNOW_WIFI_MODE_STATION 0 + +// Channel to be used by the ESP-NOW protocol from 1 to 13 #define ESPNOW_WIFI_CHANNEL 1 #if ESPNOW_WIFI_MODE_STATION // ESP-NOW using WiFi Station mode From 2b7730c36eb187c30a7d986f68d17b88e80b643c Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Fri, 22 Mar 2024 11:56:10 +0100 Subject: [PATCH 08/37] Skip esp-now example for esp32h2 --- libraries/ESP_NOW/examples/ESP_NOW_Serial/.skip.esp32h2 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 libraries/ESP_NOW/examples/ESP_NOW_Serial/.skip.esp32h2 diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/.skip.esp32h2 b/libraries/ESP_NOW/examples/ESP_NOW_Serial/.skip.esp32h2 new file mode 100644 index 00000000000..e69de29bb2d From deacaacd15e6edd2a55769bfeee5c8e49aab0827 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 25 Mar 2024 10:34:51 -0300 Subject: [PATCH 09/37] Add broadcast address constant --- libraries/ESP_NOW/src/ESP32_NOW.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h index bbab443def7..2fd3a3f7cc2 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.h +++ b/libraries/ESP_NOW/src/ESP32_NOW.h @@ -3,6 +3,7 @@ #include "esp_wifi_types.h" #include "Print.h" #include "esp_now.h" +#include "MacAddress.h" class ESP_NOW_Peer { private: @@ -19,6 +20,8 @@ class ESP_NOW_Peer { size_t send(const uint8_t * data, int len); public: + const MacAddress BROADCAST_ADDR(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel=0, wifi_interface_t iface=WIFI_IF_AP, const uint8_t *lmk=NULL); virtual ~ESP_NOW_Peer() {} From 271f94b45d7161537c8a128ef1c4786afd78152a Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:30:37 -0300 Subject: [PATCH 10/37] Change return value to align with other APIs --- libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index 39744de975b..0d6e22d61c4 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -82,7 +82,7 @@ void ESP_NOW_Serial_Class::end(){ //Stream int ESP_NOW_Serial_Class::available(void){ if(rx_queue == NULL){ - return -1; + return 0; } return uxQueueMessagesWaiting(rx_queue); } From 8751b986b42064f6f5405f4e3e13d9f35397f0b4 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:59:48 -0300 Subject: [PATCH 11/37] Apply suggested changes --- .../ESP_NOW_Serial/ESP_NOW_Serial.ino | 70 ++++++------------- libraries/ESP_NOW/src/ESP32_NOW.h | 4 +- 2 files changed, 24 insertions(+), 50 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino index de0c1800adb..e3b26b6cca6 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino @@ -3,6 +3,7 @@ Lucas Saavedra Vaz - 2024 Send data between two ESP32s using the ESP-NOW protocol in one-to-one (unicast) configuration. Note that different MAC addresses are used for different interfaces. + Set the peer MAC address according to the device that will receive the data. To properly visualize the data being sent, set the line ending in the Serial Monitor to "Both NL & CR". */ @@ -13,34 +14,28 @@ // 0: AP mode, 1: Station mode #define ESPNOW_WIFI_MODE_STATION 0 -// Channel to be used by the ESP-NOW protocol from 1 to 13 +// Channel to be used by the ESP-NOW protocol #define ESPNOW_WIFI_CHANNEL 1 #if ESPNOW_WIFI_MODE_STATION // ESP-NOW using WiFi Station mode -#define ESPNOW_WIFI_IF WIFI_IF_STA -#define GET_IF_MAC WiFi.macAddress - -// Station mode MAC addresses of the devices in the network -// Device 1 - F4:12:FA:42:B6:E8 -const MacAddress mac1({0xF4, 0x12, 0xFA, 0x42, 0xB6, 0xE8}); -// Device 2 - F4:12:FA:40:64:4C -const MacAddress mac2({0xF4, 0x12, 0xFA, 0x40, 0x64, 0x4C}); + #define ESPNOW_WIFI_IF WIFI_IF_STA + #define GET_IF_MAC WiFi.macAddress + + // Set the Station MAC address of the device that will receive the data + // For example: F4:12:FA:40:64:4C + const MacAddress peer_mac({0xF4, 0x12, 0xFA, 0x40, 0x64, 0x4C}); #else // ESP-NOW using WiFi AP mode -#define ESPNOW_WIFI_IF WIFI_IF_AP -#define GET_IF_MAC WiFi.softAPmacAddress - -// AP mode MAC addresses of the devices in the network -// Device 1 - F6:12:FA:42:B6:E8 -const MacAddress mac1({0xF6, 0x12, 0xFA, 0x42, 0xB6, 0xE8}); -// Device 2 - F6:12:FA:40:64:4C -const MacAddress mac2({0xF6, 0x12, 0xFA, 0x40, 0x64, 0x4C}); + #define ESPNOW_WIFI_IF WIFI_IF_AP + #define GET_IF_MAC WiFi.softAPmacAddress + + // Set the AP MAC address of the device that will receive the data + // For example: F6:12:FA:40:64:4C + const MacAddress peer_mac({0xF6, 0x12, 0xFA, 0x40, 0x64, 0x4C}); #endif -ESP_NOW_Serial_Class *esp_now_serial; +ESP_NOW_Serial_Class NowSerial(peer_mac, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF); void setup() { - MacAddress current_mac; - Serial.begin(115200); Serial.print("WiFi Mode: "); @@ -48,6 +43,7 @@ void setup() { #if ESPNOW_WIFI_MODE_STATION Serial.println("STA"); WiFi.mode(ESPNOW_WIFI_MODE); + // ToDo: Set the channel using WiFi.setChannel() when using Station mode esp_wifi_set_channel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE); #else Serial.println("AP"); @@ -57,46 +53,24 @@ void setup() { Serial.print("Channel: "); Serial.println(ESPNOW_WIFI_CHANNEL); - String mac = GET_IF_MAC(); Serial.print("MAC Address: "); - current_mac.fromString(mac); - Serial.println(mac); - - WiFi.disconnect(); - - if (current_mac == mac1) - { - Serial.println("I'm the Device 1\n"); - // Pass the MAC address of the other device to the ESP_NOW_Serial_Class - esp_now_serial = new ESP_NOW_Serial_Class(mac2, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF); - } - else if (current_mac == mac2) - { - Serial.println("I'm the Device 2\n"); - // Pass the MAC address of the other device to the ESP_NOW_Serial_Class - esp_now_serial = new ESP_NOW_Serial_Class(mac1, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF); - } - else - { - Serial.println("Unknown MAC address. Please update the mac addresses in the sketch\n"); - while(1); - } + Serial.println(GET_IF_MAC()); // Start the ESP-NOW communication Serial.println("ESP-NOW communication starting..."); - esp_now_serial->begin(115200); + NowSerial.begin(115200); Serial.println("You can now send data between the devices using the Serial Monitor\n"); } void loop() { - while (esp_now_serial->available() > 0) + while (NowSerial.available()) { - Serial.write(esp_now_serial->read()); + Serial.write(NowSerial.read()); } - while (Serial.available() && esp_now_serial->availableForWrite()) + while (Serial.available() && NowSerial.availableForWrite()) { - if (esp_now_serial->write(Serial.read()) <= 0) + if (NowSerial.write(Serial.read())) { Serial.println("Failed to send data"); break; diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h index 2fd3a3f7cc2..359aabb6e57 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.h +++ b/libraries/ESP_NOW/src/ESP32_NOW.h @@ -20,8 +20,6 @@ class ESP_NOW_Peer { size_t send(const uint8_t * data, int len); public: - const MacAddress BROADCAST_ADDR(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel=0, wifi_interface_t iface=WIFI_IF_AP, const uint8_t *lmk=NULL); virtual ~ESP_NOW_Peer() {} @@ -46,6 +44,8 @@ class ESP_NOW_Peer { class ESP_NOW_Class : public Print { public: + const MacAddress BROADCAST_ADDR = MacAddress(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + ESP_NOW_Class(); ~ESP_NOW_Class(); From 6d04c837867a4fd131cdd840666f501ad9a6b2e8 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:00:45 -0300 Subject: [PATCH 12/37] Improve example --- .../ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino index e3b26b6cca6..ef586cf3ed6 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino @@ -4,6 +4,11 @@ Send data between two ESP32s using the ESP-NOW protocol in one-to-one (unicast) configuration. Note that different MAC addresses are used for different interfaces. Set the peer MAC address according to the device that will receive the data. + Example setup: + - Device 1: AP mode, peer MAC address set to the Station MAC address of Device 2 + - Device 2: Station mode, peer MAC address set to the AP MAC address of Device 1 + + The device running this sketch will also receive and print data from any device that has its MAC address set as the peer MAC address. To properly visualize the data being sent, set the line ending in the Serial Monitor to "Both NL & CR". */ @@ -59,7 +64,7 @@ void setup() { // Start the ESP-NOW communication Serial.println("ESP-NOW communication starting..."); NowSerial.begin(115200); - Serial.println("You can now send data between the devices using the Serial Monitor\n"); + Serial.println("You can now send data to the peer device using the Serial Monitor.\n"); } void loop() { From 8a6025c30c7b21636150703300ab2e38a6acffe4 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:15:31 -0300 Subject: [PATCH 13/37] Fix example --- .../ESP_NOW_Serial/ESP_NOW_Serial.ino | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino index ef586cf3ed6..cacf688c19a 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino @@ -3,10 +3,15 @@ Lucas Saavedra Vaz - 2024 Send data between two ESP32s using the ESP-NOW protocol in one-to-one (unicast) configuration. Note that different MAC addresses are used for different interfaces. + The devices can be in different modes (AP or Station) and still communicate using ESP-NOW. + The only requirement is that the devices are on the same Wi-Fi channel. Set the peer MAC address according to the device that will receive the data. + Example setup: - - Device 1: AP mode, peer MAC address set to the Station MAC address of Device 2 - - Device 2: Station mode, peer MAC address set to the AP MAC address of Device 1 + - Device 1: AP mode with MAC address F6:12:FA:42:B6:E8 + Peer MAC address set to the Station MAC address of Device 2 (F4:12:FA:40:64:4C) + - Device 2: Station mode with MAC address F4:12:FA:40:64:4C + Peer MAC address set to the AP MAC address of Device 1 (F6:12:FA:42:B6:E8) The device running this sketch will also receive and print data from any device that has its MAC address set as the peer MAC address. To properly visualize the data being sent, set the line ending in the Serial Monitor to "Both NL & CR". @@ -16,8 +21,10 @@ #include "MacAddress.h" #include "WiFi.h" +#include "esp_wifi.h" + // 0: AP mode, 1: Station mode -#define ESPNOW_WIFI_MODE_STATION 0 +#define ESPNOW_WIFI_MODE_STATION 1 // Channel to be used by the ESP-NOW protocol #define ESPNOW_WIFI_CHANNEL 1 @@ -26,16 +33,16 @@ #define ESPNOW_WIFI_IF WIFI_IF_STA #define GET_IF_MAC WiFi.macAddress - // Set the Station MAC address of the device that will receive the data - // For example: F4:12:FA:40:64:4C - const MacAddress peer_mac({0xF4, 0x12, 0xFA, 0x40, 0x64, 0x4C}); + // Set the MAC address of the device that will receive the data + // For example: F6:12:FA:42:B6:E8 + const MacAddress peer_mac({0xF6, 0x12, 0xFA, 0x42, 0xB6, 0xE8}); #else // ESP-NOW using WiFi AP mode #define ESPNOW_WIFI_IF WIFI_IF_AP #define GET_IF_MAC WiFi.softAPmacAddress - // Set the AP MAC address of the device that will receive the data - // For example: F6:12:FA:40:64:4C - const MacAddress peer_mac({0xF6, 0x12, 0xFA, 0x40, 0x64, 0x4C}); + // Set the MAC address of the device that will receive the data + // For example: F4:12:FA:40:64:4C + const MacAddress peer_mac({0xF4, 0x12, 0xFA, 0x40, 0x64, 0x4C}); #endif ESP_NOW_Serial_Class NowSerial(peer_mac, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF); @@ -47,7 +54,7 @@ void setup() { #if ESPNOW_WIFI_MODE_STATION Serial.println("STA"); - WiFi.mode(ESPNOW_WIFI_MODE); + WiFi.mode(WIFI_STA); // ToDo: Set the channel using WiFi.setChannel() when using Station mode esp_wifi_set_channel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE); #else @@ -75,7 +82,7 @@ void loop() { while (Serial.available() && NowSerial.availableForWrite()) { - if (NowSerial.write(Serial.read())) + if (NowSerial.write(Serial.read()) <= 0) { Serial.println("Failed to send data"); break; From 6bf981e535ef2c05117f14a1855620890e928bbf Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Tue, 26 Mar 2024 10:28:08 -0300 Subject: [PATCH 14/37] Improve serial example --- .../ESP_NOW_Serial/ESP_NOW_Serial.ino | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino index cacf688c19a..2487e1dc815 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino @@ -30,15 +30,15 @@ #define ESPNOW_WIFI_CHANNEL 1 #if ESPNOW_WIFI_MODE_STATION // ESP-NOW using WiFi Station mode - #define ESPNOW_WIFI_IF WIFI_IF_STA - #define GET_IF_MAC WiFi.macAddress + #define ESPNOW_WIFI_MODE WIFI_STA // WiFi Mode + #define ESPNOW_WIFI_IF WIFI_IF_STA // WiFi Interface // Set the MAC address of the device that will receive the data // For example: F6:12:FA:42:B6:E8 const MacAddress peer_mac({0xF6, 0x12, 0xFA, 0x42, 0xB6, 0xE8}); #else // ESP-NOW using WiFi AP mode - #define ESPNOW_WIFI_IF WIFI_IF_AP - #define GET_IF_MAC WiFi.softAPmacAddress + #define ESPNOW_WIFI_MODE WIFI_AP // WiFi Mode + #define ESPNOW_WIFI_IF WIFI_IF_AP // WiFi Interface // Set the MAC address of the device that will receive the data // For example: F4:12:FA:40:64:4C @@ -51,22 +51,15 @@ void setup() { Serial.begin(115200); Serial.print("WiFi Mode: "); - - #if ESPNOW_WIFI_MODE_STATION - Serial.println("STA"); - WiFi.mode(WIFI_STA); - // ToDo: Set the channel using WiFi.setChannel() when using Station mode - esp_wifi_set_channel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE); - #else - Serial.println("AP"); - WiFi.softAP(WiFi.getHostname(), NULL, ESPNOW_WIFI_CHANNEL, 1); - #endif + Serial.println(ESPNOW_WIFI_MODE == WIFI_AP ? "AP" : "Station"); + WiFi.mode(ESPNOW_WIFI_MODE); Serial.print("Channel: "); Serial.println(ESPNOW_WIFI_CHANNEL); + WiFi.setChannel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE); Serial.print("MAC Address: "); - Serial.println(GET_IF_MAC()); + Serial.println(ESPNOW_WIFI_MODE == WIFI_AP ? WiFi.softAPmacAddress() : WiFi.macAddress()); // Start the ESP-NOW communication Serial.println("ESP-NOW communication starting..."); From 07f7de0635cf4861d460128bc46d016f900f38af Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Tue, 26 Mar 2024 13:25:30 -0300 Subject: [PATCH 15/37] Add argument to receive callback to know if a message was broadcasted --- libraries/ESP_NOW/src/ESP32_NOW.cpp | 5 +++-- libraries/ESP_NOW/src/ESP32_NOW.h | 5 ++--- libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 4 ++-- libraries/ESP_NOW/src/ESP32_NOW_Serial.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp index 76215057438..2098eb5b529 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -104,7 +104,8 @@ static esp_err_t _esp_now_modify_peer(const uint8_t *mac_addr, uint8_t channel, } static void _esp_now_rx_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len){ - log_v(MACSTR", data lenght : %d", MAC2STR(info->src_addr), len); + bool broadcast = memcmp(info->des_addr, ESP_NOW.BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0; + log_v("%s from " MACSTR ", data lenght : %u", broadcast ? "Broadcast" : "Unicast", MAC2STR(info->src_addr), len); log_buf_v(data, len); if(!esp_now_is_peer_exist(info->src_addr) && new_cb != NULL){ log_v("Calling new_cb, peer not found."); @@ -114,7 +115,7 @@ static void _esp_now_rx_cb(const esp_now_recv_info_t *info, const uint8_t *data, //find the peer and call it's callback for(uint8_t i=0; isrc_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0){ - _esp_now_peers[i]->_onReceive(data, len); + _esp_now_peers[i]->_onReceive(data, len, broadcast); return; } } diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h index 359aabb6e57..f70d1339b86 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.h +++ b/libraries/ESP_NOW/src/ESP32_NOW.h @@ -3,7 +3,6 @@ #include "esp_wifi_types.h" #include "Print.h" #include "esp_now.h" -#include "MacAddress.h" class ESP_NOW_Peer { private: @@ -38,13 +37,13 @@ class ESP_NOW_Peer { operator bool() const; //must be implemented by the upper class - virtual void _onReceive(const uint8_t * data, size_t len) = 0; + virtual void _onReceive(const uint8_t * data, size_t len, bool broadcast) = 0; virtual void _onSent(bool success) = 0; }; class ESP_NOW_Class : public Print { public: - const MacAddress BROADCAST_ADDR = MacAddress(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + const uint8_t BROADCAST_ADDR[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; ESP_NOW_Class(); ~ESP_NOW_Class(); diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index 0d6e22d61c4..0f2e7edfc63 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -140,11 +140,11 @@ void ESP_NOW_Serial_Class::flush(){ } //RX callback -void ESP_NOW_Serial_Class::_onReceive(const uint8_t * data, size_t len){ +void ESP_NOW_Serial_Class::_onReceive(const uint8_t * data, size_t len, bool broadcast){ if(rx_queue == NULL){ return; } - log_v(MACSTR ", data lenght : %u", MAC2STR(addr()), len); + log_v("%s from " MACSTR ", data lenght : %u", broadcast ? "Broadcast" : "Unicast", MAC2STR(addr()), len); for(uint32_t i=0; i Date: Wed, 27 Mar 2024 09:32:48 -0300 Subject: [PATCH 16/37] Update libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp --- libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index 0f2e7edfc63..65af4dd4f34 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -144,7 +144,6 @@ void ESP_NOW_Serial_Class::_onReceive(const uint8_t * data, size_t len, bool bro if(rx_queue == NULL){ return; } - log_v("%s from " MACSTR ", data lenght : %u", broadcast ? "Broadcast" : "Unicast", MAC2STR(addr()), len); for(uint32_t i=0; i Date: Wed, 27 Mar 2024 09:37:11 -0300 Subject: [PATCH 17/37] Simplify example --- .../examples/ESP_NOW_Serial/ESP_NOW_Serial.ino | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino index 2487e1dc815..8e7b2041a2d 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino @@ -32,19 +32,15 @@ #if ESPNOW_WIFI_MODE_STATION // ESP-NOW using WiFi Station mode #define ESPNOW_WIFI_MODE WIFI_STA // WiFi Mode #define ESPNOW_WIFI_IF WIFI_IF_STA // WiFi Interface - - // Set the MAC address of the device that will receive the data - // For example: F6:12:FA:42:B6:E8 - const MacAddress peer_mac({0xF6, 0x12, 0xFA, 0x42, 0xB6, 0xE8}); #else // ESP-NOW using WiFi AP mode #define ESPNOW_WIFI_MODE WIFI_AP // WiFi Mode #define ESPNOW_WIFI_IF WIFI_IF_AP // WiFi Interface - - // Set the MAC address of the device that will receive the data - // For example: F4:12:FA:40:64:4C - const MacAddress peer_mac({0xF4, 0x12, 0xFA, 0x40, 0x64, 0x4C}); #endif +// Set the MAC address of the device that will receive the data +// For example: F4:12:FA:40:64:4C +const MacAddress peer_mac({0xF4, 0x12, 0xFA, 0x40, 0x64, 0x4C}); + ESP_NOW_Serial_Class NowSerial(peer_mac, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IF); void setup() { From 03e837cca67d25f7b4a436a155ee9c2f94405e50 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Wed, 27 Mar 2024 10:01:48 -0300 Subject: [PATCH 18/37] Add broadcast example --- .../ESP_NOW_Broadcast_Master/.skip.esp32h2 | 0 .../ESP_NOW_Broadcast_Master.ino | 136 ++++++++++++++++++ .../ESP_NOW_Broadcast_Slave/.skip.esp32h2 | 0 .../ESP_NOW_Broadcast_Slave.ino | 132 +++++++++++++++++ 4 files changed, 268 insertions(+) create mode 100644 libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/.skip.esp32h2 create mode 100644 libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino create mode 100644 libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/.skip.esp32h2 create mode 100644 libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/.skip.esp32h2 b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/.skip.esp32h2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino new file mode 100644 index 00000000000..0a5959b47e8 --- /dev/null +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino @@ -0,0 +1,136 @@ +/* + ESP-NOW Broadcast Master + Lucas Saavedra Vaz - 2024 + + This sketch demonstrates how to broadcast messages to all devices within the ESP-NOW network. + This example is intended to be used with the ESP-NOW Broadcast Slave example. + + The master device will broadcast a message every 5 seconds to all devices within the network. + This will be done using by registering a peer object with the broadcast address. + + The slave devices will receive the broadcasted messages and print them to the Serial Monitor. +*/ + +#include "ESP32_NOW.h" +#include "WiFi.h" + +#include // For the MAC2STR and MACSTR macros + +/* Definitions */ + +#define ESPNOW_WIFI_CHANNEL 6 + +/* Classes */ + +// Create a new class that inherits from the ESP_NOW_Peer class is required to implement the _onReceive and _onSent methods. + +class ESP_NOW_Peer_Class : public ESP_NOW_Peer { +public: + ESP_NOW_Peer_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk); + ~ESP_NOW_Peer_Class(); + + bool add_peer(); + bool send_message(const uint8_t *data, size_t len); + + // ESP_NOW_Peer interfaces + void _onReceive(const uint8_t *data, size_t len, bool broadcast); + void _onSent(bool success); +}; + +/* Methods */ + +// Constructor of the class +ESP_NOW_Peer_Class::ESP_NOW_Peer_Class(const uint8_t *mac_addr, + uint8_t channel, + wifi_interface_t iface, + const uint8_t *lmk) : ESP_NOW_Peer(mac_addr, channel, iface, lmk) {} + +// Destructor of the class +ESP_NOW_Peer_Class::~ESP_NOW_Peer_Class() { + remove(); +} + +// Function to register the broadcast peer +bool ESP_NOW_Peer_Class::add_peer() { + if (!add()) { + log_e("Failed to register the broadcast peer"); + return false; + } + return true; +} + +// Function to send a message to all devices within the network +bool ESP_NOW_Peer_Class::send_message(const uint8_t *data, size_t len) { + if (!send(data, len)) { + log_e("Failed to broadcast message"); + return false; + } + return true; +} + +void ESP_NOW_Peer_Class::_onReceive(const uint8_t *data, size_t len, bool broadcast) { + // The broadcast peer will never receive any data. Rather, it will only send data. + // Data broadcasted will be received by the actual object of the peer that made the broadcast. + // It is still required to be implemented because it is a pure virtual method. +} + +void ESP_NOW_Peer_Class::_onSent(bool success) { + // As broadcast messages does not require any acknowledgment, this method will never be called. + // It is still required to be implemented because it is a pure virtual method. +} + +/* Global Variables */ + +uint32_t msg_count = 0; + +// Create a peer object using the broadcast address +ESP_NOW_Peer_Class broadcast_peer(ESP_NOW.BROADCAST_ADDR, ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL); + +/* Main */ + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + + Serial.println("ESP-NOW Example - Broadcast Master"); + Serial.println("Wi-Fi parameters:"); + Serial.println(" Mode: STA"); + Serial.println(" MAC Address: " + WiFi.macAddress()); + Serial.printf(" Channel: %d\n", ESPNOW_WIFI_CHANNEL); + + // Initialize the Wi-Fi module + WiFi.mode(WIFI_STA); + WiFi.setChannel(ESPNOW_WIFI_CHANNEL); + + // Initialize the ESP-NOW protocol + if (!ESP_NOW.begin()) { + Serial.println("Failed to initialize ESP-NOW"); + Serial.println("Reebooting in 5 seconds..."); + delay(5000); + ESP.restart(); + } + + // Register the broadcast peer + if (!broadcast_peer.add_peer()) { + Serial.println("Failed to register the broadcast peer"); + Serial.println("Reebooting in 5 seconds..."); + delay(5000); + ESP.restart(); + } + + Serial.println("Setup complete. Broadcasting messages every 5 seconds."); +} + +void loop() { + // Broadcast a message to all devices within the network + char data[32]; + snprintf(data, sizeof(data), "Hello, World! #%lu", msg_count++); + + Serial.printf("Broadcasting message: %s\n", data); + + if (!broadcast_peer.send_message((uint8_t *)data, sizeof(data))) { + Serial.println("Failed to broadcast message"); + } + + delay(5000); +} diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/.skip.esp32h2 b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/.skip.esp32h2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino new file mode 100644 index 00000000000..773c39def79 --- /dev/null +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino @@ -0,0 +1,132 @@ +/* + ESP-NOW Broadcast Slave + Lucas Saavedra Vaz - 2024 + + This sketch demonstrates how to receive broadcast messages from a master device using the ESP-NOW protocol. + + The master device will broadcast a message every 5 seconds to all devices within the network. + + The slave devices will receive the broadcasted messages. If they are not from a known master, they will be registered as a new master + using a callback function. +*/ + +#include "ESP32_NOW.h" +#include "WiFi.h" + +#include // For the MAC2STR and MACSTR macros + +#include + +/* Definitions */ + +#define ESPNOW_WIFI_CHANNEL 6 + +/* Classes */ + +// Create a new class that inherits from the ESP_NOW_Peer class is required to implement the _onReceive and _onSent methods. + +class ESP_NOW_Peer_Class : public ESP_NOW_Peer { +public: + ESP_NOW_Peer_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk); + ~ESP_NOW_Peer_Class(); + + bool add_peer(); + + // ESP_NOW_Peer interfaces + void _onReceive(const uint8_t *data, size_t len, bool broadcast); + void _onSent(bool success); +}; + +/* Methods */ + +// Constructor of the class +ESP_NOW_Peer_Class::ESP_NOW_Peer_Class(const uint8_t *mac_addr, + uint8_t channel, + wifi_interface_t iface, + const uint8_t *lmk) : ESP_NOW_Peer(mac_addr, channel, iface, lmk) {} + +// Destructor of the class +ESP_NOW_Peer_Class::~ESP_NOW_Peer_Class() { + remove(); +} + +// Function to register the master peer +bool ESP_NOW_Peer_Class::add_peer() { + if (!add()) { + log_e("Failed to register the broadcast peer"); + return false; + } + return true; +} + +// Function to print the received messages from the master +void ESP_NOW_Peer_Class::_onReceive(const uint8_t *data, size_t len, bool broadcast) { + Serial.printf("Received a message from master " MACSTR " (%s)\n", MAC2STR(addr()), broadcast ? "broadcast" : "unicast"); + Serial.printf(" Message: %s\n", (char *)data); +} + +void ESP_NOW_Peer_Class::_onSent(bool success) { + // In this example the slave will never send any data, so this method will never be called. + // It is still required to be implemented because it is a pure virtual method. +} + +/* Global Variables */ + +// List of all the masters. It will be populated when a new master is registered +std::vector masters; + +/* Callbacks */ + +// Callback called when an unknown peer sends a message +void register_new_master(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg) { + if (memcmp(info->des_addr, ESP_NOW.BROADCAST_ADDR, 6) == 0) { + Serial.printf("Unknown peer " MACSTR " sent a broadcast message\n", MAC2STR(info->src_addr)); + Serial.println("Registering the peer as a master"); + + ESP_NOW_Peer_Class new_master(info->src_addr, ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL); + + masters.push_back(new_master); + if (!masters.back().add_peer()) { + Serial.println("Failed to register the new master"); + return; + } + } else { + // The slave will only receive broadcast messages + log_v("Received a unicast message from " MACSTR, MAC2STR(info->src_addr)); + log_v("Igorning the message"); + } +} + +/* Main */ + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + + Serial.println("ESP-NOW Example - Broadcast Slave"); + Serial.println("Wi-Fi parameters:"); + Serial.println(" Mode: STA"); + Serial.println(" MAC Address: " + WiFi.macAddress()); + Serial.printf(" Channel: %d\n", ESPNOW_WIFI_CHANNEL); + + // Initialize the Wi-Fi module + WiFi.mode(WIFI_STA); + WiFi.setChannel(ESPNOW_WIFI_CHANNEL); + + // Initialize the ESP-NOW protocol + if (!ESP_NOW.begin()) { + Serial.println("Failed to initialize ESP-NOW"); + Serial.println("Reeboting in 5 seconds..."); + delay(5000); + ESP.restart(); + } + + // Register the new peer callback + ESP_NOW.onNewPeer(register_new_master, NULL); + + Serial.println("Setup complete. Waiting for a master to broadcast a message..."); +} + +void loop() { + delay(1000); +} From 6a0774caa9d2dff6d91ce2312c794eca3447619d Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Wed, 27 Mar 2024 10:03:08 -0300 Subject: [PATCH 19/37] Change comments --- libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index 65af4dd4f34..f3a4ffa61e8 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -170,7 +170,7 @@ size_t ESP_NOW_Serial_Class::tryToSend(){ size_t sent = send(queued_buff, queued_size); if(!sent){ //_onSent will not be called anymore - //sucks that we lose the data here + //the data is lost in this case vRingbufferReturnItem(tx_ring_buf, queued_buff); queued_buff = NULL; xSemaphoreGive(tx_sem); From 34168a13761f1952f04a76cdee463062e7135b7a Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Wed, 27 Mar 2024 10:03:25 -0300 Subject: [PATCH 20/37] Change comment --- libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index f3a4ffa61e8..364ffe47bd2 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -261,7 +261,7 @@ void ESP_NOW_Serial_Class::_onSent(bool success){ tryToSend(); } else { //resend limit reached - //sucks that we lose the data here + //the data is lost in this case vRingbufferReturnItem(tx_ring_buf, queued_buff); queued_buff = NULL; xSemaphoreGive(tx_sem); From ab31ab85cebf9491d5c16531307fcec46a6a6a99 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Thu, 28 Mar 2024 10:49:30 -0300 Subject: [PATCH 21/37] Improve broadcast master example --- .../ESP_NOW_Broadcast_Master.ino | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino index 0a5959b47e8..523bebd1fc4 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino @@ -24,12 +24,12 @@ // Create a new class that inherits from the ESP_NOW_Peer class is required to implement the _onReceive and _onSent methods. -class ESP_NOW_Peer_Class : public ESP_NOW_Peer { +class ESP_NOW_Broadcast_Peer : public ESP_NOW_Peer { public: - ESP_NOW_Peer_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk); - ~ESP_NOW_Peer_Class(); + ESP_NOW_Broadcast_Peer(uint8_t channel, wifi_interface_t iface, const uint8_t *lmk); + ~ESP_NOW_Broadcast_Peer(); - bool add_peer(); + bool begin(); bool send_message(const uint8_t *data, size_t len); // ESP_NOW_Peer interfaces @@ -39,28 +39,26 @@ public: /* Methods */ -// Constructor of the class -ESP_NOW_Peer_Class::ESP_NOW_Peer_Class(const uint8_t *mac_addr, - uint8_t channel, - wifi_interface_t iface, - const uint8_t *lmk) : ESP_NOW_Peer(mac_addr, channel, iface, lmk) {} +// Constructor of the class using the broadcast address +ESP_NOW_Broadcast_Peer::ESP_NOW_Broadcast_Peer(uint8_t channel, wifi_interface_t iface, const uint8_t *lmk) + : ESP_NOW_Peer(ESP_NOW.BROADCAST_ADDR, channel, iface, lmk) {} // Destructor of the class -ESP_NOW_Peer_Class::~ESP_NOW_Peer_Class() { +ESP_NOW_Broadcast_Peer::~ESP_NOW_Broadcast_Peer() { remove(); } -// Function to register the broadcast peer -bool ESP_NOW_Peer_Class::add_peer() { - if (!add()) { - log_e("Failed to register the broadcast peer"); +// Function to properly initialize the ESP-NOW and register the broadcast peer +bool ESP_NOW_Broadcast_Peer::begin() { + if (!ESP_NOW.begin() || !add()) { + log_e("Failed to initialize ESP-NOW or register the broadcast peer"); return false; } return true; } // Function to send a message to all devices within the network -bool ESP_NOW_Peer_Class::send_message(const uint8_t *data, size_t len) { +bool ESP_NOW_Broadcast_Peer::send_message(const uint8_t *data, size_t len) { if (!send(data, len)) { log_e("Failed to broadcast message"); return false; @@ -68,13 +66,13 @@ bool ESP_NOW_Peer_Class::send_message(const uint8_t *data, size_t len) { return true; } -void ESP_NOW_Peer_Class::_onReceive(const uint8_t *data, size_t len, bool broadcast) { +void ESP_NOW_Broadcast_Peer::_onReceive(const uint8_t *data, size_t len, bool broadcast) { // The broadcast peer will never receive any data. Rather, it will only send data. // Data broadcasted will be received by the actual object of the peer that made the broadcast. // It is still required to be implemented because it is a pure virtual method. } -void ESP_NOW_Peer_Class::_onSent(bool success) { +void ESP_NOW_Broadcast_Peer::_onSent(bool success) { // As broadcast messages does not require any acknowledgment, this method will never be called. // It is still required to be implemented because it is a pure virtual method. } @@ -83,8 +81,8 @@ void ESP_NOW_Peer_Class::_onSent(bool success) { uint32_t msg_count = 0; -// Create a peer object using the broadcast address -ESP_NOW_Peer_Class broadcast_peer(ESP_NOW.BROADCAST_ADDR, ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL); +// Create a boradcast peer object +ESP_NOW_Broadcast_Peer broadcast_peer(ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL); /* Main */ @@ -102,17 +100,9 @@ void setup() { WiFi.mode(WIFI_STA); WiFi.setChannel(ESPNOW_WIFI_CHANNEL); - // Initialize the ESP-NOW protocol - if (!ESP_NOW.begin()) { - Serial.println("Failed to initialize ESP-NOW"); - Serial.println("Reebooting in 5 seconds..."); - delay(5000); - ESP.restart(); - } - // Register the broadcast peer - if (!broadcast_peer.add_peer()) { - Serial.println("Failed to register the broadcast peer"); + if (!broadcast_peer.begin()) { + Serial.println("Failed to initialize broadcast peer"); Serial.println("Reebooting in 5 seconds..."); delay(5000); ESP.restart(); From 5ca2af1d1519cccd237144a7df57f86167de1d47 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:39:38 -0300 Subject: [PATCH 22/37] Remove examples using IDF's API --- .../ESPNow/ESPNow_Basic_Master/.skip.esp32h2 | 0 .../ESPNow_Basic_Master.ino | 262 ------------------ .../ESPNow/ESPNow_Basic_Slave/.skip.esp32h2 | 0 .../ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino | 92 ------ .../ESPNow_MultiSlave_Master/.skip.esp32h2 | 0 .../ESPNow_MultiSlave_Master.ino | 244 ---------------- .../ESPNow_MultiSlave_Slave/.skip.esp32h2 | 0 .../ESPNow_MultiSlave_Slave.ino | 94 ------- 8 files changed, 692 deletions(-) delete mode 100644 libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/.skip.esp32h2 delete mode 100644 libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/ESPNow_Basic_Master.ino delete mode 100644 libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/.skip.esp32h2 delete mode 100644 libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino delete mode 100644 libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/.skip.esp32h2 delete mode 100644 libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/ESPNow_MultiSlave_Master.ino delete mode 100644 libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/.skip.esp32h2 delete mode 100644 libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/ESPNow_MultiSlave_Slave.ino diff --git a/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/.skip.esp32h2 b/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/.skip.esp32h2 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/ESPNow_Basic_Master.ino b/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/ESPNow_Basic_Master.ino deleted file mode 100644 index b2e6b35506c..00000000000 --- a/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/ESPNow_Basic_Master.ino +++ /dev/null @@ -1,262 +0,0 @@ -/** - ESPNOW - Basic communication - Master - Date: 26th September 2017 - Author: Arvind Ravulavaru - Purpose: ESPNow Communication between a Master ESP32 and a Slave ESP32 - Description: This sketch consists of the code for the Master module. - Resources: (A bit outdated) - a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf - b. http://www.esploradores.com/practica-6-conexion-esp-now/ - - << This Device Master >> - - Flow: Master - Step 1 : ESPNow Init on Master and set it in STA mode - Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) - Step 3 : Once found, add Slave as peer - Step 4 : Register for send callback - Step 5 : Start Transmitting data from Master to Slave - - Flow: Slave - Step 1 : ESPNow Init on Slave - Step 2 : Update the SSID of Slave with a prefix of `slave` - Step 3 : Set Slave in AP mode - Step 4 : Register for receive callback and wait for data - Step 5 : Once data arrives, print it in the serial monitor - - Note: Master and Slave have been defined to easily understand the setup. - Based on the ESPNOW API, there is no concept of Master and Slave. - Any devices can act as master or salve. -*/ - -#include -#include -#include // only for esp_wifi_set_channel() - -// Global copy of slave -esp_now_peer_info_t slave; -#define CHANNEL 1 -#define PRINTSCANRESULTS 0 -#define DELETEBEFOREPAIR 0 - -// Init ESP Now with fallback -void InitESPNow() { - WiFi.disconnect(); - if (esp_now_init() == ESP_OK) { - Serial.println("ESPNow Init Success"); - } - else { - Serial.println("ESPNow Init Failed"); - // Retry InitESPNow, add a counte and then restart? - // InitESPNow(); - // or Simply Restart - ESP.restart(); - } -} - -// Scan for slaves in AP mode -void ScanForSlave() { - int16_t scanResults = WiFi.scanNetworks(false, false, false, 300, CHANNEL); // Scan only on one channel - // reset on each scan - bool slaveFound = 0; - memset(&slave, 0, sizeof(slave)); - - Serial.println(""); - if (scanResults == 0) { - Serial.println("No WiFi devices in AP Mode found"); - } else { - Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices "); - for (int i = 0; i < scanResults; ++i) { - // Print SSID and RSSI for each device found - String SSID = WiFi.SSID(i); - int32_t RSSI = WiFi.RSSI(i); - String BSSIDstr = WiFi.BSSIDstr(i); - - if (PRINTSCANRESULTS) { - Serial.print(i + 1); - Serial.print(": "); - Serial.print(SSID); - Serial.print(" ("); - Serial.print(RSSI); - Serial.print(")"); - Serial.println(""); - } - delay(10); - // Check if the current device starts with `Slave` - if (SSID.indexOf("Slave") == 0) { - // SSID of interest - Serial.println("Found a Slave."); - Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println(""); - // Get BSSID => Mac Address of the Slave - int mac[6]; - if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) { - for (int ii = 0; ii < 6; ++ii ) { - slave.peer_addr[ii] = (uint8_t) mac[ii]; - } - } - - slave.channel = CHANNEL; // pick a channel - slave.encrypt = 0; // no encryption - - slaveFound = 1; - // we are planning to have only one slave in this example; - // Hence, break after we find one, to be a bit efficient - break; - } - } - } - - if (slaveFound) { - Serial.println("Slave Found, processing.."); - } else { - Serial.println("Slave Not Found, trying again."); - } - - // clean up ram - WiFi.scanDelete(); -} - -// Check if the slave is already paired with the master. -// If not, pair the slave with master -bool manageSlave() { - if (slave.channel == CHANNEL) { - if (DELETEBEFOREPAIR) { - deletePeer(); - } - - Serial.print("Slave Status: "); - // check if the peer exists - bool exists = esp_now_is_peer_exist(slave.peer_addr); - if ( exists) { - // Slave already paired. - Serial.println("Already Paired"); - return true; - } else { - // Slave not paired, attempt pair - esp_err_t addStatus = esp_now_add_peer(&slave); - if (addStatus == ESP_OK) { - // Pair success - Serial.println("Pair success"); - return true; - } else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) { - // How did we get so far!! - Serial.println("ESPNOW Not Init"); - return false; - } else if (addStatus == ESP_ERR_ESPNOW_ARG) { - Serial.println("Invalid Argument"); - return false; - } else if (addStatus == ESP_ERR_ESPNOW_FULL) { - Serial.println("Peer list full"); - return false; - } else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) { - Serial.println("Out of memory"); - return false; - } else if (addStatus == ESP_ERR_ESPNOW_EXIST) { - Serial.println("Peer Exists"); - return true; - } else { - Serial.println("Not sure what happened"); - return false; - } - } - } else { - // No slave found to process - Serial.println("No Slave found to process"); - return false; - } -} - -void deletePeer() { - esp_err_t delStatus = esp_now_del_peer(slave.peer_addr); - Serial.print("Slave Delete Status: "); - if (delStatus == ESP_OK) { - // Delete success - Serial.println("Success"); - } else if (delStatus == ESP_ERR_ESPNOW_NOT_INIT) { - // How did we get so far!! - Serial.println("ESPNOW Not Init"); - } else if (delStatus == ESP_ERR_ESPNOW_ARG) { - Serial.println("Invalid Argument"); - } else if (delStatus == ESP_ERR_ESPNOW_NOT_FOUND) { - Serial.println("Peer not found."); - } else { - Serial.println("Not sure what happened"); - } -} - -uint8_t data = 0; -// send data -void sendData() { - data++; - const uint8_t *peer_addr = slave.peer_addr; - Serial.print("Sending: "); Serial.println(data); - esp_err_t result = esp_now_send(peer_addr, &data, sizeof(data)); - Serial.print("Send Status: "); - if (result == ESP_OK) { - Serial.println("Success"); - } else if (result == ESP_ERR_ESPNOW_NOT_INIT) { - // How did we get so far!! - Serial.println("ESPNOW not Init."); - } else if (result == ESP_ERR_ESPNOW_ARG) { - Serial.println("Invalid Argument"); - } else if (result == ESP_ERR_ESPNOW_INTERNAL) { - Serial.println("Internal Error"); - } else if (result == ESP_ERR_ESPNOW_NO_MEM) { - Serial.println("ESP_ERR_ESPNOW_NO_MEM"); - } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) { - Serial.println("Peer not found."); - } else { - Serial.println("Not sure what happened"); - } -} - -// callback when data is sent from Master to Slave -void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { - char macStr[18]; - snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", - mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); - Serial.print("Last Packet Sent to: "); Serial.println(macStr); - Serial.print("Last Packet Send Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); -} - -void setup() { - Serial.begin(115200); - //Set device in STA mode to begin with - WiFi.mode(WIFI_STA); - esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE); - Serial.println("ESPNow/Basic/Master Example"); - // This is the mac address of the Master in Station Mode - Serial.print("STA MAC: "); Serial.println(WiFi.macAddress()); - Serial.print("STA CHANNEL "); Serial.println(WiFi.channel()); - // Init ESPNow with a fallback logic - InitESPNow(); - // Once ESPNow is successfully Init, we will register for Send CB to - // get the status of Trasnmitted packet - esp_now_register_send_cb(OnDataSent); -} - -void loop() { - // In the loop we scan for slave - ScanForSlave(); - // If Slave is found, it would be populate in `slave` variable - // We will check if `slave` is defined and then we proceed further - if (slave.channel == CHANNEL) { // check if slave channel is defined - // `slave` is defined - // Add slave as peer if it has not been added already - bool isPaired = manageSlave(); - if (isPaired) { - // pair success or already paired - // Send data to device - sendData(); - } else { - // slave pair failed - Serial.println("Slave pair failed!"); - } - } - else { - // No slave found to process - } - - // wait for 3seconds to run the logic again - delay(3000); -} diff --git a/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/.skip.esp32h2 b/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/.skip.esp32h2 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino b/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino deleted file mode 100644 index 50711b18fd5..00000000000 --- a/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino +++ /dev/null @@ -1,92 +0,0 @@ -/** - ESPNOW - Basic communication - Slave - Date: 26th September 2017 - Author: Arvind Ravulavaru - Purpose: ESPNow Communication between a Master ESP32 and a Slave ESP32 - Description: This sketch consists of the code for the Slave module. - Resources: (A bit outdated) - a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf - b. http://www.esploradores.com/practica-6-conexion-esp-now/ - - << This Device Slave >> - - Flow: Master - Step 1 : ESPNow Init on Master and set it in STA mode - Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) - Step 3 : Once found, add Slave as peer - Step 4 : Register for send callback - Step 5 : Start Transmitting data from Master to Slave - - Flow: Slave - Step 1 : ESPNow Init on Slave - Step 2 : Update the SSID of Slave with a prefix of `slave` - Step 3 : Set Slave in AP mode - Step 4 : Register for receive callback and wait for data - Step 5 : Once data arrives, print it in the serial monitor - - Note: Master and Slave have been defined to easily understand the setup. - Based on the ESPNOW API, there is no concept of Master and Slave. - Any devices can act as master or salve. -*/ - -#include -#include - -#define CHANNEL 1 - -// Init ESP Now with fallback -void InitESPNow() { - WiFi.disconnect(); - if (esp_now_init() == ESP_OK) { - Serial.println("ESPNow Init Success"); - } - else { - Serial.println("ESPNow Init Failed"); - // Retry InitESPNow, add a counte and then restart? - // InitESPNow(); - // or Simply Restart - ESP.restart(); - } -} - -// config AP SSID -void configDeviceAP() { - const char *SSID = "Slave_1"; - bool result = WiFi.softAP(SSID, "Slave_1_Password", CHANNEL, 0); - if (!result) { - Serial.println("AP Config failed."); - } else { - Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID)); - Serial.print("AP CHANNEL "); Serial.println(WiFi.channel()); - } -} - -void setup() { - Serial.begin(115200); - Serial.println("ESPNow/Basic/Slave Example"); - //Set device in AP mode to begin with - WiFi.mode(WIFI_AP); - // configure device AP mode - configDeviceAP(); - // This is the mac address of the Slave in AP Mode - Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); - // Init ESPNow with a fallback logic - InitESPNow(); - // Once ESPNow is successfully Init, we will register for recv CB to - // get recv packer info. - esp_now_register_recv_cb(OnDataRecv); -} - -// callback when data is recv from Master -void OnDataRecv(const esp_now_recv_info_t * info, const uint8_t *data, int data_len) { - char macStr[18]; - snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", - info->src_addr[0], info->src_addr[1], info->src_addr[2], info->src_addr[3], info->src_addr[4], info->src_addr[5]); - Serial.print("Last Packet Recv from: "); Serial.println(macStr); - Serial.print("Last Packet Recv Data: "); Serial.println(*data); - Serial.println(""); -} - -void loop() { - // Chill -} diff --git a/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/.skip.esp32h2 b/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/.skip.esp32h2 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/ESPNow_MultiSlave_Master.ino b/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/ESPNow_MultiSlave_Master.ino deleted file mode 100644 index 6e212dd1121..00000000000 --- a/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/ESPNow_MultiSlave_Master.ino +++ /dev/null @@ -1,244 +0,0 @@ -/** - ESPNOW - Basic communication - Master - Date: 26th September 2017 - Author: Arvind Ravulavaru - Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves - Description: This sketch consists of the code for the Master module. - Resources: (A bit outdated) - a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf - b. http://www.esploradores.com/practica-6-conexion-esp-now/ - - << This Device Master >> - - Flow: Master - Step 1 : ESPNow Init on Master and set it in STA mode - Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) - Step 3 : Once found, add Slave as peer - Step 4 : Register for send callback - Step 5 : Start Transmitting data from Master to Slave(s) - - Flow: Slave - Step 1 : ESPNow Init on Slave - Step 2 : Update the SSID of Slave with a prefix of `slave` - Step 3 : Set Slave in AP mode - Step 4 : Register for receive callback and wait for data - Step 5 : Once data arrives, print it in the serial monitor - - Note: Master and Slave have been defined to easily understand the setup. - Based on the ESPNOW API, there is no concept of Master and Slave. - Any devices can act as master or salve. - - - // Sample Serial log with 1 master & 2 slaves - Found 12 devices - 1: Slave:24:0A:C4:81:CF:A4 [24:0A:C4:81:CF:A5] (-44) - 3: Slave:30:AE:A4:02:6D:CC [30:AE:A4:02:6D:CD] (-55) - 2 Slave(s) found, processing.. - Processing: 24:A:C4:81:CF:A5 Status: Already Paired - Processing: 30:AE:A4:2:6D:CD Status: Already Paired - Sending: 9 - Send Status: Success - Last Packet Sent to: 24:0a:c4:81:cf:a5 - Last Packet Send Status: Delivery Success - Send Status: Success - Last Packet Sent to: 30:ae:a4:02:6d:cd - Last Packet Send Status: Delivery Success - -*/ - -#include -#include - -// Global copy of slave -#define NUMSLAVES 20 -esp_now_peer_info_t slaves[NUMSLAVES] = {}; -int SlaveCnt = 0; - -#define CHANNEL 3 -#define PRINTSCANRESULTS 0 - -// Init ESP Now with fallback -void InitESPNow() { - WiFi.disconnect(); - if (esp_now_init() == ESP_OK) { - Serial.println("ESPNow Init Success"); - } - else { - Serial.println("ESPNow Init Failed"); - // Retry InitESPNow, add a counte and then restart? - // InitESPNow(); - // or Simply Restart - ESP.restart(); - } -} - -// Scan for slaves in AP mode -void ScanForSlave() { - int8_t scanResults = WiFi.scanNetworks(); - //reset slaves - memset(slaves, 0, sizeof(slaves)); - SlaveCnt = 0; - Serial.println(""); - if (scanResults == 0) { - Serial.println("No WiFi devices in AP Mode found"); - } else { - Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices "); - for (int i = 0; i < scanResults; ++i) { - // Print SSID and RSSI for each device found - String SSID = WiFi.SSID(i); - int32_t RSSI = WiFi.RSSI(i); - String BSSIDstr = WiFi.BSSIDstr(i); - - if (PRINTSCANRESULTS) { - Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println(""); - } - delay(10); - // Check if the current device starts with `Slave` - if (SSID.indexOf("Slave") == 0) { - // SSID of interest - Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println(""); - // Get BSSID => Mac Address of the Slave - int mac[6]; - - if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) { - for (int ii = 0; ii < 6; ++ii ) { - slaves[SlaveCnt].peer_addr[ii] = (uint8_t) mac[ii]; - } - } - slaves[SlaveCnt].channel = CHANNEL; // pick a channel - slaves[SlaveCnt].encrypt = 0; // no encryption - SlaveCnt++; - } - } - } - - if (SlaveCnt > 0) { - Serial.print(SlaveCnt); Serial.println(" Slave(s) found, processing.."); - } else { - Serial.println("No Slave Found, trying again."); - } - - // clean up ram - WiFi.scanDelete(); -} - -// Check if the slave is already paired with the master. -// If not, pair the slave with master -void manageSlave() { - if (SlaveCnt > 0) { - for (int i = 0; i < SlaveCnt; i++) { - Serial.print("Processing: "); - for (int ii = 0; ii < 6; ++ii ) { - Serial.print((uint8_t) slaves[i].peer_addr[ii], HEX); - if (ii != 5) Serial.print(":"); - } - Serial.print(" Status: "); - // check if the peer exists - bool exists = esp_now_is_peer_exist(slaves[i].peer_addr); - if (exists) { - // Slave already paired. - Serial.println("Already Paired"); - } else { - // Slave not paired, attempt pair - esp_err_t addStatus = esp_now_add_peer(&slaves[i]); - if (addStatus == ESP_OK) { - // Pair success - Serial.println("Pair success"); - } else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) { - // How did we get so far!! - Serial.println("ESPNOW Not Init"); - } else if (addStatus == ESP_ERR_ESPNOW_ARG) { - Serial.println("Add Peer - Invalid Argument"); - } else if (addStatus == ESP_ERR_ESPNOW_FULL) { - Serial.println("Peer list full"); - } else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) { - Serial.println("Out of memory"); - } else if (addStatus == ESP_ERR_ESPNOW_EXIST) { - Serial.println("Peer Exists"); - } else { - Serial.println("Not sure what happened"); - } - delay(100); - } - } - } else { - // No slave found to process - Serial.println("No Slave found to process"); - } -} - - -uint8_t data = 0; -// send data -void sendData() { - data++; - for (int i = 0; i < SlaveCnt; i++) { - const uint8_t *peer_addr = slaves[i].peer_addr; - if (i == 0) { // print only for first slave - Serial.print("Sending: "); - Serial.println(data); - } - esp_err_t result = esp_now_send(peer_addr, &data, sizeof(data)); - Serial.print("Send Status: "); - if (result == ESP_OK) { - Serial.println("Success"); - } else if (result == ESP_ERR_ESPNOW_NOT_INIT) { - // How did we get so far!! - Serial.println("ESPNOW not Init."); - } else if (result == ESP_ERR_ESPNOW_ARG) { - Serial.println("Invalid Argument"); - } else if (result == ESP_ERR_ESPNOW_INTERNAL) { - Serial.println("Internal Error"); - } else if (result == ESP_ERR_ESPNOW_NO_MEM) { - Serial.println("ESP_ERR_ESPNOW_NO_MEM"); - } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) { - Serial.println("Peer not found."); - } else { - Serial.println("Not sure what happened"); - } - delay(100); - } -} - -// callback when data is sent from Master to Slave -void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { - char macStr[18]; - snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", - mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); - Serial.print("Last Packet Sent to: "); Serial.println(macStr); - Serial.print("Last Packet Send Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); -} - -void setup() { - Serial.begin(115200); - //Set device in STA mode to begin with - WiFi.mode(WIFI_STA); - Serial.println("ESPNow/Multi-Slave/Master Example"); - // This is the mac address of the Master in Station Mode - Serial.print("STA MAC: "); Serial.println(WiFi.macAddress()); - // Init ESPNow with a fallback logic - InitESPNow(); - // Once ESPNow is successfully Init, we will register for Send CB to - // get the status of Trasnmitted packet - esp_now_register_send_cb(OnDataSent); -} - -void loop() { - // In the loop we scan for slave - ScanForSlave(); - // If Slave is found, it would be populate in `slave` variable - // We will check if `slave` is defined and then we proceed further - if (SlaveCnt > 0) { // check if slave channel is defined - // `slave` is defined - // Add slave as peer if it has not been added already - manageSlave(); - // pair success or already paired - // Send data to device - sendData(); - } else { - // No slave found to process - } - - // wait for 3seconds to run the logic again - delay(1000); -} diff --git a/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/.skip.esp32h2 b/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/.skip.esp32h2 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/ESPNow_MultiSlave_Slave.ino b/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/ESPNow_MultiSlave_Slave.ino deleted file mode 100644 index ad3b94037c3..00000000000 --- a/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/ESPNow_MultiSlave_Slave.ino +++ /dev/null @@ -1,94 +0,0 @@ -/** - ESPNOW - Basic communication - Slave - Date: 26th September 2017 - Author: Arvind Ravulavaru - Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves - Description: This sketch consists of the code for the Slave module. - Resources: (A bit outdated) - a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf - b. http://www.esploradores.com/practica-6-conexion-esp-now/ - - << This Device Slave >> - - Flow: Master - Step 1 : ESPNow Init on Master and set it in STA mode - Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) - Step 3 : Once found, add Slave as peer - Step 4 : Register for send callback - Step 5 : Start Transmitting data from Master to Slave(s) - - Flow: Slave - Step 1 : ESPNow Init on Slave - Step 2 : Update the SSID of Slave with a prefix of `slave` - Step 3 : Set Slave in AP mode - Step 4 : Register for receive callback and wait for data - Step 5 : Once data arrives, print it in the serial monitor - - Note: Master and Slave have been defined to easily understand the setup. - Based on the ESPNOW API, there is no concept of Master and Slave. - Any devices can act as master or salve. -*/ - -#include -#include - -#define CHANNEL 1 - -// Init ESP Now with fallback -void InitESPNow() { - WiFi.disconnect(); - if (esp_now_init() == ESP_OK) { - Serial.println("ESPNow Init Success"); - } - else { - Serial.println("ESPNow Init Failed"); - // Retry InitESPNow, add a counte and then restart? - // InitESPNow(); - // or Simply Restart - ESP.restart(); - } -} - -// config AP SSID -void configDeviceAP() { - String Prefix = "Slave:"; - String Mac = WiFi.macAddress(); - String SSID = Prefix + Mac; - String Password = "123456789"; - bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL, 0); - if (!result) { - Serial.println("AP Config failed."); - } else { - Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID)); - } -} - -void setup() { - Serial.begin(115200); - Serial.println("ESPNow/Basic/Slave Example"); - //Set device in AP mode to begin with - WiFi.mode(WIFI_AP); - // configure device AP mode - configDeviceAP(); - // This is the mac address of the Slave in AP Mode - Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); - // Init ESPNow with a fallback logic - InitESPNow(); - // Once ESPNow is successfully Init, we will register for recv CB to - // get recv packer info. - esp_now_register_recv_cb(OnDataRecv); -} - -// callback when data is recv from Master -void OnDataRecv(const esp_now_recv_info_t * info, const uint8_t *data, int data_len) { - char macStr[18]; - snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", - info->src_addr[0], info->src_addr[1], info->src_addr[2], info->src_addr[3], info->src_addr[4], info->src_addr[5]); - Serial.print("Last Packet Recv from: "); Serial.println(macStr); - Serial.print("Last Packet Recv Data: "); Serial.println(*data); - Serial.println(""); -} - -void loop() { - // Chill -} From c435a7fa767dba2a46651163aca0d12925b5c152 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 29 Mar 2024 17:19:26 -0300 Subject: [PATCH 23/37] Fix example --- .../ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino index 773c39def79..fdac6cf3a51 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino @@ -46,9 +46,7 @@ ESP_NOW_Peer_Class::ESP_NOW_Peer_Class(const uint8_t *mac_addr, const uint8_t *lmk) : ESP_NOW_Peer(mac_addr, channel, iface, lmk) {} // Destructor of the class -ESP_NOW_Peer_Class::~ESP_NOW_Peer_Class() { - remove(); -} +ESP_NOW_Peer_Class::~ESP_NOW_Peer_Class() {} // Function to register the master peer bool ESP_NOW_Peer_Class::add_peer() { From 6ad83cffa276597721a2c4434e0e4be62b25552b Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 29 Mar 2024 19:50:23 -0300 Subject: [PATCH 24/37] Add network example --- .../ESP_NOW_Network/ESP_NOW_Network.ino | 371 ++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino new file mode 100644 index 00000000000..71e167b6560 --- /dev/null +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino @@ -0,0 +1,371 @@ +/* + ESP-NOW Network Example + Lucas Saavedra Vaz - 2024 + + This example is based on the ESP-NOW example from the ESP-IDF framework. + + The aim of this example is to demonstrate how to create a network of devices using the ESP-NOW protocol. + The slave devices will broadcast random data to the master device every 5 seconds and from time to time + they will ping the other slave devices with a "Hello!" message. + + The master device will receive the data from the slave devices and print it to the Serial Monitor. From time + to time, the master device will calculate the average of the priorities of the slave devices and send it to + all the slave devices. + + Each device will have a priority that will be used to decide which device will be the master. + The device with the highest priority will be the master. + + Flow: + 1. Each device will generate a priority based on its MAC address. + 2. The devices will broadcast their priority on the network. + 3. The devices will listen to the broadcast messages and register the priorities of the other devices. + 4. After all devices have been registered, the device with the highest priority will be the master. + 5. The slave devices will send random data to the master every 5 seconds. + - Every "REPORT_INTERVAL" messages, the slaves will send a message to the other slaves. + 6. The master device will calculate the average of the data and send it to the slave devices every "REPORT_INTERVAL" messages. + +*/ + +#include "ESP32_NOW.h" +#include "WiFi.h" + +#include // For the MAC2STR and MACSTR macros + +#include +#include + +/* Definitions */ + +// Wi-Fi interface to be used by the ESP-NOW protocol +#define ESPNOW_WIFI_IFACE WIFI_IF_STA + +// Channel to be used by the ESP-NOW protocol +#define ESPNOW_WIFI_CHANNEL 4 + +// Delay between sending messages +#define ESPNOW_SEND_INTERVAL_MS 5000 + +// Number of peers to wait for (excluding this device) +#define ESPNOW_PEER_COUNT 2 + +// Report to other devices every 5 messages +#define REPORT_INTERVAL 5 + +/* + ESP-NOW uses the CCMP method, which is described in IEEE Std. 802.11-2012, to protect the vendor-specific action frame. + The Wi-Fi device maintains a Primary Master Key (PMK) and several Local Master Keys (LMK). + The lengths of both PMK and LMK need to be 16 bytes. + + PMK is used to encrypt LMK with the AES-128 algorithm. If PMK is not set, a default PMK will be used. + + LMK of the paired device is used to encrypt the vendor-specific action frame with the CCMP method. + The maximum number of different LMKs is six. If the LMK of the paired device is not set, the vendor-specific + action frame will not be encrypted. + + Encrypting multicast (broadcast address) vendor-specific action frame is not supported. + + PMK needs to be the same for all devices in the network. LMK only needs to be the same between paired devices. +*/ + +// Primary Master Key (PMK) and Local Master Key (LMK) +#define ESPNOW_EXAMPLE_PMK "pmk1234567890123" +#define ESPNOW_EXAMPLE_LMK "lmk1234567890123" + +/* Structs */ + +// The following struct is used to send data to the peer device. +// We use the attribute "packed" to ensure that the struct is not padded (all data +// is contiguous in the memory and without gaps). +// The maximum size of the complete message is 250 bytes (ESP_NOW_MAX_DATA_LEN). + +typedef struct { + uint32_t count; + uint32_t priority; + uint32_t data; + char str[7]; +} __attribute__((packed)) esp_now_data_t; + +/* Global Variables */ + +uint32_t self_priority = 0; // Priority of this device +uint8_t current_peer_count = 0; // Number of peers that have been found +uint8_t check_count = 0; // Counter to wait after all peers have been found +bool device_is_master = false; // Flag to indicate if this device is the master +bool master_decided = false; // Flag to indicate if the master has been decided +uint32_t sent_msg_count = 0; // Counter for the messages sent. Only starts counting after all peers have been found +uint32_t recv_msg_count = 0; // Counter for the messages received. Only starts counting after all peers have been found +esp_now_data_t new_msg; // Message that will be sent to the peers +std::vector last_data(5); // Vector that will store the last 5 data received + +/* Classes */ + +// We need to create a class that inherits from ESP_NOW_Peer to implement the _onReceive and _onSent methods. +// This class will be used to store the priority of the device and to send messages to the peers. +// For more information about the ESP_NOW_Peer class, see the ESP_NOW_Peer class in the ESP32_NOW.h file. + +class ESP_NOW_Network_Peer : public ESP_NOW_Peer { +public: + uint32_t priority; + bool peer_is_master = false; + + // Revert the lmk later + ESP_NOW_Network_Peer(const uint8_t *mac_addr, uint32_t priority = 0, const uint8_t *lmk = nullptr); + ~ESP_NOW_Network_Peer(); + + bool begin(); + bool send_message(const uint8_t *data, size_t len); + + // ESP_NOW_Peer interfaces + void _onReceive(const uint8_t *data, size_t len, bool broadcast); + void _onSent(bool success); +}; + +/* Methods */ + +ESP_NOW_Network_Peer::ESP_NOW_Network_Peer(const uint8_t *mac_addr, uint32_t priority, const uint8_t *lmk) + : ESP_NOW_Peer(mac_addr, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IFACE, lmk) + , priority(priority) {} + +ESP_NOW_Network_Peer::~ESP_NOW_Network_Peer() {} + +bool ESP_NOW_Network_Peer::begin() { + // In this example the ESP-NOW protocol will already be initialized as we require it to receive broadcast messages. + if (!add()) { + log_e("Failed to initialize ESP-NOW or register the peer"); + return false; + } + return true; +} + +bool ESP_NOW_Network_Peer::send_message(const uint8_t *data, size_t len) { + if (data == NULL || len == 0) { + log_e("Data to be sent is NULL or has a length of 0"); + return false; + } + + // Call the parent class method to send the data + return send(data, len); +} + +void ESP_NOW_Network_Peer::_onReceive(const uint8_t *data, size_t len, bool broadcast) { + if (!broadcast) { + esp_now_data_t *msg = (esp_now_data_t *)data; + recv_msg_count++; + if (device_is_master) { + Serial.printf("Received a message from peer " MACSTR "\n", MAC2STR(addr())); + Serial.printf(" Count: %lu\n", msg->count); + Serial.printf(" Random data: %lu\n", msg->data); + last_data.push_back(msg->data); + last_data.erase(last_data.begin()); + } else if (peer_is_master) { + Serial.println("Received a message from the master"); + Serial.printf(" Average data: %lu\n", msg->data); + } + else { + Serial.printf("Peer " MACSTR " says: %s\n", MAC2STR(addr()), msg->str); + } + } +} + +void ESP_NOW_Network_Peer::_onSent(bool success) { + bool broadcast = memcmp(addr(), ESP_NOW.BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0; + if (broadcast) { + log_v("Broadcast message reported as sent %s", success ? "successfully" : "unsuccessfully"); + } + else { + log_v("Unicast message reported as sent %s to peer " MACSTR, success ? "successfully" : "unsuccessfully", MAC2STR(addr())); + } +} + +/* Peers */ + +std::vector peers; // Create a vector to store the peer pointers +ESP_NOW_Network_Peer broadcast_peer(ESP_NOW.BROADCAST_ADDR, 0, NULL); // Register the broadcast peer (no encryption support for the broadcast address) +ESP_NOW_Network_Peer *master_peer = nullptr; // Pointer to peer that is the master + +/* Helper functions */ + +// Function to reboot the device +void fail_reboot() { + Serial.println("Rebooting in 5 seconds..."); + delay(5000); + ESP.restart(); +} + +// Function to check which device has the highest priority +uint32_t check_highest_priority() { + uint32_t highest_priority = 0; + for (auto &peer : peers) { + if (peer->priority > highest_priority) { + highest_priority = peer->priority; + } + } + return std::max(highest_priority, self_priority); +} + +// Function to calculate the average of the data received +uint32_t calc_average() { + uint32_t avg = 0; + for (auto &d : last_data) { + avg += d; + } + avg /= last_data.size(); + return avg; +} + +/* Callbacks */ + +// Callback called when a new peer is found +void register_new_peer(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg) { + esp_now_data_t *msg = (esp_now_data_t *)data; + int priority = msg->priority; + + if (priority == self_priority) { + Serial.println("ERROR! Device has the same priority as this device"); + fail_reboot(); + } + + if (current_peer_count < ESPNOW_PEER_COUNT) { + Serial.printf("New peer found: " MACSTR " with priority %d\n", MAC2STR(info->src_addr), priority); + ESP_NOW_Network_Peer *new_peer = new ESP_NOW_Network_Peer(info->src_addr, priority); + if (!new_peer->begin()) { + Serial.println("Failed to create the new peer"); + delete new_peer; + return; + } + peers.push_back(new_peer); + if (!peers.back()->begin()) { + Serial.println("Failed to register the new peer"); + peers.pop_back(); + return; + } + current_peer_count++; + if (current_peer_count == ESPNOW_PEER_COUNT) { + Serial.println("All peers have been found"); + Serial.println("Broadcasting the priority 3 more times to ensure that all devices have received it"); + } + } +} + +/* Main */ + +void setup() { + uint8_t self_mac[6]; + + Serial.begin(115200); + while (!Serial) delay(10); + + Serial.println("ESP-NOW Network Example"); + Serial.println("Wi-Fi parameters:"); + Serial.println(" Mode: STA"); + Serial.println(" MAC Address: " + WiFi.macAddress()); + Serial.printf(" Channel: %d\n", ESPNOW_WIFI_CHANNEL); + + // Initialize the Wi-Fi module + WiFi.mode(WIFI_STA); + WiFi.setChannel(ESPNOW_WIFI_CHANNEL); + + // Generate yhis device's priority based on the 3 last bytes of the MAC address + WiFi.macAddress(self_mac); + self_priority = self_mac[3] << 16 | self_mac[4] << 8 | self_mac[5]; + Serial.printf("This device's priority: %lu\n", self_priority); + + // Initialize the ESP-NOW protocol + if (!ESP_NOW.begin((const uint8_t *)ESPNOW_EXAMPLE_PMK)) { + Serial.println("Failed to initialize ESP-NOW"); + fail_reboot(); + } + + if (!broadcast_peer.begin()) { + Serial.println("Failed to initialize broadcast peer"); + fail_reboot(); + } + + // Register the callback to be called when a new peer is found + ESP_NOW.onNewPeer(register_new_peer, NULL); + + Serial.println("Setup complete. Broadcasting own priority to find the master..."); + memset(&new_msg, 0, sizeof(new_msg)); + strncpy(new_msg.str, "Hello!", sizeof(new_msg.str)); + new_msg.priority = self_priority; +} + +void loop() { + if (!master_decided) { + // Broadcast the priority to find the master + if (!broadcast_peer.send_message((const uint8_t *)&new_msg, sizeof(new_msg))) { + Serial.println("Failed to broadcast message"); + } + + // Check if all peers have been found + if (current_peer_count == ESPNOW_PEER_COUNT) { + // Transmit the priority 3 more times to ensure that all devices have received it + if (check_count >= 3) { + // Check which device has the highest priority + master_decided = true; + uint32_t highest_priority = check_highest_priority(); + if (highest_priority == self_priority) { + device_is_master = true; + Serial.println("This device is the master"); + } else { + for (int i = 0; i < ESPNOW_PEER_COUNT; i++) { + if (peers[i]->priority == highest_priority) { + peers[i]->peer_is_master = true; + master_peer = peers[i]; + Serial.printf("Peer " MACSTR " is the master with priority %lu\n", MAC2STR(peers[i]->addr()), highest_priority); + break; + } + } + } + Serial.println("The master has been decided"); + } else { + Serial.printf("%d...\n", check_count + 1); + check_count++; + } + } + } else { + if (!device_is_master) { + // Send a message to the master + new_msg.count = sent_msg_count + 1; + new_msg.data = random(10000); + if (!master_peer->send_message((const uint8_t *)&new_msg, sizeof(new_msg))) { + Serial.println("Failed to send message to the master"); + } else { + Serial.printf("Sent message to the master. Count: %lu, Data: %lu\n", new_msg.count, new_msg.data); + sent_msg_count++; + } + + // Check if it is time to report to peers + if (sent_msg_count % REPORT_INTERVAL == 0) { + // Send a message to the peers + for (auto &peer : peers) { + if (!peer->peer_is_master) { + if (!peer->send_message((const uint8_t *)&new_msg, sizeof(new_msg))) { + Serial.printf("Failed to send message to peer " MACSTR "\n", MAC2STR(peer->addr())); + } else { + Serial.printf("Sent message \"%s\" to peer " MACSTR "\n", new_msg.str, MAC2STR(peer->addr())); + } + } + } + } + } else { + // Check if it is time to report to peers + if (recv_msg_count % REPORT_INTERVAL == 0) { + // Report average data to the peers + uint32_t avg = calc_average(); + new_msg.count = sent_msg_count + 1; + new_msg.data = avg; + for (auto &peer : peers) { + if (!peer->send_message((const uint8_t *)&new_msg, sizeof(new_msg))) { + Serial.printf("Failed to send message to peer " MACSTR "\n", MAC2STR(peer->addr())); + } else { + Serial.printf("Sent message to peer " MACSTR ". Recv: %lu, Sent: %lu, Avg: %lu\n", MAC2STR(peer->addr()), recv_msg_count, new_msg.count, new_msg.data); + sent_msg_count++; + } + } + } + } + } + + delay(ESPNOW_SEND_INTERVAL_MS); +} From c0b2042b8415c8b5e9e663211cb5c6dbe57aa255 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 29 Mar 2024 19:56:53 -0300 Subject: [PATCH 25/37] Add skip file --- libraries/ESP_NOW/examples/ESP_NOW_Network/.skip.esp32h2 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 libraries/ESP_NOW/examples/ESP_NOW_Network/.skip.esp32h2 diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/.skip.esp32h2 b/libraries/ESP_NOW/examples/ESP_NOW_Network/.skip.esp32h2 new file mode 100644 index 00000000000..e69de29bb2d From 4085a2f49236534f6c6fb2b8cbb94ccb50e3e054 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 29 Mar 2024 20:03:30 -0300 Subject: [PATCH 26/37] Add LMK back --- libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino index 71e167b6560..0b2cc286cf0 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino @@ -108,8 +108,7 @@ public: uint32_t priority; bool peer_is_master = false; - // Revert the lmk later - ESP_NOW_Network_Peer(const uint8_t *mac_addr, uint32_t priority = 0, const uint8_t *lmk = nullptr); + ESP_NOW_Network_Peer(const uint8_t *mac_addr, uint32_t priority = 0, const uint8_t *lmk = (const uint8_t *)ESPNOW_EXAMPLE_LMK); ~ESP_NOW_Network_Peer(); bool begin(); From f7278fa8619d82a3afe6c0c75f6d4a9b86ee356f Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Fri, 29 Mar 2024 20:05:11 -0300 Subject: [PATCH 27/37] Add logs --- libraries/ESP_NOW/src/ESP32_NOW.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp index 2098eb5b529..db4bc35ac64 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -114,7 +114,11 @@ static void _esp_now_rx_cb(const esp_now_recv_info_t *info, const uint8_t *data, } //find the peer and call it's callback for(uint8_t i=0; iaddr())); + } if(_esp_now_peers[i] != NULL && memcmp(info->src_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0){ + log_v("Calling _onReceive"); _esp_now_peers[i]->_onReceive(data, len, broadcast); return; } From 6f6e88992dce64c16654593af8c266223275f3da Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 1 Apr 2024 10:14:50 -0300 Subject: [PATCH 28/37] Improve example --- .../ESP_NOW_Network/ESP_NOW_Network.ino | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino index 0b2cc286cf0..c9849537ea3 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino @@ -31,7 +31,6 @@ #include // For the MAC2STR and MACSTR macros -#include #include /* Definitions */ @@ -82,6 +81,7 @@ typedef struct { uint32_t count; uint32_t priority; uint32_t data; + bool ready; char str[7]; } __attribute__((packed)) esp_now_data_t; @@ -89,7 +89,6 @@ typedef struct { uint32_t self_priority = 0; // Priority of this device uint8_t current_peer_count = 0; // Number of peers that have been found -uint8_t check_count = 0; // Counter to wait after all peers have been found bool device_is_master = false; // Flag to indicate if this device is the master bool master_decided = false; // Flag to indicate if the master has been decided uint32_t sent_msg_count = 0; // Counter for the messages sent. Only starts counting after all peers have been found @@ -107,6 +106,7 @@ class ESP_NOW_Network_Peer : public ESP_NOW_Peer { public: uint32_t priority; bool peer_is_master = false; + bool peer_ready = false; ESP_NOW_Network_Peer(const uint8_t *mac_addr, uint32_t priority = 0, const uint8_t *lmk = (const uint8_t *)ESPNOW_EXAMPLE_LMK); ~ESP_NOW_Network_Peer(); @@ -147,8 +147,14 @@ bool ESP_NOW_Network_Peer::send_message(const uint8_t *data, size_t len) { } void ESP_NOW_Network_Peer::_onReceive(const uint8_t *data, size_t len, bool broadcast) { + esp_now_data_t *msg = (esp_now_data_t *)data; + + if (peer_ready == false && msg->ready == true) { + Serial.printf("Peer " MACSTR " reported ready\n", MAC2STR(addr())); + peer_ready = true; + } + if (!broadcast) { - esp_now_data_t *msg = (esp_now_data_t *)data; recv_msg_count++; if (device_is_master) { Serial.printf("Received a message from peer " MACSTR "\n", MAC2STR(addr())); @@ -212,6 +218,16 @@ uint32_t calc_average() { return avg; } +// Function to check if all peers are ready +bool check_all_peers_ready() { + for (auto &peer : peers) { + if (!peer->peer_ready) { + return false; + } + } + return true; +} + /* Callbacks */ // Callback called when a new peer is found @@ -220,28 +236,23 @@ void register_new_peer(const esp_now_recv_info_t *info, const uint8_t *data, int int priority = msg->priority; if (priority == self_priority) { - Serial.println("ERROR! Device has the same priority as this device"); + Serial.println("ERROR! Device has the same priority as this device. Unsupported behavior."); fail_reboot(); } if (current_peer_count < ESPNOW_PEER_COUNT) { Serial.printf("New peer found: " MACSTR " with priority %d\n", MAC2STR(info->src_addr), priority); ESP_NOW_Network_Peer *new_peer = new ESP_NOW_Network_Peer(info->src_addr, priority); - if (!new_peer->begin()) { - Serial.println("Failed to create the new peer"); + if (new_peer == nullptr || !new_peer->begin()) { + Serial.println("Failed to create or register the new peer"); delete new_peer; return; } peers.push_back(new_peer); - if (!peers.back()->begin()) { - Serial.println("Failed to register the new peer"); - peers.pop_back(); - return; - } current_peer_count++; if (current_peer_count == ESPNOW_PEER_COUNT) { Serial.println("All peers have been found"); - Serial.println("Broadcasting the priority 3 more times to ensure that all devices have received it"); + new_msg.ready = true; } } } @@ -298,8 +309,9 @@ void loop() { // Check if all peers have been found if (current_peer_count == ESPNOW_PEER_COUNT) { - // Transmit the priority 3 more times to ensure that all devices have received it - if (check_count >= 3) { + // Wait until all peers are ready + if (check_all_peers_ready()) { + Serial.println("All peers are ready"); // Check which device has the highest priority master_decided = true; uint32_t highest_priority = check_highest_priority(); @@ -318,8 +330,7 @@ void loop() { } Serial.println("The master has been decided"); } else { - Serial.printf("%d...\n", check_count + 1); - check_count++; + Serial.println("Waiting for all peers to be ready..."); } } } else { From 705b1eecb2b33bdf147f3fca77fe896b7a2d478d Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Mon, 1 Apr 2024 11:11:00 -0300 Subject: [PATCH 29/37] Fix example --- libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino index c9849537ea3..37852dbb262 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino @@ -363,9 +363,9 @@ void loop() { if (recv_msg_count % REPORT_INTERVAL == 0) { // Report average data to the peers uint32_t avg = calc_average(); - new_msg.count = sent_msg_count + 1; new_msg.data = avg; for (auto &peer : peers) { + new_msg.count = sent_msg_count + 1; if (!peer->send_message((const uint8_t *)&new_msg, sizeof(new_msg))) { Serial.printf("Failed to send message to peer " MACSTR "\n", MAC2STR(peer->addr())); } else { From 5fe5f7763548c28503fc7abdea6ca2ce49d16415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Tue, 2 Apr 2024 12:24:08 +0200 Subject: [PATCH 30/37] Apply @suglider suggestions from code review Co-authored-by: Rodrigo Garcia --- libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index 364ffe47bd2..6d71aa147e4 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -27,10 +27,10 @@ ESP_NOW_Serial_Class::~ESP_NOW_Serial_Class(){ size_t ESP_NOW_Serial_Class::setTxBufferSize(size_t tx_queue_len){ if(tx_ring_buf){ - if(!tx_queue_len){ - vRingbufferDelete(tx_ring_buf); - tx_ring_buf = NULL; - } + vRingbufferDelete(tx_ring_buf); + tx_ring_buf = NULL; + } + if(!tx_queue_len){ return 0; } tx_ring_buf = xRingbufferCreate(tx_queue_len, RINGBUF_TYPE_BYTEBUF); @@ -42,10 +42,10 @@ size_t ESP_NOW_Serial_Class::setTxBufferSize(size_t tx_queue_len){ size_t ESP_NOW_Serial_Class::setRxBufferSize(size_t rx_queue_len){ if(rx_queue){ - if(!rx_queue_len){ - vQueueDelete(rx_queue); - rx_queue = NULL; - } + vQueueDelete(rx_queue); + rx_queue = NULL; + } + if(!rx_queue_len){ return 0; } rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); From 901706729d231d7c225e4269e234c73279243537 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:05:18 +0200 Subject: [PATCH 31/37] Add documentation --- docs/en/api/espnow.rst | 274 ++++++++++++++++++++++++++++-- libraries/ESP_NOW/src/ESP32_NOW.h | 1 - 2 files changed, 260 insertions(+), 15 deletions(-) diff --git a/docs/en/api/espnow.rst b/docs/en/api/espnow.rst index e6c5328c188..6b9f32e4f73 100644 --- a/docs/en/api/espnow.rst +++ b/docs/en/api/espnow.rst @@ -2,29 +2,275 @@ ESP-NOW ####### -ESP-NOW is a fast, connectionless communication technology featuring a short packet transmission. +About +----- + +ESP-NOW is a communication protocol designed for low-power, low-latency, and high-throughput communication between ESP32 devices without the need for an access point (AP). +It is ideal for scenarios where devices need to communicate directly with each other in a local network. ESP-NOW is ideal for smart lights, remote control devices, sensors and other applications. -.. note:: This is a work in progress project and this section is still missing. If you want to contribute, please see the `Contributions Guide <../contributing.html>`_. +This library provides an easy-to-use interface for setting up ESP-NOW communication, adding and removing peers, and sending and receiving data packets. + +Arduino-ESP32 ESP-NOW API +------------------------- + +ESP-NOW Class +************* + +The `ESP_NOW_Class` is the main class used for managing ESP-NOW communication. + +begin +^^^^^ + +Initialize the ESP-NOW communication. This function must be called before using any other ESP-NOW functionalities. + +.. code-block:: cpp + + bool begin(const uint8_t *pmk = NULL); + +* ``pmk``: Optional. Pass the pairwise master key (PMK) if encryption is enabled. + +Returns ``true`` if initialization is successful, ``false`` otherwise. + +end +^^^ + +End the ESP-NOW communication. This function releases all resources used by the ESP-NOW library. + +.. code-block:: cpp + + bool end(); + +Returns ``true`` if the operation is successful, ``false`` otherwise. + +getTotalPeerCount +^^^^^^^^^^^^^^^^^ + +Get the total number of peers currently added. + +.. code-block:: cpp + + int getTotalPeerCount(); + +Returns the total number of peers, or ``-1`` if an error occurs. + +getEncryptedPeerCount +^^^^^^^^^^^^^^^^^^^^^ + +Get the number of peers using encryption. + +.. code-block:: cpp + + int getEncryptedPeerCount(); + +Returns the number of peers using encryption, or ``-1`` if an error occurs. + +onNewPeer +^^^^^^^^^ + +You can register a callback function to handle incoming data from new peers using the `onNewPeer` function. + +.. code-block:: cpp + + void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg), void *arg); + +* ``cb``: Pointer to the callback function. +* ``arg``: Optional. Pointer to user-defined argument to be passed to the callback function. + +``cb`` function signature: + +.. code-block:: cpp + + void cb(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg); + +``info``: Information about the received packet. +``data``: Pointer to the received data. +``len``: Length of the received data. +``arg``: User-defined argument passed to the callback function. + +ESP-NOW Peer Class +****************** + +The `ESP_NOW_Peer` class represents a peer device in the ESP-NOW network. + +Constructor +^^^^^^^^^^^ + +Create an instance of the `ESP_NOW_Peer` class. + +.. code-block:: cpp + + ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk); + +* ``mac_addr``: MAC address of the peer device. +* ``channel``: Communication channel. +* ``iface``: WiFi interface. +* ``lmk``: Optional. Pass the local master key (LMK) if encryption is enabled. + +add +^^^ + +Add the peer to the ESP-NOW network. + +.. code-block:: cpp + + bool add(); + +Returns ``true`` if the peer is added successfully, ``false`` otherwise. + +remove +^^^^^^ + +Remove the peer from the ESP-NOW network. + +.. code-block:: cpp + + bool remove(); + +Returns ``true`` if the peer is removed successfully, ``false`` otherwise. + +send +^^^^ + +Send data to the peer. + +.. code-block:: cpp + + size_t send(const uint8_t *data, int len); + +* ``data``: Pointer to the data to be sent. +* ``len``: Length of the data in bytes. + +Returns the number of bytes sent, or ``0`` if an error occurs. + +addr +^^^^ + +Get the MAC address of the peer. + +.. code-block:: cpp + + const uint8_t * addr() const; + +Returns a pointer to the MAC address. + +addr +^^^^ + +Set the MAC address of the peer. + +.. code-block:: cpp + + void addr(const uint8_t *mac_addr); + +* ``mac_addr``: MAC address of the peer. + +getChannel +^^^^^^^^^^ + +Get the communication channel of the peer. + +.. code-block:: cpp + + uint8_t getChannel() const; + +Returns the communication channel. + +setChannel +^^^^^^^^^^ + +Set the communication channel of the peer. + +.. code-block:: cpp + + void setChannel(uint8_t channel); + +* ``channel``: Communication channel. + +getInterface +^^^^^^^^^^^^ + +Get the WiFi interface of the peer. + +.. code-block:: cpp + + wifi_interface_t getInterface() const; + +Returns the WiFi interface. + +setInterface +^^^^^^^^^^^^ + +Set the WiFi interface of the peer. + +.. code-block:: cpp + + void setInterface(wifi_interface_t iface); + +* ``iface``: WiFi interface. + +isEncrypted +^^^^^^^^^^^ + +Check if the peer is using encryption. + +.. code-block:: cpp + + bool isEncrypted() const; + +Returns ``true`` if the peer is using encryption, ``false`` otherwise. + +setKey +^^^^^^ + +Set the local master key (LMK) for the peer. + +.. code-block:: cpp + + void setKey(const uint8_t *lmk); + +* ``lmk``: Local master key. + +_onReceive +^^^^^^^^^^ + +Callback function to handle incoming data from the peer, must be implemented by the upper class. + +.. code-block:: cpp + + void _onReceive(const uint8_t *data, int len, bool broadcast); + +* ``data``: Pointer to the received data. +* ``len``: Length of the received data. +* ``broadcast``: ``true`` if the data is broadcasted, ``false`` otherwise. + +_onSent +^^^^^^^ + +Callback function to handle the completion of sending data to the peer, must be implemented by the upper class. + +.. code-block:: cpp + + void _onSent(bool success); + +* ``success``: ``true`` if the data is sent successfully, ``false`` otherwise. Examples -------- -ESP-NOW Master -************** +Set of 2 examples of the ESP-NOW library to send and receive data between multiple ESP32 devices (1 master, multiple slaves). -.. literalinclude:: ../../../libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/ESPNow_Basic_Master.ino - :language: arduino +1. ESP-NOW Broadcast Master Example: -ESP-NOW Slave -************* +.. literalinclude:: libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino + :language: cpp -.. literalinclude:: ../../../libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino - :language: arduino +2. ESP-NOW Broadcast Slave Example: -Resources ---------- +.. literalinclude:: libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino + :language: cpp -* `ESP-NOW`_ (User Guide) +Example of the ESP-NOW Serial library to send and receive data between 2 ESP32 devices using the serial port: -.. _ESP-NOW: https://www.espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf +.. literalinclude:: libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino + :language: cpp diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h index f70d1339b86..dead3d5bb3a 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.h +++ b/libraries/ESP_NOW/src/ESP32_NOW.h @@ -60,7 +60,6 @@ class ESP_NOW_Class : public Print { void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t * data, int len, void * arg), void * arg); - //TODO: Add function to set peer rate - esp_now_set_peer_rate_config() }; extern ESP_NOW_Class ESP_NOW; From 2b43448803fd5abd8b0dc88c881d1d77a77a7a40 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:28:06 +0200 Subject: [PATCH 32/37] fix examples links in docs --- docs/en/api/espnow.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/api/espnow.rst b/docs/en/api/espnow.rst index 6b9f32e4f73..1a1ed901b20 100644 --- a/docs/en/api/espnow.rst +++ b/docs/en/api/espnow.rst @@ -262,15 +262,15 @@ Set of 2 examples of the ESP-NOW library to send and receive data between multip 1. ESP-NOW Broadcast Master Example: -.. literalinclude:: libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino +.. literalinclude:: ../../../libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino :language: cpp 2. ESP-NOW Broadcast Slave Example: -.. literalinclude:: libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino +.. literalinclude:: ../../../libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino :language: cpp Example of the ESP-NOW Serial library to send and receive data between 2 ESP32 devices using the serial port: -.. literalinclude:: libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino +.. literalinclude:: ../../../libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino :language: cpp From fc7616e5749a01ed9b0e4a4228ba8a06887ec5e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Tue, 2 Apr 2024 19:41:16 +0200 Subject: [PATCH 33/37] Apply @lucasssvaz suggestions to docs Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> --- docs/en/api/espnow.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/en/api/espnow.rst b/docs/en/api/espnow.rst index 1a1ed901b20..9efc34704d0 100644 --- a/docs/en/api/espnow.rst +++ b/docs/en/api/espnow.rst @@ -91,7 +91,7 @@ You can register a callback function to handle incoming data from new peers usin ESP-NOW Peer Class ****************** -The `ESP_NOW_Peer` class represents a peer device in the ESP-NOW network. +The `ESP_NOW_Peer` class represents a peer device in the ESP-NOW network. It is an abstract class that must be inherited by a child class that properly handles the peer connections and implements the `_onReceive` and `_onSent` methods. Constructor ^^^^^^^^^^^ @@ -234,7 +234,7 @@ Set the local master key (LMK) for the peer. _onReceive ^^^^^^^^^^ -Callback function to handle incoming data from the peer, must be implemented by the upper class. +Callback function to handle incoming data from the peer. This is a pure virtual method that must be implemented by the upper class. .. code-block:: cpp @@ -247,7 +247,7 @@ Callback function to handle incoming data from the peer, must be implemented by _onSent ^^^^^^^ -Callback function to handle the completion of sending data to the peer, must be implemented by the upper class. +Callback function to handle the completion of sending data to the peer. This is a pure virtual method that must be implemented by the upper class. .. code-block:: cpp @@ -258,7 +258,7 @@ Callback function to handle the completion of sending data to the peer, must be Examples -------- -Set of 2 examples of the ESP-NOW library to send and receive data between multiple ESP32 devices (1 master, multiple slaves). +Set of 2 examples of the ESP-NOW library to send and receive data using broadcast messages between multiple ESP32 devices (multiple masters, multiple slaves). 1. ESP-NOW Broadcast Master Example: @@ -270,7 +270,7 @@ Set of 2 examples of the ESP-NOW library to send and receive data between multip .. literalinclude:: ../../../libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino :language: cpp -Example of the ESP-NOW Serial library to send and receive data between 2 ESP32 devices using the serial port: +Example of the ESP-NOW Serial library to send and receive data as a stream between 2 ESP32 devices using the serial monitor: .. literalinclude:: ../../../libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino :language: cpp From 14f19be74e0dbe88260eed8372b1440f1433a390 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:03:04 +0200 Subject: [PATCH 34/37] Update espnow.rst --- docs/en/api/espnow.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/api/espnow.rst b/docs/en/api/espnow.rst index 9efc34704d0..89438395a53 100644 --- a/docs/en/api/espnow.rst +++ b/docs/en/api/espnow.rst @@ -7,7 +7,7 @@ About ESP-NOW is a communication protocol designed for low-power, low-latency, and high-throughput communication between ESP32 devices without the need for an access point (AP). It is ideal for scenarios where devices need to communicate directly with each other in a local network. -ESP-NOW is ideal for smart lights, remote control devices, sensors and other applications. +ESP-NOW can be used for smart lights, remote control devices, sensors and many other applications. This library provides an easy-to-use interface for setting up ESP-NOW communication, adding and removing peers, and sending and receiving data packets. From ad193aeb88673268155658105b4305566521717a Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Date: Wed, 3 Apr 2024 08:52:11 -0300 Subject: [PATCH 35/37] Update examples --- .../ESP_NOW_Broadcast_Master.ino | 74 +++++------- .../ESP_NOW_Broadcast_Slave.ino | 63 +++++------ .../ESP_NOW_Network/ESP_NOW_Network.ino | 106 ++++++++---------- 3 files changed, 104 insertions(+), 139 deletions(-) diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino index 523bebd1fc4..33a47342b2c 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino @@ -26,56 +26,44 @@ class ESP_NOW_Broadcast_Peer : public ESP_NOW_Peer { public: - ESP_NOW_Broadcast_Peer(uint8_t channel, wifi_interface_t iface, const uint8_t *lmk); - ~ESP_NOW_Broadcast_Peer(); + // Constructor of the class using the broadcast address + ESP_NOW_Broadcast_Peer(uint8_t channel, wifi_interface_t iface, const uint8_t *lmk) + : ESP_NOW_Peer(ESP_NOW.BROADCAST_ADDR, channel, iface, lmk) {} - bool begin(); - bool send_message(const uint8_t *data, size_t len); - - // ESP_NOW_Peer interfaces - void _onReceive(const uint8_t *data, size_t len, bool broadcast); - void _onSent(bool success); -}; - -/* Methods */ - -// Constructor of the class using the broadcast address -ESP_NOW_Broadcast_Peer::ESP_NOW_Broadcast_Peer(uint8_t channel, wifi_interface_t iface, const uint8_t *lmk) - : ESP_NOW_Peer(ESP_NOW.BROADCAST_ADDR, channel, iface, lmk) {} - -// Destructor of the class -ESP_NOW_Broadcast_Peer::~ESP_NOW_Broadcast_Peer() { - remove(); -} + // Destructor of the class + ~ESP_NOW_Broadcast_Peer() { + remove(); + } -// Function to properly initialize the ESP-NOW and register the broadcast peer -bool ESP_NOW_Broadcast_Peer::begin() { - if (!ESP_NOW.begin() || !add()) { - log_e("Failed to initialize ESP-NOW or register the broadcast peer"); - return false; + // Function to properly initialize the ESP-NOW and register the broadcast peer + bool begin() { + if (!ESP_NOW.begin() || !add()) { + log_e("Failed to initialize ESP-NOW or register the broadcast peer"); + return false; + } + return true; } - return true; -} -// Function to send a message to all devices within the network -bool ESP_NOW_Broadcast_Peer::send_message(const uint8_t *data, size_t len) { - if (!send(data, len)) { - log_e("Failed to broadcast message"); - return false; + // Function to send a message to all devices within the network + bool send_message(const uint8_t *data, size_t len) { + if (!send(data, len)) { + log_e("Failed to broadcast message"); + return false; + } + return true; } - return true; -} -void ESP_NOW_Broadcast_Peer::_onReceive(const uint8_t *data, size_t len, bool broadcast) { - // The broadcast peer will never receive any data. Rather, it will only send data. - // Data broadcasted will be received by the actual object of the peer that made the broadcast. - // It is still required to be implemented because it is a pure virtual method. -} + void _onReceive(const uint8_t *data, size_t len, bool broadcast) { + // The broadcast peer will never receive any data. Rather, it will only send data. + // Data broadcasted will be received by the actual object of the peer that made the broadcast. + // It is still required to be implemented because it is a pure virtual method. + } -void ESP_NOW_Broadcast_Peer::_onSent(bool success) { - // As broadcast messages does not require any acknowledgment, this method will never be called. - // It is still required to be implemented because it is a pure virtual method. -} + void _onSent(bool success) { + // As broadcast messages does not require any acknowledgment, this method will never be called. + // It is still required to be implemented because it is a pure virtual method. + } +}; /* Global Variables */ diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino index fdac6cf3a51..f2c6f2c260a 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino @@ -27,46 +27,35 @@ class ESP_NOW_Peer_Class : public ESP_NOW_Peer { public: - ESP_NOW_Peer_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk); - ~ESP_NOW_Peer_Class(); - - bool add_peer(); - - // ESP_NOW_Peer interfaces - void _onReceive(const uint8_t *data, size_t len, bool broadcast); - void _onSent(bool success); -}; - -/* Methods */ - -// Constructor of the class -ESP_NOW_Peer_Class::ESP_NOW_Peer_Class(const uint8_t *mac_addr, - uint8_t channel, - wifi_interface_t iface, - const uint8_t *lmk) : ESP_NOW_Peer(mac_addr, channel, iface, lmk) {} - -// Destructor of the class -ESP_NOW_Peer_Class::~ESP_NOW_Peer_Class() {} - -// Function to register the master peer -bool ESP_NOW_Peer_Class::add_peer() { - if (!add()) { - log_e("Failed to register the broadcast peer"); - return false; + // Constructor of the class + ESP_NOW_Peer_Class(const uint8_t *mac_addr, + uint8_t channel, + wifi_interface_t iface, + const uint8_t *lmk) : ESP_NOW_Peer(mac_addr, channel, iface, lmk) {} + + // Destructor of the class + ~ESP_NOW_Peer_Class() {} + + // Function to register the master peer + bool add_peer() { + if (!add()) { + log_e("Failed to register the broadcast peer"); + return false; + } + return true; } - return true; -} -// Function to print the received messages from the master -void ESP_NOW_Peer_Class::_onReceive(const uint8_t *data, size_t len, bool broadcast) { - Serial.printf("Received a message from master " MACSTR " (%s)\n", MAC2STR(addr()), broadcast ? "broadcast" : "unicast"); - Serial.printf(" Message: %s\n", (char *)data); -} + // Function to print the received messages from the master + void _onReceive(const uint8_t *data, size_t len, bool broadcast) { + Serial.printf("Received a message from master " MACSTR " (%s)\n", MAC2STR(addr()), broadcast ? "broadcast" : "unicast"); + Serial.printf(" Message: %s\n", (char *)data); + } -void ESP_NOW_Peer_Class::_onSent(bool success) { - // In this example the slave will never send any data, so this method will never be called. - // It is still required to be implemented because it is a pure virtual method. -} + void _onSent(bool success) { + // In this example the slave will never send any data, so this method will never be called. + // It is still required to be implemented because it is a pure virtual method. + } +}; /* Global Variables */ diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino index 37852dbb262..59b56d509fa 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino @@ -108,79 +108,67 @@ public: bool peer_is_master = false; bool peer_ready = false; - ESP_NOW_Network_Peer(const uint8_t *mac_addr, uint32_t priority = 0, const uint8_t *lmk = (const uint8_t *)ESPNOW_EXAMPLE_LMK); - ~ESP_NOW_Network_Peer(); + ESP_NOW_Network_Peer(const uint8_t *mac_addr, uint32_t priority = 0, const uint8_t *lmk = (const uint8_t *)ESPNOW_EXAMPLE_LMK) + : ESP_NOW_Peer(mac_addr, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IFACE, lmk) + , priority(priority) {} - bool begin(); - bool send_message(const uint8_t *data, size_t len); + ~ESP_NOW_Network_Peer() {} - // ESP_NOW_Peer interfaces - void _onReceive(const uint8_t *data, size_t len, bool broadcast); - void _onSent(bool success); -}; - -/* Methods */ - -ESP_NOW_Network_Peer::ESP_NOW_Network_Peer(const uint8_t *mac_addr, uint32_t priority, const uint8_t *lmk) - : ESP_NOW_Peer(mac_addr, ESPNOW_WIFI_CHANNEL, ESPNOW_WIFI_IFACE, lmk) - , priority(priority) {} - -ESP_NOW_Network_Peer::~ESP_NOW_Network_Peer() {} - -bool ESP_NOW_Network_Peer::begin() { - // In this example the ESP-NOW protocol will already be initialized as we require it to receive broadcast messages. - if (!add()) { - log_e("Failed to initialize ESP-NOW or register the peer"); - return false; + bool begin() { + // In this example the ESP-NOW protocol will already be initialized as we require it to receive broadcast messages. + if (!add()) { + log_e("Failed to initialize ESP-NOW or register the peer"); + return false; + } + return true; } - return true; -} -bool ESP_NOW_Network_Peer::send_message(const uint8_t *data, size_t len) { - if (data == NULL || len == 0) { - log_e("Data to be sent is NULL or has a length of 0"); - return false; + bool send_message(const uint8_t *data, size_t len) { + if (data == NULL || len == 0) { + log_e("Data to be sent is NULL or has a length of 0"); + return false; + } + + // Call the parent class method to send the data + return send(data, len); } - // Call the parent class method to send the data - return send(data, len); -} + void _onReceive(const uint8_t *data, size_t len, bool broadcast) { + esp_now_data_t *msg = (esp_now_data_t *)data; -void ESP_NOW_Network_Peer::_onReceive(const uint8_t *data, size_t len, bool broadcast) { - esp_now_data_t *msg = (esp_now_data_t *)data; + if (peer_ready == false && msg->ready == true) { + Serial.printf("Peer " MACSTR " reported ready\n", MAC2STR(addr())); + peer_ready = true; + } - if (peer_ready == false && msg->ready == true) { - Serial.printf("Peer " MACSTR " reported ready\n", MAC2STR(addr())); - peer_ready = true; + if (!broadcast) { + recv_msg_count++; + if (device_is_master) { + Serial.printf("Received a message from peer " MACSTR "\n", MAC2STR(addr())); + Serial.printf(" Count: %lu\n", msg->count); + Serial.printf(" Random data: %lu\n", msg->data); + last_data.push_back(msg->data); + last_data.erase(last_data.begin()); + } else if (peer_is_master) { + Serial.println("Received a message from the master"); + Serial.printf(" Average data: %lu\n", msg->data); + } + else { + Serial.printf("Peer " MACSTR " says: %s\n", MAC2STR(addr()), msg->str); + } + } } - if (!broadcast) { - recv_msg_count++; - if (device_is_master) { - Serial.printf("Received a message from peer " MACSTR "\n", MAC2STR(addr())); - Serial.printf(" Count: %lu\n", msg->count); - Serial.printf(" Random data: %lu\n", msg->data); - last_data.push_back(msg->data); - last_data.erase(last_data.begin()); - } else if (peer_is_master) { - Serial.println("Received a message from the master"); - Serial.printf(" Average data: %lu\n", msg->data); + void _onSent(bool success) { + bool broadcast = memcmp(addr(), ESP_NOW.BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0; + if (broadcast) { + log_v("Broadcast message reported as sent %s", success ? "successfully" : "unsuccessfully"); } else { - Serial.printf("Peer " MACSTR " says: %s\n", MAC2STR(addr()), msg->str); + log_v("Unicast message reported as sent %s to peer " MACSTR, success ? "successfully" : "unsuccessfully", MAC2STR(addr())); } } -} - -void ESP_NOW_Network_Peer::_onSent(bool success) { - bool broadcast = memcmp(addr(), ESP_NOW.BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0; - if (broadcast) { - log_v("Broadcast message reported as sent %s", success ? "successfully" : "unsuccessfully"); - } - else { - log_v("Unicast message reported as sent %s to peer " MACSTR, success ? "successfully" : "unsuccessfully", MAC2STR(addr())); - } -} +}; /* Peers */ From 51ce71f9c372087bdd7f5a47e27d1b5943b438c1 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:35:17 +0200 Subject: [PATCH 36/37] make onSent optional and remove underscores for virtual functions --- docs/en/api/espnow.rst | 10 +++++----- .../ESP_NOW_Broadcast_Master.ino | 7 +------ .../examples/ESP_NOW_Network/ESP_NOW_Network.ino | 4 ++-- libraries/ESP_NOW/src/ESP32_NOW.cpp | 6 +++--- libraries/ESP_NOW/src/ESP32_NOW.h | 7 +++++-- libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp | 4 ++-- libraries/ESP_NOW/src/ESP32_NOW_Serial.h | 4 ++-- 7 files changed, 20 insertions(+), 22 deletions(-) diff --git a/docs/en/api/espnow.rst b/docs/en/api/espnow.rst index 89438395a53..0dfe81a27b6 100644 --- a/docs/en/api/espnow.rst +++ b/docs/en/api/espnow.rst @@ -231,27 +231,27 @@ Set the local master key (LMK) for the peer. * ``lmk``: Local master key. -_onReceive +onReceive ^^^^^^^^^^ Callback function to handle incoming data from the peer. This is a pure virtual method that must be implemented by the upper class. .. code-block:: cpp - void _onReceive(const uint8_t *data, int len, bool broadcast); + void onReceive(const uint8_t *data, int len, bool broadcast); * ``data``: Pointer to the received data. * ``len``: Length of the received data. * ``broadcast``: ``true`` if the data is broadcasted, ``false`` otherwise. -_onSent +onSent ^^^^^^^ -Callback function to handle the completion of sending data to the peer. This is a pure virtual method that must be implemented by the upper class. +Optional callback function to handle the completion of sending data to the peer. This is a pure virtual method that must be implemented by the upper class. .. code-block:: cpp - void _onSent(bool success); + void onSent(bool success); * ``success``: ``true`` if the data is sent successfully, ``false`` otherwise. diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino index 33a47342b2c..8a4d838cced 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino @@ -53,16 +53,11 @@ public: return true; } - void _onReceive(const uint8_t *data, size_t len, bool broadcast) { + void onReceive(const uint8_t *data, size_t len, bool broadcast) { // The broadcast peer will never receive any data. Rather, it will only send data. // Data broadcasted will be received by the actual object of the peer that made the broadcast. // It is still required to be implemented because it is a pure virtual method. } - - void _onSent(bool success) { - // As broadcast messages does not require any acknowledgment, this method will never be called. - // It is still required to be implemented because it is a pure virtual method. - } }; /* Global Variables */ diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino index 59b56d509fa..33dfc6334de 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino @@ -133,7 +133,7 @@ public: return send(data, len); } - void _onReceive(const uint8_t *data, size_t len, bool broadcast) { + void onReceive(const uint8_t *data, size_t len, bool broadcast) { esp_now_data_t *msg = (esp_now_data_t *)data; if (peer_ready == false && msg->ready == true) { @@ -159,7 +159,7 @@ public: } } - void _onSent(bool success) { + void onSent(bool success) { bool broadcast = memcmp(addr(), ESP_NOW.BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0; if (broadcast) { log_v("Broadcast message reported as sent %s", success ? "successfully" : "unsuccessfully"); diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp index db4bc35ac64..f1ffa79da7b 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -118,8 +118,8 @@ static void _esp_now_rx_cb(const esp_now_recv_info_t *info, const uint8_t *data, log_v("Checking peer " MACSTR, MAC2STR(_esp_now_peers[i]->addr())); } if(_esp_now_peers[i] != NULL && memcmp(info->src_addr, _esp_now_peers[i]->addr(), ESP_NOW_ETH_ALEN) == 0){ - log_v("Calling _onReceive"); - _esp_now_peers[i]->_onReceive(data, len, broadcast); + log_v("Calling onReceive"); + _esp_now_peers[i]->onReceive(data, len, broadcast); return; } } @@ -130,7 +130,7 @@ static void _esp_now_tx_cb(const uint8_t *mac_addr, esp_now_send_status_t status //find the peer and call it's callback for(uint8_t i=0; iaddr(), ESP_NOW_ETH_ALEN) == 0){ - _esp_now_peers[i]->_onSent(status == ESP_NOW_SEND_SUCCESS); + _esp_now_peers[i]->onSent(status == ESP_NOW_SEND_SUCCESS); return; } } diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h index dead3d5bb3a..b5d87fecaee 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.h +++ b/libraries/ESP_NOW/src/ESP32_NOW.h @@ -3,6 +3,7 @@ #include "esp_wifi_types.h" #include "Print.h" #include "esp_now.h" +#include "esp32-hal-log.h" class ESP_NOW_Peer { private: @@ -37,8 +38,10 @@ class ESP_NOW_Peer { operator bool() const; //must be implemented by the upper class - virtual void _onReceive(const uint8_t * data, size_t len, bool broadcast) = 0; - virtual void _onSent(bool success) = 0; + virtual void onReceive(const uint8_t * data, size_t len, bool broadcast) = 0; + + //optional callback + virtual void onSent(bool success) { log_v("Message reported as sent %s", success ? "successfully" : "unsuccessfully"); } }; class ESP_NOW_Class : public Print { diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp index 6d71aa147e4..b562b893258 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp @@ -140,7 +140,7 @@ void ESP_NOW_Serial_Class::flush(){ } //RX callback -void ESP_NOW_Serial_Class::_onReceive(const uint8_t * data, size_t len, bool broadcast){ +void ESP_NOW_Serial_Class::onReceive(const uint8_t * data, size_t len, bool broadcast){ if(rx_queue == NULL){ return; } @@ -241,7 +241,7 @@ size_t ESP_NOW_Serial_Class::write(const uint8_t *buffer, size_t size, uint32_t return size; } //TX Done Callback -void ESP_NOW_Serial_Class::_onSent(bool success){ +void ESP_NOW_Serial_Class::onSent(bool success){ log_v(MACSTR" : %s", MAC2STR(addr()), success?"OK":"FAIL"); if(tx_sem == NULL || tx_ring_buf == NULL || !added){ return; diff --git a/libraries/ESP_NOW/src/ESP32_NOW_Serial.h b/libraries/ESP_NOW/src/ESP32_NOW_Serial.h index 6877fbc1c6b..a2f97948682 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW_Serial.h +++ b/libraries/ESP_NOW/src/ESP32_NOW_Serial.h @@ -39,8 +39,8 @@ class ESP_NOW_Serial_Class : public Stream, public ESP_NOW_Peer { size_t write(const uint8_t *buffer, size_t size){ return write(buffer, size, 1000); } size_t write(uint8_t data){ return write(&data, 1); } //ESP_NOW_Peer - void _onReceive(const uint8_t * data, size_t len, bool broadcast); - void _onSent(bool success); + void onReceive(const uint8_t * data, size_t len, bool broadcast); + void onSent(bool success); }; From 55a6193e618acdbc1d8a746195dd22cebb309157 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:27:59 +0200 Subject: [PATCH 37/37] Make onRecieve also optional and make constructor protected --- docs/en/api/espnow.rst | 4 ++-- .../ESP_NOW_Broadcast_Master.ino | 8 +------- .../ESP_NOW_Broadcast_Slave.ino | 7 +------ .../examples/ESP_NOW_Network/ESP_NOW_Network.ino | 2 +- libraries/ESP_NOW/src/ESP32_NOW.cpp | 1 - libraries/ESP_NOW/src/ESP32_NOW.h | 14 ++++++++------ 6 files changed, 13 insertions(+), 23 deletions(-) diff --git a/docs/en/api/espnow.rst b/docs/en/api/espnow.rst index 0dfe81a27b6..48472881599 100644 --- a/docs/en/api/espnow.rst +++ b/docs/en/api/espnow.rst @@ -234,7 +234,7 @@ Set the local master key (LMK) for the peer. onReceive ^^^^^^^^^^ -Callback function to handle incoming data from the peer. This is a pure virtual method that must be implemented by the upper class. +Callback function to handle incoming data from the peer. This is a virtual method can be implemented by the upper class for custom handling. .. code-block:: cpp @@ -247,7 +247,7 @@ Callback function to handle incoming data from the peer. This is a pure virtual onSent ^^^^^^^ -Optional callback function to handle the completion of sending data to the peer. This is a pure virtual method that must be implemented by the upper class. +Callback function to handle the completion of sending data to the peer. This is a virtual method can be implemented by the upper class for custom handling. .. code-block:: cpp diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino index 8a4d838cced..e3e9e62386d 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Master/ESP_NOW_Broadcast_Master.ino @@ -22,7 +22,7 @@ /* Classes */ -// Create a new class that inherits from the ESP_NOW_Peer class is required to implement the _onReceive and _onSent methods. +// Creating a new class that inherits from the ESP_NOW_Peer class is required. class ESP_NOW_Broadcast_Peer : public ESP_NOW_Peer { public: @@ -52,12 +52,6 @@ public: } return true; } - - void onReceive(const uint8_t *data, size_t len, bool broadcast) { - // The broadcast peer will never receive any data. Rather, it will only send data. - // Data broadcasted will be received by the actual object of the peer that made the broadcast. - // It is still required to be implemented because it is a pure virtual method. - } }; /* Global Variables */ diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino index f2c6f2c260a..ac553bdceff 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Broadcast_Slave/ESP_NOW_Broadcast_Slave.ino @@ -23,7 +23,7 @@ /* Classes */ -// Create a new class that inherits from the ESP_NOW_Peer class is required to implement the _onReceive and _onSent methods. +// Creating a new class that inherits from the ESP_NOW_Peer class is required. class ESP_NOW_Peer_Class : public ESP_NOW_Peer { public: @@ -50,11 +50,6 @@ public: Serial.printf("Received a message from master " MACSTR " (%s)\n", MAC2STR(addr()), broadcast ? "broadcast" : "unicast"); Serial.printf(" Message: %s\n", (char *)data); } - - void _onSent(bool success) { - // In this example the slave will never send any data, so this method will never be called. - // It is still required to be implemented because it is a pure virtual method. - } }; /* Global Variables */ diff --git a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino index 33dfc6334de..2c72921ea2b 100644 --- a/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino +++ b/libraries/ESP_NOW/examples/ESP_NOW_Network/ESP_NOW_Network.ino @@ -98,7 +98,7 @@ std::vector last_data(5); // Vector that will store the last 5 data r /* Classes */ -// We need to create a class that inherits from ESP_NOW_Peer to implement the _onReceive and _onSent methods. +// We need to create a class that inherits from ESP_NOW_Peer and implement the _onReceive and _onSent methods. // This class will be used to store the priority of the device and to send messages to the peers. // For more information about the ESP_NOW_Peer class, see the ESP_NOW_Peer class in the ESP32_NOW.h file. diff --git a/libraries/ESP_NOW/src/ESP32_NOW.cpp b/libraries/ESP_NOW/src/ESP32_NOW.cpp index f1ffa79da7b..3e2329e7a8c 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.cpp +++ b/libraries/ESP_NOW/src/ESP32_NOW.cpp @@ -2,7 +2,6 @@ #include #include "esp_system.h" #include "esp32-hal.h" -#include "esp_mac.h" #include "esp_wifi.h" static void (*new_cb)(const esp_now_recv_info_t *info, const uint8_t * data, int len, void * arg) = NULL; diff --git a/libraries/ESP_NOW/src/ESP32_NOW.h b/libraries/ESP_NOW/src/ESP32_NOW.h index b5d87fecaee..5ad26df574f 100644 --- a/libraries/ESP_NOW/src/ESP32_NOW.h +++ b/libraries/ESP_NOW/src/ESP32_NOW.h @@ -4,6 +4,7 @@ #include "Print.h" #include "esp_now.h" #include "esp32-hal-log.h" +#include "esp_mac.h" class ESP_NOW_Peer { private: @@ -19,8 +20,9 @@ class ESP_NOW_Peer { bool remove(); size_t send(const uint8_t * data, int len); -public: ESP_NOW_Peer(const uint8_t *mac_addr, uint8_t channel=0, wifi_interface_t iface=WIFI_IF_AP, const uint8_t *lmk=NULL); + +public: virtual ~ESP_NOW_Peer() {} const uint8_t * addr() const; @@ -37,11 +39,11 @@ class ESP_NOW_Peer { operator bool() const; - //must be implemented by the upper class - virtual void onReceive(const uint8_t * data, size_t len, bool broadcast) = 0; - - //optional callback - virtual void onSent(bool success) { log_v("Message reported as sent %s", success ? "successfully" : "unsuccessfully"); } + //optional callbacks to be implemented by the upper class + virtual void onReceive(const uint8_t * data, size_t len, bool broadcast) { + log_i("Received %d bytes from " MACSTR " %s", len, MAC2STR(mac), broadcast ? "broadcast" : ""); + } + virtual void onSent(bool success) { log_i("Message reported as sent %s", success ? "successfully" : "unsuccessfully"); } }; class ESP_NOW_Class : public Print {