From a66b544d18daaa99508e69a5ff199a99b71759ae Mon Sep 17 00:00:00 2001 From: Arvind Ravulavaru Date: Wed, 27 Sep 2017 14:16:17 +0530 Subject: [PATCH] Added ESPNow Multi-Slave example (#669) * Added ESPNow basic example * fixed meta doc for slave * refactored folder structure * bug fixes * Added Single Master Multi-Slave * updated meta docs --- .../examples/ESPNow/Basic/Master/Master.ino | 13 +- .../ESPNow/Multi-Slave/Master/Master.ino | 245 ++++++++++++++++++ .../ESPNow/Multi-Slave/Slave/Slave.ino | 93 +++++++ 3 files changed, 341 insertions(+), 10 deletions(-) create mode 100644 libraries/ESP32/examples/ESPNow/Multi-Slave/Master/Master.ino create mode 100644 libraries/ESP32/examples/ESPNow/Multi-Slave/Slave/Slave.ino diff --git a/libraries/ESP32/examples/ESPNow/Basic/Master/Master.ino b/libraries/ESP32/examples/ESPNow/Basic/Master/Master.ino index 01c9362a..26e020f6 100644 --- a/libraries/ESP32/examples/ESPNow/Basic/Master/Master.ino +++ b/libraries/ESP32/examples/ESPNow/Basic/Master/Master.ino @@ -55,7 +55,10 @@ void InitESPNow() { // Scan for slaves in AP mode void ScanForSlave() { int8_t scanResults = WiFi.scanNetworks(); + // reset on each scan bool slaveFound = 0; + memset(&slave, 0, sizeof(slave)); + Serial.println(""); if (scanResults == 0) { Serial.println("No WiFi devices in AP Mode found"); @@ -128,14 +131,6 @@ bool manageSlave() { // Slave already paired. Serial.println("Already Paired"); return true; - } else if (exists == ESP_ERR_ESPNOW_NOT_INIT) { - // How did we get so far!! - Serial.println("ESPNOW Not InitESP_ERR_ESPNOW_NOT_INIT"); - return false; - } else if (exists == ESP_ERR_ESPNOW_ARG) { - // Invalid Argument - Serial.println("Invalid Argument"); - return false; } else { // Slave not paired, attempt pair esp_err_t addStatus = esp_now_add_peer(peer); @@ -191,8 +186,6 @@ void deletePeer() { } } - - uint8_t data = 0; // send data void sendData() { diff --git a/libraries/ESP32/examples/ESPNow/Multi-Slave/Master/Master.ino b/libraries/ESP32/examples/ESPNow/Multi-Slave/Master/Master.ino new file mode 100644 index 00000000..87b8c331 --- /dev/null +++ b/libraries/ESP32/examples/ESPNow/Multi-Slave/Master/Master.ino @@ -0,0 +1,245 @@ +/** + ESPNOW - Basic communication - Master + Date: 26th September 2017 + Author: Arvind Ravulavaru + Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves + Description: This sketch consists of the code for the Master module. + Resources: (A bit outdated) + a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf + b. http://www.esploradores.com/practica-6-conexion-esp-now/ + + << This Device Master >> + + Flow: Master + Step 1 : ESPNow Init on Master and set it in STA mode + Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) + Step 3 : Once found, add Slave as peer + Step 4 : Register for send callback + Step 5 : Start Transmitting data from Master to Slave(s) + + Flow: Slave + Step 1 : ESPNow Init on Slave + Step 2 : Update the SSID of Slave with a prefix of `slave` + Step 3 : Set Slave in AP mode + Step 4 : Register for receive callback and wait for data + Step 5 : Once data arrives, print it in the serial monitor + + Note: Master and Slave have been defined to easily understand the setup. + Based on the ESPNOW API, there is no concept of Master and Slave. + Any devices can act as master or salve. + + + // Sample Serial log with 1 master & 2 slaves + Found 12 devices + 1: Slave:24:0A:C4:81:CF:A4 [24:0A:C4:81:CF:A5] (-44) + 3: Slave:30:AE:A4:02:6D:CC [30:AE:A4:02:6D:CD] (-55) + 2 Slave(s) found, processing.. + Processing: 24:A:C4:81:CF:A5 Status: Already Paired + Processing: 30:AE:A4:2:6D:CD Status: Already Paired + Sending: 9 + Send Status: Success + Last Packet Sent to: 24:0a:c4:81:cf:a5 + Last Packet Send Status: Delivery Success + Send Status: Success + Last Packet Sent to: 30:ae:a4:02:6d:cd + Last Packet Send Status: Delivery Success + +*/ + +#include +#include + +// Global copy of slave +#define NUMSLAVES 20 +esp_now_peer_info_t slaves[NUMSLAVES] = {}; +int SlaveCnt = 0; + +#define CHANNEL 3 +#define PRINTSCANRESULTS 0 + +// Init ESP Now with fallback +void InitESPNow() { + 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%c", &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++) { + const esp_now_peer_info_t *peer = &slaves[i]; + const uint8_t *peer_addr = slaves[i].peer_addr; + 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(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(peer); + 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"); + } +} + + +uint8_t data = 0; +// send data +void sendData() { + data++; + for (int i = 0; i < SlaveCnt; i++) { + const uint8_t *peer_addr = slaves[i].peer_addr; + if (i == 0) { // print only for first slave + Serial.print("Sending: "); + Serial.println(data); + } + esp_err_t result = esp_now_send(peer_addr, &data, sizeof(data)); + 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"); +} + +void setup() { + Serial.begin(115200); + //Set device in STA mode to begin with + WiFi.mode(WIFI_STA); + 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); +} + +void loop() { + // 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 + // Send data to device + sendData(); + } else { + // No slave found to process + } + + // wait for 3seconds to run the logic again + delay(1000); +} \ No newline at end of file diff --git a/libraries/ESP32/examples/ESPNow/Multi-Slave/Slave/Slave.ino b/libraries/ESP32/examples/ESPNow/Multi-Slave/Slave/Slave.ino new file mode 100644 index 00000000..8837d9c1 --- /dev/null +++ b/libraries/ESP32/examples/ESPNow/Multi-Slave/Slave/Slave.ino @@ -0,0 +1,93 @@ +/** + ESPNOW - Basic communication - Slave + Date: 26th September 2017 + Author: Arvind Ravulavaru + Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves + Description: This sketch consists of the code for the Slave module. + Resources: (A bit outdated) + a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf + b. http://www.esploradores.com/practica-6-conexion-esp-now/ + + << This Device Slave >> + + Flow: Master + Step 1 : ESPNow Init on Master and set it in STA mode + Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) + Step 3 : Once found, add Slave as peer + Step 4 : Register for send callback + Step 5 : Start Transmitting data from Master to Slave(s) + + Flow: Slave + Step 1 : ESPNow Init on Slave + Step 2 : Update the SSID of Slave with a prefix of `slave` + Step 3 : Set Slave in AP mode + Step 4 : Register for receive callback and wait for data + Step 5 : Once data arrives, print it in the serial monitor + + Note: Master and Slave have been defined to easily understand the setup. + Based on the ESPNOW API, there is no concept of Master and Slave. + Any devices can act as master or salve. +*/ + +#include +#include + +#define CHANNEL 1 + +// Init ESP Now with fallback +void InitESPNow() { + 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(); + } +} + +// config AP SSID +void configDeviceAP() { + String Prefix = "Slave:"; + String Mac = WiFi.macAddress(); + String SSID = Prefix + Mac; + String Password = "123456789"; + bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL, 0); + if (!result) { + Serial.println("AP Config failed."); + } else { + Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID)); + } +} + +void setup() { + Serial.begin(115200); + Serial.println("ESPNow/Basic/Slave Example"); + //Set device in AP mode to begin with + WiFi.mode(WIFI_AP); + // configure device AP mode + configDeviceAP(); + // This is the mac address of the Slave in AP Mode + Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); + // Init ESPNow with a fallback logic + InitESPNow(); + // Once ESPNow is successfully Init, we will register for recv CB to + // get recv packer info. + esp_now_register_recv_cb(OnDataRecv); +} + +// callback when data is recv from Master +void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) { + 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 Recv from: "); Serial.println(macStr); + Serial.print("Last Packet Recv Data: "); Serial.println(*data); + Serial.println(""); +} + +void loop() { + // Chill +} \ No newline at end of file