esp-now-enviar-struct-con-esp32

Enviar una struct con ESP-NOW en ESP32

En entradas anteriores, hemos visto qué es ESP-NOW y cómo configurar una comunicación básica entre dos dispositivos ESP32 para enviar una variable simple.

En esta entrada, vamos a profundizar en el uso de ESP-NOW para enviar una estructura de datos (struct) en una comunicación 1 a 1.

En proyectos avanzados, no siempre es suficiente enviar una sola variable. A menudo, necesitamos enviar múltiples datos relacionados entre sí (como un mensaje de texto, un número entero, un valor decimal y un booleano).

Una opción muy cómoda para hacer esto es enviarlos agruparlos en una estructura de datos (struct). Esto simplifica el código y además incluso mejora la eficiencia de la comunicación (que mal no hace)

En las próximas entradas, exploraremos cómo enviar strings, JSON, y cómo manejar comunicaciones 1 a muchos, muchos a 1, y muchos a muchos.

Enviar un struct

Supongamos que tenemos una estructura Message, que define un conjunto de datos que queremos enviar:

  • text[20]: Un array de caracteres para almacenar un mensaje de texto.
  • integer: Un número entero.
  • decimal: Un número decimal (float).
  • boolean: Un valor booleano (true/false).

Esta estructura se serializa y se envía como un bloque de bytes a través de ESP-NOW.

El funcionamiento es muy similar al que vimos en la entrada anterior para mandar un simple dato. La diferencia es que ahora vamos a mandar todo el struct (en lugar de una variable primitiva)

Message payload;
strcpy(payload.text, "MESSAGE TEXT");
payload.integer = random(1, 100);
payload.decimal = 2.1;
payload.boolean = false;

esp_err_t result = esp_now_send(MAC_RECEIVER_1, (uint8_t*)&payload, sizeof(Message));

De igual forma, al recibirlo, tendremos que castear a Message*.

auto payload = (Message*)(data);

Como vemos, en realidad no es mucho más complicado mandar la estructura que un tipo primitivo.

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.
  • Envío del mensaje: Se crea una instancia de la estructura Message, se llena con datos y se envía al receptor utilizando esp_now_send.
#include <esp_now.h>
#include <WiFi.h>

#include "const.h"
#include "message.hpp"

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()
{
	Message payload;
	strcpy(payload.text, "MESSAGE TEXT");
	payload.integer = random(1, 100);
	payload.decimal = 2.1;
	payload.boolean = false;

	esp_err_t result = esp_now_send(MAC_RECEIVER_1, (uint8_t*)&payload, sizeof(Message));

	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 deserializa la estructura Message y se imprimen sus valores en el monitor serial.
#include <esp_now.h>
#include <WiFi.h>

#include "const.h"
#include "message.hpp"

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);

	auto payload = (Message*)(data);
	Serial.print("Char: ");
	Serial.println(payload->text);
	Serial.print("Int: ");
	Serial.println(payload->integer);
	Serial.print("Float: ");
	Serial.println(payload->decimal);
	Serial.print("Bool: ");
	Serial.println(payload->boolean);
	Serial.println();
}

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()
{

}
typedef struct Message
{
	char text[20];
	int integer;
	float decimal;
	bool boolean;
} Message;
const uint8_t MAC_SENDER_1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const uint8_t MAC_RECEIVER_1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };