In this tutorial, we will see how to send data from one ESP32/ESP8266 to multiple ESP32 and ESP8266 boards using ESP-NOW and Arduino IDE. In other words, we will transmit data from one ESP32 to many ESP32 and ESP8266 boards (One to Many Communication). Previously, we sent data from one ESP32 to another ESP32 via ESP NOW one way communication. Additionally, we also transmitted sensor readings between two ESP32 boards and displayed the readings on an OLED display via ESP-NOW two-way communication.
You can access both of the user guides below:
- ESP32 ESP-NOW Getting Started Tutorial with Arduino IDE
- ESP32 ESP-NOW Two way Communication (Arduino IDE)
ESP-NOW Protocol Introduction
ESP-NOW is a low-power, secure, and direct wireless communication protocol that enables multiple ESP32 devices to communicate with each other without the need for Wi-Fi or a router. Using ESP-NOW, we can perform one-way and even two-way communication between ESP MCU devices without using a Wi-Fi network.
- It allows low overhead peer-to-peer wireless data transfers but in small packets. A maximum of 250 bytes of data can be transferred. Thus if a larger amount of data needs to be transferred then using this protocol is not useful.
- Using ESP-NOW, the connection protocol is simplified which results in low power consumption as a lesser amount of time is required for the transmission of data.
- Additionally, the ESP-NOW uses the same 2.4 GHz band as the Wi-Fi but does not need to connect or interfere with the local network connection.
It is a fast and convenient communication protocol for the transmission of a smaller amount of data.
ESP32 ESP-NOW one-way communication
In one-way communication, one peered device acts as the sender/master and the other as the receiver/slave. We can have multiple configurations of the sender-receiver in this situation.
- One ESP32 board sends data to another ESP32 board
As you can view in the picture below, one ESP32 board act as the sender and the other board receives the data and hence acts as the receiver.
Uses: Sending sensor data, controlling ESP outputs including LEDs, relays, buzzers, etc.
- One ESP32 sender board sends data to various other ESP32 receiver boards
In this scenario, one ESP32 board will act as the sender/master and send data to multiple ESP32 boards that will act as receivers/slaves.
Uses: remote control
- One ESP32 board receives data from various other ESP32 sender boards
Lastly, in this case, one ESP32 board (receiver/slave) receives data from multiple ESP32 boards (senders/masters).
Uses: Receiving sensor data from various sensors.
ESP-NOW One to Many Communication Project Overview
This project consists of four ESP32 boards where one will act as the sender and the other three will be the receivers. Our aim will be to show you how to send data from the sender ESP32 board to the three other receivers’ ESP32/ESP8266 boards. First, we will find the MAC address of each board through an Arduino sketch to differentiate between the four modules. Then, after programming the boards with their respective sender and receiver sketches, receiver boards will start receiving data from the sender ESP32 board through ESP-NOW protocol. You can also use the sketches to transmit useful information between ESP devices including sensor data.
Required Hardware:
4x ESP32 or ESP8266 development boards
4x power cables
Setting up Arduino IDE
We will use Arduino IDE to program our ESP32/ESP8266 development board. Thus, you should have the latest version of Arduino IDE. Additionally, you also need to install the ESP32 and the ESP8266 plugin. If your IDE does not have the plugins installed you can visit the links below:
Now, first, we will introduce you to an Arduino sketch which will help us to identify our ESP board so that we know exactly which board to transmit the data to. It will display our ESP module’s MAC address on the serial monitor which we will later use in another sketch.
Arduino Sketch for obtaining the MAC Address for the ESP32/ESP8266 board
Open your Arduino IDE and go to File > New to open a new file. Copy the code given below in that file and save it.
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
void setup(){
Serial.begin(115200);
Serial.println();
Serial.println(WiFi.macAddress());
}
void loop(){
}
In the setup() function, we are first setting our ESP32/ESP8266 board in station mode. Then by using the WiFi.macAddress() method we will obtain the unique MAC address in our serial monitor.
Make sure you choose the correct board and COM port before uploading your code to the board. Go to Tools > Board and select your board. Next, go to Tools > Port and select the appropriate port through which your board is connected. In this case, we are using the ESP32 development board which is connected to COM5.
Click on the upload button to upload the code into the ESP32 development board. Press its ENABLE button after the sketch has been uploaded.
In your Arduino IDE, open up the serial monitor and you will be able to see the unique MAC address of your ESP32 module.
Obtain the MAC address for each ESP board and label it. We will need the unique MAC address of the receiver boards while programming the sender ESP board.
ESP-NOW ESP32/ESP8266 (One to many) Arduino Sketch
Now, let us learn how to send data from one ESP32/ESP8266 board to another, using the ESP-NOW protocol. We will use the one-to-many configuration, where one ESP32 board acts as the sender and multiple other ESP32 boards act as receivers. You can use the method given below to transmit sensor data or any type of information from one ESP board to another. For this project, we will require two Arduino sketches one for the sender and the other for the receivers.
ESP-NOW ESP32 Arduino Sketch for Sender Side
Open your Arduino IDE and go to File > New to open a new file. Copy the code given below in that file and save it. This sketch follows the points given below:
- Firstly, we will initialize ESP NOW by using esp_now_init() function.
- Then we will create a callback function called data_sent() and register it as a callback function using esp_now_register_send_cb() . This will return a message in the serial monitor showing whether the data was transmitted successfully or not.
- The next step will be to add the receiver ESP boards by using their unique MAC address.
- We will then send the data to these peer devices that we set up.
#include <esp_now.h>
#include <WiFi.h>
// REPLACE WITH YOUR ESP RECEIVER'S MAC ADDRESS
uint8_t Receiver_Address1[] = {0x7C, 0x9E, 0xBD, 0x37, 0x28, 0x4C};,
uint8_t Receiver_Address2[] = {0x7C, 0x9E, 0xBD, 0x37, 0xCA, 0x84};
uint8_t Receiver_Address3[] = {0x84, 0xCC, 0xA8, 0x5E, 0x52, 0x44};
typedef struct struct_message {
int integer;
char character[100];
} struct_message;
struct_message message;
void data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
char address[18];
Serial.print("Sent to: ");
snprintf(address, sizeof(address), "%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(address);
Serial.print(" 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(data_sent);
esp_now_peer_info_t peerInfo;
peerInfo.channel = 0;
peerInfo.encrypt = false;
memcpy(peerInfo.peer_addr, Receiver_Address1, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
memcpy(peerInfo.peer_addr, Receiver_Address2, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
memcpy(peerInfo.peer_addr, Receiver_Address3, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
}
void loop() {
message.integer = random(0,50);
strcpy(message.character, "Welcome to Microcontrollerslab! This is test example.");
esp_err_t outcome = esp_now_send(0, (uint8_t *) &message, sizeof(struct_message));
if (outcome == ESP_OK) {
Serial.println("Sent with success");
}
else {
Serial.println("Error sending the data");
}
delay(2000);
}
How the Code Works?
Including Libraries
Firstly, we will include the necessary libraries. For the sender sketch, we are using two of them. These include esp_now.h for the ESP-NOW communication protocol and WiFi.h will allow our ESP32 board to use the Wi-Fi functionalities.
#include <esp_now.h>
#include <WiFi.h>
Specifying MAC Addresses of Receiver Boards
Secondly, we will specify the MAC Addresses of the three ESP32 boards which will act as the receivers. We will use the same sketch above to find the MAC addresses. Replace the address with the unique MAC addresses of your own ESP32 boards. You can use the sketch which was given previously, to find the MAC addresses of your modules.
// REPLACE WITH YOUR ESP RECEIVER'S MAC ADDRESS
uint8_t Receiver_Address1[] = {0x7C, 0x9E, 0xBD, 0x37, 0x28, 0x4C};,
uint8_t Receiver_Address2[] = {0x7C, 0x9E, 0xBD, 0x37, 0xCA, 0x84};
uint8_t Receiver_Address3[] = {0x84, 0xCC, 0xA8, 0x5E, 0x52, 0x44};
Defining structure for sending data
Now, we will define a structure named ‘struct_message.’ Inside the structure, we will initialize the variables which will hold our data that we will transmit to the receiver boards via ESP-NOW. These will be of type int and char.
typedef struct struct_message {
int integer;
char character[100];
} struct_message;
Next, we will create a new variable of type struct_message and call it message. This will be used later on in the sketch to acquire the data and transmit it accordingly.
struct_message message;
data_sent()
The data_sent() function acts as the callback function which we will define now. It will be used as a parameter when we will register this callback function for sending messages. This prints whether the message was successfully delivered or not for each ESP board on the serial monitor whenever a message will be sent from the ESP32 sender side.
void data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
char address[18];
Serial.print("Sent to: ");
snprintf(address, sizeof(address), "%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(address);
Serial.print(" status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
setup()
Inside the setup() function, we will open a serial connection at a baud rate of 115200 and set up the ESP32 board in station mode.
Serial.begin(115200);
WiFi.mode(WIFI_STA);
The following lines of code will initialize the ESP-NOW protocol. In case of an unsuccessful connection, the serial monitor will display ‘Error initializing ESP-NOW.’
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
Now we will register the data_sent() function as the callback function. This will make sure that whenever a message will be sent from the sender side, the data_sent() function will be called.
esp_now_register_send_cb(data_sent);
The following lines of code will pair the ESP32 sender board with the three receiver boards.
esp_now_peer_info_t peerInfo;
peerInfo.channel = 0;
peerInfo.encrypt = false;
memcpy(peerInfo.peer_addr, Receiver_Address1, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
memcpy(peerInfo.peer_addr, Receiver_Address2, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
memcpy(peerInfo.peer_addr, Receiver_Address3, 6);
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
loop()
Inside the loop() function, we will transmit the message to the receiver ESP32 boards. After every 2 seconds, the following message will be sent:
“Welcome to Microcontrollerslab! This is a test example” as the character and a random integer between 0-50.
You can easily change the structure ‘message’ to send data according to your needs. We have incorporated some of the common data types here.
message.integer = random(0,50);
strcpy(message.character, "Welcome to Microcontrollerslab! This is test example.");
Then we will send the message and monitor if it was sent successfully or not.
esp_err_t outcome = esp_now_send(0, (uint8_t *) &message, sizeof(struct_message));
if (outcome == ESP_OK) {
Serial.println("Sent with success");
}
else {
Serial.println("Error sending the data");
}
delay(2000);
ESP-NOW ESP32 Arduino Sketch for Receiver Side
Open your Arduino IDE and go to File > New to open a new file. Copy the code given below in that file and save it. This sketch follows the points given below:
- Again we will first initialize ESP NOW by using esp_now_init() function.
- Then, we will create another function called data_receive() and register it as a callback function using esp_now_register_rcv_cb(). This callback function will be called whenever the data will be received by the receiver ESP32 board.
#include <esp_now.h>
#include <WiFi.h>
//Must match the sender structure
typedef struct struct_message {
int integer;
char character[100];
} struct_message;
struct_message message;
void data_receive(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&message, incomingData, sizeof(message));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Integer: ");
Serial.println(message.integer);
Serial.print("Character: ");
Serial.println(message.character);
Serial.println();
}
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_recv_cb(data_receive);
}
void loop() {
}
How the Code Works?
Including Libraries
Firstly, we will include the necessary libraries. For the receiver sketch, we are also using the same two libraries which we did for the sender sketch. These include esp_now.h for the ESP-NOW communication protocol and WiFi.h will allow our ESP32 board to use the Wi-Fi functionalities.
#include <esp_now.h>
#include <WiFi.h>
Defining structure for receiving data
Now, we will define the same structure named ‘struct_message’ which we did for the sender sketch. This structure will be used to receive the data that will be received from the receiver ESP32 board via ESP NOW. Make sure that the structure is the same in both the sketches.
//Must match the sender structure
typedef struct struct_message {
int integer;
char character[100];
} struct_message;
Next, we will create a new variable of type struct_message and call it a message. This will be used later on in the sketch to receive the data.
struct_message message;
data_receive()
The data_receive() function acts as the callback function which we will define now. It will be used as a parameter when we will register this callback function for receiving messages. This prints the message on the serial monitor whenever a message is received from the ESP32 sender side.
void data_receive(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&message, incomingData, sizeof(message));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Integer: ");
Serial.println(message.integer);
Serial.print("Character: ");
Serial.println(message.character);
Serial.println();
}
setup()
Inside the setup() function, we will open a serial connection at a baud rate of 115200 and set up the ESP32 receiver board in station mode as well.
Serial.begin(115200);
WiFi.mode(WIFI_STA);
The following lines of code will initialize the ESP-NOW protocol. In case of an unsuccessful connection, the serial monitor will display ‘Error initializing ESP-NOW.’
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
Now we will register the data_receive() function as the callback function as shown below. This will make sure that whenever a message will be received from the sender side, the data_receive() function will be called.
esp_now_register_recv_cb(data_receive);
Demonstration ESP32 ESP-NOW one way communication (one to many)
Now after saving both of the sender and receiver sketches upload them onto their respective ESP32 boards. Make sure all the four boards are powered on throughout the demonstration.
First, open the sender sketch. Choose the correct board and COM port before uploading your code to the sender ESP32 board. Go to Tools > Board and select ESP32 Dev Module.
Next, go to Tools > Port and select the appropriate port through which your board is connected.
Click on the upload button to upload the code into the ESP32 board (sender). After you have uploaded your code to the board press its ENABLE button.
Next, follow the same steps and upload the receiver side sketch to the three receiver ESP32 modules. Make sure you choose the correct COM port through which they are connected. After you have uploaded your code to the board press its ENABLE button.
In the sender side’s serial monitor you will be able to view the text that the message was successfully delivered against each MAC address of the receiver side ESP32 boards.
Now, open one of the receiver side serial monitor. You will be able to see the messages being displayed on the receiver side after every 2 seconds. These include the char and the int parameters which we specified in the program sketch.
Conclusion
In conclusion, we have learned about the ESP-NOW one-to-many communication configuration. As an example, we sent a small packet of data from one ESP32 board to multiple ESP32 boards without using any WiFi or internet connection. You can use the same sketch to transfer useful data including sensor readings or even control the output pins of the ESP32 boards through another ESP32 board easily. Although, we have shown you ESP NOW one way communication( one to many configurations). But you can also use ESP NOW two-way communication as well to promptly transfer data two ways.
You may also like to read:
Hi
I have been trying to use your code examples for the esp now protocol.
But I’m having issues not being able to send packages fast enough.
with a package size of only 2 bytes i need a delay in the loop at minimum 35ms to make every package transmission successful. in other words. 28 packages per second. It doesn’t seem like a lot to me, and it’s a bottleneck for my projekt.
How do i increase the rate of data?
Thanks.
Best regards
Max Bursell
Hi Max,
You can refer to documentation of esp-now on their official page here:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html
As per official documentation of esp-now, the message body can be between 0~250 bytes.The default ESP-NOW bit rate is 1 Mbps
Thanks for your reply.
I have read the documentation. I found no explanation on how to do fast data rate.I know that it is capable of 1 Mbps. is a said, with the code you provided in the tutorial. I was only able to get 28 packages a second each containing 2 bytes of data. that equals 0.000448 Mbps.
So my question is HOW do I get a faster data rate?
Thanks
I really appreciate your time
Best regards
Max Bursell
Can you share your sketches to see how you are measuring data transfer rate?
That seems right for my project of 10 senders using ESP8266, but I would like some guidance on how to send and receive the RF data to a micro-controller instead of using the pins of a devboard like NodeMcu or WEMOS etc. Not enough i/o pins nor analogs for my project. So the question is: Can I use your setup (Esp-Now) plus some added lines to program a ESP8266 (with External antenna) using Arduino so I can send and receive data to and from my micro-controller. There will be an info byte from RF that will tell the micro-controller to send 10-20 bytes of data to the RF.
If this is not doable then do you have an idea.
Thanks for your help.
Hi. I’m trying to test the above codes, I changed the mac address to correspond to my receivers. The code compiles without any errors but I get “Error sending data” on the sender side of the serial monitor and nothing on the receiver side. Can you please help ?