I dont have much ESP background/exposure yet.. mostly been old ESP8266 stuff.. with locally hosted site/data/gui stuff..
or some ESP32 MQTT stuff..
ESP-NOW is new me in general..
I read a bunch of tutorials (one on one, one to many, many to one.etc).. and most of them always 'hard-code' mac addresses (turned me off right away) LOL.
I wanted to learn more. and play around. (for me.. I need a 'goal' though.. otherwise random stuff I read/learn doesnt 'click' until I have a real world solution I know it can apply to)
So I just wanted to play around.. and understand things as I go.
The RNT auto-pairing tutorials was great. Opened up doors. I just needed to try and tweak things in a way "I" thought was easier/better/more productive for an end use project.
Ahh.. ok.... I just sending a 'pointer'.. which loads/sets all that 'peers' data as the current 'peer_info'... is this accurate/correct?
Hmmm.. so do you think (would be better than wasting my time here/playing with these built in functions).. to just collect these mac address by myself/manually.. and save them in an array or something? So then I -can- use it the same way I outlined above perhaps?
HA!.. I think you might be right..(I think?) just collect the mac addresses myself (manually).. and use my own array? (right?)
I am OK with the device limit being 20.. (so no issues there)
I guess now (new goal).. figure out to correct store/save this mac address (data) to an array
Do I need to (forward) think about any specific formatting? or var type stuff? (I come from a 'spoiled' web developer background.. where 'we' are spoiled so much we rarely have to worry about type/format stuff)
Just create (char?) array.. with length/size or 120?.. and then save things however they come from the (native) appPeer() function?
when button clicked.. it will (randomly) select one of the mac address in the list.. and send a message to it.
So each time the button is clicked.. it grabs a mac address and does (whatever the purpose of the button is).. send that message to the 'receiver' board.
One of the buttons is for a 'broadcast' message as well (so that mac address will be hard-coded to ff, ff, ff, ff...etc)
Do you think the 'manual' approach is... dumb? (why? as in just silly 'overkill'?) I started down -this- path originally... but then was like 'DOH.. dont be stupid.. use the assets already available in the sketch'.. (which started me down this path/post of HOW to correctly get the full mac addresses from the peer/slave list)..
But my (incorrect) thinking of it as an 'array' was a waste of time. Not a fan of the always starts from top of list requirement still
Oh.. just saw your last minute update:
Yes, you are correct you need the mac address to use the esp_now_send() command.
Do I need to pre-think of any special ways this needs to be done? (formatting? pre/post?) specific var types? Or just make a huge char array?
Having it stored in the array with the correct formatting: {0x08, 0xD1, 0xF9, 0xD0, 0x5D, 0x94}
would help when being used in the end/function param.
Given that, it's probably worth having your own copy of the peer information that can be accessed randomly. I might create a std::vector of esp_now_peer_info_t objects and populate it as peers are added. A vector can be accessed by index and also allows element to be easily removed if a peer is deleted.
OH? I dont believe I haven even really edited these? These are all come from other (worked/validated?) tutorials.
And in my other tests.... using it as such.. did work/send messages..etc (parsed and turned on leds in the 'receiver' devices..etc)
I guess I'll have to look into that more then? (confused as to why it has been working as expected so far.. both broadcast and direct (hard-coded) mac addresses?
Thanks!
update:
OK.. looks like this part of the comment....was removed? (so it ok/legit then? ......correct?)
thank you for the example. (I wasnt even thinking about the original [hard-coded] address being arrays... I was just thinking each 'entry' into the array would be a mac address 'string') (eye roll)
So I'd still need to set the correct 'index'.. and then loop through to grab all values, and pass on to the esp_now_send()..
example:
esp_err_t result = esp_now_send(targetMacAddress, (uint8_t *) &myData, sizeof(myData));
I need to make sure the that 'targetMacAddress' I add as a param -is- an array.
Not late here... (but I do need to take a break. This project, plus some MQTT issue trying to work out, and -real work- is all starting to combine into a..................headache!) LOL
Either way.. appreciate all the time/effort everyone has done.. not only for answers, but education/enlightenment.
//static/hard-coded broadcast mac address
uint8_t broadcastMacAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
//placeholder array for incoming/auto-paired mac addresses
uint8_t totalPeerList[20][6];
then right above the fetch call,,.. I added a quick loop to populate the array:
//output peer list
Serial.println("Current Peer List: ");
//Serial.println("");
if((pn.total_num) > 0){
int i = 0;
int j = 0;
//collect default mac address data
Serial.print("MAC ADDRESS (DEFAULT) ");
Serial.print(i+1);
Serial.print(": ");
for(j=0; j < 6; j++){
//Serial.println("");
//Serial.print("MAC ADDRESS ");
//Serial.print(j);
//Serial.print(": ");
Serial.print(slave.peer_addr[j], HEX);
Serial.print(":");
//add to array
totalPeerList[i][j] =
}
Serial.println();
//original process below
boolean from_head = true;
while (esp_now_fetch_peer(from_head, &slave) == ESP_OK){
from_head = false;
Serial.print("MAC ADDRESS (PARSED) ");
Serial.print(i+1);
Serial.print(": ");
printMAC(slave.peer_addr);
Serial.println("");
i++;
}
}
return true;
which I am getting this output:
Current Peer List:
MAC ADDRESS (DEFAULT) 0: 8:D1:F9:D0:5D:94:
MAC ADDRESS (DEFAULT) 1: 8:D1:F9:D0:CB:6C:
MAC ADDRESS (PARSED) 0: 08:d1:f9:d0:5d:94
MAC ADDRESS (PARSED) 1: 08:d1:f9:d0:cb:6c
I am not sure if these need to be (somehow) converted to HEX before populating the array? (or does it not matter?)
** I do see the trailing ':'..but that is just part of the output/display (debug) check.
I am saving 'default' values to the array but using:
Serial.print(slave.peer_addr[j], HEX);
for output to display it as HEX visually in serial monitor.
(not sure if that matters? or or how to populate the array as 0xXX, 0xXX, 0xXX...etc)
No, HEX is just a different representation of the binary content . The mac data are handed over to the different functions just as an array of unsigned byte (uint8_t).
You only get HEX to make it easier for humans to read and compare.
I'm not sure where and how you got the data printed in post #34, but the function you posted should throw an error when you try to compile it:
//add to array
totalPeerList[i][j] =
}
I have made a simple "emulation" of the esp_now_fetch_peer function so that I can demo how to populate and print the list:
IAt every place where you usually have to use a reference to e.g. slave.peer_addr you can insert totalPeerList[1] or whatever index applies. Be aware that the second index is not used!
In the sketch above I have also added a for-loop in printMAC() to get uppercase letters in the HEX data. Just looks nicer ...
BTW: You should definitely get yourself a C++ book ... it is really worth it ...
Here is a fully commented version of the demo sketch (not the fake esp_now_fetch_peer() )
/*
Forum: https://forum.arduino.cc/t/esp32-esp-now-with-auto-pairing-loop-through-peer-list-help/1199296
Wokwi: https://wokwi.com/projects/383925663410460673
The following declarations and functions handle a mac address list
*/
#include "dummyESPFunctions.h"
// maxPeers is defined as a constant and holds the content of 20
// It will be used to define the number of peer MAC addresses that
// can be stored in the totalPeerList[]
constexpr int maxPeers {20};
// totalPeerList is a two-dimensional array with maxPeers rows and 6 columns
// for the MAC addresses that will be stored in this array
// MAC addresses consist of 6 bytes like e.g. {8,250,30,24,25,1}
// For easier reception by users they are usually written as HEX data
// but when used by ESPNOW it's just six adjacent memory "cells"
//
// To understand the two-D array just think of it as a table (e.g. in a Calc Sheet):
// * The first index addresses the row (in C/C++ index has a range from 0..(n-1) if you have n rows)
// * The second index addresses the column (in C/C++ index has a range from 0..(m-1) if you have m columns)
//
// The short form "totalPeerList[5]" points to the starting "cell" of the sixth row (counted from zero!)
// You may write "totalPeerList[5][3]" if you want to address the forth element in the sixth row
//
// Always remind yourself that C/C++ counts from zero in arrays!
//
uint8_t totalPeerList[maxPeers][6];
// noOfPeersInList is a variable that shall hold the actual number of peers which
// were retrieved via esp_now_fetch_peer()
// It is set to zero so that - if we call printList() - it will not print invalid data
int noOfPeersInList = 0;
// We need a variable of type esp_now_peer_info_t to communicate with the ESPNOW library.
// The content is defined in
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html
//
// In addition with further information this variable might be filled by ESPNOW functions
// with the MAC address of paired peers.
//
// esp_now_peer_info_t declares a structure, that is a combination of data that is bundled
// under one name. To access one of those data you use the name of the structure variable
// (here: slave) and add the name of the internal variable (e.g. peer_addr) with a "." in
// between: slave.peer_addr is a valid name as well as slave.channel.
//
esp_now_peer_info_t slave;
// In setup() we call two functions that are defined after loop()
void setup() {
Serial.begin(115200);
populateList();
printList();
}
// Nothing to be done here for demo purposes
void loop() {
}
// The function populateList() does not need any parameters
// It collects (if available) the MAC addresses of all paired
// peers and copies them one by one in the totalPeerList[]
void populateList() {
// from_head is set to true, so that in the very first call
// of esp_now_fetch_peer() we get the very first entry from the
// ESPNOW's internal list
boolean from_head = true;
// We set the variable count to zero. It is used
// a) as the index where the next entry shall be written in totalPeerList[]
// b) as a counter for the number of peers we get from the function
int count = 0;
// We use the return value of the ESPNOW function to detect whether a
// call was succesful or not
// If it was successful "slave" will hold a valid MAC address
// and the sketch enters the while-loop
//
// otherwise it will skip the while-loop and commence with the
// statement after the closing curly bracket
// So if we don't get a ESP_OK on the first call
// noOfPeersInList will be set to zero (as count is still zero)
// a call of printlist() will not show anything.
//
// If the while-loop is entered ...
while (esp_now_fetch_peer(from_head, &slave) == ESP_OK) {
// from_head is set to false in the first entry here
// This way only the first call starts at the Top of the ESPNOW internal list
// Every following call in while(esp_...) will search for the next entry in
// that internal list
from_head = false;
// The function call in while() has filled the memory where the variable "slave"
// is stored in memory with the content from the ESPNOW internal list.
// We are only interested in the peer_addr part and therefore
// use the standard function memcpy()
// See https://en.cppreference.com/w/cpp/string/byte/memcpy
// to copy 6 bytes from source (slave.peer_addr) to destination totalPeerList[count]
//
// On the first entry count is zero, so we fill totalPeerList[0
//
memcpy(totalPeerList[count],slave.peer_addr,6);
// Now we increase count by one; after the first entry it becomes 1 now
// That's nice:
// a) That is the number of peer MAC addresses we have stored now and
// b) It points to the next row in totalPeerList[] where a further address may
// be stored - if available -
count++;
}
// After all is done count does its last duty: It hands over the number of
// stored MAC addresses to noOfPeersInList and ... passes away as typical for local variables ... ;-)
// while noOfPeersInList - being a global variable - survives and saves the heritage of "count"
// for further functions
noOfPeersInList = count;
}
//
// printList() is just trying to print
// from 0 to noOfPeersInList-1
// it calls the separate function printMAC() handing over the address where the first cell out of
// six is that (hopefully) holds a valid MAC address
// Serial.printf() is a function available to ESP controllers that eases mixed printing of
// text and numbers
//
// It uses a format string (here "MAC ADRESS %2d: ") that includes possible text and placeholders
// starting with a "%" and formatting commands for decimal, floating point numbers etc.
//
// The variable(s) which are associated with each placeholder are listed after the format
// string in the same order as their placeholders and separated by a comma
//
// see https://en.cppreference.com/w/cpp/io/c/fprintf
//
void printList() {
for (int i = 0; i<noOfPeersInList;i++){
Serial.printf("MAC ADRESS %2d: ",i+1);
printMAC(totalPeerList[i]);
Serial.println();
}
}
// printMAC() gets the pointer to the begin of a six byte array holding a MAC address
// It uses the standard function snprintf() to fill the char array macStr[18] with
// the hexadecimal printed values of each single array cell.
// The additional for-loop goes through the macStr array character by character and
// converts the characters - if they are letters - to upper case
// ---------------------------- esp_ now -------------------------
void printMAC(const uint8_t * mac_addr){
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
for (int i=0;i<18;i++){
macStr[i] = toupper(macStr[i]);
}
Serial.print(macStr);
}
Good luck!
While commenting I came across the issue that ESPNOW (or somebody else) might sometime in future increase the number of peers in the internal list. We have to avoid writing after the end of our array totalPeerList[]. That;s integrated in the following snippet (and I will add it on Wokwi in the sketch mentioned above):
// The function populateList() does not need any parameters
// It collects (if available) the MAC addresses of all paired
// peers and copies them one by one in the totalPeerList[]
void populateList() {
// from_head is set to true, so that in the very first call
// of esp_now_fetch_peer() we get the very first entry from the
// ESPNOW's internal list
boolean from_head = true;
// We set the variable count to zero. It is used
// a) as the index where the next entry shall be written in totalPeerList[]
// b) as a counter for the number of peers we get from the function
int count = 0;
// We use the return value of the ESPNOW function to detect whether a
// call was succesful or not
// If it was successful "slave" will hold a valid MAC address
// and the sketch enters the while-loop
//
// otherwise it will skip the while-loop and commence with the
// statement after the closing curly bracket
// So if we don't get a ESP_OK on the first call
// noOfPeersInList will be set to zero (as count is still zero)
// a call of printlist() will not show anything.
//
// If the while-loop is entered ...
while (esp_now_fetch_peer(from_head, &slave) == ESP_OK) {
// from_head is set to false in the first entry here
// This way only the first call starts at the Top of the ESPNOW internal list
// Every following call in while(esp_...) will search for the next entry in
// that internal list
from_head = false;
// The function call in while() has filled the memory where the variable "slave"
// is stored in memory with the content from the ESPNOW internal list.
// We are only interested in the peer_addr part and therefore
// use the standard function memcpy()
// See https://en.cppreference.com/w/cpp/string/byte/memcpy
// to copy 6 bytes from source (slave.peer_addr) to destination totalPeerList[count]
//
// On the first entry count is zero, so we fill totalPeerList[0
//
memcpy(totalPeerList[count],slave.peer_addr,6);
// Now we increase count by one; after the first entry it becomes 1 now
// That's nice:
// a) That is the number of peer MAC addresses we have stored now and
// b) It points to the next row in totalPeerList[] where a further address may
// be stored - if available -
count++;
// To be on the safe side this function should be integrated also:
// If count reaches the maximum number of peers we jump out of the while loop
// to avoid writing data after the end of the array.
// It's not necessary now but might become relevant e.g. if ESPNOW allows more than twenty
// peers to pair
if (count >= maxPeers) {
break;
}
}
// After all is done count does its last duty: It hands over the number of
// stored MAC addresses to noOfPeersInList and ... passes away as typical for local variables ... ;-)
// while noOfPeersInList - being a global variable - survives and saves the heritage of "count"
// for further functions
noOfPeersInList = count;
}
I havent even had time (work break yet) to go through the initial post from today!
I will def let you know once I get a chance to play with it if I have any questions..
I'm sure (either way) I'll have some questions on my old approach vs your new one (just for educational purpose...so I can learn/put things into perspective/compare..etc)
Thanks, I know but thought the use of std::vector is harder to explain than a 2D array ...
std::vector is available for ESP32, I used it (and also std::list) to store the data of WiFi clients so that a sketch using AsyncTCP could send data to different clients and was able to reply to each separate client ...
vector and list require a deeper insight into C++ (e.g. the use of iterators).
But I agree, once you know how to use (and your controller supports) them it makes handling lists much easier ...