#include <esp_now.h>
#include <WiFi.h>
static const char *ssid = "WIFI_SSID";
static const char *password = "WIFI_PASSWORD";
// Global copy of slave
#define NUMSLAVES 20
esp_now_peer_info_t slaves[NUMSLAVES] = {};
int SlaveCnt = 0;
unsigned long timer = 0;
#define CHANNEL 1
#define PRINTSCANRESULTS 0

const int intArraySize = 30;
const int charArraySize = 40;

//this is the struct the host sends the slave(s)
typedef struct message_to_send_struct_int_array {
char structType;
int intArray[intArraySize];
} message_to_send_struct_int_array;
//this is the struct the host sends the slave(s)
typedef struct message_to_send_struct_char_array {
char structType;
char charArray[charArraySize];
} message_to_send_struct_char_array;
//this is the struct the slaves sends the host
typedef struct message_to_recieve_struct {
bool echo;
} message_to_recieve_struct;
// Variable to store if sending data was successful
String success;
// Create a struct_message to hold data to send via espNow.
message_to_send_struct_int_array message_to_send_int_array;
message_to_send_struct_char_array message_to_send_char_array;
// Create a message_to_recieve_struct called message_to_recieve to recieve player data
message_to_recieve_struct message_to_recieve;

esp_now_peer_info_t peerInfo;

void fillLargeArrayInt() {
for (int arrayPos = 0; arrayPos < intArraySize; arrayPos++) {
message_to_send_int_array.intArray[arrayPos] = random(0, 500);
Serial.println("Filling: " + String(arrayPos) + ": " + String(message_to_send_int_array.intArray[arrayPos]));
}
}
char alphaNumericGen() {
byte randomValue = random(0, 37);
if (randomValue > 26)
return (randomValue - 26) + '0';
else
return randomValue + 'a';
}
void fillLargeArrayChar() {
for (int arrayPos = 0; arrayPos < charArraySize; arrayPos++) {
message_to_send_char_array.charArray[arrayPos] = alphaNumericGen();
Serial.println("Filling: " + String(arrayPos) + ": " + String(message_to_send_char_array.charArray[arrayPos]));
}
}

// Init ESP Now with fallback
void InitESPNow() {
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
} else {
Serial.println("ESPNow Init Failed");
// Retry InitESPNow, add a counte and then restart?
// InitESPNow();
// or Simply Restart
ESP.restart();
}
}

// Scan for slaves in AP mode
void ScanForSlave() {
int8_t scanResults = WiFi.scanNetworks();
//reset slaves
memset(slaves, 0, sizeof(slaves));
SlaveCnt = 0;
Serial.println("");
if (scanResults == 0) {
Serial.println("No WiFi devices in AP Mode found");
} else {
Serial.print("Found ");
Serial.print(scanResults);
Serial.println(" devices ");
for (int i = 0; i < scanResults; ++i) {
// Print SSID and RSSI for each device found
String SSID = WiFi.SSID(i);
int32_t RSSI = WiFi.RSSI(i);
String BSSIDstr = WiFi.BSSIDstr(i);

if (PRINTSCANRESULTS) {
Serial.print(i + 1);
Serial.print(": ");
Serial.print(SSID);
Serial.print(" [");
Serial.print(BSSIDstr);
Serial.print("]");
Serial.print(" (");
Serial.print(RSSI);
Serial.print(")");
Serial.println("");
}
delay(10);
// Check if the current device starts with `Slave`
if (SSID.indexOf("Slave") == 0) {
// SSID of interest
Serial.print(i + 1);
Serial.print(": ");
Serial.print(SSID);
Serial.print(" [");
Serial.print(BSSIDstr);
Serial.print("]");
Serial.print(" (");
Serial.print(RSSI);
Serial.print(")");
Serial.println("");
// Get BSSID => Mac Address of the Slave
int mac[6];

if (6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5])) {
for (int ii = 0; ii < 6; ++ii) {
slaves[SlaveCnt].peer_addr[ii] = (uint8_t)mac[ii];
}
}
slaves[SlaveCnt].channel = CHANNEL;  // pick a channel
slaves[SlaveCnt].encrypt = 0;        // no encryption
SlaveCnt++;
}
}
}

if (SlaveCnt > 0) {
Serial.print(SlaveCnt);
Serial.println(" Slave(s) found, processing..");
} else {
Serial.println("No Slave Found, trying again.");
}

// clean up ram
WiFi.scanDelete();
}

// Check if the slave is already paired with the master.
// If not, pair the slave with master
void manageSlave() {
if (SlaveCnt > 0) {
for (int i = 0; i < SlaveCnt; i++) {
Serial.print("Processing: ");
for (int ii = 0; ii < 6; ++ii) {
Serial.print((uint8_t)slaves[i].peer_addr[ii], HEX);
if (ii != 5) Serial.print(":");
}
Serial.print(" Status: ");
// check if the peer exists
bool exists = esp_now_is_peer_exist(slaves[i].peer_addr);
if (exists) {
// Slave already paired.
Serial.println("Already Paired");
} else {
// Slave not paired, attempt pair
esp_err_t addStatus = esp_now_add_peer(&slaves[i]);
if (addStatus == ESP_OK) {
// Pair success
Serial.println("Pair success");
} else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println("ESPNOW Not Init");
} else if (addStatus == ESP_ERR_ESPNOW_ARG) {
Serial.println("Add Peer - Invalid Argument");
} else if (addStatus == ESP_ERR_ESPNOW_FULL) {
Serial.println("Peer list full");
} else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println("Out of memory");
} else if (addStatus == ESP_ERR_ESPNOW_EXIST) {
Serial.println("Peer Exists");
} else {
Serial.println("Not sure what happened");
}
delay(100);
}
}
} else {
// No slave found to process
Serial.println("No Slave found to process");
}
}
// send data
void sendIntArrayData() {
for (int i = 0; i < SlaveCnt; i++) {
const uint8_t *peer_addr = slaves[i].peer_addr;
message_to_send_int_array.structType = 'i';  //This means the struct is the integer array
timer = micros();
esp_err_t result = esp_now_send(peer_addr, (uint8_t *)&message_to_send_int_array, sizeof(message_to_send_int_array));  //send struct here
Serial.print("Send Status: ");
if (result == ESP_OK) {
Serial.println("Success");
} else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println("ESPNOW not Init.");
} else if (result == ESP_ERR_ESPNOW_ARG) {
Serial.println("Invalid Argument");
} else if (result == ESP_ERR_ESPNOW_INTERNAL) {
Serial.println("Internal Error");
} else if (result == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println("ESP_ERR_ESPNOW_NO_MEM");
} else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
Serial.println("Peer not found.");
} else {
Serial.println("Not sure what happened");
}
delay(100);
}
}
// send data
void sendCharArrayData() {
for (int i = 0; i < SlaveCnt; i++) {
const uint8_t *peer_addr = slaves[i].peer_addr;
message_to_send_char_array.structType = 'c';  //This means the struct is the char array
timer = micros();
esp_err_t result = esp_now_send(peer_addr, (uint8_t *)&message_to_send_char_array, sizeof(message_to_send_char_array));  //send struct here
Serial.print("Send Status: ");
if (result == ESP_OK) {
Serial.println("Success");
} else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println("ESPNOW not Init.");
} else if (result == ESP_ERR_ESPNOW_ARG) {
Serial.println("Invalid Argument");
} else if (result == ESP_ERR_ESPNOW_INTERNAL) {
Serial.println("Internal Error");
} else if (result == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println("ESP_ERR_ESPNOW_NO_MEM");
} else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
Serial.println("Peer not found.");
} else {
Serial.println("Not sure what happened");
}
delay(100);
}
}
// callback when data is sent from Master to Slave
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
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]);
// Serial.print("Last Packet Sent to: ");
// Serial.println(macStr);
// Serial.print("Last Packet Send Status: ");
// Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (status == ESP_NOW_SEND_SUCCESS) {
// Serial.println("Delivery Success" );
} else {
Serial.println("Delivery Fail");
}
}

// callback when data is recv from the slave
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *incoming_data, int len) {
char macStr[18];
memcpy(&message_to_recieve, incoming_data, sizeof(message_to_recieve));
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]);

Serial.print("Last Packet Recv from: ");
Serial.println(macStr);
Serial.println("Last Packet Recv Data: ");
if (message_to_recieve.echo == true) {
long ping = micros() - timer;
Serial.println("Ping time is: " + String(ping));
} else {
Serial.println("echo false");
}
}

void setup() {
pinMode(23, INPUT);
pinMode(22, INPUT);
Serial.println();
Serial.print("ESP Board MAC Address:  ");
Serial.println(WiFi.macAddress());
//initalise the client message struct content of send to be 0

Serial.begin(115200);
//Set device in STA mode to begin with
WiFi.mode(WIFI_STA);  //This mode allows the wifi to not 'turn off', thus it will send to the database but not turn off after
//thus the 'senders' from espnow can still send. This solves significant issues!
Serial.println("ESPNow/Multi-Slave/Master Example");
// This is the mac address of the Master in Station Mode
Serial.print("STA MAC: ");
Serial.println(WiFi.macAddress());
// Init ESPNow with a fallback logic
InitESPNow();
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);

// get recv packer info.
esp_now_register_recv_cb(OnDataRecv);

delay(100);
// In the loop we scan for slave
ScanForSlave();
// If Slave is found, it would be populate in `slave` variable
// We will check if `slave` is defined and then we proceed further
if (SlaveCnt > 0) {  // check if slave channel is defined
// `slave` is defined
// Add slave as peer if it has not been added already
manageSlave();
// pair success or already paired

} else {
// No slave found to process
}
fillLargeArrayChar();
fillLargeArrayInt();
}
long startTime = 0;
void loop() {
if (millis() - startTime >= 3000) {
startTime = millis();
// Send data to device
sendIntArrayData();
sendCharArrayData();
}
delay(1);
}