How to connect ESP32 and ESP8266 using ESP-Now protocol

This tutorial describes how to use ESP-Now protocol to connect ESP32 and ESP8266. Both devices support ESP-Now protocol.

What is ESP-Now protocol?

ESP-Now is a protocol developed by Espressif that enables multiple devices (ESP32 and ESP8266) to connect to each other.

ESP-Now is a low power wireless protocol that connects ESP32 and ESP8266 devices without using WiFi. It enables direct wireless connection between two ESP devices without WiFi. The same connection can be established between multiple ESP devices at the same time. In ESP-Now terminology, a device is called peer. Once the devices are paired the connection can be established without a handshake.

Where to use this wireless protocol?

This protocol is useful when we want to exchange data between ESP32 and ESP8266 devices without using a router. It is the ideal protocol when there is the need to control smart lights connected to ESP devices or when we want to exchange data between two or more peers (i.e sensor readings)

ESP-Now limitations

ESP now has some limitations:

  • payload: the maximum payload size is 250 byte
  • it is supported only by ESP devices

How to connect ESP32 and ESP822 devices

There are several scenarios where the ESP-Now protocol can be used to connect ESP32 and ESP8266 or other ESP devices. Moreover, these devices can play different roles.

One-to-one communication

In one-to-one communication two ESP devices connect to exchange data.

ESP-Now: ESP32 connects to ESP8266

Using the ESP-Now terminology, there are in this scenario two peers. It is possible to set the role of each peer:

  • Master
  • Slave
  • Combo (master and slave at the same time)

One-to-many – Broadcast: Master and slaves

In one-to-many (Broadcast), ESP32 or ESP8266 acts as a broadcaster sending the same message to all the peers connected.

ESP-Now broadcast mesage. One ESP device broadcasts a message to other ESP devices

The broadcaster plays the master role that connects to several slaves. This scenario is useful when we want to control several devices that act as slaves using a broadcaster that sends data to them. You can think about a system that switches all the lights off using a central controller.

Many-to-one: Gateway

The last scenario, where the ESP-now can be used, is many-to-one configuration. In this scenario, there is a central gateway that collects all the data incoming from the peers connected to it. You can imagine several sensors that send the data acquired to a central collector that will handle somehow this information.

ESP-Now gateway. Multiple ESP8266 send data to ESP32 using ESP-Now protocol

During this ESP-Now tutorial, we will describe and implement all the scenarios described above.

Recommended:
How to connect ESP32 to the smartphone through Node-RED
Send Email using ESP32 with SMTP Server: Plain and HTML email

How to use ESP-Now with ESP32 and ESP8266

Before going into the details about using ESP-Now to connect ESP32 and ESP822, it is useful to understand the steps to follow to initialize and connect the devices.

The ESP-Now protocol is supported by ESP32 and ESP8266 even if there are some differences in the methods. Anyway, the main steps are valid for both devices and are:

  1. Initialize the ESP-Now protocol
  2. If we are developing a master or a broadcaster
    • Add peer (if we are developing a master or broadcaster)
    • Define the callback function to know if a message is sent
    • Send a message
  3. If we are developing a slave
    • Add a callback function to know when a new message is arriving

One important thing to notice is that the ESP-Now protocol supports only 250 bytes as payload. If you need to send a bigger payload you can consider using MQTT protocol with ESP32.

ESP-Now functions

This a list of the most useful functions to use ESP-Now if we want to exchange data between ESP devices:

ESP32ESP 8266Description
esp_now_init()esp_now_init()Initialize the ESP-Now protocol
esp_now_add_peer()esp_now_add_peer()Add a new peer. These two functions differ in the parameters the accept
esp_now_register_send_cb()esp_now_register_send_cb()Callback function to know info about the message sent
esp_now_register_rcv_cb()esp_now_register_rcv_cb()Callback function invoked when a new message arrives

To have more information, you can referer to the EspressIf guide for the ESP32 and here for the ESP8266.

ESP-Now ESP8266 example code

In this paragraph, we are going to discuss how to exchange data between two ESP8266 devices in a One-to-one configuration where one of the devices is a master while the other is the slave.

This is very simple scenario, where there is a device that sends data and the other one that receives it. We will have two different codes: one for the sender and the another one for the receiver.

ESP-Now ESP8266 Sender source code

The sender source code is shown below:

/** * ESP-NOW * * Sender */ #include <Arduino.h> #include <ESP8266WiFi.h> #include <espnow.h> // Mac address of the slave uint8_t peer1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; typedef struct message { int red; int green; int blue; }; struct message myMessage; void onSent(uint8_t *mac_addr, uint8_t sendStatus) { Serial.println("Status:"); Serial.println(sendStatus); } void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); // Get Mac Add Serial.print("Mac Address: "); Serial.print(WiFi.macAddress()); Serial.println("ESP-Now Sender"); // Initializing the ESP-NOW if (esp_now_init() != 0) { Serial.println("Problem during ESP-NOW init"); return; } esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); // Register the peer Serial.println("Registering a peer"); esp_now_add_peer(peer1, ESP_NOW_ROLE_SLAVE, 1, NULL, 0); Serial.println("Registering send callback function"); esp_now_register_send_cb(onSent); } void loop() { myMessage.red = 10; myMessage.green = 80; myMessage.blue = 180; Serial.println("Send a new message"); esp_now_send(NULL, (uint8_t *) &myMessage, sizeof(myMessage)); delay(60000); }

A brief code description:

  • Line 10: This is the MAC address of the slave. We use this address to send data
  • Line 11-15: The message structure. This is the message we want to send to the ESP-Now peer (or slave). The message can hold several fields (i.e. char, int, float and so on).
  • Line 17-20: The callback function invoked when the message is sent
  • Line 29: The ESP-Now is initialized before using it
  • Line 33: The ESP8266 defines its role. This is the master role
  • Line 36: The code adds the peer to the peer list. In this case, the device, which acts as master, add the other ESP8266 (the slave) using the Mac address. In this way, the two ESP devices can exchange data through the ESP-Now protocol
  • Line 38: We register the callback function that is triggered as soon as the message is sent
  • Line 45: The master sends the message to the other ESP8266 through the ESP-Now

ESP8266 Receiver source code

The receiver code is much more simpler:

#include <Arduino.h> #include <ESP8266WiFi.h> #include <espnow.h> typedef struct message { int red; int green; int blue; } message; message myMessage; void onDataReceiver(uint8_t * mac, uint8_t *incomingData, uint8_t len) { Serial.println("Message received."); // We don't use mac to verify the sender // Let us transform the incomingData into our message structure memcpy(&myMessage, incomingData, sizeof(myMessage)); Serial.print("Red:"); Serial.println(myMessage.red); Serial.print("Green:"); Serial.println(myMessage.green); Serial.print("Blue:"); Serial.println(myMessage.blue); } void setup() { Serial.begin(115200); WiFi.disconnect(); ESP.eraseConfig(); // Wifi STA Mode WiFi.mode(WIFI_STA); // Get Mac Add Serial.print("Mac Address: "); Serial.print(WiFi.macAddress()); Serial.println("\nESP-Now Receiver"); // Initializing the ESP-NOW if (esp_now_init() != 0) { Serial.println("Problem during ESP-NOW init"); return; } //esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); // We can register the receiver callback function esp_now_register_recv_cb(onDataReceiver); } void loop() { // put your main code here, to run repeatedly: }

  • Line 10-21: This is the callback function triggered when a new message arrives through the ESP-Now protocol
  • Line 35: As in the ESP8266 sender, we have to initialize the ESP-Now protocol
  • Line 42: We register the ESP-Now callback function that will be invoked as soon as a new message arrives to the ESP8266

Testing the ESP-Now connection between ESP8266

Running the code: one in the sender device and the other in the receiver the result you get is something like:

ESP-Now connect two ESP devices

Connect ESP32 to multiple ESP8266 through ESP-Now protocol

This is little bit more complex example that describes how to use ESP-Now with ESP32. In this scenario, we can suppose that there is an ESP32 that is a broadcaster and sends data to multiple ESP8266 devices thorugh the ESP-Now protocol. This is a one-to-many configuration. To describes this scenario, we will suppose that the:

  • ESP32 connects to two ESP8266 devices through the ESP-Now protocol
  • The ESP32 broadcasts a message containing RGB color information to all the connected devices
  • The ESP8266 devices receive this message and control an RGB Led strips.

This example is interesting because we can describe how to use the ESP-Now to broadcast a message and how to integrate ESP32 and ESP8266 using the ESP-Now protocol. You can use all ESP32 or all ESP8266 in this example.

ESP32 esp now broadcast: esp_now_send

This code describes how to broadcast data to multiple peers using ESP32:

/** * ESP-NOW: ESP32 Broadcast with ESP-Now * * */ #include <Arduino.h> #include <WiFi.h> #include <esp_now.h> // ESP8266 Mac address (first peer) uint8_t mac_peer1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // ESP8266 Mac address (second peer) uint8_t mac_peer2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; esp_now_peer_info_t peer1; esp_now_peer_info_t peer2; int i = 0; typedef struct message { int red; int green; int blue; }; struct message myMessage; void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); // Get Mac Add Serial.print("Mac Address: "); Serial.print(WiFi.macAddress()); Serial.println("ESP32 ESP-Now Broadcast"); // Initializing the ESP-NOW if (esp_now_init() != 0) { Serial.println("Problem during ESP-NOW init"); return; } memcpy(peer1.peer_addr, mac_peer1, 6); peer1.channel = 4; peer1.encrypt = 0; // Register the peer Serial.println("Registering a peer 1"); if ( esp_now_add_peer(&peer1) == ESP_OK) { Serial.println("Peer 1 added"); } memcpy(peer2.peer_addr, mac_peer2, 6); peer2.channel = 4; peer2.encrypt = 0; // Register the peer Serial.println("Registering a peer 2"); if ( esp_now_add_peer(&peer2) == ESP_OK) { Serial.println("Peer 2 added"); } } void loop() { myMessage.red = random(0, 254); myMessage.green = random(0, 254); myMessage.blue = random(0, 254); Serial.println("Send a new message"); esp_now_send(NULL, (uint8_t *) &myMessage, sizeof(myMessage)); delay(2000); }

A brief code description:

  • Line 10-12: We define two variables named peer1 and peer2 that will contain the information related to the two ESP8266 that will receive the messages
  • Line 30: We initialize the ESP-Now protocol
  • Line 34-36: We define the peer1 details:
    • its Mac Address,
    • the channel we will use to send data (you can choose the ESP-Now channel you like)
    • the encryption (false in this scenario)
  • Line 39: The ESP32 add the ESP8266 (the peer1) to the peer list
  • Line 42-44: We define the peer2 details:
    • its Mac Address,
    • the channel we will use to send data (you can choose the ESP-Now channel you like)
    • the encryption (false in this scenario)
  • Line 47: The ESP32 add the ESP8266 (the peer2) to the peer list
  • Line 56: We are sending the message. Note here that we used NULL that means we want to send the message to all the peer registered

ESP8266 receiver peer: onDataReceiver

This receiver is almost the same described previously, with the only difference that when the ESP8266 receive a message it wil set the LED color.

#include <Arduino.h> #include <ESP8266WiFi.h> #include <espnow.h> #include <Adafruit_NeoPixel.h> #define NUM_OF_LEDS D6 #define PIN 12 typedef struct message { int red; int green; int blue; } message; uint8_t key[] = {0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44, 0x33, 0x44}; message myMessage; // Neopixel LEDs strip Adafruit_NeoPixel pixels(NUM_OF_LEDS, PIN, NEO_GRB + NEO_KHZ800); void onDataReceiver(uint8_t * mac, uint8_t *incomingData, uint8_t len) { Serial.println("Message received."); // We don't use mac to verify the sender // Let us transform the incomingData into our message structure memcpy(&myMessage, incomingData, sizeof(myMessage)); Serial.print("Red:"); Serial.println(myMessage.red); Serial.print("Green:"); Serial.println(myMessage.green); Serial.print("Blue:"); Serial.println(myMessage.blue); pixels.fill(pixels.Color(myMessage.red, myMessage.green, myMessage.blue)); pixels.show(); } void setup() { Serial.begin(115200); WiFi.disconnect(); ESP.eraseConfig(); // Initialize Neopixel pixels.begin(); // Wifi STA Mode WiFi.mode(WIFI_STA); // Get Mac Add Serial.print("Mac Address: "); Serial.print(WiFi.macAddress()); Serial.println("\nESP-Now Receiver"); // Initializing the ESP-NOW if (esp_now_init() != 0) { Serial.println("Problem during ESP-NOW init"); return; } //esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); // We can register the receiver callback function esp_now_register_recv_cb(onDataReceiver); } void loop() { // put your main code here, to run repeatedly: }

If you are using Wemos D1 mini, there could be a bug that prevents this device to receive broadcast messages. In this case, you can follow this guide to know how to fix it.

Testing the ESP-Now with ESP32 and ESP8266 controlling LEDs

If you run the code in the ESP32 and ESP8266 devices you will notice that very 2 seconds the LEDs, connected to the ESP8266, change color. The ESP32 sends messages with random RGB values.

Use ESP32 to collect sensor data

In the last part of this tutorial, we will use the ESP32 as an ESP-Now gateway to collect sensor readings connected to multiple ESP8266. In other words, ESP8266 devices send data to the ESP32.

ESP32 gateway

This is the code of the ESP32 gateway that is connected to other ESP8266 using ESP-Now:

#include <Arduino.h> #include <WiFi.h> #include <esp_now.h> typedef struct message { float temperature; float humidity; }; struct message myMessage; void onDataReceiver(const uint8_t * mac, const uint8_t *incomingData, int len) { Serial.println("Message received."); // We don't use mac to verify the sender // Let us transform the incomingData into our message structure memcpy(&myMessage, incomingData, sizeof(myMessage)); Serial.println("=== Data ==="); Serial.print("Mac address: "); for (int i = 0; i < 6; i++) { Serial.print("0x"); Serial.print(mac[i], HEX); Serial.print(":"); } Serial.print("\n\nTemperature: "); Serial.println(myMessage.temperature); Serial.print("\nHumidity: "); Serial.println(myMessage.humidity); Serial.println(); } void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); // Get Mac Add Serial.print("Mac Address: "); Serial.print(WiFi.macAddress()); Serial.println("ESP32 ESP-Now Broadcast"); // Initializing the ESP-NOW if (esp_now_init() != 0) { Serial.println("Problem during ESP-NOW init"); return; } esp_now_register_recv_cb(onDataReceiver); } void loop() { // put your main code here, to run repeatedly: }

Notice the message (line 5-8) is different than before because it holds the temperature and the humidity. The other aspects are almost the same covered previously.

ESP8266 sender

There are two ESP8266 senders that wirelessly sends data to the ESP32. The ESP sender code is shown below:

/** * ESP-NOW * * Sender */ #include <Arduino.h> #include <ESP8266WiFi.h> #include <espnow.h> #include <SPI.h> #include <Wire.h> #include <DHT.h> #define DHTTYPE DHT11 #define DHTPin D6 uint8_t peer1[] = {0x24, 0x6F, 0x28, 0x10, 0x67, 0xD8}; typedef struct message { float temperature; float humidity; }; struct message myMessage; // Initialize DHT sensor. DHT dht(DHTPin, DHTTYPE); void onSent(uint8_t *mac_addr, uint8_t sendStatus) { Serial.println("Status:"); Serial.println(sendStatus); } void setup() { Serial.begin(115200); dht.begin(); WiFi.mode(WIFI_STA); // Get Mac Add Serial.print("Mac Address: "); Serial.print(WiFi.macAddress()); Serial.println("ESP-Now Sender"); // Initializing the ESP-NOW if (esp_now_init() != 0) { Serial.println("Problem during ESP-NOW init"); return; } esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); // Register the peer Serial.println("Registering a peer"); esp_now_add_peer(peer1, ESP_NOW_ROLE_SLAVE, 1, NULL, 0); Serial.println("Registering send callback function"); esp_now_register_send_cb(onSent); } void loop() { myMessage.temperature = dht.readTemperature(); myMessage.humidity = dht.readHumidity(); Serial.println("Send a new message"); esp_now_send(NULL, (uint8_t *) &myMessage, sizeof(myMessage)); delay(60000); }

Every minute, these two ESP8266 devices send the temperature and the humidity acquired by DHT11 sensor.

The final result is shown in the picture below:

ESP-Now between ESP devices

Wrapping up

This post describes how to use ESP-Now wireless protocol. The ESP-Now is fast and reliable protocol that connects different devices. There are different scenarios where we can use ESP-Now. We have used ESP-Now protocol to connect ESP8266 with an ESP8266 in one-to-one configuration. Moreover, we have learned how to use ESP-Now to connect ESP32 and ESP8266 where the ESP32 receives data from multiple ESP8266 devices. On the other hand, the ESP8266 can send data to ESP8266.

Tags: ,