Aprende a usar ESP-NOW para intercambiar datos entre placas ESP32 programadas con Arduino IDE. ESP-NOW es un protocolo de comunicación sin conexión desarrollado por Espressif que se caracteriza por la transmisión de paquetes cortos. Este protocolo permite que múltiples dispositivos hablen entre sí de forma muy sencilla, sin necesidad de router ni de red Wi-Fi.
¿Qué es ESP-NOW y por qué es tan útil?
Según la documentación oficial de Espressif, ESP-NOW es un “protocolo desarrollado por Espressif, que permite que múltiples dispositivos se comuniquen entre sí sin usar Wi-Fi. El protocolo es similar a la conectividad inalámbrica de 2,4 GHz de bajo consumo. El emparejamiento entre dispositivos es necesario antes de su comunicación. Una vez hecho el emparejamiento, la conexión es segura y peer-to-peer, sin necesidad de handshake.”
Esto significa que después de emparejar un dispositivo con otro, la conexión es persistente. Es decir, si de repente una de tus placas pierde energía o se reinicia, cuando vuelve a arrancar, se reconectará automáticamente con su peer para continuar la comunicación. Esto lo hace especialmente robusto para proyectos donde la fiabilidad es crítica.
ESP-NOW soporta las siguientes características:
Comunicación unicast cifrada y no cifrada, dispositivos peer mixtos (cifrados y no cifrados), payload de hasta 250 bytes y función de callback de envío que se puede configurar para informar a la capa de aplicación del éxito o fallo de la transmisión.
ESP-NOW también tiene las siguientes limitaciones:
Peers cifrados limitados: un máximo de 10 peers cifrados en modo Station, 6 como máximo en modo SoftAP o SoftAP + Station. Se soportan múltiples peers no cifrados, pero su número total debe ser inferior a 20, incluyendo los peers cifrados. El payload está limitado a 250 bytes.
En palabras simples, ESP-NOW es un protocolo de comunicación rápido que se puede usar para intercambiar mensajes pequeños (de hasta 250 bytes) entre placas ESP32. Es muy versátil y puedes tener comunicación unidireccional o bidireccional en diferentes configuraciones.
Configuraciones posibles con ESP-NOW
Comunicación unidireccional
En comunicación unidireccional, puedes tener escenarios como estos:
Una placa ESP32 enviando datos a otra placa ESP32: esta configuración es muy fácil de implementar y es ideal para enviar datos de una placa a otra, como lecturas de sensores o comandos ON/OFF para controlar GPIOs.
Un ESP32 “maestro” enviando datos a múltiples ESP32 “esclavos”: una placa ESP32 envía los mismos o diferentes comandos a distintas placas ESP32. Esta configuración es ideal para construir algo como un control remoto. Puedes tener varias placas ESP32 repartidas por la casa controladas por una placa ESP32 principal.
Un ESP32 “esclavo” recibiendo datos de múltiples “maestros”: esta configuración es ideal si quieres recopilar datos de varios nodos sensores en una sola placa ESP32. Esta puede configurarse como servidor web para mostrar los datos de todas las demás placas.
Nota: en la documentación de ESP-NOW no existe el concepto de “sender/master” y “receiver/slave”. Cada placa puede ser emisora o receptora. Sin embargo, para mantener la claridad usaremos los términos “emisor” y “receptor” o “maestro” y “esclavo”.
Comunicación bidireccional
Con ESP-NOW, cada placa puede ser emisora y receptora al mismo tiempo. Así que puedes establecer comunicación bidireccional entre placas. Por ejemplo, puedes tener dos placas comunicándose entre sí. También puedes añadir más placas a esta configuración y tener algo que se parece a una red donde todas las placas ESP32 se comunican entre sí.
En resumen, ESP-NOW es ideal para construir una red en la que puedes tener varias placas ESP32 intercambiando datos entre ellas.
Obtener la dirección MAC del ESP32
Para comunicarte vía ESP-NOW, necesitas conocer la dirección MAC del receptor ESP32. Así sabrás a qué dispositivo enviar los datos. Cada ESP32 tiene una dirección MAC única, y así es como identificamos cada placa para enviarle datos usando ESP-NOW.
Para obtener la dirección MAC de tu placa, sube el siguiente código:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Detalles completos del proyecto en https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/
*/
#include <WiFi.h>
#include <esp_wifi.h>
void readMacAddress(){
uint8_t baseMac[6];
esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
if (ret == ESP_OK) {
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
baseMac[0], baseMac[1], baseMac[2],
baseMac[3], baseMac[4], baseMac[5]);
} else {
Serial.println("Failed to read MAC address");
}
}
void setup(){
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.STA.begin();
Serial.print("[DEFAULT] ESP32 Board MAC Address: ");
readMacAddress();
}
void loop(){
}
Después de subir el código, abre el Monitor Serie a 115200 baudios y pulsa el botón RST/EN del ESP32. La dirección MAC debería imprimirse con el formato habitual (seis pares hexadecimales separados por dos puntos). Guarda la dirección MAC de tu placa, porque la necesitarás para enviar datos a la placa correcta vía ESP-NOW.
Comunicación punto a punto unidireccional con ESP-NOW
Para empezar con la comunicación inalámbrica ESP-NOW, construiremos un proyecto sencillo que muestra cómo enviar un mensaje de un ESP32 a otro. Uno será el “emisor” y el otro el “receptor”.
Enviaremos una estructura que contiene una variable de tipo char, int, float y boolean. Después, puedes modificar la estructura para enviar los tipos de variables que sean adecuados para tu proyecto (como lecturas de sensores o variables booleanas para encender o apagar algo).
En el sketch del emisor debes incluir:
Inicializar ESP-NOW. Registrar una función de callback al enviar datos — la función OnDataSent se ejecutará cuando se envíe un mensaje. Esto puede decirnos si el mensaje se entregó correctamente o no. Añadir un dispositivo peer (el receptor). Para esto, necesitas conocer la dirección MAC del receptor. Enviar un mensaje al dispositivo peer.
En el lado del receptor, el sketch debe incluir:
Inicializar ESP-NOW. Registrar una función de callback de recepción (OnDataRecv). Esta es la función que se ejecutará cuando se reciba un mensaje. Dentro de esa función de callback, guardar el mensaje en una variable para ejecutar cualquier tarea con esa información.
ESP-NOW funciona con funciones de callback que se llaman cuando un dispositivo recibe un mensaje o cuando se envía un mensaje (y te informan si el mensaje se entregó correctamente o falló).
Funciones útiles de ESP-NOW
Estas son las funciones más esenciales de ESP-NOW:
esp_now_init(): inicializa ESP-NOW. Debes inicializar Wi-Fi antes de inicializar ESP-NOW. esp_now_add_peer(): llama a esta función para emparejar un dispositivo y pasar como argumento la dirección MAC del peer. esp_now_send(): envía datos con ESP-NOW. esp_now_register_send_cb(): registra una función de callback que se dispara al enviar datos. Cuando se envía un mensaje, se llama a una función que devuelve si la entrega fue exitosa o no. esp_now_register_recv_cb(): registra una función de callback que se dispara al recibir datos. Cuando se reciben datos vía ESP-NOW, se llama a una función.
Sketch del emisor ESP32
Aquí tienes el código del emisor ESP32. Cópialo en tu Arduino IDE, pero no lo subas todavía. Necesitas hacer algunas modificaciones para que funcione en tu caso.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Detalles completos del proyecto en https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
*/
#include <esp_now.h>
#include <WiFi.h>
// REEMPLAZA CON LA DIRECCIÓN MAC DE TU RECEPTOR
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// Estructura de ejemplo para enviar datos
// Debe coincidir con la estructura del receptor
typedef struct struct_message {
char a[32];
int b;
float c;
bool d;
} struct_message;
// Crea un struct_message llamado myData
struct_message myData;
esp_now_peer_info_t peerInfo;
// Callback cuando se envían datos
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup() {
// Inicia el Monitor Serie
Serial.begin(115200);
// Configura el dispositivo como Wi-Fi Station
WiFi.mode(WIFI_STA);
// Inicia ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Una vez ESP-NOW está inicializado con éxito, registramos el CB de envío
// para obtener el estado del paquete transmitido
esp_now_register_send_cb(esp_now_send_cb_t(OnDataSent));
// Registra el peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Añade el peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
}
void loop() {
// Establece los valores a enviar
strcpy(myData.a, "THIS IS A CHAR");
myData.b = random(1,20);
myData.c = 1.2;
myData.d = false;
// Envía el mensaje vía ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
if (result == ESP_OK) {
Serial.println("Sent with success");
}
else {
Serial.println("Error sending the data");
}
delay(2000);
}
Cómo funciona el código del emisor
Primero, incluye las librerías esp_now.h y WiFi.h. En la siguiente línea, debes insertar la dirección MAC del receptor ESP32:
uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x07, 0x0D, 0x64};
Necesitas reemplazar esa variable con tu propia dirección MAC, la que obtuviste con el sketch anterior.
Después, se crea una estructura que contiene el tipo de datos que queremos enviar. La llamamos struct_message y contiene 4 tipos de variables diferentes. Puedes cambiarla para enviar otros tipos de variables.
Después, se crea una nueva variable de tipo struct_message llamada myData que almacenará los valores de las variables. Se crea una variable de tipo esp_now_peer_info_t para almacenar información sobre el peer. Después, se define la función OnDataSent(). Es una función de callback que se ejecutará cuando se envíe un mensaje. En este caso, simplemente imprime si el mensaje se entregó con éxito o no.
En el setup(), se inicializa el Monitor Serie, se configura el dispositivo como Wi-Fi Station, se inicializa ESP-NOW y se registra la función de callback de envío. Después, necesitamos emparejar con otro dispositivo ESP-NOW para enviar datos. Eso es lo que hacemos en las siguientes líneas:
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
En el loop(), enviaremos un mensaje vía ESP-NOW cada 2 segundos. Primero, establecemos los valores de las variables. Recuerda que myData es una estructura. Aquí asignamos los valores que queremos enviar dentro de la estructura: un char, un int aleatorio, un float y un boolean. Creamos este tipo de estructura para mostrarte cómo enviar los tipos de variables más comunes.
Finalmente, enviamos el mensaje con esp_now_send(). Después, comprobamos si el mensaje se envió con éxito:
if (result == ESP_OK) {
Serial.println("Sent with success");
} else {
Serial.println("Error sending the data");
}
El loop() se ejecuta cada 2000 milisegundos (2 segundos).
Sketch del receptor ESP32
Sube el siguiente código a tu placa receptora ESP32:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Detalles completos del proyecto en https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
*/
#include <esp_now.h>
#include <WiFi.h>
// Estructura de ejemplo para recibir datos
// Debe coincidir con la estructura del emisor
typedef struct struct_message {
char a[32];
int b;
float c;
bool d;
} struct_message;
// Crea un struct_message llamado myData
struct_message myData;
// Función de callback que se ejecutará cuando se reciban datos
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&myData, incomingData, sizeof(myData));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Char: ");
Serial.println(myData.a);
Serial.print("Int: ");
Serial.println(myData.b);
Serial.print("Float: ");
Serial.println(myData.c);
Serial.print("Bool: ");
Serial.println(myData.d);
Serial.println();
}
void setup() {
// Inicia el Monitor Serie
Serial.begin(115200);
// Configura el dispositivo como Wi-Fi Station
WiFi.mode(WIFI_STA);
// Inicia ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Una vez ESP-NOW está inicializado con éxito, registramos el CB de recepción
// para obtener info del paquete recibido
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}
void loop() {
}
Cómo funciona el código del receptor
De forma similar al emisor, se incluyen las librerías. Se crea una estructura para recibir los datos. Esta estructura debe ser la misma que la definida en el sketch del emisor. Se crea una variable struct_message llamada myData.
Después, se crea una función de callback que se llamará cuando el ESP32 reciba los datos vía ESP-NOW. La función se llama OnDataRecv() y debe aceptar varios parámetros:
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
Se copia el contenido de la variable incomingData en la variable myData:
memcpy(&myData, incomingData, sizeof(myData));
Ahora, la estructura myData contiene varias variables con los valores enviados por el emisor. Para acceder a la variable a, por ejemplo, solo necesitamos llamar a myData.a. En este ejemplo simplemente imprimimos los datos recibidos, pero en una aplicación práctica puedes mostrar los datos en una pantalla, por ejemplo.
En el setup(), se inicializa el Monitor Serie, se configura el dispositivo como Wi-Fi Station, se inicializa ESP-NOW y se registra la función de callback de recepción.
Probar la comunicación ESP-NOW
Sube el sketch del emisor al ESP32 emisor y el sketch del receptor al ESP32 receptor. Ahora, abre dos ventanas de Arduino IDE. Una para el receptor y otra para el emisor. Abre el Monitor Serie para cada placa. Debería ser un puerto COM diferente para cada placa.
En el lado del emisor deberías ver un mensaje de “Sent with success” cada 2 segundos, junto con el estado de entrega del último paquete (Delivery Success o Delivery Fail). En el lado del receptor deberías ver los valores recibidos cada 2 segundos. Fíjate en que la variable Int cambia entre cada lectura recibida (porque la establecimos como un número aleatorio en el lado del emisor).
Hicimos pruebas del rango de comunicación entre las dos placas, y somos capaces de obtener una comunicación estable de hasta 220 metros (aproximadamente 722 pies) en campo abierto. En este experimento, ambas antenas integradas del ESP32 estaban apuntándose mutuamente.
Conclusión: lo que has aprendido
Hemos intentado mantener los ejemplos lo más simples posible para que entiendas mejor cómo funciona todo. Hay más funciones relacionadas con ESP-NOW que pueden ser útiles en tus proyectos, como: gestionar peers, borrar peers, escanear dispositivos esclavos, etc. Para un ejemplo completo, en tu Arduino IDE puedes ir a Archivo > Ejemplos > ESP32 > ESPNow y elegir uno de los sketches de ejemplo.
Esperamos que esta introducción a ESP-NOW te haya resultado útil. Como ejemplo simple de inicio, te hemos mostrado cómo enviar datos como una estructura de un ESP32 a otro. La idea es reemplazar los valores de la estructura con lecturas de sensores o estados de GPIO, por ejemplo.
Además, con ESP-NOW, cada placa puede ser simultáneamente emisora y receptora. Una placa puede enviar datos a múltiples placas y también recibir datos de múltiples placas. Esto lo convierte en la alternativa perfecta al Wi-Fi cuando necesitas comunicación rápida, de bajo consumo y sin dependencia de infraestructura entre varios dispositivos ESP32.
ESP-NOW es la joya oculta del ESP32: pocos saben que existe, pero los que lo descubren lo usan para proyectos donde el Wi-Fi tradicional sería un lastre. Sin router, sin handshake, sin configuración de red, sin latencia — solo dos placas hablando entre sí de forma directa, rápida y fiable, incluso a cientos de metros de distancia.
Descubre más desde CIBERED
Suscríbete y recibe las últimas entradas en tu correo electrónico.
