The article discusses the use of communication developed by espressif to communicate between its microcontrollers via wireless communication, as an alternative to the development of a non-linear Client/Server system. It describes the working process of working as a service provider, commander, and a set of related instructions through the Arduino core, along with explaining the working examples that come with both Arduino cores, which are basic and Multi-slave, which can be applied variously.
ESP-NOW
ESP-NOW is a communication protocol designed by espressif, the manufacturer of the esp8266 and esp32 microcontrollers for communication between devices via wireless or WiFi. It supports encrypted and non-encrypted communications, transmits/receives up to 250 bytes per frame, and callback for receiving notification of transmission results. However, the ESP-NEW is limited by 3 issues:
- When using encryption in communication, only 10 devices are available in Station mode and only 6 devices are available in SoftAP or SoftAP+Station mode.
- Decrypted communication is compatible with up to 20 devices.
- The data in the send/receive frame or payload portion cannot exceed 250 bytes.
The communication architecture of ESP-NOW requires that each communication band have a node known as a master or controller and a slave or peer. There are two types of communication:
- One-way communication in which one device is the sender and the other is the receiver. It works in three ways:
- 1 sender and 1 receiver (one to one)
- 1 sender, multiple receivers (one master, multiple slaves)
- Multiple senders and one receiver (multiple masters, one slave)
- Two-way communication where both master and slave can be both sender and receiver.
Instruction set
Here are some known commands and constants.
Error code
This residual constant is the result returned of type esp_err_t , which is a data type returned from an ESP-NOW-related routine.
Error | Description |
---|---|
ESP_ERR_ESPNOW_NOT_INIT | The programmer has not yet called esp_now_init() |
ESP_ERR_ESPNOW_ARG | The argument passed to the command has an error. |
ESP_ERR_ESPNOW_NO_MEM | Insufficient memory. |
ESP_ERR_ESPNOW_FULL | The number of peers in the full list. |
ESP_ERR_ESPNOW_NOT_FOUND | ESP-NOW Peer not found. |
ESP_ERR_ESPNOW_INTERNAL | An internal error has occurred. |
ESP_ERR_ESPNOW_EXIST | Already have this Peer. |
ESP_ERR_ESPNOW_IF | Already have this PeerAn interface error has occurred. |
If the command is executed successfully or the send/receive is successful, it returns ESP_OK
Constants inside ESP-NOW
Here is a list of reference constants regarding data amount, key size, and peer count.
- ESP_NOW_ETH_ALEN A value of 6 is the size of the peer’s MAC address.
- ESP_NOW_KEY_LEN A value of 16 is the size of the Peer master key.
- ESP_NOW_MAX_TOTAL_PEER_NUM A value of 20 is the maximum number of peers.
- ESP_NOW_MAX_ENCRYPT_PEER_NUM A value of 6 is the maximum number of Peers when communicating encrypted.
- ESP_NOW_MAX_DATA_LEN A value of 250 is the maximum number of bytes of data used for communication per frame.
Peer information
The data structure for storing details of each Peer is named esp_now_peer_info or esp_now_peer_info_t. which contains the following information:
typedef struct esp_now_peer_info {
uint8_t peer_addr[ESP_NOW_ETH_ALEN];
uint8_t lmk[ESP_NOW_KEY_LEN];
uint8_t channel;
wifi_interface_t ifidx;
bool encrypt;
void *priv;
} esp_now_peer_info_t;
From such a structure, it can be seen that
- peer_addr is the MAC address of Peer which is used in Station or SoftAP mode.
- lmk is the size of the original key (master key) used to encrypt and decrypt data.
- channel is the number of communication channels between each other but if set to 0 means using the communication channel by Station or SoftAP communicates with for another case, the channel number must be specified to match the station or SoftAP communicating.
- ifidx is the numeric value of an interface or interface (IF: Interface).
- encrypt: If true means communication with peers is encrypted, if false it is non-encrypted communication.
- priv is a pointer variable that points to the peer’s private data.
Start command
esp_err_t esp_now_init(void);
This command is used to initialize ESP-NOW and restore.
- ESP_OK if successful
- ESP_ERR_ESPNOW_INTERNAL
esp_err_t esp_now_deinit(void);
This command is used to terminate ESP-NOW and will return ESP_OK after the abort is complete.
Command to see the version of ESP-NOW
esp_err_t esp_now_get_version(uint32_t *version);
This command is used to read the version number of ESP-NOW, it must pass a variable of type uint32_t and store the referenced version in memory. Then return the value to ESP_OK or ESP_ERR_ESPNOW_ARG, if there is a problem asking for arguments passed to a function.
callback
The form of the callback used to be called when ESP-NOW receives data must have a function definition structure:
typedef void (*esp_now_recv_cb_t)(const uint8_t *mac_addr, const uint8_t *data, int data_len);
The form of the callback function to be executed when a transmission error occurs must be structured as follows:
typedef void (*esp_now_send_cb_t)(const uint8_t *mac_addr, esp_now_send_status_t status);
The command to define the callback function when the register send event occurs is as follows:
esp_err_t esp_now_register_send_cb(esp_now_send_cb_t cb);
From the command, cb is the name of the callback function written to be called and the return has the following effect:
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_INTERNAL
The command for defining the callback function to be executed when receiving data has the following format:
esp_err_t esp_now_register_recv_cb(esp_now_recv_cb_t cb);
The return value from the commands are
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_INTERNAL
The command for unregistering the callback function that is called after data acquisition has occurred in the following format:
esp_err_t esp_now_unregister_recv_cb(void);
The return value from the commands are
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
The command to unregister a callback function in response to transmission has the following form:
esp_err_t esp_now_unregister_send_cb(void);
The return value from the command is
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
Data transmission command
The command to send data len size to peer with position value peer_addr has the following format:
esp_err_t esp_now_send(const uint8_t *peer_addr, const uint8_t *data, size_t len);
The return value is
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_ARG
- ESP_ERR_ESPNOW_INTERNAL
- ESP_ERR_ESPNOW_NO_MEM
- ESP_ERR_ESPNOW_NOT_FOUND
- ESP_ERR_ESPNOW_IF
Peer command
The command for adding peers to the system has the following form:
esp_err_t esp_now_add_peer(const esp_now_peer_info_t *peer);
The return value of the peer add function are:
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_ARG
- ESP_ERR_ESPNOW_FULL
- ESP_ERR_ESPNOW_NO_MEM
- ESP_ERR_ESPNOW_EXIST
If you want to remove unwanted peers by specifying peer_addr , here is the form of usage:
esp_err_t esp_now_del_peer(const uint8_t *peer_addr);
When the work is done, the results of the work will be reported.
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_ARG
- ESP_ERR_ESPNOW_NOT_FOUND
To change the peer’s data, a new set of values must be passed to the following function.
esp_err_t esp_now_mod_peer(const esp_now_peer_info_t *peer);
Return value from function esp_now_mod_peer() namely.
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_ARG
- ESP_ERR_ESPNOW_FULL
For reading peer data with position value peer_addr, a buffer must be provided for storing esp_now_peer_info_t and pass the position value to the following command to read the specified peer’s data and store it in the prepared buffer.
esp_err_t esp_now_get_peer(const uint8_t *peer_addr, esp_now_peer_info_t *peer);
The result of the work is as follows.
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_ARG
- ESP_ERR_ESPNOW_NOT_FOUND
If the number of peers to be read is unknown, programmers can read from a list of peers with the following command to access the list by setting from_head to true means reading the first item from the list and if set to false, it will be the next item on every run.
esp_err_t esp_now_fetch_peer(bool from_head, esp_now_peer_info_t *peer);
Return from esp_now_fetch_peer() is as follows
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_ARG
- ESP_ERR_ESPNOW_NOT_FOUND
To check if peer_addr is in the peer list, the result is true or false.
bool esp_now_is_peer_exist(const uint8_t *peer_addr);
If you want to know the number of peers added to the system, the number of peers can be counted with the esp_now_get_peer_num() command by passing the position of the peer storage variable to the following function.
esp_err_t esp_now_get_peer_num(esp_now_peer_num_t *num);
The result of the function’s execution or the return value from that function:
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_ARG
Commands about master
The command for setting PMK (Primary Master Key), which is the key for accessing and decrypting the communication within the network of ESP-NOW, is used as follows.
esp_err_t esp_now_set_pmk(const uint8_t *pmk);
The return values from the encryption and decryption code configuration are:
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
- ESP_ERR_ESPNOW_ARG
Settings for exiting power saving mode by configuring window in microseconds. which ranges from 0 to 65535 for the chip to be awakened in every window has the following format.
esp_err_t esp_now_set_wake_window(uint16_t window);
The return value of the chip wake-up time setting function is as follows:
- ESP_OK
- ESP_ERR_ESPNOW_NOT_INIT
Note
- It is effective only when the mode is ESP_WIFI_STA_DISCONNECTED_PM_ENABLE.
- This configuration is only possible with Station mode and when in a disconnected location.
- If multiple module settings are called, the chip will select the largest value as the active value.
- If there is a gap between time and window value less than 5ms, it means the chip is working all the time.
- If the window value is not set, the chip will wake up when there is no connection when using ESP-NOW.
Example Code
In the Arduino core for ESP32 kit, there are 2 examples to study:
Master-side programming algorithm
- ESPNow Init on Master and set it in STA mode
- Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup)
- Once found, add Slave as peer
- Register for send callback
- Start Transmitting data from Master to Slave
Slave-side programming algorithm
- ESPNow Init on Slave
- Update the SSID of Slave with a prefix of `slave`
- Set Slave in AP mode
- Register for receive callback and wait for data
- Once data arrives, print it in the serial monitor
Basic
The Basic example consists of a master and slave side program used to communicate with each other. The master checks if there is a slave in the system and when found it will report the information received from the slave. The slave side registers the system and sends the data out. The working example is shown in Figure 1.
Master code
/**
ESPNOW - Basic communication - Master
Date: 26th September 2017
Author: Arvind Ravulavaru <https://github.com/arvindr21>
Purpose: ESPNow Communication between a Master ESP32 and a Slave ESP32
Description: This sketch consists of the code for the Master module.
Resources: (A bit outdated)
a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
b. http://www.esploradores.com/practica-6-conexion-esp-now/
<< This Device Master >>
..
Note: Master and Slave have been defined to easily understand the setup.
Based on the ESPNOW API, there is no concept of Master and Slave.
Any devices can act as master or salve.
*/
#include <esp_now.h>
#include <WiFi.h>
// Global copy of slave
esp_now_peer_info_t slave;
#define CHANNEL 3
#define PRINTSCANRESULTS 0
#define DELETEBEFOREPAIR 0
// Init ESP Now with fallback
void InitESPNow() {
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
else {
Serial.println("ESPNow Init Failed");
// Retry InitESPNow, add a counte and then restart?
// InitESPNow();
// or Simply Restart
ESP.restart();
}
}
// Scan for slaves in AP mode
void ScanForSlave() {
int8_t scanResults = WiFi.scanNetworks();
// reset on each scan
bool slaveFound = 0;
memset(&slave, 0, sizeof(slave));
Serial.println("");
if (scanResults == 0) {
Serial.println("No WiFi devices in AP Mode found");
} else {
Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices ");
for (int i = 0; i < scanResults; ++i) {
// Print SSID and RSSI for each device found
String SSID = WiFi.SSID(i);
int32_t RSSI = WiFi.RSSI(i);
String BSSIDstr = WiFi.BSSIDstr(i);
if (PRINTSCANRESULTS) {
Serial.print(i + 1);
Serial.print(": ");
Serial.print(SSID);
Serial.print(" (");
Serial.print(RSSI);
Serial.print(")");
Serial.println("");
}
delay(10);
// Check if the current device starts with `Slave`
if (SSID.indexOf("Slave") == 0) {
// SSID of interest
Serial.println("Found a Slave.");
Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");
// Get BSSID => Mac Address of the Slave
int mac[6];
if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) {
for (int ii = 0; ii < 6; ++ii ) {
slave.peer_addr[ii] = (uint8_t) mac[ii];
}
}
slave.channel = CHANNEL; // pick a channel
slave.encrypt = 0; // no encryption
slaveFound = 1;
// we are planning to have only one slave in this example;
// Hence, break after we find one, to be a bit efficient
break;
}
}
}
if (slaveFound) {
Serial.println("Slave Found, processing..");
} else {
Serial.println("Slave Not Found, trying again.");
}
// clean up ram
WiFi.scanDelete();
}
// Check if the slave is already paired with the master.
// If not, pair the slave with master
bool manageSlave() {
if (slave.channel == CHANNEL) {
if (DELETEBEFOREPAIR) {
deletePeer();
}
Serial.print("Slave Status: ");
// check if the peer exists
bool exists = esp_now_is_peer_exist(slave.peer_addr);
if ( exists) {
// Slave already paired.
Serial.println("Already Paired");
return true;
} else {
// Slave not paired, attempt pair
esp_err_t addStatus = esp_now_add_peer(&slave);
if (addStatus == ESP_OK) {
// Pair success
Serial.println("Pair success");
return true;
} else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println("ESPNOW Not Init");
return false;
} else if (addStatus == ESP_ERR_ESPNOW_ARG) {
Serial.println("Invalid Argument");
return false;
} else if (addStatus == ESP_ERR_ESPNOW_FULL) {
Serial.println("Peer list full");
return false;
} else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println("Out of memory");
return false;
} else if (addStatus == ESP_ERR_ESPNOW_EXIST) {
Serial.println("Peer Exists");
return true;
} else {
Serial.println("Not sure what happened");
return false;
}
}
} else {
// No slave found to process
Serial.println("No Slave found to process");
return false;
}
}
void deletePeer() {
esp_err_t delStatus = esp_now_del_peer(slave.peer_addr);
Serial.print("Slave Delete Status: ");
if (delStatus == ESP_OK) {
// Delete success
Serial.println("Success");
} else if (delStatus == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println("ESPNOW Not Init");
} else if (delStatus == ESP_ERR_ESPNOW_ARG) {
Serial.println("Invalid Argument");
} else if (delStatus == ESP_ERR_ESPNOW_NOT_FOUND) {
Serial.println("Peer not found.");
} else {
Serial.println("Not sure what happened");
}
}
uint8_t data = 0;
// send data
void sendData() {
data++;
const uint8_t *peer_addr = slave.peer_addr;
Serial.print("Sending: "); Serial.println(data);
esp_err_t result = esp_now_send(peer_addr, &data, sizeof(data));
Serial.print("Send Status: ");
if (result == ESP_OK) {
Serial.println("Success");
} else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println("ESPNOW 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("Not sure what happened");
}
}
// callback when data is sent from Master to Slave
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.print("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 setup() {
Serial.begin(115200);
//Set device in STA mode to begin with
WiFi.mode(WIFI_STA);
Serial.println("ESPNow/Basic/Master Example");
// This is the mac address of the Master in Station Mode
Serial.print("STA MAC: "); Serial.println(WiFi.macAddress());
// Init ESPNow with a fallback logic
InitESPNow();
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);
}
void loop() {
// In the loop we scan for slave
ScanForSlave();
// If Slave is found, it would be populate in `slave` variable
// We will check if `slave` is defined and then we proceed further
if (slave.channel == CHANNEL) { // check if slave channel is defined
// `slave` is defined
// Add slave as peer if it has not been added already
bool isPaired = manageSlave();
if (isPaired) {
// pair success or already paired
// Send data to device
sendData();
} else {
// slave pair failed
Serial.println("Slave pair failed!");
}
}
else {
// No slave found to process
}
// wait for 3seconds to run the logic again
delay(3000);
}
slave code
/**
ESPNOW - Basic communication - Slave
Date: 26th September 2017
Author: Arvind Ravulavaru <https://github.com/arvindr21>
Purpose: ESPNow Communication between a Master ESP32 and a Slave ESP32
Description: This sketch consists of the code for the Slave module.
Resources: (A bit outdated)
a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
b. http://www.esploradores.com/practica-6-conexion-esp-now/
<< This Device Slave >>
...
Note: Master and Slave have been defined to easily understand the setup.
Based on the ESPNOW API, there is no concept of Master and Slave.
Any devices can act as master or salve.
*/
#include <esp_now.h>
#include <WiFi.h>
#define CHANNEL 1
// Init ESP Now with fallback
void InitESPNow() {
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
else {
Serial.println("ESPNow Init Failed");
// Retry InitESPNow, add a counte and then restart?
// InitESPNow();
// or Simply Restart
ESP.restart();
}
}
// config AP SSID
void configDeviceAP() {
const char *SSID = "Slave_1";
bool result = WiFi.softAP(SSID, "Slave_1_Password", CHANNEL, 0);
if (!result) {
Serial.println("AP Config failed.");
} else {
Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID));
}
}
void setup() {
Serial.begin(115200);
Serial.println("ESPNow/Basic/Slave Example");
//Set device in AP mode to begin with
WiFi.mode(WIFI_AP);
// configure device AP mode
configDeviceAP();
// This is the mac address of the Slave in AP Mode
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
// Init ESPNow with a fallback logic
InitESPNow();
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info.
esp_now_register_recv_cb(OnDataRecv);
}
// callback when data is recv from Master
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.print("Last Packet Recv from: "); Serial.println(macStr);
Serial.print("Last Packet Recv Data: "); Serial.println(*data);
Serial.println("");
}
void loop() {
// Chill
}
ง Multi-Slave
Master code
/**
ESPNOW - Basic communication - Slave
Date: 26th September 2017
Author: Arvind Ravulavaru <https://github.com/arvindr21>
Purpose: ESPNow Communication between a Master ESP32 and a Slave ESP32
Description: This sketch consists of the code for the Slave module.
Resources: (A bit outdated)
a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
b. http://www.esploradores.com/practica-6-conexion-esp-now/
<< This Device Slave >>
...
Note: Master and Slave have been defined to easily understand the setup.
Based on the ESPNOW API, there is no concept of Master and Slave.
Any devices can act as master or salve.
*/
#include <esp_now.h>
#include <WiFi.h>
#define CHANNEL 1
// Init ESP Now with fallback
void InitESPNow() {
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
else {
Serial.println("ESPNow Init Failed");
// Retry InitESPNow, add a counte and then restart?
// InitESPNow();
// or Simply Restart
ESP.restart();
}
}
// config AP SSID
void configDeviceAP() {
const char *SSID = "Slave_1";
bool result = WiFi.softAP(SSID, "Slave_1_Password", CHANNEL, 0);
if (!result) {
Serial.println("AP Config failed.");
} else {
Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID));
}
}
void setup() {
Serial.begin(115200);
Serial.println("ESPNow/Basic/Slave Example");
//Set device in AP mode to begin with
WiFi.mode(WIFI_AP);
// configure device AP mode
configDeviceAP();
// This is the mac address of the Slave in AP Mode
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
// Init ESPNow with a fallback logic
InitESPNow();
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info.
esp_now_register_recv_cb(OnDataRecv);
}
// callback when data is recv from Master
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.print("Last Packet Recv from: "); Serial.println(macStr);
Serial.print("Last Packet Recv Data: "); Serial.println(*data);
Serial.println("");
}
void loop() {
// Chill
}
Slave code
/**
ESPNOW - Basic communication - Slave
Date: 26th September 2017
Author: Arvind Ravulavaru <https://github.com/arvindr21>
Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves
Description: This sketch consists of the code for the Slave module.
Resources: (A bit outdated)
a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
b. http://www.esploradores.com/practica-6-conexion-esp-now/
<< This Device Slave >>
...
Note: Master and Slave have been defined to easily understand the setup.
Based on the ESPNOW API, there is no concept of Master and Slave.
Any devices can act as master or salve.
*/
#include <esp_now.h>
#include <WiFi.h>
#define CHANNEL 1
// Init ESP Now with fallback
void InitESPNow() {
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
else {
Serial.println("ESPNow Init Failed");
// Retry InitESPNow, add a counte and then restart?
// InitESPNow();
// or Simply Restart
ESP.restart();
}
}
// config AP SSID
void configDeviceAP() {
String Prefix = "Slave:";
String Mac = WiFi.macAddress();
String SSID = Prefix + Mac;
String Password = "123456789";
bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL, 0);
if (!result) {
Serial.println("AP Config failed.");
} else {
Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID));
}
}
void setup() {
Serial.begin(115200);
Serial.println("ESPNow/Basic/Slave Example");
//Set device in AP mode to begin with
WiFi.mode(WIFI_AP);
// configure device AP mode
configDeviceAP();
// This is the mac address of the Slave in AP Mode
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
// Init ESPNow with a fallback logic
InitESPNow();
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info.
esp_now_register_recv_cb(OnDataRecv);
}
// callback when data is recv from Master
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.print("Last Packet Recv from: "); Serial.println(macStr);
Serial.print("Last Packet Recv Data: "); Serial.println(*data);
Serial.println("");
}
void loop() {
// Chill
}
Conclusion
From this article, you will find that ESP-NOW supports both One-way and Two-way communication, making it possible to design a variety of programming. Considering the amount of data that is limited to 250 bytes and does not have a complex protocol format like when using ESP8266WiFi/WiFiClient/WiFiServer with increasing security with encryption, communication is faster than doing in the article “Programming a client/server for a weather station over a wireless network“. In addition, it can be tested and used with ESP32 and ESP32-S2 well. Finally, have fun with programming.
If you want to talk with us, feel free to leave comments below!!
References
- espressif : API Reference : Networking APIs : ESP-NOW
- Arduino core for ESP32 (ESP32): esp_now.h
- Arduino core for ESP32 (ESP32-S2): esp_now.h
- Arduino core for ESP32 (ESP32-C3): esp_now.h
- ESP-NOW : Basic, Multi-Slave
(C) 2021, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2021-12-19