En tutoriales anteriores, hemos cubierto los conceptos básicos de ESP-NOW, cómo configurar una comunicación 1 a 1 para enviar una variable simple, una estructura de datos (struct) o un string.
En este tutorial, vamos a profundizar en el uso de ESP-NOW para enviar un JSON en una comunicación 1 a 1. Este es un paso importante para manejar datos estructurados y complejos en nuestros proyectos de IoT y sistemas embebidos.
En los próximos tutoriales, exploraremos cómo manejar comunicaciones 1 a muchos, muchos a 1, y muchos a muchos. Pero por ahora, nos centraremos en cómo enviar un JSON.
¿Por qué enviar un JSON?
JSON (JavaScript Object Notation) es un formato de intercambio de datos ligero y fácil de leer tanto para humanos como para máquinas. Es muy utilizado en aplicaciones web y IoT para transmitir datos estructurados.
{
"nombre": "Luis",
"edad": 30,
"activo": true
}
Enviar un JSON nos permite enviar múltiples datos relacionados en un solo mensaje, lo que es especialmente útil para configuraciones, comandos complejos, o datos sensoriales agrupados.
Por lo demás, un JSON no deja de ser string. Así que, respecto al tutorial anterior básicamente es que tenemos que serializar los datos en el JSON queremos enviar y recibir. Por ejemplo:
String payload = "";
StaticJsonDocument<300> jsonDoc;
jsonDoc["nombre"] = "Luis";
jsonDoc["edad"] = 30;
jsonDoc["activo"] = true;
serializeJson(jsonDoc, payload);
En este caso, hemos definido un JSON con tres campos: "nombre"
, "edad"
y "activo"
.
De igual forma, para recibir el JSON, esperamos a que se ejecute la función de callback onDataReceived()
y tendremos que deserializar el JSON:
StaticJsonDocument<300> jsonDoc;
DeserializationError error = deserializeJson(jsonDoc, payload);
if(error) { Serial.print("Error packet."); return; }
const char* nombreRecibido = jsonDoc["nombre"];
int edadRecibida = jsonDoc["edad"];
bool activoRecibido = jsonDoc["activo"];
Importante: Recordad que ESP-NOW tiene un límite de 250 bytes por mensaje. Que en un JSON, puedes agotarlos realmente rápido.
Ejemplo completo
Vamos a ver el ejemplo completo 👇
- Inicialización de ESP-NOW: Se inicializa ESP-NOW y se registra un callback para saber si el mensaje se envió correctamente.
- Registro del peer: Se registra la dirección MAC del receptor como un “peer” (par) en la red ESP-NOW.
- Creación del JSON: Se crea un JSON utilizando la librería
ArduinoJson
. En este caso, el JSON contiene un solo campo"data"
con un valor de1
. - Envío del mensaje: El JSON se serializa a un string y se envía al receptor utilizando
esp_now_send
.
#include <esp_now.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include "const.h"
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 SendMessage()
{
String payload = "";
StaticJsonDocument<300> jsonDoc;
jsonDoc["data"] = 1;
serializeJson(jsonDoc, payload);
esp_err_t result = esp_now_send(MAC_RECEIVER_1, (uint8_t*)payload.c_str(), payload.length());
if(result == ESP_OK)
{
Serial.println("Sent with success");
}
else
{
Serial.println("Error sending the data");
}
}
void static RegisterPeeks()
{
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, MAC_RECEIVER_1, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if(esp_now_add_peer(&peerInfo) != ESP_OK)
{
Serial.println("Failed to add peer");
}
else
{
Serial.print("Registered peer ");
}
}
void static InitEspNow()
{
if(esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
}
else
{
esp_now_register_send_cb(OnDataSent);
RegisterPeeks();
}
}
void setup()
{
Serial.begin(115200);
delay(2000);
WiFi.mode(WIFI_STA);
InitEspNow();
}
void loop()
{
SendMessage();
delay(2000);
}
- Inicialización de ESP-NOW: Se inicializa ESP-NOW y se registra un callback para manejar los mensajes recibidos.
- Recepción del mensaje: Cuando se recibe un mensaje, se reconstruye el string a partir de los bytes recibidos.
- Deserialización del JSON: El string recibido se deserializa utilizando la librería
ArduinoJson
para extraer los datos del JSON.
#include <esp_now.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include "const.h"
void OnMessageReceived(const uint8_t* mac, const uint8_t* data, int len)
{
Serial.printf("Packet received from: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.printf("Bytes received: %d\n", len);
String payload;
payload.reserve(len);
for(auto i = 0; i < len; i++)
{
payload += (char)data[i];
}
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, payload);
if(error) { Serial.print("Error packet."); return; }
int packet_id = doc["data"];
Serial.println(payload);
Serial.println(packet_id);
}
void InitEspNow()
{
if(esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
else
{
esp_now_register_recv_cb(OnMessageReceived);
}
}
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
InitEspNow();
}
void loop()
{
}
const uint8_t MAC_SENDER_1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const uint8_t MAC_RECEIVER_1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const uint8_t* SENDERS_MACS[] = { MAC_RECEIVER_1 };
const uint8_t SENDERS_COUNT = sizeof(SENDERS_MACS) / sizeof(uint8_t*);
const uint8_t* RECEIVERS_MACS[] = { MAC_SENDER_1 };
const uint8_t RECEIVERS_COUNT = sizeof(RECEIVERS_MACS) / sizeof(uint8_t*);