ESP32 ESP-NOW Send Data to Multiple boards (One to Many Communication)

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:

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

ESP NOW one way communication configuration2
  • 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 way communication configuration3

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.

ESP NOW one to many configuration
ESP NOW one way communication (one to many configurations)

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.

ESP32 enable reset button

In your Arduino IDE, open up the serial monitor and you will be able to see the unique MAC address of your ESP32 module.

ESP NOW MAC address esp32 board serial monitor
Serial Monitor

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.

ESP NOW one to many setup

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.

select esp32 board

Next, go to Tools > Port and select the appropriate port through which your board is connected.

Selecting COM PORT ESP32

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.

ESP32 enable reset 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.

ESP32 sender side serial monitor demo
ESP32 Sender side serial monitor

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.

ESP32 receiver side serial monitor demo
ESP32 Receiver side serial monitor

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.

Leave a Comment