ESP32 ESP-NOW is a wireless communication protocol developed by Espressif Systems specifically for their ESP8266 and ESP32 microcontrollers. It offers a low-power, secure, low-cost, and direct wireless communication solution for ESP32 devices. With ESP-NOW, multiple ESP32 devices can communicate with each other without the need for WiFi or routers, creating mesh networks of devices. In this tutorial, we will learn to use ESP32 ESP-NOW to perform wireless communication between ESP32 devices. Whether you want to send sensor data, control ESP outputs, or establish two-way communication, this guide will provide you with the necessary steps.
ESP-NOW Protocol Introduction
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 Key Features
- One-to-one transmission of data (both encrypted and unencrypted).
- Supports both encrypted and unencrypted peer devices. For encrypted devices, there is a limitation of a maximum of 10 peers in the station mode and a maximum of 6 in the SoftAP or a mixture of both modes. However, for unencrypted devices, a maximum of 19 devices are allowed with no limitation on the mode they are operating in.
- A maximum of 250 bytes of data can be transmitted in the form of small packets.
- It generates a callback function that notifies the application layer whether the data was transmitted successfully or not.
To initialize the ESP-NOW connection, we will have to pair our ESP32 boards first. This connection will stay regardless of any one of the board restarts and the transmission will continue smoothly.
In this tutorial, we will demonstrate an Arduino sketch through which we will wirelessly transmit data from one ESP32 board to another (one-way communication). Before doing that, let us first have a look at a few configurations in which this communication protocol can be used.
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 see in the picture below, one ESP32 board acts 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 two-way communication
The ESP-NOW protocol also enables two-way communication between peered devices. In this case, the ESP32 board can act as both the sender (master) and the receiver (slave) simultaneously. We can have two ESP32 boards transmitting data as shown below:
Or even have a network of ESP32 boards transmitting data:
ESP-NOW Helpful Functions
Below is a list of ESP-NOW functions that come in handy and are used often while using ESP-NOW with ESP32. To view more information, take a look at the official ESP-NOW documentation.
- esp_now_init() : This function will initialize the ESP-NOW protocol. Remember to initiate Wi-Fi before initializing the ESP-NOW communication protocol.
- esp_now_add_peer() : This function will connect a device by passing the unique MAC address as an argument inside it.
- esp_now_send() : This function will send the data via ESP-NOW.
- esp_now_register_send_cb() : This function will register a callback function which will be called whenever some data will be sent from one peered device to another. It will return a message indicating whether the data was sent successfully or not.
- esp_now_register_rcv_cb() : This function will register a callback function which will be called whenever some data will be received by one peered device from another.
Setting up Arduino IDE
We will use Arduino IDE to program our ESP32 development boards. Thus, you should have the latest version of Arduino IDE. Additionally, you also need to install the ESP32 plugin. If your IDE does not have the plugin installed you can visit the link below:
Installing ESP32 library in Arduino IDE and upload code.
Now, first, we will introduce you to an Arduino sketch which will help us to identify our ESP32 board so that we know exactly which board to transmit the data to. It will display our ESP32 module’s MAC address on the serial monitor which we will later use in another sketch.
Obtaining ESP32 MAC Address
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.
#include "WiFi.h"
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_MODE_STA);
Serial.println(WiFi.macAddress());
}
void loop(){
}
In the setup() function, we are first setting our ESP32 board in station mode. Then by using the WiFi.macAddress() method we will obtain the unique MAC address in our serial monitor.
Please ensure that you select the correct board and COM port before uploading your code to the board. Select ESP32 Dev Module from the Tools > Board menu. Then, choose the appropriate port through which your board is connected from the Tools > Port menu. In this case, we are using the ESP32 development board 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.
We will use this unique address to identify the receiver ESP32 module later on.
ESP32 ESP-NOW One-way Communication Example
Now, let us learn how to send data from one ESP32 board to another, using the ESP-NOW protocol. We will use the simplest configuration, where one ESP32 board acts as the sender and the other ESP32 board acts as the receiver. You can use the method given below to transmit sensor data or any type of information from one ESP board to another. We will keep it simple and create a structure in our sketch which will store values of type char, int, float, and Boolean. This will help us in transmitting any type of data by just changing the structure in the sketch. For this project, we will require two Arduino sketches one for the sender and the other for the receiver.
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 ESP32 board by using its unique MAC address.
- We will then send the data to this peer device that we set up.
#include <esp_now.h>
#include <WiFi.h>
// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x7C, 0x9E, 0xBD, 0x37, 0xCA, 0x84};
typedef struct struct_message {
char character[100];
int integer;
float floating_value;
bool bool_value;
} struct_message;
struct_message message;
void data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nStatus of Last Message Sent:\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;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
}
void loop() {
strcpy(message.character, "Welcome to Microcontrollerslab! This is test example.");
message.integer = random(1,10);
message.floating_value = 5.6;
message.bool_value = true;
esp_err_t outcome = esp_now_send(broadcastAddress, (uint8_t *) &message, sizeof(message));
if (outcome == ESP_OK) {
Serial.println("Mesage sent successfully!");
}
else {
Serial.println("Error sending the message");
}
delay(2000);
}
How does the Code Work?
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 Receiver MAC Address
Secondly, we will specify the MAC Address of the ESP32 board which will act as the receiver. We will use the same ESP32 board which we used in the sketch above when finding the MAC address. Replace the address with the unique MAC address of your own ESP32 board. You can use the sketch which was given previously, to find the MAC address of your module.
// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x7C, 0x9E, 0xBD, 0x37, 0xCA, 0x84};
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 the data that we will transmit to the receiver board via ESP-NOW. These will be of type char, int, float, and bool.
typedef struct struct_message {
char character[100];
int integer;
float floating_value;
bool bool_value;
} 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 acquire the data and transmit it accordingly.
struct_message message;
data_sent()
The callback function, data_sent(), acts as the receiver for messages. We will now define this function as a parameter while registering it for sending messages. Whenever a message is sent from the ESP32 sender side, the serial monitor will print whether the message was successfully delivered or not.
void data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nStatus of Last Message Sent:\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 is sent from the sender side, the data_sent() function will be called.
esp_now_register_send_cb(data_sent);
The following lines of code pair the two ESP32 boards (both the sender and the receiver).
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
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 board. After every 2 seconds, the following message will be sent:
“Welcome to Microcontrollerslab! This is a test example” As the character, a random integer between 1-10, the floating number 5.6 and the value 1 as we have set the bool_value to ‘true.’
You can easily change the structure of ‘message’ to send data according to your needs. We have incorporated the common data types here.
strcpy(message.character, "Welcome to Microcontrollerslab! This is a test example.");
message.integer = random(1,10);
message.floating_value = 5.6;
message.bool_value = true;
Then we will send the message and monitor if it was sent successfully or not.
esp_err_t outcome = esp_now_send(broadcastAddress, (uint8_t *) &message, sizeof(message));
if (outcome == ESP_OK) {
Serial.println("Mesage sent successfully!");
}
else {
Serial.println("Error sending the message");
}
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 is received by the receiver ESP32 board.
#include <esp_now.h>
#include <WiFi.h>
typedef struct struct_message {
char character[100];
int integer;
float floating_value;
bool bool_value;
} 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("Char: ");
Serial.println(message.character);
Serial.print("Int: ");
Serial.println(message.integer);
Serial.print("Float: ");
Serial.println(message.floating_value);
Serial.print("Bool: ");
Serial.println(message.bool_value);
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 does the Code Work?
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.
typedef struct struct_message {
char character[100];
int integer;
float floating_value;
bool bool_value;
} 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("Char: ");
Serial.println(message.character);
Serial.print("Int: ");
Serial.println(message.integer);
Serial.print("Float: ");
Serial.println(message.floating_value);
Serial.print("Bool: ");
Serial.println(message.bool_value);
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 is 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
Now after saving both of the sender and receiver sketches upload them onto their respective ESP32 boards.
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 receiver ESP32 module. Make sure you choose the correct COM port through which it is connected. Notice, that both of the boards will be connected to different COM ports so select the COM port accordingly. Click on the upload button to upload the code into the ESP32 board (receiver). After you have uploaded your code to the board press its ENABLE button.
Now, open both the serial monitors. You will be able to see the messages being displayed on the receiver side after every 2 seconds. These include the char, int, float, and bool parameters which we specified in the program sketch.
In the sender side’s serial monitor, you will be able to view the text that the message was successfully delivered.
Notice that both COM ports are different. In our case, it is COM5 for the receiver side and COM11 for the sender side.
How to Secure ESP-NOW Communication
There are several methods you can secure ESP-NOW communication to guarantee that it is secure and private:
Encrypt the data: Encrypting the data is one of the most useful ways to secure ESP-NOW communication. You can encrypt the data using different encryption algorithms, such as AES or RSA. Encrypting the data will prevent anyone from intercepting and reading the transmitted data.
Use secure keys: ESP-NOW supports the use of secure keys to authenticate and establish a connection between devices. By using secure keys, you can ensure that only authorized devices are able to communicate with each other.
Use a secure communication protocol: If the security of your application requires more advanced security measures, you may want to consider using a different communication protocol such as WiFi, which has built-in support for encryption and authentication.
Use a separate security layer: In some cases, it may be useful to use a separate security layer on top of ESP-NOW to provide additional security. For example, you could use a secure tunneling protocol such as HTTPS to protect the data being transmitted over ESP-NOW.
ESP32 ESP-NOW Range
The range of ESP-NOW depends on a number of factors including antenna design and configuration, and the operating environment. In general, ESP-NOW has a range of up to 220 meters (772 feet)However, these ranges are approximate and can vary significantly based on the specific circumstances.
Factors that can affect the range of ESP-NOW include the following:
Radio frequency interference: ESP-NOW operates in the 2.4 GHz frequency band, which is shared with other wireless technologies such as Bluetooth and WiFi. This means that there is the potential for interference from other devices operating in the same frequency band.
Operating environment: The range of ESP-NOW can be affected by physical obstacles such as walls, ceilings, and floors, as well as environmental factors such as temperature, humidity, and atmospheric pressure.
Antenna design: The range of ESP-NOW can be affected by the type and design of the antenna used. For example, using a directional antenna can increase the range of ESP-NOW, while using an omnidirectional antenna can decrease the range.
Overall, it is important to consider the specific range requirements of your application when choosing a wireless communication protocol such as ESP-NOW.
Conclusion
In conclusion, we have learned about the ESP-NOW communication protocol and its various features. As an example, we sent a small packet of data from one ESP32 board to another in a fast and convenient manner. You can use the same sketch to transfer useful data including sensor readings or even control the output pins of one ESP32 board through another ESP32 board easily. Although, we have used two ESP32 boards to communicate with each other. But you can also use ESP-NOW for communication between ESP8266 and ESP32 boards.
You may also like to read:
Do we need to run sender and receiver from two individual computers?
Because it looks arduino instance can only access one COM port?
You can use any other serial terminal like putty.
Dear my friend ,
Thanks for clarification of espnow samples.
Can you share the source code of 2way comm. for Arduino ide. Because your examples above are about master-slave methodology.
thanks
Thank you for the example and for the explanation.
It should be noted however, that in the sender program the line ‘esp_now_peer_info_t peerInfo;’ should be place outside of the setup() function (i.e. as a global variable), otherwise we get error messages: ‘E (122) ESPNOW: Peer interface is invalid’, and
‘Failed to add peer’.
Best regards,
Istvan
Versions I used: Arduino IDE 1.8.19, ESP32 Arduino Core 2.0.2
ESP32 WROOM-32 DOIT Devkit V1
Or just correct the code to
esp_now_peer_info_t peerInfo={};
“Use secure keys: ESP-NOW supports the use of secure keys to authenticate and establish a connection between devices. By using secure keys, you can ensure that only authorized devices are able to communicate with each other.”
This is not correct. The receiver will not detect if packets are unencrypted, and accept them just fine. There is encryption in ESP-NOW but no authentication. Senders can easily set their MAC addresses and thus spoof messages. For security critical data, users need to use authentication on the application level, for example using a shared key and HMAC.