ESP NOW is a protocol which allows ESP32 devices to exchange data. For this to be possible, we need to know the Mas address of all the devices involved in the communication.
Below is a short sketch which allow to detect the MAC address of an ESP32:
/*
ESP32 MAC Address printout
esp32-mac-address.ino
Prints MAC Address to Serial Monitor
DroneBot Workshop 2022
https://dronebotworkshop.com
*/
// Include WiFi Library
#include "WiFi.h"
void setup() {
// Setup Serial Monitor
Serial.begin(115200);
// Put ESP32 into Station mode
WiFi.mode(WIFI_MODE_STA);
// Print MAC Address to Serial monitor
Serial.print("MAC Address: ");
Serial.println(WiFi.macAddress());
}
void loop() {
}
Communication can be:
- One initiator to 1 or several responders
- Bi-directional
- Several initiators to 1 responder.
Sketch for 1 initiator to 1 responder:
/*
ESP-NOW Demo - Transmit
esp-now-demo-xmit.ino
Sends data to Responder
DroneBot Workshop 2022
https://dronebotworkshop.com
*/
// Include Libraries
#include <esp_now.h>
#include <WiFi.h>
// Variables for test data
int int_value;
float float_value;
bool bool_value = true;
// MAC Address of responder - edit as required
uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0x7A, 0xAE, 0x7C};
// Define a data structure
typedef struct struct_message {
char a[32];
int b;
float c;
bool d;
} struct_message;
// Create a structured object
struct_message myData;
// Peer info
esp_now_peer_info_t peerInfo;
// Callback function called 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");
}
void setup() {
// Set up Serial Monitor
Serial.begin(115200);
// Set ESP32 as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Initilize ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Register the send callback
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;
}
}
void loop() {
// Create test data
// Generate a random integer
int_value = random(1,20);
// Use integer to make a new float
float_value = 1.3 * int_value;
// Invert the boolean value
bool_value = !bool_value;
// Format structured data
strcpy(myData.a, "Welcome to the Workshop!");
myData.b = int_value;
myData.c = float_value;
myData.d = bool_value;
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
if (result == ESP_OK) {
Serial.println("Sending confirmed");
}
else {
Serial.println("Sending error");
}
delay(2000);
}
One Way responder sketch:
/*
ESP-NOW Demo - Receive
esp-now-demo-rcv.ino
Reads data from Initiator
DroneBot Workshop 2022
https://dronebotworkshop.com
*/
// Include Libraries
#include <esp_now.h>
#include <WiFi.h>
// Define a data structure
typedef struct struct_message {
char a[32];
int b;
float c;
bool d;
} struct_message;
// Create a structured object
struct_message myData;
// Callback function executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&myData, incomingData, sizeof(myData));
Serial.print("Data received: ");
Serial.println(len);
Serial.print("Character Value: ");
Serial.println(myData.a);
Serial.print("Integer Value: ");
Serial.println(myData.b);
Serial.print("Float Value: ");
Serial.println(myData.c);
Serial.print("Boolean Value: ");
Serial.println(myData.d);
Serial.println();
}
void setup() {
// Set up Serial Monitor
Serial.begin(115200);
// Set ESP32 as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Initilize ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Register callback function
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}
Broadcast mode sketch:
/*
ESP-NOW Multi Unit Demo
esp-now-multi.ino
Broadcasts control messages to all devices in network
Load script on multiple devices
DroneBot Workshop 2022
https://dronebotworkshop.com
*/
// Include Libraries
#include <WiFi.h>
#include <esp_now.h>
// Define LED and pushbutton state booleans
bool buttonDown = false;
bool ledOn = false;
// Define LED and pushbutton pins
#define STATUS_LED 15
#define STATUS_BUTTON 5
void formatMacAddress(const uint8_t *macAddr, char *buffer, int maxLength)
// Formats MAC Address
{
snprintf(buffer, maxLength, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
}
void receiveCallback(const uint8_t *macAddr, const uint8_t *data, int dataLen)
// Called when data is received
{
// Only allow a maximum of 250 characters in the message + a null terminating byte
char buffer[ESP_NOW_MAX_DATA_LEN + 1];
int msgLen = min(ESP_NOW_MAX_DATA_LEN, dataLen);
strncpy(buffer, (const char *)data, msgLen);
// Make sure we are null terminated
buffer[msgLen] = 0;
// Format the MAC address
char macStr[18];
formatMacAddress(macAddr, macStr, 18);
// Send Debug log message to the serial port
Serial.printf("Received message from: %s - %s\n", macStr, buffer);
// Check switch status
if (strcmp("on", buffer) == 0)
{
ledOn = true;
}
else
{
ledOn = false;
}
digitalWrite(STATUS_LED, ledOn);
}
void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status)
// Called when data is sent
{
char macStr[18];
formatMacAddress(macAddr, macStr, 18);
Serial.print("Last Packet Sent to: ");
Serial.println(macStr);
Serial.print("Last Packet Send Status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void broadcast(const String &message)
// Emulates a broadcast
{
// Broadcast a message to every device in range
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
esp_now_peer_info_t peerInfo = {};
memcpy(&peerInfo.peer_addr, broadcastAddress, 6);
if (!esp_now_is_peer_exist(broadcastAddress))
{
esp_now_add_peer(&peerInfo);
}
// Send message
esp_err_t result = esp_now_send(broadcastAddress, (const uint8_t *)message.c_str(), message.length());
// Print results to serial monitor
if (result == ESP_OK)
{
Serial.println("Broadcast message success");
}
else if (result == ESP_ERR_ESPNOW_NOT_INIT)
{
Serial.println("ESP-NOW not Init.");
}
else if (result == ESP_ERR_ESPNOW_ARG)
{
Serial.println("Invalid Argument");
}
else if (result == ESP_ERR_ESPNOW_INTERNAL)
{
Serial.println("Internal Error");
}
else if (result == ESP_ERR_ESPNOW_NO_MEM)
{
Serial.println("ESP_ERR_ESPNOW_NO_MEM");
}
else if (result == ESP_ERR_ESPNOW_NOT_FOUND)
{
Serial.println("Peer not found.");
}
else
{
Serial.println("Unknown error");
}
}
void setup()
{
// Set up Serial Monitor
Serial.begin(115200);
delay(1000);
// Set ESP32 in STA mode to begin with
WiFi.mode(WIFI_STA);
Serial.println("ESP-NOW Broadcast Demo");
// Print MAC address
Serial.print("MAC Address: ");
Serial.println(WiFi.macAddress());
// Disconnect from WiFi
WiFi.disconnect();
// Initialize ESP-NOW
if (esp_now_init() == ESP_OK)
{
Serial.println("ESP-NOW Init Success");
esp_now_register_recv_cb(receiveCallback);
esp_now_register_send_cb(sentCallback);
}
else
{
Serial.println("ESP-NOW Init Failed");
delay(3000);
ESP.restart();
}
// Pushbutton uses built-in pullup resistor
pinMode(STATUS_BUTTON, INPUT_PULLUP);
// LED Output
pinMode(STATUS_LED, OUTPUT);
}
void loop()
{
if (digitalRead(STATUS_BUTTON))
{
// Detect the transition from low to high
if (!buttonDown)
{
buttonDown = true;
// Toggle the LED state
ledOn = !ledOn;
digitalWrite(STATUS_LED, ledOn);
// Send a message to all devices
if (ledOn)
{
broadcast("on");
}
else
{
broadcast("off");
}
}
// Delay to avoid bouncing
delay(500);
}
else
{
// Reset the button state
buttonDown = false;
}
}
Multiple Transmitters:
/*
ESP-NOW Remote Sensor - Transmitter (Multiple Version)
esp-now-xmit-multiple.ino
Sends Temperature & Humidity data to other ESP32 via ESP-NOW
Uses DHT22
Multiple Transmitter modification
DroneBot Workshop 2022
https://dronebotworkshop.com
*/
// Include required libraries
#include <WiFi.h>
#include <esp_now.h>
#include <DHT.h>
// Define DHT22 parameters
#define DHTPin 5
#define DHTType DHT22
// Create DHT Object
DHT dht(DHTPin, DHTType);
// Variables for temperature and humidity
float temp;
float humid;
// Integer for identification (make unique for each transmitter)
int ident = 2;
// Responder MAC Address (Replace with your responders MAC Address)
uint8_t broadcastAddress[] = {0x24, 0x0A, 0xC4, 0x04, 0xF4, 0x40};
// Define data structure
typedef struct struct_message {
float a;
float b;
int c;
} struct_message;
// Create structured data object
struct_message myData;
// Register peer
esp_now_peer_info_t peerInfo;
// Sent data callback function
void OnDataSent(const uint8_t *macAddr, esp_now_send_status_t status)
{
Serial.print("Last Packet Send Status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup() {
// Setup Serial monitor
Serial.begin(115200);
delay(100);
// Initiate DHT22
dht.begin();
// Set ESP32 WiFi mode to Station temporarly
WiFi.mode(WIFI_STA);
// Initialize ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Define callback
esp_now_register_send_cb(OnDataSent);
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() {
// Read DHT22 module values
temp = dht.readTemperature();
delay(10);
humid = dht.readHumidity();
delay(10);
Serial.print("Temp: ");
Serial.println(temp);
Serial.print("Humid: ");
Serial.println(humid);
// Add to structured data object
myData.a = temp;
myData.b = humid;
myData.c = ident;
// Send data
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
// Delay for DHT22 sensor
delay(2000);
}
Responder Sketch:
/*
ESP-NOW Remote Sensor - Receiver (Multiple Version)
esp-now-rcv.ino
Receives Temperature & Humidity data from other ESP32 via ESP-NOW
DroneBot Workshop 2022
https://dronebotworkshop.com
*/
// Include required libraries
#include <WiFi.h>
#include <esp_now.h>
// Define data structure
typedef struct struct_message {
float a;
float b;
int c;
} struct_message;
// Create structured data object
struct_message myData;
// Callback function
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len)
{
// Get incoming data
memcpy(&myData, incomingData, sizeof(myData));
// Print to Serial Monitor
Serial.print("Temp Sensor ");
Serial.print(myData.c);
Serial.print(": ");
Serial.println(myData.a);
Serial.print("Humidity Sensor ");
Serial.print(myData.c);
Serial.print(": ");
Serial.println(myData.b);
Serial.println("");
}
void setup() {
// Set up Serial Monitor
Serial.begin(115200);
// Start ESP32 in Station mode
WiFi.mode(WIFI_STA);
// Initalize ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Register callback function
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}