ESP-NOW Two-Way Communication Between ESP32 Boards

In this guide, we’ll show you how to establish a two-way communication between two ESP32 boards using ESP-NOW communication protocol. As an example, two ESP32 boards will exchange sensor readings (with a range in open field up to 220 meters ~ 722 feet).

ESP-NOW Two-Way Communication Between ESP32 Boards

Watch the Video Introduction

For an introduction to ESP-NOW protocol, you can watch the following video:

If you want to learn more about ESP-NOW, you can read this guide: Getting Started with ESP-NOW (ESP32 with Arduino IDE).

Introducing ESP-NOW

ESP-NOW is a connectionless communication protocol developed by Espressif that features short packet transmission. This protocol enables multiple devices to talk to each other without using Wi-Fi.

ESP-NOW - ESP32 Logo

This is a fast communication protocol that can be used to exchange small messages (up to 250 bytes) between ESP32 boards. ESP-NOW is very versatile and you can have one-way or two-way communication in different arrangements.

In this tutorial, we’ll show you how to establish a two-way communication between two ESP32 boards.

ESP-NOW ESP32 Two-Way Communication Protocol

Note: read our ESP-NOW Getting Started Guide for a complete introduction to ESP-NOW protocol with ESP32.

Project Overview

The following diagram shows a high-level overview of the project we’ll build.

ESP-NOW Two-Way Communication - Send Sensor Readings Between Boards
  • In this project we’ll have two ESP32 boards. Each board is connected to an OLED display and a BME280 sensor;
  • Each board gets temperature, humidity and pressure readings from their corresponding sensors;
  • Each board sends its readings to the other board via ESP-NOW;
  • When a board receives the readings, it displays them on the OLED display;
  • After sending the readings, the board displays on the OLED if the message was successfully delivered;
  • Each board needs to know the other board MAC address in order to send the message.

In this example, we’re using a two-way communication between two boards, but you can add more boards to this setup, and having all boards communicating with each other.

Prerequisites

Before proceeding with this project, make sure you check the following prerequisites.

ESP32 add-on Arduino IDE

We’ll program the ESP32 using Arduino IDE, so before proceeding with this tutorial you should have the ESP32 add-on installed in your Arduino IDE. Follow the next guide:

Install libraries

Install the following libraries in your Arduino IDE. These libraries can be installed through the Arduino Library Manager. Go to Sketch Include LibraryManage Libraries and search for the library name.

Parts Required

For this tutorial you need the following parts:

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 between each board, we need to know their 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 boards to get their MAC address.

// Complete Instructions to Get and Change ESP MAC Address: https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/

#include "WiFi.h"
 
void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_MODE_STA);
  Serial.println(WiFi.macAddress());
}
 
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

Write down the MAC address of each board to clearly identify them.

ESP32 board MAC Address label

Schematic Diagram

Wire an OLED display and a BME280 sensor to each ESP32 board. Follow the next schematic diagram.

ESP32 wiring schematic diagram to BME280 sensor and OLED display

You can use the following table as a reference when wiring the BME280 sensor.

BME280ESP32
VIN3.3V
GNDGND
SCLGPIO 22
SDAGPIO 21

You can also follow the next table to wire the OLED display to the ESP32.

OLED DisplayESP32
GNDGND
VCCVIN
SCLGPIO 22
SDAGPIO 21

Learn more about interfacing multiple I2C peripherals with the ESP32.

ESP32 Two-Way Communication ESP-NOW Code

Upload the following code to each of your boards. Before uploading the code, you need to enter the MAC address of the other board (the board you’re sending data to).

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp-now-two-way-communication-esp32/
  
  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>

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Adafruit_BME280 bme;

// REPLACE WITH THE MAC Address of your receiver 
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

// Define variables to store BME280 readings to be sent
float temperature;
float humidity;
float pressure;

// Define variables to store incoming readings
float incomingTemp;
float incomingHum;
float incomingPres;

// Variable to store if sending data was successful
String success;

//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
    float temp;
    float hum;
    float pres;
} struct_message;

// Create a struct_message called BME280Readings to hold sensor readings
struct_message BME280Readings;

// Create a struct_message to hold incoming sensor readings
struct_message incomingReadings;

esp_now_peer_info_t peerInfo;

// Callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
  if (status ==0){
    success = "Delivery Success :)";
  }
  else{
    success = "Delivery Fail :(";
  }
}

// Callback when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
  Serial.print("Bytes received: ");
  Serial.println(len);
  incomingTemp = incomingReadings.temp;
  incomingHum = incomingReadings.hum;
  incomingPres = incomingReadings.pres;
}
 
void setup() {
  // Init Serial Monitor
  Serial.begin(115200);

  // Init BME280 sensor
  bool status = bme.begin(0x76);  
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Init OLED display
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
 
  // 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 Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  // Register for a callback function that will be called when data is received
  esp_now_register_recv_cb(OnDataRecv);
}
 
void loop() {
  getReadings();
 
  // Set values to send
  BME280Readings.temp = temperature;
  BME280Readings.hum = humidity;
  BME280Readings.pres = pressure;

  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &BME280Readings, sizeof(BME280Readings));
   
  if (result == ESP_OK) {
    Serial.println("Sent with success");
  }
  else {
    Serial.println("Error sending the data");
  }
  updateDisplay();
  delay(10000);
}
void getReadings(){
  temperature = bme.readTemperature();
  humidity = bme.readHumidity();
  pressure = (bme.readPressure() / 100.0F);
}

void updateDisplay(){
  // Display Readings on OLED Display
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println("INCOMING READINGS");
  display.setCursor(0, 15);
  display.print("Temperature: ");
  display.print(incomingTemp);
  display.cp437(true);
  display.write(248);
  display.print("C");
  display.setCursor(0, 25);
  display.print("Humidity: ");
  display.print(incomingHum);
  display.print("%");
  display.setCursor(0, 35);
  display.print("Pressure: ");
  display.print(incomingPres);
  display.print("hPa");
  display.setCursor(0, 56);
  display.print(success);
  display.display();
  
  // Display Readings in Serial Monitor
  Serial.println("INCOMING READINGS");
  Serial.print("Temperature: ");
  Serial.print(incomingReadings.temp);
  Serial.println(" ºC");
  Serial.print("Humidity: ");
  Serial.print(incomingReadings.hum);
  Serial.println(" %");
  Serial.print("Pressure: ");
  Serial.print(incomingReadings.pres);
  Serial.println(" hPa");
  Serial.println();
}

View raw code

How the code works

We’ve covered in great detail how to interact with the OLED display and with the BME280 sensor in previous tutorials. Here, we’ll just take a look at the relevant parts when it comes to ESP-NOW.

The code is well commented so that you understand what each line of code does.

To use ESP-NOW, you need to include the next libraries.

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

In the next line, insert the MAC address of the receiver board:

uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x07, 0x0D, 0x64};

Create variables to store temperature, humidity and pressure readings from the BME280 sensor. These readings will be sent to the other board:

// Define variables to store BME280 readings to be sent
float temperature;
float humidity;
float pressure;

Create variables to store the sensor readings coming from the other board:

// Define variables to store incoming readings
float incomingTemp;
float incomingHum;
float incomingPres;

The following variable will store a success message if the readings are delivered successfully to the other board.

// Variable to store if sending data was successful
String success;

Create a structure that stores humidity, temperature and pressure readings.

typedef struct struct_message {
  float temp;
  float hum;
  float pres;
} struct_message;

Then, you need to create two instances of that structure. One to receive the readings and another to store the readings to be sent.

The BME280Readings will store the readings to be sent.

// Create a struct_message called BME280Readings to hold sensor readings
struct_message BME280Readings;

The incomingReadings will store the data coming from the other board.

// Create a struct_message to hold incoming sensor readings
struct_message incomingReadings;

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

esp_now_peer_info_t peerInfo;

Then, we need to create two callback functions. One will be called when data is sent, and another will be called when data is received.

OnDataSent() callback function

The OnDataSent() function will be called when new data is sent. This function simply prints if the message was successfully delivered or not. If the message is delivered successfully, the status variable returns 0, so we can set our success message to “Delivery Success”:

Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (status ==0) {
  success = "Delivery Success :)";
}

If the success message returns 1, it means the delivery failed:

else {
  success = "Delivery Fail :(";
}

OnDataRecv() callback function

The OnDataRecv() function will be called when a new packet arrives.

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

We save the new packet in the incomingReadings structure we’ve created previously:

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

We print the message length on the serial monitor. You can only send 250 bytes in each packet.

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

Then, store the incoming readings in their corresponding variables. To access the temperature variable inside incomingReadings structure, you just need to do call incomingReadings.temp as follows:

incomingTemp = incomingReadings.temp;

The same process is done for the other variables:

incomingHum = incomingReadings.hum;
incomingPres = incomingReadings.pres;

setup()

In the setup(), initialize ESP-NOW.

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

Then, register for the OnDataSent callback function.

esp_now_register_send_cb(OnDataSent);

In order to send data to another board, you need to pair it as a peer. The following lines register and add a new peer.

// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;

// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}

Register for the OnDataRecv callback function.

esp_now_register_recv_cb(OnDataRecv);

loop()

In the loop(), we call the getReadings() function that is responsible for getting new temperature readings from the sensor. That function is created after the loop().

After getting new temperature, humidity and pressure readings, we update our BME280Reading structure with those new values:

BME280Readings.temp = temperature;
BME280Readings.hum = humidity;
BME280Readings.pres = pressure;

Then, we can send the BME280Readings structure via ESP-NOW:

// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &BME280Readings, sizeof(BME280Readings));

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

Finally, call the updateDisplay() function that will update the OLED display with the readings coming from the other ESP32 board.

updateDisplay();

The loop() is executed every 10 seconds.

That’s pretty much how the code works. You should upload the code to both of your boards. You just need to modify the code with the MAC address of the board you’re sending data to.

Recommended reading: Guide for OLED Display with ESP32 and Guide for BME280 Sensor with ESP32.

Demonstration

After uploading the code to both boards, you should see the OLED displaying the sensor readings from the other board, as well as a success delivery message.

ESP32 ESP-NOW Protocol Exchange Data Demonstration

As you can see, it’s working as expected:

ESP32 ESP-NOW Protocol Exchange Data Demonstration

We tested the communication range between the two boards, and we are able to get a stable communication up to 220 meters (approximately 722 feet) in open field. In this experiment both ESP32 on-board antennas were pointing to each other.

ESP-NOW communication range test with ESP32 boards

Wrapping Up

In this tutorial we’ve shown you how to establish a two-way communication with two ESP32 boards using ESP-NOW. This is a very versatile communication protocol that can be used to send packets with up to 250 bytes. ESP-NOW communication protocol can also be used with ESP8266 boards: Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE).

As an example, we’ve shown you the interaction between two boards, but you can add many boards to your setup. You just need to know the MAC address of the board you’re sending data to.

We’ll be publishing more tutorials about ESP-NOW, so stay tuned. Additionally, write a comment below saying which tutorial you would like to see with ESP-NOW.

To learn more about the ESP32 board, take a look at 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 »

Enjoyed this project? Stay updated by subscribing our newsletter!

172 thoughts on “ESP-NOW Two-Way Communication Between ESP32 Boards”

  1. Hi Rui,

    Great write up! But I am having a lot of issues compiling the code; the error is with the library. For some reason the Arduino IDE is unable to find it. I did install all of the board libraries for esp32, esp12 and esp8266. I am able to run their example sketches without any issues. I tried this on 3 different Window PC’s without much luck. Any help is welcome. Abrigado!

    Reply
      • Hi Sara,

        I get the following error when compiling the ESP_Now_Les_Example_1 sketch

        exit status 1
        esp_now.h: No such file or directory

        Thanks for helping me out!! 🙂

        Brett

        Reply
        • Hi.
          The esp_now.h file is installed by default.
          So, make sure you have an ESP32 board selected in the Boards menu and that the ESP32 boards are properly installed.
          Also, can you run the example sketch in File > Examples > ESP32 > ESPNow?
          Regards,
          Sara

          Reply
          • Hi Sara,
            I found espnow.h is for the ESP8266, and esp_now.h is for the ESP32.
            I have been taking notes as I make mistakes…and find solutions.
            With esp8266 also make sure to add:
            WiFi.mode(WIFI_STA);
            WiFi.disconnect(); // it will improve signal responses.

  2. Can you still use any of the Wi-Fi modes while using ESP-NOW?
    How can this configuration share their data with the outside world?

    Reply
  3. Hi Rui,
    This method of communication between ESP32 boards is very interesting.
    I built an arduino based audio controller, for my whole home audio system.
    I want to add control from a second station in another room, and upgrade to either an ESP32 or ESP8266.
    After seeing this system, I think it could be adapted to do what I need.
    I want it to display the current Mode in both rooms, yet allow the source selection, power off commands to be updated from either location.
    I will set up this project as a start, so I can go through the code step by step.
    Thank you, and Sara, so much for all the great tutorials!

    Reply
  4. Hi Sara and Rui,
    Great tutorial.
    As I saw in the comments in the tutorial for the “ESP-NOW One-Way communication”, it is possible to use the ESP-NOW with Wi-Fi (it is possible right?).

    And about the ESP32-CAM, does the ESP-NOW works well with it? I’m thinking in building an web server in the ESP32-CAM and this server receives the data os temperature, pressure, umidity from another ESP32, via ESP-NOW.

    Reply
  5. It is not quite the same. I saw it long time ago, and it is in the Master slave configuration.
    What Rui did here is like ESP-NOW combo mode, when each of the boards can talk when he want and is not master slave. Both are equal.

    “https://www.espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf” , page 2.7, table 2-1

    Reply
  6. Assuming i do not have sensors and no float data, if a replace float with double , can i send 8 bytes to the other end ?
    Or better,
    float replaced with double
    float replaced with double
    float replaced with double
    so in this case i can send 24 bytes from one board to other.
    I am new to that, so correct me if i am wrong.

    Reply
  7. I just found this 15 minutes ago and now it’s up and running! I just happened to get some BME280 (s) and some OLED (s) last week.

    Reply
  8. I do not know what is wrong on my side but both of the boards they display on the port monitor that they do not find BME280.
    I am surprised because they are just 4 wire.
    The power is OK 3.3V
    Also the display is completely blank/black.
    I put for the display 5V from USB as power.
    Any suggestion.

    Reply
  9. I am at the end of the rope.
    1.I am using a breakout from sparkfun for BME280:
    SparkFun Atmospheric Sensor Breakout – BME280-SEN-13676
    The address is by default 0x77 (default, ‘1’ side) – The same like in
    Adafruit library:
    #define BME280_ADDRESS (0x77) // Primary I2C Address
    I tried the simple BME test sketch from
    “ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)”
    and all the time i get the same error:
    “Could not find a valid BME280 sensor, check wiring!”
    On the Adafruit Feather board : “Assembled Adafruit HUZZAH32 – ESP32 Feather Board – with Stacking Headers”
    SCL pin is pin 11 on the battery side and
    SDA is pin 12.
    I have two identical boards and i exclude possibility to be both of them bad.
    Can anybody give me a suggestion because i do not see any one now.

    Reply
    • Hi Ion,
      I suggest you to try a different sensor. In my case, I didn’t have a BME280 and used other I²C sensors… or better, with analog or one-wire sensors.

      One question: The I²C pins in the Adafruit boards follows a different numeration? In all my ESP32 boards the SCL pin is the 22 and the SDA is the 21… this is the other suggestion that I can tell you right now…. I’m not as good as Rui or Sara!

      Reply
      • Thank you Eduardo. I will try tomorrow with different sensors if i get them in time. For pinout, i just follow the Adafruit pinout table, not the numbers, like here
        “https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/pinouts”

        Reply
        • I never used this board.
          Now I understand when you said that used pins 11 and 12.
          Well, I’ll try to find some free time in this next days and try to organize and document what I built this weekend. I built a project using I²C sensors a ESP32 and a ESP32-CAM. After organizing it I can upload the project to my github, if someone is interested.

          Reply
    • Hi Ion.
      The SDA and SCL pins of the Huzzah 32 are: GPIO 23 (SDA) and GPIO 22 (SCL)
      By default, our code uses GPIO 21 (SDA) and GPIO 22 (SCL). So, this might be the problem.
      I suggest that you run an I2C scanner sketch to see if your board is able to find the sensor. The sketch is this: https://randomnerdtutorials.com/esp32-esp8266-i2c-lcd-arduino-ide/
      If it doesn’t detect any sensor on the I2C pins, you need to add a few lines of code so that it uses other I2C pins.

      To use other I2C pins, in the setup() add the following:
      I2CBME.begin(23, 23, 400000);

      Then, initialize the sensor as follows:
      if (!bme.begin(0x76, &I2CBME)) {
      Serial.println(“Could not find a valid BME280 sensor, check wiring!”);
      while (1);
      }

      This should solve the problem.

      Also, this tutorial might be useful: https://randomnerdtutorials.com/esp32-i2c-communication-arduino-ide/

      Let me know the results.
      Regards,
      Sara

      Reply
      • Hello Sara,
        First i got an error that i have too many wifi. I tried each one at the time, but no luck. I deleted all. and of course i get
        “WiFi.h: No such file or directory”
        Which one to download again and use ?
        Thank you

        Reply
      • The scanner found the bme280 at address 77, for both of them.
        How about the I2C address for display?
        What is the brand and model of display you used ?
        More news tomorrow as i just bought 2 new NodeMCU from Amazon canada with delivery today.
        The I2C is on port GPIO 21 and 22.

        Reply
  10. Hello Sara,
    I will do the test immediately.
    is it for sure
    I2CBME.begin(23, 23, 400000);
    because above you said it use pins 22,23 .
    “The SDA and SCL pins of the Huzzah 32 are: GPIO 23 (SDA) and GPIO 22 (SCL)”

    Reply
  11. I made it to work with only one BME280
    In the sketch where i do not have BME, i just comment the “while” line like here
    ” // while (1); ”
    Now i have communication on both directions and i wait to get the parts and put them on the breadboard.
    One side display on the port monitor the temperature and Hum and Press from the other side like here
    13:30:50.317 -> Last Packet Send Status: Delivery Success
    13:30:50.317 -> INCOMING READINGS
    13:30:50.317 -> Temperature: 25.60 �C
    13:30:50.317 -> Humidity: 38.87 %
    13:30:50.317 -> Pressure: 987.90 hPa
    13:30:58.316 ->
    13:30:58.316 -> Bytes received: 12
    13:31:00.315 -> Sent with success

    And the other monitor, does not have info about the value of temp,hum, or pressure and display
    13:32:58.428 -> INCOMING READINGS
    13:32:58.428 -> Temperature: 0.00 �C
    13:32:58.428 -> Humidity: 0.00 %
    13:32:58.428 -> Pressure: 0.00 hPa
    13:33:00.362 ->
    13:33:00.362 -> Bytes received: 12
    13:33:08.426 -> Sent with success
    13:33:08.426 ->
    13:33:08.426 -> Last Packet Send Status: Delivery Success

    I want to Thank You in particular to Sara for patience to babysit me.
    I will update tomorrow when i have all the parts.
    Thank you ALL.

    Reply
      • Interesting. I have to look closer to it even though it looks big.
        I did a thermostat one time and i used MCP7940N.
        But of course i did my own PCB and i put it on the same board with the display, and BME680.

        Reply
        • You took the IC MCP7940N and built your own PCB with battery? Congratulations! It really looks great!

          The ZS-042 may look big, but is because the battery which powers it. It is a CR2032 battery (3V, 2cm of diammeter). The dimensions of the module is 2cm x 4cm.

          Also, the ZS-042 is a very nice module to use. It is I²C powered too. Of course the DS3231 don’t have all the features of the MCP7940N, but it solves my problems here!

          God luck Ion!

          Reply
          • If you write me at [email protected] i can send you a pdf print of the board.
            I do all my boards and i am happy to do them how i want, not having a pcb designer doing it 5 times until i am happy.
            Some times, i do small changes and it take me few hours and i am done.

  12. I have a question. I put an extra row on the display after pressure to display the lenght of the bytes received.
    Like here
    display.print(“Bytes Received: “);
    display.print(“len”);
    But here of course is just printing len
    I tried as a variable like is defined here
    Serial.print(“Bytes received: “);
    Serial.println(len);
    Then i wrote on the display

    display.print(“Bytes Received: “);
    display.print(len);
    and i got an error
    ESP-NOW_LEFT:177:17: error: ‘len’ was not declared in this scope
    display.print(len);
    ^
    exit status 1
    ‘len’ was not declared in this scope
    What should i write to display the number of bytes received ?
    Thank you

    Reply
    • Hi Ion.
      When you print “len”, it is a String. So, it will output exactly that “len”.
      What is happening is that the variable len is defined locally inside the OnDataRecv() function. When you define a variable locally, you can’t access it anywhere else in the code except where it was defined.
      You need to create a global variable that can be accessed anywhere in the code. Usually, variables created outside functions are global.
      To do that, you can for example: create a variable called messageLength before the setup(), for example:
      int messageLength;
      Then, inside the OnDataRecv() function update the messageLength variable to match the bytes received. You can add the following line:
      messageLength = len;
      Now, you can use the messageLength variable to display the number of bytes received:
      display.print(“Bytes Received: “);
      display.print(messageLength);
      I hope this helps.
      Regards,
      Sara

      Reply
  13. Yes I like the project a lot .What would be nice is a real time graph for the readings done on the biggest color Tiff display you can get. Have the reading and background in different colors. And maybe add some graphics. Just a thought. Thanks for the projects.

    Rainman…….

    Reply
  14. hi! can someone help me solve my problem.
    i used similar sensor and got this message from serial monitor : “Sent with success
    Last Packet Send Status: Delivery Fail”

    is it sent or not? I open the serial monitor of the received ESP32 but nothing in the monitor. so it didnt received any data?

    Reply
    • Hi Josephine.
      That means that the command to send the message was successfully executed but the other board didn’t receive the package.
      It can be due to:
      – you didn’t inserted the receiver MAC address or you’ve inserted it wrong;
      – the receiver structure doesn’t match the sender structure
      – you’ve forgotten to upload the receiver code to the other board.
      I hope this helps.
      Regards,
      Sara

      Reply
  15. Hi,

    I am planning to do a project named wireless call buttons. This project has two main devices. One is Button(esp32) and another one is receiver(esp32). The buttons are going to implement in patient rooms in a hospital. The receiver kept in one corner. When the patient press button, the receiver has to receive message from the specific button.

    May i know is this possible with ESP, because every floor in hospital has more than 10 rooms and the distance between Room No:10(button10) and receiver will be 200 meters. It may not line of sight also. In my case we should not use internet.

    ESP-Now i can use, but my doubt is how 200 meters is possible in this case?

    Reply
    • Hi.
      You have to experiment. But I’m not sure if it is possible to get a distance of 200 meters inside a building with walls and obstacles – seems very unlikely.
      But you really have to try it to figure it out.
      Regards,
      Sara

      Reply
  16. Maybe you can use a repeater.
    Put a receiver at room No:5, collect data from all 10 rooms and resend it to nurse station – your main receiver. It is unlikely that all the 10 buttons will be pressed in the same time, I mean, same fraction of second and make a collision on the traffic. On the repeater i suggest to have a ESP to receive data, a PIC or whatever processor to store it, and a second ESP to send it further. In this way you have a receiver ESP and a transmitter ESP. You can explore the options. Do not forget, but in the hospitals everything must be redundant. Is like planes or space shuttle. If one line fail, MUST be a second to instantly replace it and keep working.
    If the patient in room 8 press the button to call the nurse because he feel ill and needs assistance, that message MUST go to nurse station.

    Reply
    • Complementing Ion Gheorghe’s idea, wouldn’t it be nice for Yuvaraj create a Wi-Fi web server with one ESP32 and the others (doesn’t need to be a ESP32, can be a ESP8266, PIC or something cheaper) and when a button in one device is pressed the web server shows to the nurse the exactly device wich pressed the button. To solve the redundancy issue pointed by Ion, the device with the pacient sends the signal continually untill the moment that the nurse do something in the web server to tell to the pacient’s device that he/she received the message (in ESP-NOW, there is a risk of the nurse’s device receive the message but he/she don’t see it because is busy with another pacient). Also, the Wi-Fi repeaters suggested by Ion probably will work better in this sittuation.

      Of course, this suggestion is just a guessing that came in to my mind, built over I imagined whe I read Yuvaraj’s comment.

      Reply
      • Excelente idea Eduardo.
        Of course at nurse station we can get an output of the receiving ESP to drive also a buzzer or similar.
        The nurse might be busy surfing the net, chatting on the phone, having a coffee, or …..
        BUT, whatever you put in a hospital, be sure it is 1000000% reliable.
        The patients and hospitals will not hesitate to sue you for smallest issue.
        The system also must pass Safety Approval.
        I wanted to propose to a hospital in Toronto a wireless thermostat .
        Yes, a dummy thermostat but with a lot of benefits and energy saving for hospital. The safety tests i had to pass, was so expensive that i just renounced. They told me that temperature in some of the rooms is critical, and constantly recorded, and they cannot afford to use whatever system and lose some patients, medicines or similars.

        Reply
        • Yes, Ion is more right impossible…
          The best suggestion for you, Yuvaraj, is first test your idea in a different space and after beig sure that you figured out in your mins all the suing possibilities (or at least almost, because human creativity is something really to beat) I believe that you can suggest this project for your superiors.

          Well thought Ion!

          Reply
  17. Hi , i have a specific question , i have 100 points(esp8266) that have a button, this button is in deepsleep mode, when the people press the button this button send a data via espnow and go to deepsleep mode, the esp32 that receive the data can support 100 call button ? not all the 100 buttons are pressed at the same time , if this possible or i need maximun 10 call buttons ?

    can i register one button send data and after disconect this peer to de server (espnow esp32)…

    thanks

    Reply
    • Hi.
      If all buttons are in deep sleep mode and only the “receiver” is awake, I think you shouldn’t have problems with all the buttons.
      It should also work for your scenario, if you simply use the 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF MAC address. All receivers that are awake will receive the message – in your case, it’s just one.
      But as I haven’t experimented with so many devices, I can’t really tell what happens with all those buttons.
      Regards,
      Sara

      Reply
    • Hello Paolo,
      What i see:
      1-Buttons are not registered anywhere. As long as as you tell them where to send data – MAC – they do not care how many they are, nor the receiver knows in advance, and you can have in my opinion 1000s.
      2-You said, that not every button is pressed in the same time. This is a very fine statement. Button 1 is pressed now, and button 2 is pressed a fraction of second after.
      So while the server is busy receiving data from button 1, data from button 2 is lost.
      This involve your creativity in coding. Each message sent must have the MAC of sender. The receiver, must acknowledge the sender back that the message arrived in full.
      The sender button does not have to go to sleep, or permit another press until he get the response that his first message was received OK. If the receiver button does not get the acknowledge reply in let’s say 100 ms, it has to resend the message.
      100ms it is a pure imaginary value. By trying with one button only, you can find out the total time until you get the response, and replace the 100 ms.
      So, the transmitter button, will resend the message until it receive the acknowledge that the message was received.
      Here it is the BIG picture of 100 buttons or more.
      Imagine an army of messages at the gate of receiver , trying to be received by the server.
      Of course, one by one in time will be received, and finally the last one is in. But during all that period, all the buttons waiting a reply, will not respond to eventual users, nor sleep.
      BUT your purpose of the buttons is to send SUCCESSFULLY a message to server.
      Try to imagine …..

      Reply
  18. Hey guys, thanks a lot for your explanation!

    In my case i have one ds18b20 sensor connectedto one board and i have another board sending the measurement interval and resolution to this board in order to perform the measurements following the interval and resolution that it has received.

    My problem is that when i send the interval and resolution to the second board it only works correctly when both boards are close. When they are a bit more far away, it only receives the interval, instead, it doesn’t update the resolution values.
    I send the data like you the temp, hum, pres.

    Is it possible that due to the distance, it only receives a part of the message correctly (interval) and lose the resolution part? I thought that if the message reached the destination, reached the whole message.

    I calculate that interval reachs up to 18 m, instead, interval and resolution values only reach up to 12 m.

    I don’t know if you, Rui and Sara or someone have faced this kind of problems, but i would thank a lot your help.

    I’m looking forward to hearing from you!

    Reply
    • Hi.
      That issue is very strange. It seems that due to the distance, it doesn’t receive the whole message.
      Maybe you can try sending different messages. One with the interval and other with the resolution one after the other and see if that solves the problem.
      Regards,
      Sara

      Reply
      • Hi Sara. But if both messages come from the same board, how can i identify them as an interval message and resolution message?

        Normally i identified the message by the MAC of the board coming from. But in this case both messages come from the same board, so both have the same MAC.

        Thank you!

        Reply
        • Hi.
          You can send the messages as a string, in which the interval message starts with an i and the resolution message starts with an r: for example
          “i20”
          “r1250”
          Then, on the receiver, you can split the strings to get only the number. Then, you can convert them to int or float or other variable type is more suitable.
          This is just a suggestion.
          Regards,
          Sara

          Reply
    • Further to my request above do we have a tutorial on using ESP NOW between ESP32 and ESP8266. sure it will be of value to many. Cheers

      Reply
      • Hi.
        No, I don’t have that specific project.
        But what you have to do for the ESP8266 is to combine a sender and receiver ESP8266 code on the same sketch.
        Regards,
        Sara

        Reply
  19. Hey,
    I am trying to create a Wi-Fi mesh using esp32 where one esp32 node (AP) is connected to a webserver (as demonstrated in your tutorials) and the other esp32 nodes communicate with each other using esp-now ( 2 way communication). My question is how do i Incorporate the client-server and peer to peer infrastructure in one to complete a mesh.
    I am also trying to generate hops between esp32 incase one is out of range of the AP. I’d appreciate your help.

    Thanks

    Reply
  20. hi im using espnow on 2 * esp32s, one as a master sending data and 1 as a slave recieving data, I have seen examples where a master can send to many slaves. is there any examples of a slave recieving sensor details from more than 1 master. maybe in a closed mesh network??
    board 1 data send >>>
    board 2 data send >>>
    board 3 data recieve <<<<<< from board 1 and board 2?????

    Reply
  21. HI,
    Working with this code from the beginning, I now have bidirectional comms sent over ESP-NOW. But I am only in the beginning of my code. One ESP32 has a couple of DS18B20s, and it sends indoor and outdoor temperatures to it’s local display, and the remote ESP32’s display too. (GREAT! BTW!!). I created a new struct for information of switch (button) states on the return from the remote, That data will eventually act as remote control switches for functions on the local. The switches are readable on the local, so the rest will be trivial, but I came to a question because I would like to save space.

    Why do you have local variables as well as a struct for the data? My guess is because then you can use one struct to transmit either way. Is this the case? And, since I am using different data and 2 structs, then I should be able to omit the local global variables and just use the struct variables throughout the code, (since the structs are global) correct? Or am I missing something?

    Thanks,
    Dave K

    Reply
  22. Hello
    I’m trying something that I assumed would be simple — sending 4 digits from one esp32 board to a second esp32 board.

    I’ve copied and pasted the SENDER and RECEIVER sketches from the https://randomnerdtutorials.com/esp-now-two-way-communication-esp32/ page. The RECEIVER sketch uploads without trouble. But I am having trouble with the SENDER sketch.

    I tried both verifying and uploading the SENDER sketch as copied and both are fine. But when I replace the MAC address {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} with the MAC address of the RECEIVER it fails. It highlights line 16… “uint8_t broadcastAddress1[] = {24:6F:28:2B:0A:88};”

    and gives the error message… “expected ‘}’ before ‘:’ token” .

    I have done nothing more to the code other than remove reference to the broadcast addresses 2 and 3, which aren’t needed

    I see the formatting of the MAC address I have inserted is different to that in the copied sketch, but this is how it was returned when I followed the procedure to get the MAC address of my RECEIVER board.

    Any suggestions would be gratefully appreciated.

    Reply
    • Hi Andrew.
      If your MAC address is 24:6F:28:2B:0A:88
      You should place it like this:
      uint8_t broadcastAddress1[] = {0x24, 0x6F, 0x28, 0x2B, 0x0A, 0x88};
      I’m sorry if that is not clear enough.
      I hope you get it working now.
      Regards,
      Sara

      Reply
  23. hola Sara. Escribote en galego porque sendo portuguesa imaxino que entenderas ben.
    Gustoume moito o teu tutorial. Levaba moitisimo tempo na procura de alguen que conseguira unha comunicacion nos dous sentidos cas esp32.
    A parte do LCD e o sensor non me fai falta pero tentarei sacar do teu codigo a parte da comunicacion porque vale ouro.
    Moito obrigado Sara!

    Reply
      • Olá de novo Sandra.
        Andiven a traballar onte no teu codigo pero non sei o que fago mal que nin tan sequeira vense no bluetooth do movel.
        eu so quero mandar bits dun o outro e o reves.
        Iste é o meu codigo, a ver se seche ocurre cal é o problema:

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

        uint8_t broadcastAddress[] = {0x24, 0x0A, 0xC4, 0x60, 0xB5, 0x3C}; //MAC ROBOT. Direccion de envio

        int salida0=0;
        int salida2=2;
        int entrada4=4;
        int entrada5=5;
        int buttonState = 0;

        int dato1;
        int dato2;
        int dato3;
        int dato4;

        int recibido1;
        int recibido2;
        int recibido3;
        int recibido4;

        typedef struct struct_message {
        int dat1;
        int dat2;
        int dat3;
        int dat4;
        } struct_message;

        struct_message datos_propios;
        struct_message datos_recibidos;

        void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status){
        }

        void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
        memcpy(&datos_recibidos, incomingData, sizeof(datos_recibidos));
        recibido1 = datos_recibidos.dat1;
        recibido2 = datos_recibidos.dat2;
        recibido3 = datos_recibidos.dat3;
        recibido4 = datos_recibidos.dat4;
        }

        void setup() {
        Serial.begin(115200);
        WiFi.mode(WIFI_STA);

        pinMode (salida0, OUTPUT);
        pinMode (salida2, OUTPUT);
        pinMode (entrada4, INPUT);
        pinMode (entrada5, INPUT);

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

        // Register peer
        esp_now_peer_info_t peerInfo;
        memcpy(peerInfo.peer_addr, broadcastAddress, 6);
        peerInfo.channel = 0;
        peerInfo.encrypt = false;

        esp_now_register_recv_cb(OnDataRecv);
        }

        void loop() {
        getReadings();

        datos_propios.dat1 = dato1;
        datos_propios.dat2 = dato2;
        datos_propios.dat3 = dato3;
        datos_propios.dat4 = dato4;

        esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &datos_propios, sizeof(datos_propios));

        buttonState = digitalRead(recibido4);

        if (buttonState == HIGH) {
        // turn LED on:
        digitalWrite(salida0, HIGH);
        } else {
        // turn LED off:
        digitalWrite(salida0, LOW);
        }
        }

        void getReadings(){
        dato1 = salida0;
        dato2 = salida2;
        dato3 = entrada4;
        dato4 = entrada5;

        }

        bo dia Sara

        Reply
  24. This is brilliant. I have managed to create a Master which can connect to 3 Clients individually. The clients control vertical window blinds.

    I have entered the three Client MAC addresses into the Master code as such:

    uint8_t broadcastAddress[][6] = {
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
    };

    (These MAC addresses here are not the exact ones of course) I then control any one of the three blinds by sending different values using a TFT touch screen.
    Everything works perfectly fine but I would like to store the MAC address on the SD card, then call the address from the SD card and fill them into the uint8_t broadcastAddress[] [] array.
    The reason I want to do this is that if I want to add more blind controllers in the future I can just add them to the text file on the SD card instead of having to modify the Master code.
    However, when I try to do this it tells me I can’t cast String to uint8_t which is quite obvious really.
    So, is there a way to copy the MAC address String from the SD card into the uint8_t array?

    I can convert the text file into HEX format and print them but I can’t fill them into the array in the same format as the code requires.

    Hope all this makes sense!!

    Reply
  25. I had a problem with an error when attaching a peer:
    ESPNOW: Peer interface is invalid.

    One solution I found was to make the creation of peerInfo global.

    If you want to keep it local to the setup function, then it has to be initialised to zeros before changing any of the entries. I used
    memset(&peerInfo, 0, sizeof(peerInfo));

    I’m assuming that when the structure is created on the heap it probably contains invalid data.

    I hope this helps someone.

    Regards, Ian

    Reply
    • Thank you very much, very helpful!
      Yes, indeed, this part of memory is clogged with some data, if initialized during operation from a function, and it must be cleared.

      Reply
  26. I try to add a Telegram communication to the 2-way ESP NOW project. It did not work.
    Is it correct the Wifi used by ESP NOW can not be connected to the internet as the same time?
    Thanks for clarification.

    Reply
  27. Hi Rui and Sara

    Do you know if it is possible to use ESP-NOW with MicroPython on the ESP-32? If so, do you have a tutorial on it?

    Cheers

    Andy

    Reply
  28. Hi, I have two esp32s talking to each other.
    One of them sends a message then does an action. The other one receives the message, does the same action and then sends a message back.

    I need them both to be in sync with each other so the actions cant be done without the message being passed between them, however I am having to put a delay in the loop or else the messages dont get sent and received properly, do you know if this is because the loop is going too fast for the esp-now to keep up?

    Any help would be appreciated

    Reply
    • Hi Pete, I also meet this question, and I just test if the delay in loop is more than 10ms, the sync will be ok, however when I set the delay in loop is less (for example 5ms), the communication between those board will be chaos.
      So have you solve this question? can we have exchange some idea or discuss with each other?
      My email address: whensveny at gmail.com.

      Reply
  29. Hi Rui,
    I am trying the similar example but sending 5 flex sensor values from one esp to another i.e one being the master and the other being the slave
    The problem i am facing is that the receiver doesn’t get updated values when flex sensor value changes i have to reset the master to receive the updated value
    I am using your master/slave example
    Please let me know if you can help

    Reply
  30. Hi Rui/Sara
    I am sending flex sensor values from one esp to another esp but on the receiver side the values don’t update unless i push the reset button on the sender esp
    Can i know why this is happening?

    Reply
  31. Hi,
    I am been trying to set up a 2 way com between 2 ESP32 boards and MLX90614 sensors.
    Each board has a sensor and OLED display and I want Board 1 to send temp readings to Board 2. But hey don’t seems to be working. Can you help med with issue?
    //Jay

    Reply
  32. I am having a strange Problem., As soon as I move my OnDataRecv Function to any tab other than first tab, even if it is on top of second tab (before setup and loop , which are on third or fourth tab); The Error

    ‘esp_now_send_status_t’ has not been declared

    appears while compilation/verification; this error appears in OnDataSent Function. If I move OnDataRecv back to end of first tab, verification is done , code works perfectly.

    Even if I split the code from above example at OnDataSent … into two tabs … , no change in sequence of commands this error occurs

    I have also created a discussion on Arduino Forum on this too at following link:
    https://forum.arduino.cc/t/espnow-compile-error-esp-now-send-status-t-has-not-been-declared/871040?u=athersaleem

    Reply
    • I have the same problem, as soon as i move the callback to another tab this error occurs. it’s kind of strange, if you find the solution please tell me

      Reply
    • Update: I’ve just found a solution to the problem, what i understood is that function prototype of this callback is missplaced at some point and defaults is type to int instead of esp_now_send_status_t, so you only need to put the function prototype of your callback at the first ino file, the one named same as your project folder and the code now compiles without problem, i´ll leave this explanation in spanish because i can explain more clearly.

      Actualizacion: Acabo de encontrar una solucion para el problema, al parecer todo tiene que ver con que el prototipo de la funcion de callback se pierde en algun punto antes de incluir los archivos de la libreria esp_now y por eso no encuentra la definicion de esp_now_send_status_t y lo define por defecto como int, entonces lo unico que hay que hacer es declarar el prototipo de la funcion callback en el archivo ino principal, el que tiene el mismo nombre que la carpeta y todo compila bien. Espero te ayude.

      Reply
      • Hey, could you please share the code for this. I do not understand how to declare the prototype of the callback function as mentioned in the response 🙁

        Reply
  33. This tutorial has been a great help to me! A question for you: it appears that all stations are constantly listening for incoming information, even while executing other code; is this true? If so, what is a good way to suspend receiving information until desired? Thanks for your work putting these tutorials together.
    Jack

    Reply
  34. Hello, first of all congratulations for the project.

    In your project, you read data from boards every 10 seconds. How faster can I do the same? I’ve to read data every 10ms. Is It possible?

    Regards
    Maria

    Reply
  35. Hello Maria,
    Just an advice.
    I believe reading data is more related to the sensor update time.
    I did not read the sensor data sheet, but i believe it is marked somewhere in small letter how fast the sensor update itself.
    Then, second step is to take in consideration how long it take for a transmission and receiving the message if the transmission was received or not.
    Once you have these parameters you calculate the scan time of a program and reduce your update time.
    This is just my opinion.

    Reply
    • Hi Ion. First of all, thank you.
      My sensors update time is 10ms. My concerns are about the transmission.
      I am trying to set up a two-way communication multiple-to-one and I need the central receives signal every 10ms from each board. Do you think that is possible?

      Reply
  36. i pair both esp32 after change mac address
    it detect slave device
    when changing mac address
    first step
    not accepting verify fail

    Reply
  37. first of all thank you all so much for this toturial : Muito Obrigado
    era isto que procurava para o meu projecto.
    a questao que tenho e em x de ser um sensor de humidade e ter um ecra posso so ter tipo uma wireless box a comunicar entre os 2 esp32
    num liga 4 fios que sao envio e recepcao de comunicao e no outro a mesma coisa e fazerem a partilha de dados como esta no vosso projecto.
    obrigado pela atencao

    Reply
  38. Hi Maria,
    I love your examples and made them work,no problem with transmitting strings,chars,int…
    Notherless i’ve got a problem with a two-ways CHAT between two nextion screens wired
    on serial and i think it’s interrupts problem,i have to often reset one esp32 to begin receive
    or sending.
    Strange hat this problem doesn’t occur with the two arduino monitors
    attributed to two serial ports,it works in each monitors without any interruption.
    I tested it with two nextion simulators at the same time and the problem appears again.
    I also tried with hardware serial in each esp32 wired to nextion,but the same.
    i don’t use any millis delay in my sketches.
    To resume,it work one,two times and then nothing unless i reset the esp32.
    What’s going on?

    Reply
  39. Hi,
    Thanks for your great tutorials!

    I have tried unsuccessfully to send and receive two different structs using ESP32_NOW. It appears to send ok but the data seems to be received in a slightly blended way, I suspect it might have something to do with memory?? Is it possible to do? The reason I ask is because of the 250 byte struct size restriction on send.
    Any advice or sample code would be gratefully accepted.
    Regards
    Geoff
    RNT Fan

    Reply
  40. I’m starting a project and I’m having trouble doing it with 4 boards. 3 of these cards connected to one.

    This main sends and receives data from the others, would it be possible to do this?

    Reply
  41. Hi,

    Great tutorials!

    I have 2 way comms on 2 ESP32’s via ESP-NOW, is it possible for one of the ESP32’s to also act as a webserver or would I need a 3rd ESP32 to be the webserver receiver?

    Thanks
    Steve

    Reply
  42. A complete treasure trove of stuff on RNT keep it up you two wonderful people, thank you for all the great stuff.

    I am collecting parts for a combo of many of you tutorials and this one fills in a lot of gaps.

    I want to have a plethora of esp8266 connected sensors some mains powered and some solar and/or deep sleep.

    I have deduced a data structure that will encompass all the various readings I want to see and will devise a ‘no data in here’ for esp remotes that are for other readings.

    I was going to create a many to one but I will see if I can create essentially 2 receivers to receive the same data. (How would you describe Many to Two?)

    The idea is that I want to put 2 tft colour screens with the data shown graphically off the back of 2 esp32 in different rooms of my home. They will display live data from the sending esp8266 sensors.

    I want to monitor some 12 volt batteries, a greenhouse, some outside weather devices, my roof space and temperature in different parts of my home and garden.

    Sounds a lot but isn’t really, I was going to use your web server and gleam the data from json but after seeing this I am hoping to use the tft screen esp’s to allow me to send control back to some of the esp8266.

    It’s going to be a slow process as I start small and slowly add the remote esp8266 and work out their bit too.

    This is a quick draft of my generic data structure that will give me some flexibility. Voltage will be those on battery power and each remote head will be monitored for temperature using ds18b one wire chips

    EspNow Board

    Device ID 2
    Device Name – Text N+2
    Device Voltage- Float 4
    Device Temperature- Float 4
    Maintenance Mode – Boolean 1
    Alarm – Boolean 1
    Sensor1 – Float 4
    Sensor1 – Text X+2
    Sensor2 – Float 4
    Sensor2 – Text Y+2
    Digital In – Integer 2
    Digital Out – Integer 2

    Byte Count = N+X+Y+40

    It shows hopefully how data can be mixed up and still be very much smaller that 250bytes

    I haven’t worked out how as yet but a byte is 8 bits so I have the potential to read and write 8 digital devices using just the 2 digital integers. I suspect I will limit the text name too so as to increase reliability.

    It’s going to take a while but maybe you’ll be impressed in time?

    Cheers Clive

    Reply
  43. HI Sara & Rui,
    I have tried your example above with slight variations.
    I am just sending data to one ESP32 board from another ESP32 board. The boards are working with the serial monitor. I see the receiver board getting the data but if I disconnect the serial cable and battery power the sender or the receiver then the there is no data transmission. I cannot figure out why?
    //Jay

    Reply
    • Jay, have you found what caused this? I am trying to get two-way communication working. One ESP32 being powered by a battery. I have not got it to work, I am thinking I have the same issue as you.

      Reply
  44. Great tutorial and well presented.

    I am new to ESP32s and trying to get basic two way communication working for a project. I simplified your examples to just use potentiometers and the serial monitor. I always get the error “Error sending the data”. I used the MAC addresses I found using your code then I also used the common MAC address {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} and still had no luck. I confirmed the ESP32s work by using the Arduino ESP32_NOW master/slave example sketch.

    Here is the code I used:

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

    // REPLACE WITH THE MAC Address of your receiver
    uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

    // Define variables to store BME280 readings to be sent
    int Pot_Val;

    // Define variables to store incoming readings
    int incomingpot;

    // Variable to store if sending data was successful
    String success;

    //Structure example to send data
    //Must match the receiver structure
    typedef struct struct_message {
    int pot;
    } struct_message;

    // Create a struct_message called BME280Readings to hold sensor readings
    struct_message BME280Readings;

    // Create a struct_message to hold incoming sensor readings
    struct_message incomingReadings;

    // Callback when data is sent
    void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
    Serial.print(“\r\nLast Packet Send Status:\t”);
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? “Delivery Success” : “Delivery Fail”);
    if (status ==0){
    success = “Delivery Success :)”;
    }
    else{
    success = “Delivery Fail :(“;
    }
    }

    // Callback when data is received
    void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
    memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
    Serial.print(“Bytes received: “);
    Serial.println(len);
    incomingpot = incomingReadings.pot;
    }

    void setup() {
    // Init 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 Send CB to
    // get the status of Trasnmitted packet
    esp_now_register_send_cb(OnDataSent);

    // Register peer
    esp_now_peer_info_t peerInfo;
    memcpy(peerInfo.peer_addr, broadcastAddress, 6);
    peerInfo.channel = 0;
    peerInfo.encrypt = false;

    // Add peer
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println(“Failed to add peer”);
    return;
    }
    // Register for a callback function that will be called when data is received
    esp_now_register_recv_cb(OnDataRecv);
    }

    void loop() {
    getReadings();

    // Set values to send
    BME280Readings.pot = Pot_Val;

    // Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &BME280Readings, sizeof(BME280Readings));

    if (result == ESP_OK) {
    Serial.println(“Sent with success”);
    }
    else {
    Serial.println(“Error sending the data”);
    }
    updateDisplay();
    delay(1000);
    }
    void getReadings(){
    Pot_Val = analogRead(34);
    Serial.println(Pot_Val);
    }

    void updateDisplay(){

    // Display Readings in Serial Monitor
    Serial.println(“INCOMING READINGS”);
    Serial.print(“Pot “);
    Serial.print(incomingReadings.pot);
    Serial.println();
    }

    Reply
    • Excellent question, if you find an answer please share it. Whomever wrote this tutorial clearly has their head up their ****.

      Reply
    • Even I am facing same issue.
      compilation error in arduino IDE:
      error: invalid conversion from ‘void ()(const uint8_t, const uint8_t*, int)’ {aka ‘void ()(const unsigned char, const unsigned char*, int)’} to ‘esp_now_recv_cb_t’ {aka ‘void ()(const esp_now_recv_info, const unsigned char*, int)’} [-fpermissive]
      138 | esp_now_register_recv_cb(OnDataRecv);

      Reply
  45. I have two questions. First, my receiving Slave ESP32’s are using batteries and must go into DeepSleep. The ESP User’s Guide states that STAION mode alone should not be used for receiver’s using deep sleep. Why is this and what mode should I use, and will this require other codes changes? My second question is If a receiver is asleep when a message is sent, does the Master automatically resend the message until the Slave awakens and receives the message?

    Reply
  46. I see you use a broadcast MAC address to send the message to everyone. This means that I can have more than 2+ units and being able to communicate with each other?

    thank you
    Oz

    Reply
  47. Thank you very much for this Great tutorial. I have a question. Why is used the memcpy instruction? Is not posile to assign data as always (=)?

    In this part foe example:

    void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
    memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
    Serial.print(“Bytes received: “);
    Serial.println(len);
    incomingTemp = incomingReadings.temp;
    incomingHum = incomingReadings.hum;
    incomingPres = incomingReadings.pres;
    }

    It Could be something like:
    incomingTemp = incomingData.temp; etc, without the memcpy instuction?

    Thank you very much 🙂 .

    Reply
  48. Hi,

    Thank you very much for this Great tutorial. I have a question.

    is it possible to read from Rx Tx on ESP32 datas incoming from à RS485 TTL modul send throught ESP NOW reciev by an other ESP32 and write to RX TX to a RS485 modul
    (a transparent RS485 passtrough bridge ) ?

    Reply
  49. Hi and thank for this great tutoral,

    is it possible with ESP NOW to (bridge serial ports ) ?
    i need to RS485 modul > rx tx to ESP32 > wireless communication > ESP32 > rx tx to RS485 modul.

    Reply
  50. Thank you for your excellent tutorial.

    Using your tutorial I have easily been able to get two ESP32 modules with ESP-NOW talking to each other.
    But one thing I have not been able to figure out is how to detect when loss of incoming packets happens at the Rx. When the Tx is shut off the Rx just keeps chugging along on the last data sent.

    Reply
  51. Hi,
    Do they need to know each other before communication?
    Is possible to have a master wait for random unknown communication, and the slaves hold the key to authenticate in the master?
    Something like that.

    Thank lá
    Hugo

    Reply
    • Hi.
      You can do all that manually, since the master can use the FF:FF:FF:FF:FF MAC address to send data to all available devices.
      After that, you can try to handle the connections.
      Regards,
      Sara

      Reply
  52. Hi, first of all, thank you for this tutorial. It is working on my end.

    Just a question, if ESP-NOW protocol doesn’t need Wi-Fi to have multiple devices to communicate with each other, why there is a declaration of WiFi.h and the initialization of WiFi.mode(WIFI_STA) in your code? Is it possible to remove them?

    Thanks
    Daniel

    Reply
  53. wondering if esp-now protocol makes sure the packet is send and received? So, when I send something and the status of the on_data_send call is success, does that imply the other side has actually received the data? If the other side is out-of-range or the communication fails otherwise, will the call to on_data_send have a status of “fail”.
    Or do I need to write my own code with two-way communication to ensure the data was processed on the receiving end?

    Reply
    • If you are unicasting to a specific peer MAC address, the on_data_send success means that an acknowledgement was received back from that peer that the data was received accurately. That is part of the 802.11 action frames protocol that ESP-NOW uses. There is a really good explanation of this in MrDIY’s video about it youtube.com/watch?v=Xmzk6v5qIjo

      Please note that this only acknowledges that the packet was received error free. What your device does with the received data is up to you. If your data is absolutely critical, it’s probably not a bad idea to write your own checksum verification and have your application acknowledge separately. For my immediate application, I only need to send a byte or two that contain a simple command. If my byte matches what the remote unit is expecting, that’s good enough for me 🙂

      Reply
  54. Would it be possible to adapt this idea to having 4 buttons on one esp32 and 4 relays on another esp32, then just have the button presses actuate the relays through bluetooth? The buttons would be momentary switches and need to mimic that same function with the relays.

    Reply
    • I se as very possible and not difficult. From the ESP connected to the buttons, you send a message with the state of the four buttons by ESP-NOW and the receiver ESP replicate the states of the buttons in the relay module. So, when the the programmed state in a button change, the sender send another message to the receive and it replicate then in the relays.
      Of course, it’s only a possibility that I thought here, when I read your message. Probably there are another ones.

      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.