In previous posts, we have seen what ESP-NOW is and how to set up basic communication between two ESP32 devices to send a simple variable.
In this post, we will delve into the use of ESP-NOW to send a data structure (struct) in a one-to-one communication.
In advanced projects, it is not always sufficient to send a single variable. Often, we need to send multiple related data (such as a text message, an integer, a decimal value, and a boolean).
A very convenient option to do this is to group them in a data structure (struct). This simplifies the code and also improves communication efficiency (which is not a bad thing)
In the upcoming posts, we will explore how to send strings, JSON, and how to handle one-to-many, many-to-one, and many-to-many communications.
Send a struct
Let’s assume we have a structure Message
, which defines a set of data we want to send:
- text[20]: A character array to store a text message.
- integer: An integer number.
- decimal: A decimal number (float).
- boolean: A boolean value (true/false).
This structure is serialized and sent as a block of bytes over ESP-NOW.
The operation is very similar to what we saw in the previous post for sending a simple data. The difference is that now we are going to send the entire struct (instead of a primitive variable)
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));
Similarly, upon receiving it, we will need to cast to Message*
.
auto payload = (Message*)(data);
As we can see, it is not much more complicated to send the structure than a primitive type.
Complete Example
Let’s see the complete example 👇
- ESP-NOW Initialization: ESP-NOW is initialized and a callback is registered to know if the message was sent successfully.
- Peer Registration: The MAC address of the receiver is registered as a “peer” in the ESP-NOW network.
- Message Sending: An instance of the
Message
structure is created, filled with data, and sent to the receiver usingesp_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);
}
- ESP-NOW Initialization: ESP-NOW is initialized and a callback is registered to handle received messages.
- Message Reception: When a message is received, the
Message
structure is deserialized and its values are printed to the serial monitor.
#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 };