ESP-NOW between boards
Send messages between ESP32 and ESP8266 boards on one canvas with ESP-NOW: real frames, MACs, channels and ACKs, and no router or wire.
ESP-NOW is Espressif's board-to-board radio protocol: one ESP sends a short message straight to another's MAC address, and the other's radio acknowledges it. In Mokxi the frames really cross between the boards you put on the canvas. Every ESP board shares one air, the way two boards on one desk do, so you wire each board only to its own parts.
It works on every ESP board: the ESP32, ESP32-S3, ESP32-C3 and
ESP32-C6 and the boards built on them (esp_now.h, ESP-IDF's calls), and
the ESP8266 boards, NodeMCU, D1 mini and ESP-01 (espnow.h, the ESP8266
core's calls). An ESP32 and an ESP8266 talk to each other, as they do on a
desk. People search for it as esp now, esp-now or espnow.
Try it
Open ESP-NOW button and LED from the examples: two ESP32s, a button on
the left one and an LED on the right one. Press Run, then press the
button. The sender's serial monitor prints Delivery success and the
receiver's prints the message and lights its LED.
ESP-NOW on two NodeMCUs is the same idea with espnow.h: one ESP8266
sends a count and a knob reading every two seconds, the other prints them.
MAC addresses
A tutorial has you run the receiver first, copy the MAC it prints, and paste it into the sender's sketch. That works here too:
WiFi.macAddress()prints the board's MAC. Each ESP board on the canvas gets its own, worked out from the part's id, so it is the same every time you run the project.- To use the MAC a tutorial's sketch already has in it, click the receiver and
type that address into its wifiMac setting (for example
24:0A:C4:AE:AE:44). The examples do this.
Send to a MAC that no board has and nothing arrives: the send callback gets
ESP_NOW_SEND_FAIL (or 1 on an ESP8266) after the radio has tried five
times, exactly the fault you would chase on a desk.
What the radio does
- Unicast and broadcast. A frame to one MAC is acknowledged by that
board's radio, and the send callback reports success once the ACK is back.
A frame to
FF:FF:FF:FF:FF:FFreaches every board that runs ESP-NOW, and its callback reports success as soon as it has gone, because nobody acknowledges a broadcast. On an ESP32 the broadcast address has to be added as a peer first, as ESP-IDF requires. - Timing. A frame starts with the 192 microsecond preamble of 802.11b and
goes at 1 Mbit/s: a 10 byte message is on the air for about 0.4 ms, a 250
byte one for about 2.9 ms. The receive callback runs within a millisecond of
the last byte, from the WiFi task's stand-in, so it runs while your sketch is
in
delay()or between twoloop()s. - Channels. The radio is on channel 1 until the board joins WiFi, then on
the access point's channel (6), or on what
esp_wifi_set_channel()chose. Boards on different channels do not hear each other, which is the usual reason ESP-NOW stops working once one board connects to WiFi. - Two at once. A board waits for a quiet air before it sends. Two frames that do collide are both lost; a unicast one is sent again, a broadcast is not.
- Sizes. ESP32 boards speak ESP-NOW v2 (up to 1470 bytes, as ESP-IDF 5.4 and later do); the ESP8266 speaks v1, 250 bytes at most, and drops a longer frame without acknowledging it.
Both callback shapes compile on the ESP32: core 3.3's
void onSent(const wifi_tx_info_t *info, esp_now_send_status_t status) and
void onRecv(const esp_now_recv_info_t *info, const uint8_t *data, int len),
and the older ones that take a const uint8_t *mac.
What is not simulated
- No range. Every ESP board on the canvas hears every other one, however far apart you put them. There are no walls, no fading and no interference.
- No signal model. A received frame reports an RSSI of -40 dBm every time; output power and rate settings are accepted and change nothing.
- No encryption on the air. Keys and encrypted peers are stored, and the frames still go in the clear, so an encrypted peer's frames arrive even with the wrong key.
- Not under MicroPython. ESP-NOW is for Arduino sketches; MicroPython's
espnowmodule is not here.
Bluetooth and WiFi have pages of their own: WiFi, simulated and Bluetooth, simulated.