Language: EN

esp-now-comunicacion-muchos-a-uno-esp32

Many-to-One Communication with ESP-NOW on ESP32

In previous entries, we have covered the basics of ESP-NOW, how to set up a one-to-one communication, and how to handle a one-to-many communication.

In this entry, we will delve into using ESP-NOW to implement a many-to-one communication.

Again, I will focus on sending a string (because something needs to be sent). But it is easily extrapolated to sending a JSON, a struct, or anything else.

In upcoming entries, we will explore how to handle a many-to-many communication.

What is many-to-one communication?

In a many-to-one communication, multiple devices (senders) send data to a single device (receiver).

esp32-espnow-many-to-one

This type of communication is useful in applications where several sensors or nodes need to report data to a central node (such as in environmental monitoring systems, industrial control, or wireless sensor networks).

Regarding the one-to-one case, in this case, we will also have many sender MACs.

const uint8_t* SENDERS_MACS[] = { /* ... */ };
const uint8_t SENDERS_COUNT = sizeof(SENDERS_MACS) / sizeof(uint8_t*);

In this case, the registration of receivers of the senders does not change. They only need to register one in RegisterPeeks.

But now the receiver will have to discriminate who (the hell) is sending the information. For that, in the receiver’s callback, it will have to search among the MACs it knows.

int SearchSender(const uint8_t* mac)
{
	for(auto sender_id = 0; sender_id < SENDERS_COUNT; sender_id++)
	{
		if(AreMacEquals(mac, SENDERS_MACS[sender_id])) return sender_id;
	}
	return -1;
}

void OnMessageReceived(const uint8_t* mac, const uint8_t* data, int len)
{
	/* ... */ 
	
	auto sender_id = SearchSender(mac);
	Serial.printf("Sender id: %d\n", sender_id);
}

Complete Example

Let’s see how all of this would look together 👇

  • 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: A string is sent to the receiver using esp_now_send. The string is converted to a byte array using payload.c_str().
#include <esp_now.h>
#include <WiFi.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 = "MY STRING";

	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);
}
  • ESP-NOW Initialization: ESP-NOW is initialized, and a callback is registered to handle received messages.
  • Message Reception: When a message is received, the string is reconstructed from the received bytes and printed on the serial monitor.
  • Sender Identification: The MAC address of the sender is used to identify which device sent the message.
#include <esp_now.h>
#include <WiFi.h>

#include "const.h"

bool AreMacEquals(const uint8_t* src, const uint8_t* dst)
{
	for(auto i = 0; i < 6; i++)
	{
		if(src[i] != dst[i]) return false;
	}
	return true;
}

int SearchSender(const uint8_t* mac)
{
	for(auto sender_id = 0; sender_id < SENDERS_COUNT; sender_id++)
	{
		if(AreMacEquals(mac, SENDERS_MACS[sender_id])) return sender_id;
	}
	return -1;
}

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];
	}

	Serial.println(payload);
	auto sender_id = SearchSender(mac);
	Serial.printf("Sender id: %d\n", sender_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_SENDER_1 };
const uint8_t SENDERS_COUNT = sizeof(SENDERS_MACS) / sizeof(uint8_t*);

const uint8_t* RECEIVERS_MACS[] = { MAC_RECEIVER_1 };
const uint8_t RECEIVERS_COUNT = sizeof(RECEIVERS_MACS) / sizeof(uint8_t*);