feat(esp_now): Add support for ESP NOW V2 (#11524)

* feat(esp_now): Add support for ESP NOW V2

* fix(esp_now): Return -1 on error
This commit is contained in:
Lucas Saavedra Vaz 2025-06-30 06:02:12 -03:00 committed by GitHub
parent 9a35d9455f
commit 6754b1962c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 98 additions and 15 deletions

View file

@ -86,6 +86,8 @@ void setup() {
ESP.restart();
}
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
Serial.println("Setup complete. Broadcasting messages every 5 seconds.");
}

View file

@ -104,6 +104,8 @@ void setup() {
ESP.restart();
}
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
// Register the new peer callback
ESP_NOW.onNewPeer(register_new_master, nullptr);

View file

@ -75,7 +75,12 @@
// 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).
// The maximum size of the payload is 250 bytes (ESP_NOW_MAX_DATA_LEN) for ESP-NOW v1.0.
// For ESP-NOW v2.0, the maximum size of the payload is 1470 bytes (ESP_NOW_MAX_DATA_LEN_V2).
// You can use ESP_NOW.getMaxDataLen() after calling ESP_NOW.begin() to get the maximum size
// of the data that can be sent.
// Read about the compatibility between ESP-NOW v1.0 and v2.0 in the ESP-IDF documentation:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html#frame-format
typedef struct {
uint32_t count;
@ -276,6 +281,8 @@ void setup() {
fail_reboot();
}
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
if (!broadcast_peer.begin()) {
Serial.println("Failed to initialize broadcast peer");
fail_reboot();

View file

@ -64,6 +64,7 @@ void setup() {
// Start the ESP-NOW communication
Serial.println("ESP-NOW communication starting...");
NowSerial.begin(115200);
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
Serial.println("You can now send data to the peer device using the Serial Monitor.\n");
}

View file

@ -140,7 +140,10 @@ static void _esp_now_tx_cb(const uint8_t *mac_addr, esp_now_send_status_t status
}
}
ESP_NOW_Class::ESP_NOW_Class() {}
ESP_NOW_Class::ESP_NOW_Class() {
max_data_len = 0;
version = 0;
}
ESP_NOW_Class::~ESP_NOW_Class() {}
@ -155,6 +158,23 @@ bool ESP_NOW_Class::begin(const uint8_t *pmk) {
return false;
}
// Unfortunately we can't get the ESP-NOW version before initializing the Wi-Fi
uint32_t esp_now_version;
err = esp_now_get_version(&esp_now_version);
if (err != ESP_OK) {
log_w("esp_now_get_version failed! Assuming ESP-NOW v1.0");
esp_now_version = 1;
}
if (esp_now_version == 1) {
max_data_len = ESP_NOW_MAX_DATA_LEN;
} else {
max_data_len = ESP_NOW_MAX_DATA_LEN_V2;
}
version = esp_now_version;
log_i("ESP-NOW version: %lu, max_data_len: %lu", version, max_data_len);
_esp_now_has_begun = true;
memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM);
@ -212,7 +232,7 @@ bool ESP_NOW_Class::end() {
return true;
}
int ESP_NOW_Class::getTotalPeerCount() {
int ESP_NOW_Class::getTotalPeerCount() const {
if (!_esp_now_has_begun) {
return -1;
}
@ -225,7 +245,7 @@ int ESP_NOW_Class::getTotalPeerCount() {
return num.total_num;
}
int ESP_NOW_Class::getEncryptedPeerCount() {
int ESP_NOW_Class::getEncryptedPeerCount() const {
if (!_esp_now_has_begun) {
return -1;
}
@ -238,16 +258,38 @@ int ESP_NOW_Class::getEncryptedPeerCount() {
return num.encrypt_num;
}
int ESP_NOW_Class::getMaxDataLen() const {
if (max_data_len == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the max data length.");
return -1;
}
return max_data_len;
}
int ESP_NOW_Class::getVersion() const {
if (version == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the version.");
return -1;
}
return version;
}
int ESP_NOW_Class::availableForWrite() {
return ESP_NOW_MAX_DATA_LEN;
int available = getMaxDataLen();
if (available < 0) {
return 0;
}
return available;
}
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;
if (len > max_data_len) {
len = max_data_len;
}
esp_err_t result = esp_now_send(nullptr, data, len);
if (result == ESP_OK) {
@ -386,8 +428,15 @@ size_t ESP_NOW_Peer::send(const uint8_t *data, int len) {
log_e("Peer not added.");
return 0;
}
if (len > ESP_NOW_MAX_DATA_LEN) {
len = ESP_NOW_MAX_DATA_LEN;
int max_data_len = ESP_NOW.getMaxDataLen();
if (max_data_len < 0) {
log_e("Error getting max data length.");
return 0;
}
if (len > max_data_len) {
len = max_data_len;
}
esp_err_t result = esp_now_send(mac, data, len);
if (result == ESP_OK) {

View file

@ -23,8 +23,10 @@ public:
bool begin(const uint8_t *pmk = nullptr /* 16 bytes */);
bool end();
int getTotalPeerCount();
int getEncryptedPeerCount();
int getTotalPeerCount() const;
int getEncryptedPeerCount() const;
int getMaxDataLen() const;
int getVersion() const;
int availableForWrite();
size_t write(const uint8_t *data, size_t len);
@ -34,6 +36,10 @@ public:
void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg), void *arg);
bool removePeer(ESP_NOW_Peer &peer);
protected:
size_t max_data_len;
uint32_t version;
};
class ESP_NOW_Peer {

View file

@ -70,8 +70,25 @@ bool ESP_NOW_Serial_Class::begin(unsigned long baud) {
//xSemaphoreTake(tx_sem, 0);
xSemaphoreGive(tx_sem);
}
setRxBufferSize(1024); //default if not preset
setTxBufferSize(1024); //default if not preset
size_t buf_size = 0;
if (ESP_NOW.getVersion() == 2) {
// ESP-NOW v2.0 has a larger maximum data length, so we need to increase the buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(4096);
buf_size &= setTxBufferSize(4096);
} else {
// ESP-NOW v1.0 has a smaller maximum data length, so we can use the default buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(1024);
buf_size &= setTxBufferSize(1024);
}
if (buf_size == 0) {
log_e("Failed to set buffer size");
return false;
}
return true;
}
@ -164,7 +181,6 @@ void ESP_NOW_Serial_Class::onReceive(const uint8_t *data, size_t len, bool broad
//Print
int ESP_NOW_Serial_Class::availableForWrite() {
//return ESP_NOW_MAX_DATA_LEN;
if (tx_ring_buf == nullptr) {
return 0;
}
@ -189,7 +205,7 @@ bool ESP_NOW_Serial_Class::checkForTxData() {
//do we have something that failed the last time?
resend_count = 0;
if (queued_buff == nullptr) {
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW_MAX_DATA_LEN);
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW.getMaxDataLen());
} else {
log_d(MACSTR " : PREVIOUS", MAC2STR(addr()));
}