A simple example and explanation of how to use ESP-Now for communication between ESP32 devices
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
Using a modified version of my basic example of ESP-NOW usage, I tested latency and reliability of this networking strategy.
The basic setup was that one device would send a message to another and start a timer. The receiving device would immediately send the message back to the original sender. Once the original device receives the echoed message, it stops the timer and records how long it took. An error counter is incremented if the message did not complete the round trip. I added padding bytes to the basic message format so that I could test sending messages of various sizes. I tested this for 1000 messages (sent at 5hz) with the two devices right next to each other on a desk (about 4 inches away), and with the devices across the room (about 128 inches away).
This testing was performed in my apartment in a city, so the 2.4GHz spectrum is very full. I used WiFi channel 1, and did not choose it intelligently (e.g. based on the power there.) I don't expect anyone else to be able to get the exact same results, but this can be used as a guideline.
The latency overall was good. The round trip latency is shown here, which includes some parsing/processing time. The latency for devices farther away seems to be slightly higher than for closer devices. The main concern with devices farther away seems to be the error rate. I expect this latency would be worse with encryption enabled.
The error rate seen in this testing is surprisingly high, and increases quickly as the devices are moved apart. Unidirectional error rate is shown here, which is the half missed messages (since this test uses a round trip approach). If you plan to send important messages using ESP-NOW, you may want to incorporate some resend-until-confirmed-received setup to your firmware. Direct messaging instead of broadcasting may be more reliable, but that was not tested.
I'd like to begin this log by noting that I am not a networking expert, so if something I say here is wrong, I'd love to know. At the same time, I know there are many people using the ESP32 who also are not networking experts and just need a working example they can modify to get multiple devices talking to each other. This work examines the example I developed and some of the issues I ran into while making it. The example allows one ESP32 device to blink an LED on another ESP32 device wirelessly, with no configuration (but also no security.) In the GIF below, the ESP32 device on the right acts as a sender, and the ESP32 on the left receives the messages and toggles its LED when it does. Note that "sender" and "receiver" only relate to my example. ESP-NOW supports two-way communication with no such designations.
First, I recommend reading the documentation that Espressif provides about ESP-NOW. It will provide an overview of what ESP-NOW is. If you are not a networking person, a lot of the technical details probably don't mean a lot. But, as builders of things, many of us just want easy to use microcontrollers that can easily talk wirelessly to other microcontrollers. ESP-NOW can be used for that.
My example is built on the concept of sending some arbitrary payload to all ESP32 devices within range, without security. To send to all devices, use the broadcast MAC address, which is all 0xFF.
static uint8_t broadcast_mac[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
We then define some payload to send. You can change this to whatever you want, as long as it is less than 250 bytes long, since that is the maximum size of the ESP-NOW data body. For my example, I include an address index and a counter. For another project of mine, I plan to build in some ad-hoc message addressing using this address index. The counter here is simply to monitor how reliable the connection is.
typedef struct __attribute__((packed)) esp_now_msg_t
{
uint32_t address;
uint32_t counter;
// Can put lots of things here...
} esp_now_msg_t;
My example uses the Arduino ESP32 interface, which makes using the ESP32 very easy. Within the Arduino "setup" routine, I simply set up the Serial connection, the LED, and call my ESP-NOW setup function.
void setup() {
Serial.begin(115200);
pinMode(LED_PIN,OUTPUT);
digitalWrite(LED_PIN,LOW);
network_setup();
}
Within the network_setup function, I initialize ESP-NOW using Espressifs API, as well as linking callback functions that are called upon sending or receiving of data. First, you must but the device into station mode, and disconnect WiFi (WiFi is likely not connected, but this is here in case it will be brought into someone else's code which uses WiFi also).
static void network_setup(void)
{
//Puts ESP in STATION MODE
WiFi.mode(WIFI_STA);
WiFi.disconnect();
Next, the "esp_now_init" function is called. This is Espressif's API. My code does not try to recover if it fails, but you may want to act upon the returned value.
if (esp_now_init() != 0)
{
return;
}
The next step is critical, at least for how I wanted to use ESP-NOW. The other basic examples I've seen for this either require you to hardcode the MAC addresses of the other devices on your network into the firmware, or share the MAC addresses in a process where each "slave" node enters soft-AP mode, the master connects to it, and receives the MAC address, then switches into ESP-NOW mode. That feels very clunky and could span the air with large numbers of SSIDs only used for configuration. Instead, I set it up so all messages are broadcast to all other devices on the network. You can develop an ad-hoc addressing layer on top if you want. This ensures you can add a device to the network without knowing anything about the other devices.
esp_now_peer_info_t peer_info;
peer_info.channel = WIFI_CHANNEL;
memcpy(peer_info.peer_addr, broadcast_mac, 6);
peer_info.ifidx = ESP_IF_WIFI_STA;
peer_info.encrypt = false;
esp_err_t...
Read more »
Create an account to leave a comment. Already have an account? Log In.
Bad news for me i think, your #define WIFI_CHANNEL (5) and later peer_info.channel = WIFI_CHANNEL; does nothing, that means all radio channels remain on Ch1.
It was just a coincidence: It worked above because sender&receiver fixed on Ch1, and the Wifi-Connect to the Home-AP was also on Ch1 at this time.
Do you want to debug your code regarding the channel setting? Would be nice ....
Thanks for the post. I'm going to try to program an ESP3266. Do you think the ESP32 code is compatible?
Im not sure, it's worth trying though. I have not worked with ESP8266 in a while and never tried ESP now with them. If you try it please report back if it worked or not
Thanks Jake. Will do. I like the simplicity of your code and another 8266 specific example. By blending them together I should get there. Andreas Spiess also has some great stuff on subject.
Followup: Jake, I found some other ESPNOW code that was ESP8266 specific and used that instead. It works. Transmission time is less than 2S. HarringayMakerSpace (https://github.com/HarringayMakerSpace/ESP-Now/blob/master/espnow-sensor-minimal/espnow-sensor-minimal.ino) shows how to get TX time down to 40uS. I was able to get it down to around 100mS. Enormous savings. Now I'm able to use 100 mAh button cells to sensor temperature for weeks or months (must remove the power LED from the ESP.)
Hi, can i send a brodcast destination message without pairing participant (or adding peer to peerlist)? i mean if everyone will receive and able to process the payload in the broadcast msg in vicinity? can i have payload (those 250byte part) in the broadcast msg? I'm thinking about to bypass the 20peer limit with it. just have some byte of unique ID stated in the payload and every node can figure out itself if that broadcast msg is for him then ack it same way with another broadcast msg.
(stupid questions after 2 days research on espnow). the scenario is a 100 esp32 in a room talking randomly to each other.
regards, lev
Hi Lev, yes that is exactly how the example I provided works. You can put whatever you want in the payload and create your own ad-hoc message addressing methods without pairing first. I've never tested it on that many ESP32s at once but I'd love to see someone try it!
Hi, check out our latency test using ESP-NOW here https://hackaday.io/project/161896-linux-espnow/log/161047-some-results. You can actually speed up your round trip time and latency by increasing the data rate. With the ESP32, the default data rate is 1Mbps, but can be configure to 54Mbps. You can find the ESP code here https://github.com/thomasfla/Linux-ESPNOW/tree/master/ESP32-Test
That's really good to know! I was surprised at how poor the performance I was getting was and I imagined there would be some way to make it better.
Absolutely, I plan to add some logs about the process I went through to get it working, as well as some latency and power consumption testing. Hopefully within the next week or two.
Hi Jake! It would be great if you could write this up i more detail here. I'd love to add this to our ESP tutorials list: https://hackaday.io/list/160548-esp8266-tutorials
We don't have anything on ESP-Now yet!
Hi Sophi, I just added more details and some results from latency testing to the project logs.
Become a member to follow this project and never miss any updates
Your code helped me a lot, but surprisingly, but Sender/Receiver works for me also with different channels !? Would be very nice, if it's true and no faulty 'magic' .....
My Setup:
- ESPnow-Sender on Ch5. Your code only extended to connect to a Home-AP (->Ch1). Later I will add a small webpage-server to it to display some informations over WiFi.
- ESPnow-Receiver on Ch11. No Connection prepared to Home-AP.
So ... Sender<->Reveiver and Home-AP-connect are working in parallel on three Channels :-)