Properly capturing multiple ESP32 data from ESP-NOW receiver

I have managed to get data from an ESP32 board setup as a receiver for ESP32 senders connected to receiver via ESP-NOW. I'm testing a bunch of ways to use that data thru relays and LEDs connected to the receiver and it looks like the data overlaps or is not received like if I have ESP32 sender 2 and 3, there would be times I only receive ESP32 sender 2 data for a number of seconds before I received data from ESP32 sender 3. I have already tried changing the delay rate of each board to not be the same but the problem persist.

Is there a way to mitigate this issue?

Sender code:

/* Sender */

#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>  // Include this library for esp_wifi_set_channel

// Define the structure for the message
typedef struct struct_message {
    char a[32];
    int b;
    float c = 0;
    bool d;
} struct_message;

// Define the receiver's MAC address (replace with the correct address)
uint8_t receiverAddress[] = {0xE8, 0x6B, 0xEA, 0xCF, 0xE3, 0xF0};  // Replace with the correct MAC address

// Create a message structure
struct_message myData;

// Channel for ESP-NOW
// const int CHANNEL = 1;

// Wi-Fi credentials
const char* ssid = "HOMEWIFI"; //This is a dummy ssid
const char* password = "password"; //This is a dummy password

int32_t getWiFiChannel(const char *ssid) {
  if (int32_t n = WiFi.scanNetworks()) {
      for (uint8_t i=0; i<n; i++) {
          if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
              return WiFi.channel(i);
          }
      }
  }
  return 0;
}

void setup() {
    Serial.begin(115200);  // Initialize serial communication

    // Initialize Wi-Fi in STA mode
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

    // Check if Wi-Fi is connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    Serial.println(WiFi.localIP());  // Print the IP address assigned to the ESP32

    // // Set the Wi-Fi channel
    // esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
    // Serial.print("Wi-Fi Channel set to: ");
    // Serial.println(CHANNEL);

   // Set the Wi-Fi channel
    int32_t channel = getWiFiChannel(ssid);

    WiFi.printDiag(Serial); // Uncomment to verify channel number before
    esp_wifi_set_promiscuous(true);
    esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
    esp_wifi_set_promiscuous(false);
    WiFi.printDiag(Serial); // Uncomment to verify channel change after

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // Register the send callback function
    esp_now_register_send_cb(OnDataSent);

    // Initialize peer information
    esp_now_peer_info_t peerInfo;
    memset(&peerInfo, 0, sizeof(peerInfo));  // Clear the peerInfo structure
    memcpy(peerInfo.peer_addr, receiverAddress, 6);  // Copy the receiver's MAC address
    // peerInfo.channel = CHANNEL;
    peerInfo.encrypt = false;

    // Add peer to the ESP-NOW peer list
    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("Peer added successfully");
}

void loop() {
    // Prepare data to send
    strcpy(myData.a, "Hello from sender");
    myData.b = random(1, 20);
    myData.c += 1;
    myData.d = false;

    // Send data via ESP-NOW
    esp_err_t result = esp_now_send(receiverAddress, (uint8_t *)&myData, sizeof(myData));

    if (result == ESP_OK) {
        Serial.println("Sent with success");
    } else {
        Serial.println("Error sending the data");
    }

    delay(2000);
}

// Callback function when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
    Serial.print("\r\nLast Packet Send Status: ");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

Receiver code:

/* Receiver */

#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>  // Include this library for esp_wifi_set_channel
#include <WebServer.h>  // Include WebServer library

// Define the structure for the message
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} struct_message;

// Create a message structure to hold incoming data
struct_message incomingData;

// Channel for ESP-NOW
const int CHANNEL = 6;

// Create a web server object on port 80
WebServer server(80);

// Variable to hold received data as a string for web display
String receivedData = "";

// Wi-Fi credentials
const char* ssid = "HOMEWIFI"; //This is a dummy ssid
const char* password = "password"; //This is a dummy password 

void setup() {
    Serial.begin(115200);  // Initialize serial communication at a baud rate of 115200

    // Initialize Wi-Fi in STA (station) mode
    WiFi.mode(WIFI_AP_STA);
    WiFi.begin(ssid, password);  // Connect to the Wi-Fi network

    // Check if Wi-Fi is connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    Serial.println(WiFi.localIP());  // Print the IP address assigned to the ESP32

    // Set the Wi-Fi channel to match the ESP-NOW communication channel
    esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);  // Set the Wi-Fi channel
    Serial.print("Wi-Fi Channel set to: ");
    Serial.println(CHANNEL);

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // Register the receive callback function
    esp_now_register_recv_cb(OnDataRecv);

    // Start the web server
    server.on("/", handleRoot);  // Define the root URL handler
    server.begin();  // Start the web server
    Serial.println("Web server started");
}

void loop() {
    server.handleClient();  // Handle incoming web requests
}

// Callback function when data is received via ESP-NOW
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
    // Cast the incoming data to the structure type
    struct_message* data = (struct_message*)incomingData;

    Serial.print("Bytes received: ");
    Serial.println(len);
    Serial.print("String: ");
    Serial.println(data->a);  // Correctly access struct members
    Serial.print("Int: ");
    Serial.println(data->b);
    Serial.print("Float: ");
    Serial.println(data->c);
    Serial.print("Bool: ");
    Serial.println(data->d);

    // Store received data as a string for web display
    receivedData = "String: " + String(data->a) + "\n" +
                   "Int: " + String(data->b) + "\n" +
                   "Float: " + String(data->c) + "\n" +
                   "Bool: " + String(data->d);

    // Print sender's MAC address
    char macStr[18];
    snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    Serial.print("From MAC address: ");
    Serial.println(macStr);
}

// Handle root URL
void handleRoot() {
    server.send(200, "text/plain", receivedData);  // Send the received data as a plain text response
}

the receiver could poll each transmitter in turn for data
also have a look at ESP-MESH

With the code I have now, what can I do to do this polling process? any clues?

add a random delay on the senders so the packages don't interfere.

Do you mean like the delay is something like "delay = random(1000,1600)"

  1. each transmitter code has a nodeID
  2. the receiver polls each nodeID in turn for data
  3. when a transmitter receives a polling packet with its nodeID it transmits data

e.g. a receiver polling three nodes - it uses multicast to transmit the polling packet

// ESP-NOW receive a structure using polling

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <WiFi.h>

// multicast address for polling transmitters
uint8_t broadcastAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
//uint8_t broadcastAddress[] = { 0xD4, 0x8A, 0xFC, 0xC6, 0xC6, 0x74 };

esp_now_peer_info_t peerInfo;

// test structure
struct __attribute__((packed)) Data {
  byte NodeID;  // ID of transmitting node
  int16_t seq;  // sequence number
  int32_t distance;
  float voltage;
  char text[50];
} struct1;

// used for polling
byte nodeIDs[] = { 1, 2, 3 };       // list of nodeIDs to poll
byte polledOK[] = { 2, 2, 2 };      // indicate polling sucess/failure
int seqNumbers[] = { 0, 0, 0, 0 };  // sequence number check
int nodeIndex = 0;                  // index into above arrays
int errors = 0;
int seqErrors = 0;

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  Serial.println("ESP-NOW receive a structure polled version");
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  Serial.print("ESP32 Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  // Add peer
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }
  // Once ESPNow is successfully Init, we will register for recv CB to get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
  checkIfPacketReceived();  // if packet received process it
  pollNextSlave();          // check if time to poll next node
}

// ************* poll next slave node for data  ? ****************
void pollNextSlave(void) {
  static unsigned long timer = 0;       // used to time polling
  if (millis() - timer < 5000) return;  // check if time to poll next node
  timer = millis();                     // poll next slave - reset timer for next poll
  if (--polledOK[nodeIndex] == 0) {     // did last receive response?
    Serial.print("Node failed to respond to polling ID = ");
    Serial.println(nodeIDs[nodeIndex]);
    polledOK[nodeIndex] = 1;
  }
  Serial.print("polling ID = ");  // poll next node
  Serial.println(nodeIDs[nodeIndex]);
  //Serial.println(nodeIndex);
  esp_now_send(broadcastAddress, (uint8_t *)&nodeIDs[nodeIndex], sizeof(nodeIDs[0]));  // poll next transmitter
  if (++nodeIndex >= sizeof(nodeIDs)) nodeIndex = 0;
}

volatile int packetReceived = 0;  // set when packet received

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
  packetReceived = len;        // indicate packet received
  if (len == sizeof(struct1))  // if valid length copy packet
    memcpy((void *)&struct1, (void *)incomingData, len);
}

// called to check if packet has been received - if so process it
void checkIfPacketReceived(void) {
  if (!packetReceived) return;  // if no packet has been received return
  Serial.print("packet received size ");
  Serial.print(packetReceived);
  if (packetReceived != sizeof(struct1)) {
    Serial.printf("ERROR! packet size expected %d receive %d errors %d\n", sizeof(struct1), packetReceived, ++errors);
    return;
  }
  Serial.print(" from Node ");  // display packet contents
  Serial.print(struct1.NodeID);
  Serial.print(" seq number ");
  Serial.print(struct1.seq);
  Serial.print(" distance 1 = ");
  Serial.print(struct1.distance);
  Serial.print(" voltage 1 = ");
  Serial.print(struct1.voltage);
  Serial.print(" text = ");
  Serial.print(struct1.text);
  checkSeqNumber(struct1.NodeID, struct1.seq);
  Serial.printf(" errors %d seqErrors %d\n", errors, seqErrors);
  packetReceived = 0;  // clear for next time
}

// check received sequence number
void checkSeqNumber(int NodeID, int seq) {
  if (NodeID >= sizeof(seqNumbers) / sizeof(int)) return;
  if (seq != seqNumbers[NodeID]) {  // check for sequence error!
    Serial.print("\nERROR! seq number error expected ");
    Serial.print(seqNumbers[NodeID]);
    Serial.print(" received ");
    Serial.print(seq);
    Serial.print("  seq  errors ");
    Serial.println(++seqErrors);
    seqNumbers[NodeID] = seq;
  }
  seqNumbers[NodeID]++;      // next sequence nunber expected
  polledOK[NodeID - 1] = 2;  // indicate polling sucess
}

nodeID 2 transmitter

// ESP-NOW transmit a structure using polling

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <WiFi.h>

// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = { 0x24, 0x62, 0xAB, 0xE0, 0x64, 0x54 };  //{ 0x84, 0xCC, 0xA8, 0x7A, 0x56, 0x6C };  //{0x24,0x62,0xAB,0xE0,0x64,0x54};

esp_now_peer_info_t peerInfo;

#define nodeID 2  //  <<< set up required node ID

// test structure
struct __attribute__((packed)) Data {
  byte NodeID;  // ID of transmitting node
  int16_t seq;  // sequence number
  int32_t distance;
  float voltage;
  char text[50];
} struct1 = { nodeID, 0, 56, 3.14159, "hello " };  // sample data

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("Last Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
  delay(3000);
  Serial.printf("\n\nESP-NOW transmitting a structure polled version nodeID %d\n", nodeID);
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  Serial.print("ESP32 Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  // Once ESPNow is successfully Init, we will register for Send CB to get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {  // Add peer
    Serial.println("Failed to add peer");
    return;
  }
  // Once ESPNow is successfully Init, we will register for recv CB to get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
}

// loops check to see if we have been polled
void loop() {
  checkIfPacketReceived();  // if packet received ios it polling me?
}

volatile int nodeIDreceived = 0;  // nodeID set when packet received
// callback function that will be executed when data is received
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
  //Serial.println("data received");    // avoid calling Serial in callback functions
  if (len != 1) return;            // if not a poll packet return
  nodeIDreceived = *incomingData;  // get polled node ID
}

// called to check if packet has been received - if polled
void checkIfPacketReceived(void) {
  if (!nodeIDreceived) return;  // if no packet has been received return
  Serial.print("nodeID polled ");
  Serial.print(nodeIDreceived);
  if (nodeID == nodeIDreceived) {  // polled for this structID?
    Serial.println(" sending packet!");
    sendMessage();  // send a message
  } else Serial.println();
  nodeIDreceived = 0;  // clear ready for next poll
}

// transmit a message packet
void sendMessage() {
  struct1.seq++;          // increment packet sequence number
  struct1.distance += 1;  // setup next test values
  struct1.voltage += 1;
  struct1.text[4]++;
  //struct1.z[0] += 1;
  esp_now_send(broadcastAddress, (uint8_t *)&struct1, sizeof(struct1)); // transmit data
  Serial.print("Tx Node ");  // packet recived display data
  Serial.print(nodeID);
  Serial.print(" seq number ");
  Serial.print(" seq number ");
  Serial.print(struct1.seq);
  Serial.print(" distance = ");
  Serial.print(struct1.distance);
  Serial.print(" voltage = ");
  Serial.print(struct1.voltage);
  Serial.print(" text = ");
  Serial.println(struct1.text);
}

receiver serial monitor output

ESP-NOW receive a structure polled version
ESP32 Board MAC Address:  24:62:AB:E0:64:54
polling ID = 1
polling ID = 2
polling ID = 3
Node failed to respond to polling ID = 1
polling ID = 1
Node failed to respond to polling ID = 2
polling ID = 2
Node failed to respond to polling ID = 3
polling ID = 3
Node failed to respond to polling ID = 1
polling ID = 1
Node failed to respond to polling ID = 2
polling ID = 2
packet received size 61 from Node 2 seq number 1 distance 1 = 57 voltage 1 = 4.14 text = hellp
ERROR! seq number error expected 0 received 1  seq  errors 1
 errors 0 seqErrors 1
Node failed to respond to polling ID = 3
polling ID = 3
Node failed to respond to polling ID = 1
polling ID = 1
polling ID = 2
packet received size 61 from Node 2 seq number 2 distance 1 = 58 voltage 1 = 5.14 text = hellq  errors 0 seqErrors 1
Node failed to respond to polling ID = 3
polling ID = 3
Node failed to respond to polling ID = 1
polling ID = 1
polling ID = 2
packet received size 61 from Node 2 seq number 3 distance 1 = 59 voltage 1 = 6.14 text = hellr  errors 0 seqErrors 1
Node failed to respond to polling ID = 3
polling ID = 3
Node failed to respond to polling ID = 1
polling ID = 1
packet received size 61 from Node 1 seq number 1 distance 1 = 57 voltage 1 = 4.14 text = hellp
ERROR! seq number error expected 0 received 1  seq  errors 2
 errors 0 seqErrors 2
polling ID = 2
packet received size 61 from Node 2 seq number 4 distance 1 = 60 voltage 1 = 7.14 text = hells  errors 0 seqErrors 2
Node failed to respond to polling ID = 3
polling ID = 3
polling ID = 1
packet received size 61 from Node 1 seq number 2 distance 1 = 58 voltage 1 = 5.14 text = hellq  errors 0 seqErrors 2
polling ID = 2
packet received size 61 from Node 2 seq number 5 distance 1 = 61 voltage 1 = 8.14 text = hellt  errors 0 seqErrors 2
Node failed to respond to polling ID = 3
polling ID = 3
polling ID = 1
packet received size 61 from Node 1 seq number 3 distance 1 = 59 voltage 1 = 6.14 text = hellr  errors 0 seqErrors 2
polling ID = 2
packet received size 61 from Node 2 seq number 6 distance 1 = 62 voltage 1 = 9.14 text = hellu  errors 0 seqErrors 2
Node failed to respond to polling ID = 3

nodeID 1 serial monitor output

ESP-NOW transmitting a structure polled version nodeID 1
ESP32 Board MAC Address:  D4:8A:FC:C6:C6:74
nodeID polled 2
nodeID polled 3
nodeID polled 1 sending packet!
Tx Node 1 seq number  seq number 1 distance = 57 voltage = 4.14 text = hellp 
Last Packet Send Status:	Delivery Success
nodeID polled 2
nodeID polled 3
nodeID polled 1 sending packet!
Tx Node 1 seq number  seq number 2 distance = 58 voltage = 5.14 text = hellq 
Last Packet Send Status:	Delivery Success
nodeID polled 2
nodeID polled 3
nodeID polled 1 sending packet!
Tx Node 1 seq number  seq number 3 distance = 59 voltage = 6.14 text = hellr 
Last Packet Send Status:	Delivery Success
nodeID polled 2
nodeID polled 3
nodeID polled 1 sending packet!
Tx Node 1 seq number  seq number 4 distance = 60 voltage = 7.14 text = hells 
Last Packet Send Status:	Delivery Success
nodeID polled 2
nodeID polled 3
nodeID polled 1 sending packet!
Tx Node 1 seq number  seq number 5 distance = 61 voltage = 8.14 text = hellt 
Last Packet Send Status:	Delivery Success
nodeID polled 2

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.