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.

To get started with ESP-NOW on the ESP32 or ESP8266, read the following ESP-NOW guides first:
This tutorial shows how to send data from one ESP32 to multiple ESP32 or ESP8266 boards using ESP-NOW (one-to-many configuration).

This tutorial covers these two scenarios:
You may also like reading: ESP-NOW Two-Way Communication Between ESP32 Boards.
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.
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!
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(){ }
After uploading the code, press the RST/EN button, and the MAC address should be displayed on the Serial Monitor.

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

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(esp_now_send_cb_t(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); }
First, include the esp_now.h and WiFi.h libraries.
#include <esp_now.h> #include <WiFi.h>
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;
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"); }
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);
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; }
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.
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);
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(esp_now_send_cb_t(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); }
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() { }
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));
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() { }
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.
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.

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.

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.

Then, you should see the messages being received.

Open a serial communication for each of your boards and check that they are receiving the messages.
Copyright ©2025. All Rights Reserved Emblab THE RAVE INNOVATION