ESP-NOW pair
Two boards talk directly over the Wi-Fi radio, with no router. Each sends a counter and prints what the other sends.
Wiring
Nothing to wire. This one runs on the bare board.
Tested on this board
Not run on this board yet. Treat the wiring and code as a first draft.
Firmware, Arduino sketch for ESP32 Dev Module
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
const char NAME = 'A'; // set to 'B' before flashing the second board
const int CHANNEL = 1; // both boards must use the same channel
const uint8_t BROADCAST[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
struct Message {
char from;
uint32_t count;
};
uint32_t count = 0;
void onReceive(const esp_now_recv_info_t* info, const uint8_t* data, int len) {
if (len != sizeof(Message)) return;
Message m;
memcpy(&m, data, sizeof m);
if (m.from == NAME) return;
const uint8_t* a = info->src_addr;
Serial.printf("rx %c #%lu from %02X:%02X:%02X:%02X:%02X:%02X rssi %d\n",
m.from, (unsigned long)m.count, a[0], a[1], a[2], a[3], a[4], a[5], info->rx_ctrl->rssi);
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
if (esp_now_init() != ESP_OK) {
Serial.println("esp-now init failed");
for (;;) delay(1000);
}
esp_now_register_recv_cb(onReceive);
// Broadcast, so neither board needs the other's MAC address.
esp_now_peer_info_t peer = {};
memcpy(peer.peer_addr, BROADCAST, 6);
peer.channel = CHANNEL;
peer.ifidx = WIFI_IF_STA;
peer.encrypt = false;
esp_now_add_peer(&peer);
Serial.printf("esp-now ready on channel %d, this board is %c, MAC %s\n", CHANNEL, NAME, WiFi.macAddress().c_str());
}
void loop() {
Message m = {NAME, ++count};
esp_err_t r = esp_now_send(BROADCAST, (const uint8_t*)&m, sizeof m);
Serial.printf("tx %c #%lu %s\n", NAME, (unsigned long)m.count, r == ESP_OK ? "sent" : esp_err_to_name(r));
delay(2000);
}Wiring
Nothing to wire. This one runs on the bare board.
Tested on this board
Not run on this board yet. Treat the wiring and code as a first draft.
Firmware, Arduino sketch for ESP32S3 Dev Module
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
const char NAME = 'A'; // set to 'B' before flashing the second board
const int CHANNEL = 1; // both boards must use the same channel
const uint8_t BROADCAST[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
struct Message {
char from;
uint32_t count;
};
uint32_t count = 0;
void onReceive(const esp_now_recv_info_t* info, const uint8_t* data, int len) {
if (len != sizeof(Message)) return;
Message m;
memcpy(&m, data, sizeof m);
if (m.from == NAME) return;
const uint8_t* a = info->src_addr;
Serial.printf("rx %c #%lu from %02X:%02X:%02X:%02X:%02X:%02X rssi %d\n",
m.from, (unsigned long)m.count, a[0], a[1], a[2], a[3], a[4], a[5], info->rx_ctrl->rssi);
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
if (esp_now_init() != ESP_OK) {
Serial.println("esp-now init failed");
for (;;) delay(1000);
}
esp_now_register_recv_cb(onReceive);
// Broadcast, so neither board needs the other's MAC address.
esp_now_peer_info_t peer = {};
memcpy(peer.peer_addr, BROADCAST, 6);
peer.channel = CHANNEL;
peer.ifidx = WIFI_IF_STA;
peer.encrypt = false;
esp_now_add_peer(&peer);
Serial.printf("esp-now ready on channel %d, this board is %c, MAC %s\n", CHANNEL, NAME, WiFi.macAddress().c_str());
}
void loop() {
Message m = {NAME, ++count};
esp_err_t r = esp_now_send(BROADCAST, (const uint8_t*)&m, sizeof m);
Serial.printf("tx %c #%lu %s\n", NAME, (unsigned long)m.count, r == ESP_OK ? "sent" : esp_err_to_name(r));
delay(2000);
}Wiring
Nothing to wire. This one runs on the bare board.
Tested on this board
Not run on this board yet. Treat the wiring and code as a first draft.
Firmware, Arduino sketch for ESP32C3 Dev Module
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
const char NAME = 'A'; // set to 'B' before flashing the second board
const int CHANNEL = 1; // both boards must use the same channel
const uint8_t BROADCAST[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
struct Message {
char from;
uint32_t count;
};
uint32_t count = 0;
void onReceive(const esp_now_recv_info_t* info, const uint8_t* data, int len) {
if (len != sizeof(Message)) return;
Message m;
memcpy(&m, data, sizeof m);
if (m.from == NAME) return;
const uint8_t* a = info->src_addr;
Serial.printf("rx %c #%lu from %02X:%02X:%02X:%02X:%02X:%02X rssi %d\n",
m.from, (unsigned long)m.count, a[0], a[1], a[2], a[3], a[4], a[5], info->rx_ctrl->rssi);
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
if (esp_now_init() != ESP_OK) {
Serial.println("esp-now init failed");
for (;;) delay(1000);
}
esp_now_register_recv_cb(onReceive);
// Broadcast, so neither board needs the other's MAC address.
esp_now_peer_info_t peer = {};
memcpy(peer.peer_addr, BROADCAST, 6);
peer.channel = CHANNEL;
peer.ifidx = WIFI_IF_STA;
peer.encrypt = false;
esp_now_add_peer(&peer);
Serial.printf("esp-now ready on channel %d, this board is %c, MAC %s\n", CHANNEL, NAME, WiFi.macAddress().c_str());
}
void loop() {
Message m = {NAME, ++count};
esp_err_t r = esp_now_send(BROADCAST, (const uint8_t*)&m, sizeof m);
Serial.printf("tx %c #%lu %s\n", NAME, (unsigned long)m.count, r == ESP_OK ? "sent" : esp_err_to_name(r));
delay(2000);
}Parts
| Quantity | Part | Where to buy |
|---|---|---|
| 2× | ESP32 dev boards, any mix of ESP32, S3 and C3 | Buy at Amazon |
| 2× | USB cables, or one cable and a USB power supply |
Amazon buy links may include an Associates tag, and this site may earn a commission from qualifying Amazon purchases at no extra cost to you. Adafruit links are direct.
Libraries
WiFi (built in), esp_now (built in)
Load it
- In the Arduino IDE, install the esp32 board package and pick the board named above the sketch.
- Paste the sketch, choose the board's port and upload. Hold BOOT if the upload stalls at Connecting.
- Close the IDE's serial monitor, then open the bench here to watch the output.
Field notes
- Flash the same sketch to both boards, but change NAME to 'B' on the second one.
- Watch both sides at once: on the Bench page, choose Add a second board and connect one board to each monitor.
- Broadcasts are not acknowledged, so 'sent' only means the radio queued the message. Seeing it arrive on the other board is the real test.
- Both boards must be on the same channel. A board that also joins a Wi-Fi network moves to that network's channel, so set CHANNEL to match it.
- Messages are not encrypted. Do not send anything private this way.
Not tested yet
- Not tested on hardware yet. Compiles for every board listed with Arduino-ESP32 core 3.3.12.