ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many)

In this tutorial, you’ll learn how to use ESP-NOW communication protocol to send data from one ESP32 to multiple ESP32 or ESP8266 boards (one-to-many configuration). The boards will be programmed using Arduino IDE.

ESP-NOW with ESP32: Send Data to Multiple Boards one-to-many ESP8266 NodeMCU

To get started with ESP-NOW on the ESP32 or ESP8266, read the following ESP-NOW guides first:

Project Overview

This tutorial shows how to send data from one ESP32 to multiple ESP32 or ESP8266 boards using ESP-NOW (one-to-many configuration).

ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many) Project Overview
  • One ESP32 acts as a sender;
  • Multiple ESP32 or ESP8266 boards act as receivers. We tested this setup with two ESP32 boards and one ESP8266 board simultaneously. You should be able to add more boards to your setup;
  • The ESP32 sender receives an acknowledge message if the messages are successfully delivered. You know which boards received the message and which boards didn’t;
  • You need to upload a slightly different receiver code depending if you’re using an ESP32 or ESP8266;
  • As an example, we’ll exchange random values between the boards. You should modify this example to send commands or sensor readings (exchange sensor readings using ESP-NOW).

This tutorial covers these two scenarios:

  • sending the same message to all boards;
  • sending a different message to each board.

You may also like reading: ESP-NOW Two-Way Communication Between ESP32 Boards.

Prerequisites

We’ll program the ESP32/ESP8266 boards using Arduino IDE, so before proceeding with this tutorial, make sure you have these boards installed in your Arduino IDE.

Parts Required

To follow this tutorial, you need multiple ESP32 boards and/or ESP8266 boards.

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Getting the Boards MAC Address

To send messages via ESP-NOW, you need to know the receiver boards’ MAC address. Each board has a unique MAC address (learn how to Get and Change the ESP32 MAC Address).

Upload the following code to each of your receiver boards to get its MAC address.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/
  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.
*/
#ifdef ESP32
  #include <WiFi.h>
  #include <esp_wifi.h>
#else
  #include <ESP8266WiFi.h>
#endif

void setup(){
  Serial.begin(115200);

  Serial.print("ESP Board MAC Address: ");
  #ifdef ESP32
    WiFi.mode(WIFI_STA);
    WiFi.STA.begin();
    uint8_t baseMac[6];
    esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
    if (ret == ESP_OK) {
      Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
                    baseMac[0], baseMac[1], baseMac[2],
                    baseMac[3], baseMac[4], baseMac[5]);
    } else {
      Serial.println("Failed to read MAC address");
    }
  #else
    Serial.println(WiFi.macAddress());
  #endif
}
 
void loop(){

}

View raw code

After uploading the code, press the RST/EN button, and the MAC address should be displayed on the Serial Monitor.

ESP32 board MAC Address with Arduino IDE Serial Monitor

You can write down the boards’ MAC address on a label to clearly identify each board.

Identify ESP32 Board MAC Address

ESP32 Sender Code (ESP-NOW)

The following code sends data to multiple (three) ESP boards via ESP-NOW. You should modify the code with your receiver boards’ MAC address. You should also add or delete lines of code depending on the number of receiver boards.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp-now-one-to-many-esp32-esp8266/
  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 ESP RECEIVER'S MAC ADDRESS
uint8_t broadcastAddress1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t broadcastAddress2[] = {0xFF, , , , , };
uint8_t broadcastAddress3[] = {0xFF, , , , , };

typedef struct test_struct {
  int x;
  int y;
} test_struct;

test_struct test;

esp_now_peer_info_t peerInfo;

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  char macStr[18];
  Serial.print("Packet to: ");
  // Copies the sender mac address to a string
  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(macStr);
  Serial.print(" send status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
 
void setup() {
  Serial.begin(115200);
 
  WiFi.mode(WIFI_STA);
 
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  esp_now_register_send_cb(OnDataSent);
   
  // register peer
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  // register first peer  
  memcpy(peerInfo.peer_addr, broadcastAddress1, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  // register second peer  
  memcpy(peerInfo.peer_addr, broadcastAddress2, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  /// register third peer
  memcpy(peerInfo.peer_addr, broadcastAddress3, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  test.x = random(0,20);
  test.y = random(0,20);
 
  esp_err_t result = esp_now_send(0, (uint8_t *) &test, sizeof(test_struct));
   
  if (result == ESP_OK) {
    Serial.println("Sent with success");
  }
  else {
    Serial.println("Error sending the data");
  }
  delay(2000);
}

View raw code

How the code works

First, include the esp_now.h and WiFi.h libraries.

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

Receivers’ MAC Address

Insert the receivers’ MAC address. In our example, we’re sending data to three boards.

uint8_t broadcastAddress1[] = {0x3C, 0x71, 0xBF, 0xC3, 0xBF, 0xB0};
uint8_t broadcastAddress2[] = {0x24, 0x0A, 0xC4, 0xAE, 0xAE, 0x44};
uint8_t broadcastAddress3[] = {0x80, 0x7D, 0x3A, 0x58, 0xB4, 0xB0};

Then, create a structure that contains the data we want to send. We called this structure test_struct and it contains two integer variables. You can change this to send whatever variable types you want.

typedef struct test_struct {
  int x;
  int y;
} test_struct;

Create a new variable of type test_struct that is called test that will store the variables’ values.

test_struct test;

Create a variable of type esp_now_peer_info_t to store information about the peer.

esp_now_peer_info_t peerInfo;

OnDataSent() callback function

Next, define the OnDataSent() function. This is a callback function that will be executed when a message is sent. In this case, this function prints if the message was successfully delivered or not and for which MAC address. So, you know which boards received the message or and which boards didn’t.

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  char macStr[18];
  Serial.print("Packet from: ");
  // Copies the sender mac address to a string
  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(macStr);
  Serial.print(" send status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

setup()

In the setup(), initialize the serial monitor for debugging purposes:

Serial.begin(115200);

Set the device as a Wi-Fi station:

WiFi.mode(WIFI_STA);

Initialize ESP-NOW:

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

After successfully initializing ESP-NOW, register the callback function that will be called when a message is sent. In this case, register for the OnDataSent() function created previously.

esp_now_register_send_cb(OnDataSent);

Add peers

After that, we need to pair with other ESP-NOW devices to send data. That’s what we do in the next lines – register peers:

// register peer
peerInfo.channel = 0;
peerInfo.encrypt = false;
// register first peer
memcpy(peerInfo.peer_addr, broadcastAddress1, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}
// register second peer
memcpy(peerInfo.peer_addr, broadcastAddress2, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}
/// register third peer
memcpy(peerInfo.peer_addr, broadcastAddress3, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}

If you want to add more peers you just need to duplicate these lines and pass the peer MAC address:

memcpy(peerInfo.peer_addr, broadcastAddress, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}

loop()

In the loop(), we’ll send a message via ESP-NOW every 2 seconds (you can change this delay time).

Assign a value to each variable:

test.x = random(0,20);
test.y = random(0,20);

Remember that test is a structure. Here assign the values that you want to send inside the structure. In this case, we’re just sending random values. In a practical application these should be replaced with commands or sensor readings, for example.

Send the same data to multiple boards

Finally, send the message as follows:

esp_err_t result = esp_now_send(0, (uint8_t *) &test, sizeof(test_struct));

The first argument of the esp_now_send() function is the receiver’s MAC address. If you pass 0 as an argument, it will send the same message to all registered peers. If you want to send a different message to each peer, follow the next section.

Check if the message was successfully sent:

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

The loop() is executed every 2000 milliseconds (2 seconds).

delay(2000);

Send different data to each board

The code to send a different message to each board is very similar tothe previous one. So, we’ll just take a look at the differences.

If you want to send a different message to each board, you need to create a data structure for each of your boards, for example:

test_struct test;
test_struct test2;
test_struct test3;

In this case, we’re sending the same structure type (test_struct). You can send a different structure type as long as the receiver code is prepared to receive that type of structure.

Then, assign different values to the variables of each structure. In this example, we’re just setting them to random numbers.

test.x = random(0,20);
test.y = random(0,20);
test2.x = random(0,20);
test2.y = random(0,20);
test3.x = random(0,20);
test3.y = random(0,20);

Finally, you need to call the esp_now_send() function for each receiver.

For example, send the test structure to the board whose MAC address is broadcastAddress1.

esp_err_t result1 = esp_now_send(
  broadcastAddress1, 
  (uint8_t *) &test,
  sizeof(test_struct));
   
if (result1 == ESP_OK) {
  Serial.println("Sent with success");
}
else {
  Serial.println("Error sending the data");
}

Do the same for the other boards. For the second board send the test2 structure:

esp_err_t result2 = esp_now_send(
  broadcastAddress2, 
  (uint8_t *) &test2,
  sizeof(test_struct));

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

And finally, for the third board, send the test3 structure:

esp_err_t result3 = esp_now_send(
  broadcastAddress3, 
  (uint8_t *) &test3,
  sizeof(test_struct));

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

Here’s the complete code that sends a different message to each board.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp-now-one-to-many-esp32-esp8266/
  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 ESP RECEIVER'S MAC ADDRESS
uint8_t broadcastAddress1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t broadcastAddress2[] = {0xFF, , , , , };
uint8_t broadcastAddress3[] = {0xFF, , , , , };

typedef struct test_struct {
  int x;
  int y;
} test_struct;

esp_now_peer_info_t peerInfo;

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  char macStr[18];
  Serial.print("Packet to: ");
  // Copies the sender mac address to a string
  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(macStr);
  Serial.print(" send status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
 
void setup() {
 
  Serial.begin(115200);
 
  WiFi.mode(WIFI_STA);
 
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  esp_now_register_send_cb(OnDataSent);

  // register peer
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
    
  memcpy(peerInfo.peer_addr, broadcastAddress1, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  
  memcpy(peerInfo.peer_addr, broadcastAddress2, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  memcpy(peerInfo.peer_addr, broadcastAddress3, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  test_struct test;
  test_struct test2;
  test_struct test3;
  test.x = random(0,20);
  test.y = random(0,20);
  test2.x = random(0,20);
  test2.y = random(0,20);
  test3.x = random(0,20);
  test3.y = random(0,20);
 
  esp_err_t result1 = esp_now_send(
    broadcastAddress1, 
    (uint8_t *) &test,
    sizeof(test_struct));
   
  if (result1 == ESP_OK) {
    Serial.println("Sent with success");
  }
  else {
    Serial.println("Error sending the data");
  }
  delay(500);
  esp_err_t result2 = esp_now_send(
    broadcastAddress2, 
    (uint8_t *) &test2,
    sizeof(test_struct));

  if (result2 == ESP_OK) {
    Serial.println("Sent with success");
  }
  else {
    Serial.println("Error sending the data");
  }
  
  delay(500);  
  esp_err_t result3 = esp_now_send(
    broadcastAddress3, 
    (uint8_t *) &test3,
    sizeof(test_struct));
   
  if (result3 == ESP_OK) {
    Serial.println("Sent with success");
  }
  else {
    Serial.println("Error sending the data");
  }
  delay(2000);
}

View raw code

ESP32 Receiver Code (ESP-NOW)

Upload the next code to the receiver boards (in our example, we’ve used three receiver boards).

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp-now-one-to-many-esp32-esp8266/
  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>

//Structure example to receive data
//Must match the sender structure
typedef struct test_struct {
  int x;
  int y;
} test_struct;

//Create a struct_message called myData
test_struct myData;

//callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("x: ");
  Serial.println(myData.x);
  Serial.print("y: ");
  Serial.println(myData.y);
  Serial.println();
}
 
void setup() {
  //Initialize Serial Monitor
  Serial.begin(115200);
  
  //Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  //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 recv CB to
  // get recv packer info
  esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}
 
void loop() {

}

View raw code

How the code works

Similarly to the sender, start by including the libraries:

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

Create a structure to receive the data. This structure should be the same defined in the sender sketch.

typedef struct test_struct {
  int x;
  int y;
} test_struct;

Create a test_struct variable called myData.

test_struct myData;

Create a callback function that is called when the ESP32 receives the data via ESP-NOW. The function is called onDataRecv() and should accept several parameters as follows:

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {

Copy the content of the incomingData data variable into the myData variable.

memcpy(&myData, incomingData, sizeof(myData));

Now, the myData structure contains several variables inside with the values sent by the sender ESP32. To access variable x, for example, call myData.x.

In this example, we print the received data, but in a practical application you can print the data on an OLED display, for example.

Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("x: ");
Serial.println(myData.x);
Serial.print("y: ");
Serial.println(myData.y);
Serial.println();

In the setup(), intialize the Serial Monitor.

Serial.begin(115200);

Set the device as a Wi-Fi Station.

WiFi.mode(WIFI_STA);

Initialize ESP-NOW:

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

Register for a callback function that will be called when data is received. In this case, we register for the OnDataRecv() function that was created previously.

esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));

ESP8266 Receiver Code (ESP-NOW)

If you’re using an ESP8266 board as a receiver, upload the following code instead.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp-now-one-to-many-esp32-esp8266/
  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 <ESP8266WiFi.h>
#include <espnow.h>

//Structure example to receive data
//Must match the sender structure
typedef struct test_struct {
  int x;
  int y;
} test_struct;

//Create a struct_message called myData
test_struct myData;

//callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("x: ");
  Serial.println(myData.x);
  Serial.print("y: ");
  Serial.println(myData.y);
  Serial.println();
}
 
void setup() {
  //Initialize Serial Monitor
  Serial.begin(115200);
  
  //Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  //Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
}
 
void loop() {

}

View raw code

Apart from small details, this code is very similar tothe ESP32 receiver code. So, we won’t explain how it works. To learn more you can read our ESP-NOW Getting Started Guide with ESP8266 NodeMCU.

Demonstration

Having all your boards powered on, open the Arduino IDE Serial Monitor for the COM port the sender is connected to.

You should start receiving “Delivery Success” messages with the corresponding receiver’s MAC address in the Serial Monitor.

ESP32 ESP-NOW Send Data To Multiple Boards Delivery Status Serial Monitor

If you remove power from one of the boards, you’ll receive a “Delivery Fail” message for that specific board. So, you can quickly identify which board didn’t receive the message.

ESP32 ESP-NOW Send Data To Multiple Boards Delivery Status Failed Serial Monitor

If you want to check if the boards are actually receiving the messages, you can open the Serial Monitor for the COM port they are connected to, or you can use PuTTY to establish a serial communication with your boards.

If you’re using PuTTY, select Serial communication, write the COM port number and the baud rate (115200) as shown below and click Open.

Serial Communication ESP Boards PuTTY

Then, you should see the messages being received.

ESP32 ESP8266 NodeMCU ESP-NOW Send Data To Multiple Boards Delivery Success Demonstration

Open a serial communication for each of your boards and check that they are receiving the messages.

Wrapping Up

In this tutorial, you’ve learned how to send data to multiple ESP32 or ESP8266 boards from a single ESP32 using ESP-NOW (one-to-many communication).

We hope you’ve found this tutorial useful. We have other ESP-NOW tutorials that you may like:

Learn more about the ESP32 with our resources:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

66 thoughts on “ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many)”

  1. Hi Rui and Sara, another great project!!!

    Please please make a project ESP32: RECEIVE Data FROM Multiple Boards (one-from-many) WITH WEBSERVER DISPLAY AJAX DATA FROM MULTIPLE BOARDS!!!
    P L E A S E !!!!!

    Reply
  2. Hi Sara,
    Thank you so much for the wonderful tutorial. Just what I needed!
    I have two questions though:
    1. If I want to perform a function in the sender sketch, say blink and LED (initially defined), when the data has been delivered successfully to the receiver, can I write:
    If (status== ESP_NOW_SEND_SUCCESS)
    {
    blinkLED() ;
    }
    If yes, how do I write it for a particular receiver?
    2. Can ESP-01 be programmed as one of the receivers?
    Thank you in anticipation.

    Reply
    • yea I have done this, you are right about If (status== ESP_NOW_SEND_SUCCESS) I have used digitalWrite function in that loop, I am trying to turn ON LED when data is sent to 2 boards and I want to happen this in all of 3 boards, Thanks

      Reply
    • Hi David, I have done that using ESP-Now between two devices. The issue is, apparently, the ESP device cannot do ESP-Now and be linked to the WiFi simultaneously. The code I am running which I did not write switches between the two communication methods. I am testing by reading a BME280 sensor every 15 minutes. the Wemos D1 mini (battery powered) wakes up takes a reading sends it to a second Wemos D1 using ESP-Now, the second Wemos( uses a permanent power supply) receives the ESP_Now communication then switches to Wifi and sends the output via MQTT to NR. I think Ruis latest offering could be adapted to do a similar thing. However, what we need is a single receiver to collect data from multiple sensors and send it via MQTT. As far as I can see there is no reason why a many to one set up with the ‘one’ sending MQTT data would not work for sensors where the data is not required too frequently. This set up is ideal were battery powered sensors only need to supply data, say, evey 15 minutes.

      Reply
      • That is what I need. I want to monitor temperature, humidity and soil moisture for my irrigation system. I have a separate WiFi just for that system.

        Reply
        • Hi David, thats pretty much what I am doing. PC crashed at the moment, so I’m on my tablet. I can provide more info when I get the PC sorted. I would be interested how you implemented a separate wifi.
          Bob

          Reply
      • Probably your statement is wrong. AP (Software AP) and the hardware WiFi have differnet MAC addresses, so it is possible to do ESP-NOW and run WEB server on AP simoultaneously.

        Reply
  3. Hi Rui and Sara

    What is the maximum distance between sender and receiver with obstacles like wall etc and without obstacles like open room or hall.

    Thanks

    Reply
    • Hi Rajiv,

      with obstacles it highly depends on the nature of the obstacles.
      through an Iron-armed cement wall you might not get even through the wall even if you put the two device directly on the surface of the wall on both sides.

      If it is in open space with free sight it still depends somehow on how much 2,4 Ghz-Noise is in the air. I estimate 100 to 200 feet

      If you need a maximized range you could use LoRa (Long-range) modules

      Reply
  4. Hi Sara,

    if something follows a fixed pattern it is pre-determined to be done by a computer.
    MAC-Adresses are such a thing. So I wrote a “Print-MAC-Adresse-code that allows to just copy & paste a line of the serial monitor into your code replacing the ‘#’ symbol with a number and coding the line

    uint8_t broadcastAddress1[] = { 0x2C, 0x3A, 0xE8, 0x22, 0x5F, 0x70 };

    is done

    her it is

    #ifdef ESP32
    #include <WiFi.h>
    #else
    #include <ESP8266WiFi.h>
    #endif

    String MacAdrStr;
    char HexByteDigits[2];

    void setup()
    {
    Serial.begin(115200);
    Serial.println();
    Serial.println();

    MacAdrStr = WiFi.macAddress();
    Serial.print(“ESP Board MAC Address: “);
    Serial.println(MacAdrStr);

    Serial.println();
    Serial.println(“copy the line below and replace the ‘#’ with a number”);
    Serial.println();
    Serial.print(“uint8_t broadcastAddress#[] = { “);
    for (uint8_t i = 0; i < 16; i = i + 3)
    { // 12:34
    HexByteDigits[0] = MacAdrStr[i];
    HexByteDigits[1] = MacAdrStr[i+1];
    Serial.print(“0x”);
    Serial.print(HexByteDigits);
    if (i < 14) Serial.print(“, “);
    }
    Serial.println(” };”);
    Serial.println();
    }

    void loop(){

    }

    best regards

    Stefan

    Reply
  5. Hi Sara,
    I want to add something. I tried to transmit strings in a code that is using ESP-NOW but it did not work. On my research to solve this problem I came across this websitehttps://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/

    Which explains why you should AVOID Strings. They eat up all RAM over time causing the code to fail in very strange and hard to find ways. Code using Strings that does something repeatedly will lead straight into such problems. So I switched over to arrays of chars. It is a little more typing coding with arrays of chars but it is SECURE.
    In the ongoing research I discovered the library “PString” which offers (most) of the comfort Strings do but in a 100% SECURE way.

    Especcially with transmitting data over ESP-NW with structures I recommend using arrays of chars instead of Strings.

    best regards

    Stefan

    Reply
    • Hi Nahla,

      the ESP-NOW-libraries of ESP32 and ESP8266 are different in many points.
      It would be a lot of work to adapt ESP32-ESP-NOW-code to make it work on ESP8266
      registering a peer is completely different on ESP8266.

      So it is much better to start with a code that is written for ESP8266.

      as a short description: each send-command includes the MAC_ADRESS of the RECEIVING-board. It is very clear: If you send something you must define WHO is meant as receiver?

      therefore for each receiver you have to execute a function call

      esp_now_send (ESP_NOW_MAC_adrOfRecv, (uint8_t *) &myESP_NOW_Data, sizeof(myESP_NOW_Data));

      and setup the ESP_NOW_MAC_adrOfRecv to the right MAC-ADRESS.

      If you plan to do BI-directional communication via ESP-NOW AVOID the command delay() as the plaque.

      delay makes the CPU count up as fast as the CPU can which means there is no calculation-power left to manage receiving ESP-NOW-messages. If your receiving unit is executing a delay-command and a ESP-NOW-message arrives the transmission will fail.

      So you have to use NON-blocking timer-techniques that make use of the command millis().

      Next thing is AVOID String-variables ! The variable-type with the CAPITAL “S”
      Strings eat up all memory over time and start overwrite your code which means your code MUST crash. It may take days or weeks but your code WILL crash.

      use array of char or “PStrings” instead.

      best regards

      Stefan

      Reply
    • Hi Nahla,

      so I have written a send / receive-demo-code which explains in the comments not all but a lot of details.

      Additionaly this demo-code includes code for non-blocking timers and some useful “tools”

      printout filename of the sketch including the path and timestamp date and time of compiling right before upload
      Print WiFi-Macadress in a line of code which is ready to mark, copy & paste into your code
      demonstrating the use of PString which is a highly-secure alternative for Strings
      democode that shows how to add integers and floats to the ESP-NOW-Data that shall be sended

      variabletype String is unsecure and often will make your code crash

      So this democode should answer most (surely not all) questions how to use ESP-NOW to send and receive bi-directional between two or up to 20 ESP8266-boards

      I have tested this code with a WeMos D1 mini and a GeekCreit nodeMCU
      The only things that have to be adapted is the MAC-adresses and the datastructure you want to send over ESP-NOW to match your needs

      So I would like to read from you what questions you still have regarrding my democode or if you successfully adapted it to your projects

      As this Comment-function of RNT does not allow inserting formatted code I uploaded the democode as an attachment to this post on
      Arduino.cc

      …. hm trying to reach the Arduino-Forum I get an error Error 504 Ray ID: 594fdaa05b4d9736 • 2020-05-17 19:49:06 UTC
      Gateway time-out

      So I posted my code here

      https://www.arduinoforum.de/arduino-Thread-ESP8266-Democode-bi-directional-send-receive-using-ESP-NOW

      best regards

      Stefan

      Reply
    • Hi.
      I haven’t tried it, but the documentation mentions:
      – Limited encrypted peers. 10 encrypted peers at the most are supported in Station mode; 6 at the most in SoftAP or SoftAP + Station mode;
      – Multiple unencrypted peers are supported, however, their total number should be less than 20, including encrypted peers;
      Regards,
      Sara

      Reply
    • Hi.
      This is what is mentioned in the documentation:
      Limited encrypted peers. 10 encrypted peers at the most are supported in Station mode; 6 at the most in SoftAP or SoftAP + Station mode;
      Multiple unencrypted peers are supported, however, their total number should be less than 20, including encrypted peers;
      Regards,
      Sara

      Reply
      • what if we need to connect hundreds of clients to a single master ,encryption is not important for me ,is there a way to do that?

        Reply
  6. All worked perfectly. Now the big question, how to do you control the gpio pins of the receiver units from the sender? Would like to have all controlled on one webpage.

    Is that possible? Any example codes I can check out? (newbie here)

    Thanks.

    Bob

    Reply
  7. hello i need a question for you guys, can you help me??
    Have you ever used Heltec LORA 32 sx1276 to be a gateway? do you have any coding examples ??

    Reply
  8. Hi, can this ESP now work together with Firebase? Because I’m trying to create a server client project whereby server will send data from sensor to Firebase and client part simultaneously and I found out that if I succeed in sending my data to Firebase the packet will fail to send to client and vice versa. Can anyone help with this?

    Reply
  9. I tried to send multiple Esp8266 to one Esp32 but I could etablish such a communication with ESP NOW. I think it is not possible!

    Thanks

    Reply
    • Hi.
      It is possible to use ESP8266 and ESP32 together with ESP-NOW.
      The code for each board is slightly different.
      Regards,
      Sara

      Reply
  10. Hello, is it possible to send digitalWrite command to the other board. Basically for my project my ESP32 CAM will be used to create a webserver. My robots motors are connected to an ESP32. I want to control the motors from the ESP32 CAM server. Basically from the ESP32 CAM webserver, if i press forward, it send that data to the ESP32 to control the wheel. Thank You

    Reply
  11. Hello,

    I have read through the tutorial (and watched many Youtube videos) … but I am a complete novice when it comes to ESP32 coding.
    I have code running on an ESP32 (https://github.com/TheDIYGuy999/Rc_Engine_Sound_ESP32) that works 100%, what code do I need to get the exact same output on the 5 pins below from the master to the slave.

    #define TAILLIGHT_PIN 15
    #define INDICATOR_LEFT_PIN 2
    #define INDICATOR_RIGHT_PIN 4
    #define REVERSING_LIGHT_PIN 17
    #define SIDELIGHT_PIN 18

    Thank you,

    Frikkie

    Reply
  12. Hi,

    Thank you so much for this tutorial.

    I have a question about ESP-NOW combo mode. If I want a ‘middle’ (#2) esp8266 to get data from a (#1) esp8266 and add to that data to later send to a (#3) esp8266, how would I go about this using dataReceived & esp_now_send functions? I am working on a turbidity sensor project for college and any help would be greatly appreciated.

    Thanks,
    Jeremy

    Reply
  13. Hello,

    Thanks for this tutorial ! I am trying to combine both this tutorial “Send Data to Multiple Boards (one-to-many)” and your other one “Receive Data from Multiple Boards (many-to-one)”, but i have not succeeded till now. I have 3 esp32 let’s say A, B and C. I need A to send data to B, and also B and C should send data to A. Is it possible ?

    Thank you for your help
    Regards,
    Florian

    Reply
    • Hi.
      Yes, it should be possible.
      But remember that you need to use the same data structure on all boards.
      Regards,
      Sara

      Reply
  14. Has anyone ever tried to run two ESP-now networks in the same physical space, is it possible?

    I am asking because I want to broadcast a message to >20 receivers, but the ESP-Now docs say that it is only possible up to 20 peers (I am guessing “peer” means the amount of receivers). So now I am wondering if I can just use a second ESP32 to broadcast to another 20 receivers? (the transmitters will be next to each other)

    Reply
  15. Hii
    Whenever i download receiver code and reset then i got such error please suggest me what i do
    Guru Meditation Error: Core 0 panic’ed (IllegalInstruction). Exception was unhandled.\CR\LFMemory dump at 0x40128724: 1b0c23a6 f03df23d 22002652\CR\LFCore 0 register dump:\CR\LFPC : 0x40128728 PS : 0x00060030 A0 : 0x80128996 A1 : 0x3ffb5560 \CR\LFA2 : 0x00000000 A3 : 0x00000000 A4 : 0x3ffb55b0 A5 : 0x00000000 \CR\LFA6 : 0x3ffc5b5c A7 : 0x00000000 A8 : 0x00000c1c A9 : 0x3ffb5550 \CR\LFA10 : 0x0000005c A11 : 0x00000001 A12 : 0x00000c1c A13 : 0x00000c1c \CR\LFA14 : 0x00000000 A15 : 0x00000000 SAR : 0x00000007 EXCCAUSE: 0x00000000 \CR\LFEXCVADDR: 0x00000000 LBEG : 0x40126f78 LEND : 0x40126f82 LCOUNT : 0x00000000 \CR\LF\CR\LFELF file SHA256: 0000000000000000\CR\LF\CR\LFBacktrace: 0x40128728:0x3ffb5560 0x40128993:0x3ffb55b0 0x40126fc1:0x3ffb55f0 0x40127125:0x3ffb5630 0x40127d2e:0x3ffb5650 0x4012c0a5:0x3ffb5680 0x4012c336:0x3ffb56b0 0x400ddee0:0x3ffb56e0 0x400ddfad:0x3ffb5700 0x400de234:0x3ffb5720 0x400db18a:0x3ffb5740 0x401008ee:0x3ffb5760 0x40089792:0x3ffb5790\CR\LF\CR\LFRebooting…\CR\LF

    Reply
  16. I want to know about how to control LED on /off and brightness by IR remote control on ESP NOW protocol of ESP8266 broadcast many board. One remote to control LED in same board and other boards.

    Reply
  17. Hi Rui & Sara,

    I tried to set the code from one ESP32 sending messages to another two, but it is not working. Only sends messages to the first MAC Address defined, and I have even changed the first "Sender MAC Address" to check boards integrity and they are good.
    It seems to not even be trying to set communication with the 2nd defined MAC Address, once I do not get the "Delivery Fail message" from the OnDataSent message releated to the address.

    Should the “void OnDataSent” be adjusted and repeated to different boards/address?

    This seems to be those dumb mistakes but I could not solve 😐

    Tks in advanced

    Reply
      • I’ve had issues sending to multiple boards if I am sending the messages one immediately after the other. It seems like the second message doesn’t get transmitted as it is still dealing with the first. Have you tried adding a delay between sending messages?

        Reply
  18. Hi Rui & Sara,
    I have trouble when I use Blue Tooth and EspNow in one project. If I use
    SerialBT.println(n);
    I got

    Last Packet Send Status: Delivery Fail
    message. Can I use this two interfaces simultaneusly?

    Reply
    • Did you ever get resolution? I also am trying to send one to two. Only one board makes “contact.”

      Referring to lines 16 and 17 as I copied the code.
      uint8_t broadcastAddress1[] = { 0x78, etc
      uint8_t broadcastAddress2[] = { 0x94, etc

      In the above case only board { 0x78, etc works.

      Changing the address to…
      uint8_t broadcastAddress2[] = { 0x78, etc
      uint8_t broadcastAddress1[] = { 0x94, etc

      In the above case only board { 0x94, etc works.

      The problem seems to be in the registration process starting at line 57. Only the first peer registers.

      memcpy(peerInfo.peer_addr, broadcastAddress1, 6);
      Only board “1” works.

      Making board 2 the first peer and board 1 the second peer like so…
      memcpy(peerInfo.peer_addr, broadcastAddress2, 6);
      Only board “2” works.

      I am stuck.

      Reply
      • Gary,
        I had the same issue and I discovered that it was due to my 2nd receiver not being on the same channel as the 1st receiver. My first receiver connects to my wifi and it sets itself to the channel of that wifi network. My 2nd receiver would just be set up as WiFi_STA and not get a channel from the wifi network as I only use it to receive and display esp-now messages.

        On my 2nd receiver I am using the following code:

        // Insert your SSID
        constexpr char WIFI_SSID[] = “?????”; //enter name of wifi network that AP is connecting to
        constexpr char WIFI_SSID2[] = “?????”; //enter name of wifi network that AP is connecting to
        const char *networkdetect;
        int32_t channel;

        int32_t getWiFiChannelmulti() {
        const char *ssid = WIFI_SSID;
        const char *ssid2 = WIFI_SSID2;
        if (int32_t n = WiFi.scanNetworks()) {
        for (uint8_t i=0; i<n; i++) {
        if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
        networkdetect = ssid;
        return WiFi.channel(i);
        }
        else if (!strcmp(ssid2, WiFi.SSID(i).c_str())) {
        networkdetect = ssid2;
        return WiFi.channel(i);
        }
        }
        }
        return 9; //if network not found, will return 9
        }

        void initwifiandespnow(){
        channel = getWiFiChannelmulti();
        Serial.print(“channel: “);
        Serial.println(channel);
        esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);

        WiFi.useStaticBuffers(true);
        WiFi.mode(WIFI_STA);// Set device as a Wi-Fi Station…
        then add esp-now init code after this…

        In other words, make sure all devices are on the same WiFi channel and they will all find each other and talk to each other. Hope this helps!

        Reply
  19. Hi Ruis and Sara, thank you for this great tutorial. I wanted to ask; whilst the above does send different structures to each of several boards, as you say:

    “In this case, we’re sending the same structure type (test_struct). You can send a different structure type as long as the receiver code is prepared to receive that type of structure.”

    But…I cannot see how to prepare a single receiver to receive multiple structure types anywhere. The ‘on data receive’ callback function, and the registration for that callback, seem only to refer to receiving the one type, common to all boards.

    I am looking to send a ‘long message’ (a structure with, for example, 10 variables) early in my loop (or end of setup) that will pass ‘configuration’ information to each of the receiver boards, and then also, after this, have a ‘short message’ structure (2 variables) which will be sent more frequently once the system is up and running. In both cases, it will be sending ‘one to many’.

    Can you help? At the ‘receivers’ end (many), can I create, and register for, multiple different callback functions on receive (on each board), one for each type of signal?

    In the sender code, I imagine it would look something like:

    //the long message type…
    typedef struct test_struct1 {
    int a;
    int b;
    int c;
    int d;
    int e;
    //etc.
    } test_struct1;

    test_struct1 test_signal1;

    // and a shorter type….
    typedef struct test_struct2 {
    int x;
    int y;
    } test_struct2;

    test_struct2 test_signal2;
    //

    I want the receiving board to react differently to each type of signal.

    Thanks for any help you can provide.

    Kind regards,

    Alex

    Reply
  20. Hi Sara , just built 1 station of your ESP now wifi communications. Worked like a charm , Thanks again for another wonderful example. Instead of numbers I want to send hex code like I use from an infrared remote.
    I changed x & y to test.x = (0xFF5AA5); test.y = (0xFF10EF); But on the reciever end it still recieves a digital
    16734885 for X . How can I clean up the code to get rid of the uint8 code and replace it with Hex code ?
    I want to use if ((myData.x)==FF5AA5) to turn my mobile robot car to the right , ETC.
    Thanks
    Greg

    Reply
  21. The ESPNow library has been updated and the above code generates a peer format error.

    You now have to declare this explicitly in the setup when you register a peer:

    peerInfo.ifidx=WIFI_IF_STA;
    or
    peerInfo.ifidx=WIFI_IF_AP;

    Reply
  22. Hello, I am trying to turn on LED in 3 ESP32 while connected. I have successfully done this for 2 ESP32.
    1. The LED should be on when and only when both of other boards are connected, it should not blink, yea I know it is connection less protocol
    2. I have done this by adding digitalWrite instruction in OnDataSent subroutine., while data sent successfully LED should ON else OFF,

    Please help I am working this since 5 days but no success,

    thank you with honors.

    Reply
  23. I am not sure if this is monitored anymore, but I appear to have an odd phenomenon happening when I use a ‘0’ in the send string (0 meaning the master sense to all of the slaves).

    I can get four slave devices working quite well when they receive data, but when I add a fifth device, one of the slave devices (it seems at random) repeatedly drops off and doesn’t receive the payload.

    Any insights on this?

    Reply
    • Dan,
      Please try increasing your “cfg.cache_tx_buf_num = 4” to something greater than 4. It is found in WiFiGeneric.cpp.

      if(!WiFiGenericClass::useStaticBuffers()) {
      cfg.static_tx_buf_num = 0;
      cfg.dynamic_tx_buf_num = 32;
      cfg.tx_buf_type = 1;
      cfg.cache_tx_buf_num = 4; // can’t be zero! <—– Here
      cfg.static_rx_buf_num = 4;
      cfg.dynamic_rx_buf_num = 32;
      }

      github.com/espressif/esp-idf/issues/8992

      Hope that helps!

      Reply
      • Thanks for this! I am addressing it now by looping through all the clients and it works, but i will try this and incorporate into my next project.

        Reply
  24. IM trying control servo with espnow, i’m use servo,potensiometer, esp32 and esp8266. Esp 32 and esp8266 successfully communication but why the servo can’t move ?. I’m use your code and little modify

    Reply
  25. Hi Rui and Sara,
    Thanks for all the great tutorials. I’m quite new to ESP32 and I’m trying to better understand the delay() that’s used at the end of the sender code. I’m seeing that some sort of delay is needed. If I remove delay(2000) then I see that the data isn’t transmitted and I get an error like the one below. For my project I want to transmit data as fast as possible to 10 receivers. Ideally 24bits would be transmitted to each receiver every 100ms. What’s the best way to do that? Thanks!

    Error sending the data
    E (107598) wifi: esf_buf: t=3 l=44 max:32, alloc:32 no eb, TXQ_BLOCK=2000
    Error sending the data
    E (107698) wifi: esf_buf: t=3 l=44 max:32, alloc:32 no eb, TXQ_BLOCK=2000
    Error sending the data

    Reply
  26. Great tutorial.. Is it possible to add “auto-peer” stuff to this? Or do you need to connect to a real/live ‘network’ (username/password required) to do such a thing?

    Close to this tutorial:
    https://randomnerdtutorials.com/esp-now-auto-pairing-esp32-esp8266/

    but I dont need any ‘server’
    no connect to a wifi/ssid (name/password)..etc (all just local ESP32 devices)

    Q: Or do you -have- to connect to a network (name/password) to actually do the auto-pairing stuff in the other tutorial? (I liked everything but dont need server stuff..and no outside network connection…everything local to ESP32 boards) Adding the ‘peers’ to a list was nice so you can loop through or randomly pick one..etc.

    In this tutorial.. only thing I dont understand yet is how to dynamically grab these ‘peers’ addresses… and build a list dynamically?

    THANKS!

    Reply
  27. Hi Sara.
    I try to send data from One ESP32 Board to two ESP32
    Exactly with your code. The problem is it sends data only for few meters distance.
    In longer distance (~20m) I’m getting msg “Delivery Fail”
    I use DEVKIT V1.
    Could you tell me why?

    Reply
  28. Hi,
    I try your code (one ESP32 sender and 3 ESP8266 receiver) and it works fine ! Thank you.
    But when I extend with 6 ESP8266 receiver I noticed on the Arduino IDE Serial Monitor of the ESP32 sender sent only 4 or sometime 5 “Delivery Success” message!
    It looks like a timing jam… Do you have an idea why.
    I would like to send data to 20 receivers IN THE SAME TIME! Can you provide me any help ?
    Thank’s

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.