ESP-NOW ESP32 communication is a game-changing protocol developed by Espressif that enables direct peer-to-peer wireless communication between ESP32 boards without any WiFi router, access point, or internet connection. With latency under 1 millisecond and range up to 480 metres in open space, ESP-NOW is perfect for remote controls, sensor networks, drone telemetry, and any application where speed and simplicity matter more than internet connectivity.
Table of Contents
- What is ESP-NOW?
- ESP-NOW vs WiFi vs BLE: When to Use Each
- Step 1: Get Your ESP32 MAC Addresses
- One-Way Communication: Sender to Receiver
- Two-Way Communication with Acknowledgement
- Multiple Senders, One Receiver
- Practical ESP-NOW Projects
- Frequently Asked Questions
What is ESP-NOW?
ESP-NOW is a connectionless wireless communication protocol developed by Espressif Systems. It uses the same 2.4 GHz radio hardware as WiFi but operates at a much lower level — there is no connection establishment, no IP addresses, no TCP/UDP overhead. Devices simply send packets directly to each other using MAC addresses.
Key features:
- Latency: Less than 1 ms (compared to 10-100 ms for WiFi)
- Range: Up to 480 metres outdoors with external antenna ESP32 boards
- Payload: Up to 250 bytes per message
- Peers: Up to 20 peers (7 encrypted, 13 unencrypted) on ESP32
- No router needed: Direct device-to-device communication
- Coexistence: Can work simultaneously with WiFi on the same ESP32
- Encryption: Optional CCMP encryption for secure communication
- Power: Lower than WiFi since there is no connection/authentication overhead
ESP-NOW vs WiFi vs BLE: When to Use Each
| Feature | ESP-NOW | WiFi | BLE |
|---|---|---|---|
| Latency | < 1 ms | 10-100 ms | 5-20 ms |
| Range | Up to 480 m | 30-100 m | 10-30 m |
| Router Needed | No | Yes | No |
| Internet Access | No (local only) | Yes | Via phone |
| Max Payload | 250 bytes | Unlimited | 512 bytes |
| Setup Complexity | Simple | Medium | Complex |
| Best For | Remote control, sensors | Cloud, web dashboards | Phone apps, wearables |
Choose ESP-NOW when: You need fast, reliable communication between ESP32 boards without internet. Perfect for RC cars, drones, sensor networks, and remote controls. ESP-NOW can even work alongside WiFi — your ESP32 can send sensor data via ESP-NOW to a gateway node that forwards it to the cloud via WiFi.
Step 1: Get Your ESP32 MAC Addresses
ESP-NOW uses MAC addresses to identify peers. Flash this sketch to each ESP32 to find its MAC address:
#include <WiFi.h>
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
Serial.print("ESP32 MAC Address: ");
Serial.println(WiFi.macAddress());
}
void loop() {}
Note down the MAC address of each ESP32 (format: AA:BB:CC:DD:EE:FF). You will use the receiver’s MAC address in the sender’s code.
One-Way Communication: Sender to Receiver
Sender Code
#include <esp_now.h>
#include <WiFi.h>
// Replace with your RECEIVER's MAC address
uint8_t receiverMAC[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
// Data structure (must match on both sender and receiver)
typedef struct SensorData {
float temperature;
float humidity;
int lightLevel;
bool motionDetected;
} SensorData;
SensorData sensorData;
esp_now_peer_info_t peerInfo;
// Callback when data is sent
void onDataSent(const uint8_t *mac, esp_now_send_status_t status) {
Serial.print("Send Status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "OK" : "FAIL");
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("ESP-NOW init failed!");
return;
}
esp_now_register_send_cb(onDataSent);
// Register peer
memcpy(peerInfo.peer_addr, receiverMAC, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
Serial.println("ESP-NOW Sender Ready");
}
void loop() {
// Read sensors (replace with actual sensor code)
sensorData.temperature = 32.5;
sensorData.humidity = 65.0;
sensorData.lightLevel = analogRead(34);
sensorData.motionDetected = digitalRead(27);
// Send data
esp_err_t result = esp_now_send(receiverMAC,
(uint8_t *)&sensorData, sizeof(sensorData));
if (result == ESP_OK) {
Serial.printf("Sent: T=%.1f, H=%.1f, L=%d, M=%dn",
sensorData.temperature, sensorData.humidity,
sensorData.lightLevel, sensorData.motionDetected);
}
delay(2000);
}
Receiver Code
#include <esp_now.h>
#include <WiFi.h>
typedef struct SensorData {
float temperature;
float humidity;
int lightLevel;
bool motionDetected;
} SensorData;
SensorData receivedData;
// Callback when data is received
void onDataReceive(const esp_now_recv_info *info,
const uint8_t *data, int len) {
memcpy(&receivedData, data, sizeof(receivedData));
Serial.printf("From: %02X:%02X:%02X:%02X:%02X:%02Xn",
info->src_addr[0], info->src_addr[1], info->src_addr[2],
info->src_addr[3], info->src_addr[4], info->src_addr[5]);
Serial.printf(" Temp: %.1f Cn", receivedData.temperature);
Serial.printf(" Humidity: %.1f %%n", receivedData.humidity);
Serial.printf(" Light: %dn", receivedData.lightLevel);
Serial.printf(" Motion: %sn",
receivedData.motionDetected ? "YES" : "No");
Serial.println();
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("ESP-NOW init failed!");
return;
}
esp_now_register_recv_cb(onDataReceive);
Serial.println("ESP-NOW Receiver Ready");
Serial.print("MAC: ");
Serial.println(WiFi.macAddress());
}
void loop() {
// Nothing needed - callback handles incoming data
}
Two-Way Communication with Acknowledgement
ESP-NOW supports bidirectional communication. Here is how to build a controller (sends commands) and actuator (receives commands, sends status back):
// Controller (sends commands, receives status)
#include <esp_now.h>
#include <WiFi.h>
uint8_t actuatorMAC[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
typedef struct Command {
char action[20];
int value;
} Command;
typedef struct Status {
bool relayState;
float currentDraw;
int uptime;
} Status;
Command cmd;
Status deviceStatus;
esp_now_peer_info_t peerInfo;
void onDataReceive(const esp_now_recv_info *info,
const uint8_t *data, int len) {
memcpy(&deviceStatus, data, sizeof(deviceStatus));
Serial.printf("Status: Relay=%s, Current=%.2fA, Uptime=%dsn",
deviceStatus.relayState ? "ON" : "OFF",
deviceStatus.currentDraw,
deviceStatus.uptime);
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
esp_now_init();
esp_now_register_recv_cb(onDataReceive);
memcpy(peerInfo.peer_addr, actuatorMAC, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
esp_now_add_peer(&peerInfo);
Serial.println("Controller Ready. Commands: 'on', 'off', 'status'");
}
void loop() {
if (Serial.available()) {
String input = Serial.readStringUntil('n');
input.trim();
strncpy(cmd.action, input.c_str(), 19);
cmd.value = 0;
esp_now_send(actuatorMAC, (uint8_t *)&cmd, sizeof(cmd));
Serial.printf("Sent command: %sn", cmd.action);
}
}
Multiple Senders, One Receiver
ESP-NOW excels at collecting data from multiple sensor nodes. The receiver does not need to register each sender — it simply processes all incoming ESP-NOW packets:
// Gateway receiver - collects from multiple senders
#include <esp_now.h>
#include <WiFi.h>
typedef struct SensorPacket {
uint8_t nodeId;
char location[20];
float temperature;
float humidity;
float batteryVoltage;
} SensorPacket;
void onDataReceive(const esp_now_recv_info *info,
const uint8_t *data, int len) {
SensorPacket packet;
memcpy(&packet, data, sizeof(packet));
Serial.printf("[Node %d - %s] T=%.1fC H=%.1f%% Batt=%.2fVn",
packet.nodeId, packet.location,
packet.temperature, packet.humidity,
packet.batteryVoltage);
// Here you could forward to WiFi/MQTT/cloud
// since ESP-NOW and WiFi can coexist
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
esp_now_init();
esp_now_register_recv_cb(onDataReceive);
Serial.println("Multi-Sensor Gateway Ready");
Serial.println("Waiting for sensor data...");
}
void loop() {}
Each sender node uses a different nodeId and location string. The receiver identifies which room/sensor the data came from without needing to check MAC addresses.
Practical ESP-NOW Projects
Wireless RC Car Controller
Build a low-latency remote control for an RC car or robot. The controller reads joystick values and sends them via ESP-NOW at 50+ updates per second. The latency is so low that the car responds instantly to joystick movements.
// Controller side - reads joystick, sends via ESP-NOW
typedef struct JoystickData {
int16_t x; // -512 to 511
int16_t y; // -512 to 511
bool button; // Pressed or not
uint8_t speed; // 0-255
} JoystickData;
void loop() {
JoystickData js;
js.x = analogRead(34) - 2048; // Centre at 0
js.y = analogRead(35) - 2048;
js.button = !digitalRead(25);
js.speed = map(analogRead(32), 0, 4095, 0, 255);
esp_now_send(carMAC, (uint8_t *)&js, sizeof(js));
delay(20); // 50 Hz update rate
}
Wireless Doorbell with Camera
Use ESP-NOW to trigger a notification on an indoor display when someone presses a button at the door. The outdoor unit can be battery-powered since ESP-NOW uses minimal power. Add an ESP32-CAM at the door and send the image data in chunks via ESP-NOW.
Distributed Weather Station
Place ESP32 sensor nodes around your property — one in each room, one on the terrace, one in the garden. All nodes send temperature, humidity, and light data to a central gateway via ESP-NOW. The gateway displays the data on a web dashboard and logs it to an SD card.
Farm Sensor Network
For small farms (under 500 metres), ESP-NOW provides a cheaper alternative to LoRa for collecting soil moisture, temperature, and water level data from multiple points in the field. No internet needed — the gateway can display data on a local screen and sound alarms when thresholds are exceeded.
Frequently Asked Questions
What is the maximum range of ESP-NOW?
With the standard PCB antenna on most ESP32 development boards, ESP-NOW reaches approximately 200 metres outdoors and 30-50 metres indoors. With external antenna ESP32 boards, range extends to 480 metres or more. Lowering the data rate with esp_wifi_config_espnow_rate() can further increase range.
Can ESP-NOW and WiFi work simultaneously?
Yes, but with a limitation — both must use the same WiFi channel. If your ESP32 is connected to a WiFi router on channel 6, ESP-NOW communication must also use channel 6. Set the channel when registering peers: peerInfo.channel = 6;. If no WiFi is used, channel 0 (auto) works.
Can ESP8266 use ESP-NOW?
Yes, ESP-NOW works on ESP8266 as well. The API is slightly different. ESP-NOW communication between ESP32 and ESP8266 boards works, but both must be on the same WiFi channel. The ESP8266 has fewer peer slots (up to 10) compared to ESP32 (up to 20).
Is ESP-NOW secure?
ESP-NOW supports optional CCMP encryption (AES-128). When encryption is enabled, messages can only be decoded by peers that share the same encryption key. For secure applications, enable encryption by setting peerInfo.encrypt = true and configuring the Local Master Key (LMK).
How does ESP-NOW compare to NRF24L01?
ESP-NOW offers several advantages: no extra hardware needed (built into ESP32), longer range (480 m vs 100 m), easier programming, and coexistence with WiFi and BLE. NRF24L01 advantages: works with any microcontroller (not just ESP), supports true mesh via RF24Mesh, and the PA+LNA version reaches 1100 m. Choose ESP-NOW if you are already using ESP32; choose NRF24L01 if you need to interface with Arduino, STM32, or Raspberry Pi.
Conclusion
ESP-NOW is the hidden gem of the ESP32 platform. Its sub-millisecond latency, 480-metre range, zero infrastructure requirements, and dead-simple API make it the perfect choice for peer-to-peer IoT communication. Whether you are building a wireless RC car controller, a multi-room sensor network, or a farm monitoring system, ESP-NOW delivers reliable communication at a fraction of the cost and complexity of WiFi or Bluetooth. Combined with the ESP32’s existing WiFi and BLE capabilities, ESP-NOW completes the wireless communication toolkit.
Start building with ESP-NOW today. Browse our range of ESP32 development boards at Zbotic.in — from basic 30-pin boards to feature-rich ESP32-S3 modules, we have the right board for your wireless project.
Add comment