Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esp now and Wifi client both are not working simultaneously #878

Closed
James-sjec opened this issue Nov 26, 2017 · 51 comments
Closed

esp now and Wifi client both are not working simultaneously #878

James-sjec opened this issue Nov 26, 2017 · 51 comments
Labels
Status: Stale Issue is stale stage (outdated/stuck)

Comments

@James-sjec
Copy link

James-sjec commented Nov 26, 2017

Hardware:

Board: ?ESP32 Dev Module?
Core Installation/update date: ?11/jul/2017?
IDE name: ?Arduino IDE? ?Platform.io? ?IDF component?
Flash Frequency: ?40Mhz?
Upload Speed: ?115200?

Description:

I am using mqtt protocol and sending data to AWS server.
and simultaneously receiving data from other esp32 and sending that data to the server.

The problem is before Wifi client connects to AWS , esp now is working(I am receiving data from other esp32) , but after WiFi client connects to AWS , esp now stops working (No data is received) . And when Wifi client disconnects from AWS , esp now is working.

I loaded esp_now Slave code in the esp32 which to connects AWS and the devices is configured as AP_STA mode. Esp_now Mater code in other esp32 which send its data.

My doubt : Is AP and STA cannot work simultaneously. If it is not possible tell me is there any way to receive data from other esp32 through AP and send data to the server

@me-no-dev
Copy link
Member

This sounds really strange. Generally ESP-NOW has nothing to do with TCP/UDP and runs underneath that stack. Can you please post a minimal sketch that shows this issue so we can run it internally and try to figure out what might be going wrong

@auladinamica
Copy link

Can you publish a code that work like James-sjec describe ?

i have a esp32(server) that is conected to the wifi , also have a esp_now avaiable and five sensors(esp32 now master) publish data to the server and the server send this data to the web,,, can you publish a code to do this scenario ?

thanks

@beegee-tokyo
Copy link
Contributor

beegee-tokyo commented Dec 7, 2017

On ESP8266 you can either use ESPNow or connect the module to an AP. Both together doesn't work. I just tested it (after reading about it). I can send and receive data over ESPNow until I connect the WiFi to an AP. After successful connection to AP, ESPNow send fails and I receive no more data.

Reference

My guess is that on the ESP32 it is the same.

@me-no-dev
Copy link
Member

@beegee-tokyo I raised this question to the team and they confirmed that this is not the expected behaviour on ESP32 and ESP-NOW should work together with WiFi

@beegee-tokyo
Copy link
Contributor

I build up a small test configuration with an ESP8266 sending data over ESPNow and an ESP32 receiving data over ESPNow. Then the ESP32 send the received data over MQTT to an MQTT broker and it works.

But there is one condition:

The Wifi you connect to must be on the same Wifi channel that is used for ESPNow.
In my case I tested with ESPNow sending/receiving on channel 1 and the ESP32 connected to a WiFi which is using channel 1 as well.
If I connect to another WiFi that uses e.g. channel 13, the ESP32 does not receive any ESPNow data anymore.
I tried to change the ESPNow channel to 13, but I didn't get the connection between the ESP8266 and ESP32 to work (with or without a WiFi connection). That might be a limitation on the ESP8266 (???) but I have only one ESP32 to test.
Here is the code that worked for me:
ESP8266 code adapted from ESP32 ESPNow example:

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>
extern "C" {
  #include <espnow.h>
  #include <user_interface.h>
}

/**
   ESPNOW - Basic communication - Master
   Date: 26th September 2017
   Author: Arvind Ravulavaru <https://github.com/arvindr21>
*/

typedef struct esp_now_peer_info {
    u8 peer_addr[6];    /**< ESPNOW peer MAC address that is also the MAC address of station or softap */
    uint8_t channel;                        /**< Wi-Fi channel that peer uses to send/receive ESPNOW data. If the value is 0,
                                                 use the current channel which station or softap is on. Otherwise, it must be
                                                 set as the channel that station or softap is on. */
} esp_now_peer_info_t;

// Global copy of slave
#define NUMSLAVES 20
esp_now_peer_info_t slaves[NUMSLAVES] = {};
int SlaveCnt = 0;

#define CHANNEL 1

void printMacAddress(uint8_t* macaddr) {
  Serial.print("{");
  for (int i = 0; i < 6; i++) {
    Serial.print("0x");
    Serial.print(macaddr[i], HEX);
    if (i < 5) Serial.print(',');
  }
  Serial.println("};");
}

// Init ESP Now with fallback
void InitESPNow() {
  if (esp_now_init() == 0) {
    Serial.println("ESPNow Init Success");
  }
  else {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
}

// 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);
      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
        char macPart[4];
        macPart[0] = '0';
        macPart[1] = 'x';

        macPart[2] = (char)BSSIDstr[0];
        macPart[3] = (char)BSSIDstr[1];
        slaves[SlaveCnt].peer_addr[0] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[3];
        macPart[3] = (char)BSSIDstr[4];
        slaves[SlaveCnt].peer_addr[1] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[6];
        macPart[3] = (char)BSSIDstr[7];
        slaves[SlaveCnt].peer_addr[2] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[9];
        macPart[3] = (char)BSSIDstr[10];
        slaves[SlaveCnt].peer_addr[3] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[12];
        macPart[3] = (char)BSSIDstr[13];
        slaves[SlaveCnt].peer_addr[4] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[15];
        macPart[3] = (char)BSSIDstr[16];
        slaves[SlaveCnt].peer_addr[5] = strtol(macPart,0,16);

        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];
      u8 *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((u8*)peer_addr);
      if (exists) {
        // Slave already paired.
        Serial.println("Already Paired");
      } else {
        // Slave not paired, attempt pair
        int addStatus = esp_now_add_peer((u8*)peer_addr, ESP_NOW_ROLE_CONTROLLER, CHANNEL, NULL, 0);
        if (addStatus == 0) {
          // Pair success
          Serial.println("Pair success");
        } else {
          Serial.println("Pair failed");
        }
        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++) {
    u8 *peer_addr = slaves[i].peer_addr;
    if (i == 0) { // print only for first slave
      Serial.print("Sending: ");
      Serial.println(data);
    }
    int result = esp_now_send(peer_addr, &data, sizeof(data));
    Serial.print("Send Status: ");
    if (result ==0) {
      Serial.println("Success " + String(result));
    } else {
      Serial.println("Failed " + String(result));
    }
    delay(100);
  }
}

// callback when data is sent from Master to Slave
esp_now_send_cb_t OnDataSent(const uint8_t *mac_addr, u8 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 == 0 ? "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);
  esp_now_register_send_cb([](uint8_t* macaddr, uint8_t status) {
    printMacAddress(macaddr);
    static uint32_t ok = 0;
    static uint32_t fail = 0;
    if (status == 0) {
      Serial.println("ESPNOW: SEND_OK");
      ok++;
    }
    else {
      Serial.println("ESPNOW: SEND_FAILED");
      fail++;
    }
    Serial.printf("[SUCCESS] = %lu/%lu \r\n", ok, ok+fail);
  });
}

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

ESP32 code adapted from ESP32 ESPNow example:

/**
   ESPNOW - Basic communication - Slave
   Date: 26th September 2017
   Author: Arvind Ravulavaru <https://github.com/arvindr21>
*/

#include <esp_now.h>
#include <WiFi.h>
#include <MQTTClient.h>

#define CHANNEL 1

/** MQTT client class to access mqtt broker */
MQTTClient mqttClient(2560);
/** MQTT broker URL */
static const char * mqttBroker = "xx.xx.xx.xx";
/** MQTT connection id */
static const char * mqttID = "ESP32";
/** MQTT user name */
static const char * mqttUser = "esp32";
/** MQTT password */
static const char * mqttPwd = "PASSWORD";
/** WiFi client class to receive messages from mqtt broker */
WiFiClient mqttReceiver;

void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len);

// Init ESP Now with fallback
void InitESPNow() {
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  else {
    Serial.println("ESPNow Init Failed");
    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_STA);
  WiFi.begin("MYWIFI", "MYWIFIPW");
  // configure device AP mode
  configDeviceAP();
  // This is the mac address of the Slave in AP Mode
  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());

  // Start connection to MQTT broker
  // Connect to MQTT broker
  mqttClient.begin(mqttBroker, mqttReceiver);

  Serial.println("Connecting to MQTT broker");

  int connectTimeout = 0;

  while (!mqttClient.connect(mqttID, mqttUser, mqttPwd)) {
    delay(100);
    connectTimeout++;
    if (connectTimeout > 10) { // Wait for 1 seconds to connect
      Serial.println("Can't connect to MQTT broker");
      ESP.restart();
    }
  }
  Serial.println("Connected to MQTT");

  // 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("");
  mqttClient.publish("/debug","[INFO] Last Packet Recv from: " + tftMsg);
  mqttClient.publish("/debug","[INFO] Last Packet Recv Data: " + tftMsg);
  recvMsgNum++;
}

void loop() {
  // Chill
}

Output on Serial from ESP32:

ESPNow/Basic/Slave Example
AP Config Success. Broadcasting with AP: Slave:24:0A:C4:81:CE:9C
AP MAC: 24:0A:C4:81:CE:9D
Connecting to MQTT broker
[E][WiFiClient.cpp:97] connect(): lwip_connect_r: 113
Connected to MQTT
ESPNow Init Success
Last Packet Recv from: 5c:cf:7f:01:5a:5d
Last Packet Recv Data: 91

Last Packet Recv from: 5c:cf:7f:01:5a:5d
Last Packet Recv Data: 92

Last Packet Recv from: 5c:cf:7f:01:5a:5d
Last Packet Recv Data: 93

Last Packet Recv from: 5c:cf:7f:01:5a:5d
Last Packet Recv Data: 94

Output on Serial from ESP8266:

ESPNow/Multi-Slave/Master Example
STA MAC: 5C:CF:7F:01:5A:5D
ESPNow Init Success

Found 6 devices 
2: Slave:24:0A:C4:81:CE:9C [24:0A:C4:81:CE:9D] (-55)
1 Slave(s) found, processing..
Processing: 24:A:C4:81:CE:9D Status: Pair success
Sending: 1
Send Status: Success 0
{0x24,0xA,0xC4,0x81,0xCE,0x9D};
ESPNOW: SEND_OK
[SUCCESS] = 1/1 

Output from my MQTT broker:

[INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d
[INFO] Last Packet Recv Data: 42
[INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d
[INFO] Last Packet Recv Data: 43
[INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d
[INFO] Last Packet Recv Data: 44

@auladinamica
Copy link

Hi guys :

I have many problems with ESP_NOW sometimes works and sometimes not..
here i describe my situation .

I have an esp sending data via esp_now, i have a server that receive this data, but sometimes the server not receive the data, i change only one function and the program fail..

this is a working code !!!


#include <esp_now.h>
#include <WiFi.h>

struct attribute((packed)) SENSOR_DATA_HIGROW {

int     tipo_sensor;
int     id_sensor;
float   temp_aire;
float   hum_aire;
int     hum_tierra;

} ;

#define max_Cant_sensores 10
int hume[max_Cant_sensores];
SENSOR_DATA_HIGROW sensorData_Higrow;
#define CHANNEL 1

void InitESPNow() {
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
else {
Serial.println("ESPNow Init Failed");
ESP.restart();
}
}

// config AP SSID
void configDeviceAP() {
String Prefix = "OMMA_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");
WiFi.mode(WIFI_AP_STA);
WiFi.begin("auladinamica", "ABABABABa1");
/*
if( !checkConnection()){

ESP.restart();

}
*/
configDeviceAP();

Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
InitESPNow();
esp_now_register_recv_cb(OnDataRecv);
}

boolean checkConnection() {
int count = 0;
Serial.print("Waiting for Wi-Fi connection");
while ( count < 30 ) {
if (WiFi.status() == WL_CONNECTED) {
Serial.println("Connected!");
return (true);
}
delay(500);
Serial.print(".");
count++;
}
Serial.println("Timed out.");
return false;
}

void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {

char macStr[18];
String str = (char*)data;
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.print("largo data : "); Serial.println(String(data_len));

memcpy(&sensorData_Higrow, data, sizeof(sensorData_Higrow));

if (sensorData_Higrow.tipo_sensor==1){  
  Serial.println("-----------------------------------------------------------------------");
  Serial.print("Id    Sensor     :" ); Serial.println(String(sensorData_Higrow.id_sensor));
  Serial.print("Tipo Sensor      :" ); Serial.println(String(sensorData_Higrow.tipo_sensor));
  Serial.print("Temp Aire        :" ); Serial.println(String(sensorData_Higrow.temp_aire));
  Serial.print("Hume Aire        :" ); Serial.println(String(sensorData_Higrow.hum_aire));
  Serial.print("Hume Tierra      :" ); Serial.println(String(sensorData_Higrow.hum_tierra));
  Serial.println("-----------------------------------------------------------------------");
}

hume[sensorData_Higrow.id_sensor]=sensorData_Higrow.hum_tierra;
}

void loop() {

}

But if i use the checkConnection() function the esp not receive data !!!!!

Uncoment this code in the setup function and the system fail

/*
if( !checkConnection()){

ESP.restart();

}
*/

Can somebody explainme how to solve this issue ?

Thanks

@f2knpw
Copy link

f2knpw commented Mar 25, 2018

I have exactly the same behavior 👍

either I can connect to wifi router and not get the data from ESP-NOW
or if I don't wait for wifi connection then I may receive data fromESP-NOW

I have even tried to connect to wifi only when received data but it never works... Connection always failed

// 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("");
 // mqttClient.publish("/debug","[INFO] Last Packet Recv from: " + tftMsg);
 // mqttClient.publish("/debug","[INFO] Last Packet Recv Data: " + tftMsg);
 // recvMsgNum++;

  WiFi.disconnect();
   WiFi.mode(WIFI_STA);
delay(1000);
  WiFi.begin("MySSID", "MyPassWord");
   while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
}

@beegee-tokyo
Copy link
Contributor

beegee-tokyo commented Mar 25, 2018

Is your WiFi AP on the same channel as ESPNow? Check ESPNow and connection to WiFi AP. It seems ESPNow is only working when using the same WiFi channel.

@f2knpw
Copy link

f2knpw commented Mar 25, 2018

Yes I tried with channel 6 which is my Wifi's channel. But does not work.

I tried as well to connect to my wifi router on the "master side"set in STA mode. As soon as it connected messages from ESPnow do not get the slave...
That's really a pity as I need this to connect the slave as a gateway to internet.

For the moment I will save the message with the "Preference Libary" and restart the ESP to connect to wifi. -> (Ugly solution)
(The Preferences library is a wrapper around the Non-volatile storage on ESP32 processor.)

@f2knpw
Copy link

f2knpw commented Mar 25, 2018

What I find surprising is that even if I try to Wifi.disconnect() it does not work either...
I have tried directly from the API, but same result...
...

esp_now_deinit();
 esp_wifi_disconnect();
esp_wifi_stop();
esp_wifi_restore();
   WiFi.mode(WIFI_STA);
delay(1000);
  WiFi.begin("mySSID", "myPassword");
   while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(WiFi.status());
    }

@beegee-tokyo
Copy link
Contributor

Try to set everything to channel 0. That was the only way I got it to work.

@f2knpw
Copy link

f2knpw commented Mar 26, 2018

When you say "everything" is it :
Master channel
Slave channel
And wifi router channel ?

@beegee-tokyo
Copy link
Contributor

Yes,that was the only way I got it working.

@f2knpw
Copy link

f2knpw commented Mar 26, 2018

Well, I have tried to set my wifi box on channel 0... It doesn't exist and starts at 1.
Put all to 1
but still does not work :-(

@auladinamica
Copy link

auladinamica commented Mar 27, 2018 via email

@f2knpw
Copy link

f2knpw commented Mar 27, 2018

yes !

It's basically the same as above:

/**
   ESPNOW - Basic communication - Master
   Date: 26th September 2017
   Author: Arvind Ravulavaru <https://github.com/arvindr21>
   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 <esp_now.h>
#include <WiFi.h>

// Global copy of slave
#define NUMSLAVES 20
esp_now_peer_info_t slaves[NUMSLAVES] = {};
int SlaveCnt = 0;

#define CHANNEL 0
#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);
}

and now slave:

/**
   ESPNOW - Basic communication - Slave
   Date: 26th September 2017
   Author: Arvind Ravulavaru <https://github.com/arvindr21>
*/

#include <esp_now.h>
#include <WiFi.h>
//#include <MQTTClient.h>
#include <esp_wifi.h>
#define CHANNEL 0

// MQTT client class to access mqtt broker
/*MQTTClient mqttClient(2560);
// MQTT broker URL 
static const char * mqttBroker = "xx.xx.xx.xx";
// MQTT connection id 
static const char * mqttID = "ESP32";
// MQTT user name
static const char * mqttUser = "esp32";
//MQTT password 
static const char * mqttPwd = "PASSWORD";
*/
/** WiFi client class to receive messages from mqtt broker */
//WiFiClient mqttReceiver;

void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len);

// Init ESP Now with fallback
void InitESPNow() {
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  else {
    Serial.println("ESPNow Init Failed");
    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 + Wifi Example");

  //Set device in AP + STA mode to begin with
  WiFi.mode(WIFI_AP_STA);
 
  // configure device AP mode
  configDeviceAP();
  // This is the mac address of the Slave in AP Mode
  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());

  // Start connection to MQTT broker
  // Connect to MQTT broker
 /* mqttClient.begin(mqttBroker, mqttReceiver);

  Serial.println("Connecting to MQTT broker");

  int connectTimeout = 0;

  while (!mqttClient.connect(mqttID, mqttUser, mqttPwd)) {
    delay(100);
    connectTimeout++;
    if (connectTimeout > 10) { // Wait for 1 seconds to connect
      Serial.println("Can't connect to MQTT broker");
      ESP.restart();
    }
  }
  Serial.println("Connected to MQTT");*/

  // 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("");
 // mqttClient.publish("/debug","[INFO] Last Packet Recv from: " + tftMsg);
 // mqttClient.publish("/debug","[INFO] Last Packet Recv Data: " + tftMsg);
 // recvMsgNum++;
WiFi.disconnect();
   WiFi.mode(WIFI_STA);
delay(1000);
  WiFi.begin("mySSID", "myPassword");
   while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(WiFi.status());
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
}

void loop() {
  // Chill
}

JP

@f2knpw
Copy link

f2knpw commented Mar 27, 2018

And here is a shorter version based on a broadcast instead of discovering MAC of the AP

Master:


#include <esp_now.h>
#include <WiFi.h>


#define CHANNEL 0



//Mac Address for all slaves (broadcast)

uint8_t macSlaves[][6] = {
  //only for two
  // {0x24, 0x0A, 0xC4, 0x0E, 0x3F, 0xD1}, {0x24, 0x0A, 0xC4, 0x0E, 0x4E, 0xC3}
  //for all: broadcast {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
  {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
};

void setup() {
  Serial.begin(115200);

 
  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();

  //copute number of slaves to address data
  int slavesCount = sizeof(macSlaves)/6/sizeof(uint8_t);

  for(int i=0; i<slavesCount; i++){
    //create  var to keep track of slave info
    esp_now_peer_info_t slave;
    slave.channel = CHANNEL;
    slave.encrypt = 0;
    memcpy(slave.peer_addr, macSlaves[i], sizeof(macSlaves[i]));
    esp_now_add_peer(&slave);
  }
  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  


  //send data
  send();
}

// 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();
  }
}

uint8_t data = 0;
// send data
void send(){
  data++;
  //broadcast to all slaves
  uint8_t broadcast[] = {0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF};
  esp_err_t result = esp_now_send(broadcast, &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 loop() {

  if (millis()> 10000) ESP.restart();
}

And slave:


#include <esp_now.h>
#include <WiFi.h>


void setup() {
  Serial.begin(115200);
  Serial.println("ESPNow/Basic/Slave Example");
  //Set device in STATION mode to begin with  
  WiFi.mode(WIFI_STA);
  Serial.print("Mac Address in Station: "); 
  Serial.println(WiFi.macAddress());

  InitESPNow();
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info.
  esp_now_register_recv_cb(OnDataRecv);
}

// 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();
  }
}

// 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("");
 

   WiFi.mode(WIFI_STA);
   WiFi.disconnect(1);
     WiFi.begin("mySSID", "myPassword");
   while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(WiFi.status());
    }
}

void loop() {
  // Chill
}



@f2knpw
Copy link

f2knpw commented Mar 27, 2018

both codes will work if you comment these lines:

 WiFi.mode(WIFI_STA);
   WiFi.disconnect(1);
     WiFi.begin("mySSID", "myPassword");
   while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(WiFi.status());
    }

and will block if you un comment...

JP

@AndreVanKammen
Copy link

AndreVanKammen commented Apr 22, 2018

I'm also having this same problem. I wanted to create an esp-now relay because i read it should be possible to do WiFi and esp-now simultaneously on a ESP32.

I have a working sketch but as soon as i do a WiFi begin the party is over and i won't receive esp-now packets anymore.

Even tried to call esp_now_init and esp_now_register_recv_cb after begin and even for a second time before and after but all the same behavior. As soon as i try WiFi no esp-now anymore.

I was switching to esp-now because the wifi connect on esp32 is so slow (2.5 secs vs <1sec on esp8266). On my esp-32 dev board the connection takes even longer then that.

[edit]
I made a mistake in the channel config. I have multiple WiFi. And i thought they where on channel 6 but one was not and that was the on i was connecting with. It works fine noiw
[/edit]

@beegee-tokyo
Copy link
Contributor

@AndreVanKammen check out the Wiki. The only way I got ESPNow & WiFiClient work together was to put all on Wifi channel 0. ESPNow seems to work only on channel 0 and if WiFi connection changes the channel it stops working.

@AndreVanKammen
Copy link

@beegee-tokyo

Thanks for the fast response. I had everything set to channel 6 but the accespoint i was connecting with was not on 6. So that was my problem, now i'm connecting with the right access point which is on channel 6 everything works.

@beegee-tokyo
Copy link
Contributor

@AndreVanKammen happy I could help. Please return the favor by mentioning my Wiki link where it is appropriate.

If problem is solved please close the issue.

@jacoboth7
Copy link

I have struggled with the same problem. I have solved the issue to communicate with the Slave and consecutively the Wifi-router without having to reset the ESP8266. It is important to put the device in WIFI_AP mode when receiving data from the Master via ESP-Now and in WIFI_STA mode when connecting to the Wifi-router:

void wifiConnect() {
WiFi.mode(WIFI_STA);
Serial.print("Connecting to "); Serial.print(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
Serial.print(".");
}
Serial.print("\nWiFi connected, IP address: "); Serial.println(WiFi.localIP());
delay(200);

WiFi.disconnect();
WiFi.mode(WIFI_AP);
bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL, 0);

}

I've put my code in the Loop function.

void loop() {
if (haveReading) {
haveReading = false;
wifiConnect();
}
}

Here is my complete code for the Slave. I've inherited parts from @beegee-tokyo and Arvind Ravulavaru

#include <espnow.h>
#include <ESP8266WiFi.h>

#define CHANNEL 0
#define ESP_OK 0

const char* ssid = "MyWiFi";
const char* password = "MyWiFiPassword";

String Prefix = "Slave:";
String Mac = WiFi.macAddress();
String SSID = Prefix + Mac;
String Password = "123456789";

int count = 0;
volatile boolean haveReading = false;

void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len);

// Init ESP Now with fallback
void InitESPNow() {
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
}
else {
Serial.println("ESPNow Init Failed");
ESP.restart();
}
}

// config AP SSID
void configDeviceAP() {

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

// callback when data is recv from Master
void OnDataRecv( uint8_t *mac_addr, uint8_t *data, uint8_t data_len) {
char macStr[18];
count++;
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((char *)data);
Serial.print("Count: ");
Serial.println(count);
haveReading = true;
}

void setup() {
Serial.begin(115200);
Serial.println("ESPNow/Basic/Slave Example");

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

void wifiConnect() {
WiFi.mode(WIFI_STA);
Serial.print("Connecting to "); Serial.print(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
Serial.print(".");
}
Serial.print("\nWiFi connected, IP address: "); Serial.println(WiFi.localIP());
delay(200);

WiFi.disconnect();
WiFi.mode(WIFI_AP);
bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL, 0);

}

void loop() {
if (haveReading) {
haveReading = false;
wifiConnect();

}

@dmars1972
Copy link

I'm guessing this isn't solvable without wifi connects and disconnects?

@beegee-tokyo
Copy link
Contributor

@dmars1972
Copy link

@beegee-tokyo thanks - I've read that. Unless I'm missing something, it's just saying that the channels have to be the same in the first paragraph - the problem is, while I know what channel I use at home, I don't know what someone else might use. So I would have to recompile for different routers and hope the router doesn't decide to change channels (mine's on auto, so I assume it might decide to change...).

Further, since the client is the one that decides the channel for espnow when it starts softAP, and at least in my case the client never connects to WiFi, it has no idea what channel the WiFi would use. I mean, isn't that the point? That they don't all need to connect to WiFi?

@dmars1972
Copy link

Ok, given no response, I came up with another workaround that should work in all cases, but it isn't particularly pretty.

I'm doing something like a reverse channel scan.

Slave:
WiFi.mode(WIFI_AP);

char channel = 0;

while(true) {
    ESP_LOGI(tag, "Trying channel %d", channel);

    bool result = WiFi.softAP(ssid.c_str(), NULL, channel, 0);

    if( ! result) {
        ESP_LOGI(tag, "AP Config failed");
        return;
    }

    ESP_LOGI(tag, "MAC Address: %s", WiFi.macAddress().c_str());

    init();

    long timer = millis();

    bool check = false;

    while(timer + 30000 > millis()) {
        ESP_LOGI(tag, "Checking for a response");
        if(messages.size() != 0) {
            check = true;
            break;
        }

        vTaskDelay(100);
    }
    if ( ! check) {
        ESP_LOGI(tag, "No response, trying the next channel");
        deinit();
        channel++;
        if(channel > 13)
            channel = 0;
    } else {
        ESP_LOGI(tag, "Found the right channel: %d", channel);
        break;
    }
}

Then the master connects to WiFi and gets the channel using WiFi.channel(), then just the regular scanNetworks(). Only difference in this is that it will keep trying to connect to the client until it succeeds, since the client is changing it's channel every few seconds until the master makes a connection.

@hcklawrence
Copy link

hcklawrence commented Mar 11, 2019

I have a similar problem on using esp now and wifi connection in the same code.

I am trying to give command using a espnow master, and a espnow slave will connect to a wifi spot if it received a command. I tried to wifi.begin(ssid, pw) and while(1) for wait until connected in the OnDataReceied callback function. The result is that It cannot connect to the wifi spot, and more importantly this problem is somehow causing the slave esp32 board can never receive any packet from the espnow master anymore, no matter it is in broadcast mode or direct message to the espnow slave mac address.

The exact same code was uploaded to another esp32 board, and after serveral trial, it has the same result. I have tried a normal, esp now only (no wifi connection) sample code after the problem had happened, the "broken" board still cannot receive packet from espnow master.

The solution I just came up with is that using esptool to erase the flash, with this command:
esptool.py --chip esp32 --port /dev/tty.SLAB_USBtoUART --baud 115200 --override-vddsdio 1.9V erase_flash
I don't know it this help. See if anyone have any idea on it. I hope to have a master to pass command even in no direct connection to the slave. Please share any idea if you have worked on the similar case. Thank you so much.

@cbpdk
Copy link

cbpdk commented May 7, 2019

@Larryyyyy I had the same problem regarding the sudden stop of connection and did the erase_flash the same way as you have done.
To prevent it happening again, I do the following:


void WiFiReset() {
  WiFi.persistent(false);
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
}

void setup()
{
...
 WiFiReset();

WiFi.mode(WIFI_AP_STA );  //Or other mode
...
}

Until now it has worked with no sudden connection problems when changing modules, mac address ,etc.
I have also not found a way to make espnow and wifi connection work, but still have a few tests to do.

@hcklawrence
Copy link

I have found that the problem is because esp32 will save your pervious wifi connection info, like ssid, pw, and the wifi channel (you could check the saved info with WiFi.printDiag(Serial); when not connecting to a wifi.). And the problem was caused because the erase function do not erase the channel info, so

@Larryyyyy I had the same problem regarding the sudden stop of connection and did the erase_flash the same way as you have done.
To prevent it happening again, I do the following:


void WiFiReset() {
  WiFi.persistent(false);
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
}

void setup()
{
...
 WiFiReset();

WiFi.mode(WIFI_AP_STA );  //Or other mode
...
}

Until now it has worked with no sudden connection problems when changing modules, mac address ,etc.
I have also not found a way to make espnow and wifi connection work, but still have a few tests to do.

I have found that the problem is because esp32 will save your pervious wifi connection info, like ssid, pw, and the wifi channel. (WiFi.printDiag(Serial);)

The problem was caused because the erase function do not erase the channel info. So you will connect to a wrong channel (previous router channel) and unable to communicate using esp now.

and the wifi connected esp32 cannot change its channel, even you changed, its still stay there but visually return you have changed. so you can get the not wifi connected one change to that channel, or connect to the same wifi, then they will in the same channel and able to communicate in espnow

@cbpdk
Copy link

cbpdk commented May 7, 2019

larryyyyy, you wrote:

I have found that the problem is because esp32 will save your previous wifi connection info, like ssid, pw, and the wifi channel. (WiFi.printDiag(Serial);)

The problem was caused because the erase function do not erase the channel info. So you will connect to a wrong channel (previous router channel) and unable to communicate using esp now.

and the wifi connected esp32 cannot change its channel, even you changed, its still stay there but visually return you have changed. so you can get the not wifi connected one change to that channel, or connect to the same wifi, then they will in the same channel and able to communicate in espnow

Regarding the saving of connection info, yes, I also figured that out.
And I assumed that the erase flash function did erase the connection info.
But I do not understand your last paragraph.

Do you mean the connection info must be erased in another way?
Because after an erase, the espnow still does not work when connecting to the wifi network.
Or do you mean that the right channel has to be selected for the first wifi connection, then the same is used for subsequent connections?

I do not have much experience regarding the ESP series, hence all these questions.

Below is the setup of the Wifi connection and espnow I use.

However, the transmitter(STA) always fails with:
Last Packet Send Status: Delivery Fail
when connected to the wifi network.

#define WIFI_CHANNEL 10
uint8_t remoteMac[] = {0x3C, 0x71, 0xBF, 0x03, 0x3D, 0x30};
esp_now_peer_info_t slave;
const esp_now_peer_info_t *peer = &slave;
...
void WiFiReset() {
  WiFi.persistent(false);
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
}

void setup() {
...
  WiFiReset();
  WiFi.mode(WIFI_AP_STA ); 

  Serial.println( WiFi.softAPmacAddress() );

  Serial.println("Connecting to ");
  Serial.println(ssid);

  //connect to your local wi-fi network
  WiFi.begin(ssid, password,WIFI_CHANNEL);

  //check wi-fi is connected to wi-fi network
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
  Serial.print("Channel: "); Serial.println(WiFi.channel());

  if (esp_now_init() == ESP_OK)
  {
    Serial.println("ESPNow Init Success!");
  }
  else
  {
    Serial.println("ESPNow Init Failed....");
  }
  memcpy( &slave.peer_addr, &remoteMac, 6 );
  slave.channel = WIFI_CHANNEL;
  slave.encrypt = 0;        
  slave.ifidx = ESP_IF_WIFI_AP;
  if ( esp_now_add_peer(peer) == ESP_OK)
  {
    Serial.println("Added Peer!");
  }
  ...
}

@hcklawrence
Copy link

larryyyyy, you wrote:

I have found that the problem is because esp32 will save your previous wifi connection info, like ssid, pw, and the wifi channel. (WiFi.printDiag(Serial);)

The problem was caused because the erase function do not erase the channel info. So you will connect to a wrong channel (previous router channel) and unable to communicate using esp now.

and the wifi connected esp32 cannot change its channel, even you changed, its still stay there but visually return you have changed. so you can get the not wifi connected one change to that channel, or connect to the same wifi, then they will in the same channel and able to communicate in espnow

Regarding the saving of connection info, yes, I also figured that out.
And I assumed that the erase flash function did erase the connection info.
But I do not understand your last paragraph.

Do you mean the connection info must be erased in another way?
Because after an erase, the espnow still does not work when connecting to the wifi network.
Or do you mean that the right channel has to be selected for the first wifi connection, then the same is used for subsequent connections?

I do not have much experience regarding the ESP series, hence all these questions.

Below is the setup of the Wifi connection and espnow I use.

However, the transmitter(STA) always fails with:
Last Packet Send Status: Delivery Fail
when connected to the wifi network.

#define WIFI_CHANNEL 10
uint8_t remoteMac[] = {0x3C, 0x71, 0xBF, 0x03, 0x3D, 0x30};
esp_now_peer_info_t slave;
const esp_now_peer_info_t *peer = &slave;
...
void WiFiReset() {
  WiFi.persistent(false);
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
}

void setup() {
...
  WiFiReset();
  WiFi.mode(WIFI_AP_STA ); 

  Serial.println( WiFi.softAPmacAddress() );

  Serial.println("Connecting to ");
  Serial.println(ssid);

  //connect to your local wi-fi network
  WiFi.begin(ssid, password,WIFI_CHANNEL);

  //check wi-fi is connected to wi-fi network
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
  Serial.print("Channel: "); Serial.println(WiFi.channel());

  if (esp_now_init() == ESP_OK)
  {
    Serial.println("ESPNow Init Success!");
  }
  else
  {
    Serial.println("ESPNow Init Failed....");
  }
  memcpy( &slave.peer_addr, &remoteMac, 6 );
  slave.channel = WIFI_CHANNEL;
  slave.encrypt = 0;        
  slave.ifidx = ESP_IF_WIFI_AP;
  if ( esp_now_add_peer(peer) == ESP_OK)
  {
    Serial.println("Added Peer!");
  }
  ...
}

I haven't tested on your code yet. I am trying to make redis work on esp. tell me if you had experience on it.
the command WiFi.disconnect(); only erase ssid and pw, but not the channel.
Yes you need to go with WIFI_AP_STA mode.

The situation is like that:
Master esp (not necessary to connect wifi, usually in channel 1 as the example code is using it) <-> slave esp (necessary to connect wifi for later uses, usually in channel 1 at the beginning)

day1, you used espnow for communication between master and slave. You send a wifi info from master esp to slave esp using espnow, so that the slave esp know the wifi and connect to it. the slave esp connected to the wifi: (SSID_WIFI_A, PW_WIFI_A, Channel_A). After connection, the slave esp found the channel of the wifi, using it, and saved those information.

now, without wifi, you want to use espnow for communication as usual. However , it doesnt work. because the slave's channel is in channel_A, but Master is in channel 1. Until the slave connected to wifi using command WiFi.begin(ssid, password,WIFI_CHANNEL);, it seems good. However, sometimes the wifi is still using its own channel although you set it to a specific one. I have no idea why.

So my solution to this is, keep the slave in the router wifi channel, WiFi.begin(ssid, password), do not set a specific one to the slave. Change the master channel to match it. another way you don't need to change the master's channel is that connect the master to the same wifi, and it will automatically switch to that channel.

if the slave need not to be connecting wifi, this command WiFi.begin(ssid, password,WIFI_CHANNEL); cannot be used. then how to change the channel?

uint8_t primaryChan = WIFI_CHANNEL;
wifi_second_chan_t secondChan = WIFI_SECOND_CHAN_NONE;
esp_wifi_set_channel(primaryChan, secondChan);

hopes that help😋 back to the redis research....

@hcklawrence
Copy link

hcklawrence commented May 7, 2019

larryyyyy, you wrote:

I have found that the problem is because esp32 will save your previous wifi connection info, like ssid, pw, and the wifi channel. (WiFi.printDiag(Serial);)

The problem was caused because the erase function do not erase the channel info. So you will connect to a wrong channel (previous router channel) and unable to communicate using esp now.

and the wifi connected esp32 cannot change its channel, even you changed, its still stay there but visually return you have changed. so you can get the not wifi connected one change to that channel, or connect to the same wifi, then they will in the same channel and able to communicate in espnow

Regarding the saving of connection info, yes, I also figured that out.
And I assumed that the erase flash function did erase the connection info.
But I do not understand your last paragraph.

Do you mean the connection info must be erased in another way?
Because after an erase, the espnow still does not work when connecting to the wifi network.
Or do you mean that the right channel has to be selected for the first wifi connection, then the same is used for subsequent connections?

I do not have much experience regarding the ESP series, hence all these questions.

Below is the setup of the Wifi connection and espnow I use.

However, the transmitter(STA) always fails with:
Last Packet Send Status: Delivery Fail
when connected to the wifi network.

#define WIFI_CHANNEL 10
uint8_t remoteMac[] = {0x3C, 0x71, 0xBF, 0x03, 0x3D, 0x30};
esp_now_peer_info_t slave;
const esp_now_peer_info_t *peer = &slave;
...
void WiFiReset() {
  WiFi.persistent(false);
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
}

void setup() {
...
  WiFiReset();
  WiFi.mode(WIFI_AP_STA ); 

  Serial.println( WiFi.softAPmacAddress() );

  Serial.println("Connecting to ");
  Serial.println(ssid);

  //connect to your local wi-fi network
  WiFi.begin(ssid, password,WIFI_CHANNEL);

  //check wi-fi is connected to wi-fi network
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
  Serial.print("Channel: "); Serial.println(WiFi.channel());

  if (esp_now_init() == ESP_OK)
  {
    Serial.println("ESPNow Init Success!");
  }
  else
  {
    Serial.println("ESPNow Init Failed....");
  }
  memcpy( &slave.peer_addr, &remoteMac, 6 );
  slave.channel = WIFI_CHANNEL;
  slave.encrypt = 0;        
  slave.ifidx = ESP_IF_WIFI_AP;
  if ( esp_now_add_peer(peer) == ESP_OK)
  {
    Serial.println("Added Peer!");
  }
  ...
}

so the solution is that, if wifi is not needed for master and slave , both master and slave do the following 2 steps.
1.
wifi.disconnect()
2.
uint8_t primaryChan = WIFI_CHANNEL;
wifi_second_chan_t secondChan = WIFI_SECOND_CHAN_NONE;
esp_wifi_set_channel(primaryChan, secondChan);

after that, they will in the same channel, even previous connected to other wifi or in any channel. and you may try WiFi.begin(ssid, password,WIFI_CHANNEL); now

@cbpdk
Copy link

cbpdk commented May 8, 2019

@Larryyyyy , Finally, it works :-)
Thank you very much for taking the time to describe how to set the channel.
You saved me a lot of time reading through the documentation as searching for the solution failed.
Running espnow and a simple webserver together works at last.

@SEspe
Copy link

SEspe commented May 11, 2019

HI, and the exact solution is ?

@hcklawrence
Copy link

HI, and the exact solution is ?

set the wifi channel to a specific one even you haven't connected or not planning to connect to a wifi.
esp_wifi_set_channel(primaryChan, secondChan);
the primartChan is the channel you are going to use. the scondChan I don't know when will it be used but the function needed 2 args.

@cbpdk
Copy link

cbpdk commented May 11, 2019

To illustrate it, here is a cut from my working code.
Not tried, but is it possible to set the channel using WiFi.channel() after connecting to the network?

#define WIFI_CHANNEL 10
...
...
  WiFi.mode(WIFI_AP_STA );  //WIFI_AP);
  Serial.println( WiFi.softAPmacAddress() );



  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS)) {
    Serial.println("STA Failed to configure");
  }
  
  //Force espnow to use same channel as network
  uint8_t primaryChan = WIFI_CHANNEL;
  wifi_second_chan_t secondChan = WIFI_SECOND_CHAN_NONE;
  esp_wifi_set_channel(primaryChan, secondChan);

  Serial.println("Connecting to ");
  Serial.println(ssid);


  //connect to your local wi-fi network
  WiFi.begin(ssid, password, WIFI_CHANNEL);

  //check wi-fi is connected to wi-fi network
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

  // This is the mac address of the Slave in AP Mode
  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
  Serial.print("Channel: "); Serial.println(WiFi.channel());


  if (esp_now_init() == ESP_OK)
  {
    Serial.println("ESPNow Init Success!");
  }
  else
  {
    Serial.println("ESPNow Init Failed....");
  }
  
  memcpy( &slave.peer_addr, &remoteMac, 6 );
  slave.channel = WIFI_CHANNEL;
  slave.encrypt = 0;
  slave.ifidx = ESP_IF_WIFI_AP;
  if ( esp_now_add_peer(peer) == ESP_OK)
  {
    Serial.println("Added Peer!");
  }
  Serial.print("Channel: "); Serial.println(WiFi.channel());

@f2knpw
Copy link

f2knpw commented May 18, 2019

Hi,

On my side it does not work...
What I would like is :
connect two ESP32 with ESPnow. The "master" sending values from time to time. The slave receiving them and then pushing them over wifi to somewhere on the net.

On the slave slide, I do want something independant of the router configuration...
So I got the "bug" : connexion to wifi in STA mode is not possible when the slave has been previously connected to ESPnow on another channel.

Here is the trick I found to avoid this bug (not very clean but seems to work)...

Master side is the code found in the Arduino IDE

Slave slide is adapted to reboot the ESP after receiving data from the master. A permanent variable is used to boot either with WIFI or ESPnow : RTC_DATA_ATTR bool LaunchWifi

Note that you can pass more variables with the same trick...
Then the ESP32 is switched to deepsleep during 100µs, wakes up after this small delay and fetchs the "LaunchWifi" boolean to boot in the right mode...

It seems to work ! I leave it under test during a few days to be sure !

here is the code :

`/**
ESPNOW - Basic communication - Slave
Date: 26th September 2017
Author: Arvind Ravulavaru https://github.com/arvindr21
Purpose: ESPNow Communication between a Master ESP32 and a Slave ESP32
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

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 <esp_now.h>
#include <WiFi.h>

#include <HTTPClient.h> //to access internet
HTTPClient httpc;
int httpCode;

#define CHANNEL 1
#define LED_PIN 22

RTC_DATA_ATTR bool LaunchWifi = false; //this is used to allow restart le ESP32 from deepsleep without loosing this variable

// Init ESP Now with fallback
void InitESPNow() {
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("");
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() {
char* SSID = "Slave_1";
bool result = WiFi.softAP(SSID, "Slave_1_Password", 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);

pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);

Serial.println("ESPNow/Basic/Slave Example");

esp_sleep_enable_timer_wakeup(100); //We set our ESP32 to wake up every 100 µseconds

if (LaunchWifi)
{
WiFiReset();
WiFi.mode(WIFI_STA);
delay(1000);
WiFi.begin("YOUR_SSID", "YOUR_PASSWORD");
long LastStart = millis();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print("*");
if ((millis() - LastStart) > 20000)
{
Serial.println(" --> cannot access Wifi --> restart");
esp_deep_sleep_start();
}
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("");
digitalWrite(LED_PIN, LOW);
delay(100);
digitalWrite(LED_PIN, HIGH);

//call http for test purpose
//Serial.print("[HTTP] begin...\n");
httpc.begin("http://avwx.rest/api/metar/LFBO?options=&format=json&onfail=cache");
httpCode = httpc.GET();                 // start connection and send HTTP header
if (httpCode > 0)                       // httpCode will be negative on error
{
  Serial.printf("[HTTP] GET... code: %d\n", httpCode);
  // file found at server
  if (httpCode == HTTP_CODE_OK)
  {
    String payload = httpc.getString();
    Serial.println(payload);
  }
}
else
{
  Serial.printf("[HTTP] GET... failed, error: %s\n", httpc.errorToString(httpCode).c_str());
}
httpc.end();



LaunchWifi = false;
esp_deep_sleep_start(); //and go to sleep

}

//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("");
LaunchWifi = true;
esp_deep_sleep_start();
}

void WiFiReset() {
WiFi.persistent(false);
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
}

void loop() {
// Chill
}`

@obdevel
Copy link

obdevel commented Jul 30, 2019

Having banged my head against the wall getting this to work, I thought I would write some summary notes of what works for me ... without 100s of lines of code.

  1. decide which node is the 'master', i.e. the node that will connect to an external WiFi AP
  2. choose some way of saving the WiFi credentials on the master, e.g. in EEPROM, hardcoded, etc.
  3. in the master code, do a WiFi scan and note the channel number of the SSID that matches the saved credentials. This is the one element you may not have control over, so it needs to override everything else
  4. the master and and every slave node must use this channel number for ESP-NOW comms to be successful
  5. on the master, create the soft AP using this channel number
  6. on the slave(s), do a WiFi scan for the master's soft AP and note the channel number
  7. if the slaves also create a soft AP, they must use this channel number
  8. when adding the master as a peer, use this channel number

In this way, everything is auto-configured based on one fixed variable - the channel number of the external WiFi AP. Once the master knows this number, it can propagate it to all slaves using the configuration of its soft AP.

I hope this helps someone.

@stale
Copy link

stale bot commented Sep 28, 2019

[STALE_SET] This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.

@stale stale bot added the Status: Stale Issue is stale stage (outdated/stuck) label Sep 28, 2019
@stale
Copy link

stale bot commented Oct 12, 2019

[STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.

@stale stale bot closed this as completed Oct 12, 2019
@smartkodian
Copy link

Is your WiFi AP on the same channel as ESPNow? Check ESPNow and connection to WiFi AP. It seems ESPNow is only working when using the same WiFi channel.

yes most of issue related to Wifi channel..I made them all the same for slaves and controller and wifi router and mostly stable than before...there is a drop packets every rarely time but it's better than before!

thanks for hint :)

@cbpdk
Copy link

cbpdk commented Jan 13, 2020 via email

@jacoboth7
Copy link

Since I wrote the examples for the ESPNow, the API for selecting a channel has changed, I discovered using arduino-esp32 1.0.4. Your error desciption may indicate thet the channel selection is not working. The country code for ESP32 is default CN which allows channels 1 - 13. I assume you do not change this. I have written example code for a 'master' or rather WiFi-ESPNow gateway and a slave which scans all channels looking for the gateway. You can find the explanation and code here: https://www.esp32.com/viewtopic.php?f=19&t=12992 The code is only for tests, but you can see how the new channel setting is implemented. I have not tested channel 13 as too many Wifi devies are constricted to 1 - 11! Hope this helps. Sun, 12 Jan 2020 19:54:56 -0800 quangvankts notifications@github.com wrote: I build up a small test configuration with an ESP8266 sending data over ESPNow and an ESP32 receiving data over ESPNow. Then the ESP32 send the received data over MQTT to an MQTT broker and it works. ## But there is one condition: The Wifi you connect to must be on the same Wifi channel that is used for ESPNow. In my case I tested with ESPNow sending/receiving on channel 1 and the ESP32 connected to a WiFi which is using channel 1 as well. If I connect to another WiFi that uses e.g. channel 13, the ESP32 does not receive any ESPNow data anymore. I tried to change the ESPNow channel to 13, but I didn't get the connection between the ESP8266 and ESP32 to work (with or without a WiFi connection). That might be a limitation on the ESP8266 (???) but I have only one ESP32 to test. Here is the code that worked for me: ESP8266 code adapted from ESP32 ESPNow example: c++ #include <Arduino.h> #include <ESP8266WiFi.h> #include <Ticker.h> extern "C" { #include <espnow.h> #include <user_interface.h> } /** ESPNOW - Basic communication - Master Date: 26th September 2017 Author: Arvind Ravulavaru <https://github.com/arvindr21> */ typedef struct esp_now_peer_info { u8 peer_addr[6]; /**< ESPNOW peer MAC address that is also the MAC address of station or softap */ uint8_t channel; /**< Wi-Fi channel that peer uses to send/receive ESPNOW data. If the value is 0, use the current channel which station or softap is on. Otherwise, it must be set as the channel that station or softap is on. */ } esp_now_peer_info_t; // Global copy of slave #define NUMSLAVES 20 esp_now_peer_info_t slaves[NUMSLAVES] = {}; int SlaveCnt = 0; #define CHANNEL 1 void printMacAddress(uint8_t* macaddr) { Serial.print("{"); for (int i = 0; i < 6; i++) { Serial.print("0x"); Serial.print(macaddr[i], HEX); if (i < 5) Serial.print(','); } Serial.println("};"); } // Init ESP Now with fallback void InitESPNow() { if (esp_now_init() == 0) { Serial.println("ESPNow Init Success"); } else { Serial.println("ESPNow Init Failed"); ESP.restart(); } esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); } // 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); 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 char macPart[4]; macPart[0] = '0'; macPart[1] = 'x'; macPart[2] = (char)BSSIDstr[0]; macPart[3] = (char)BSSIDstr[1]; slaves[SlaveCnt].peer_addr[0] = strtol(macPart,0,16); macPart[2] = (char)BSSIDstr[3]; macPart[3] = (char)BSSIDstr[4]; slaves[SlaveCnt].peer_addr[1] = strtol(macPart,0,16); macPart[2] = (char)BSSIDstr[6]; macPart[3] = (char)BSSIDstr[7]; slaves[SlaveCnt].peer_addr[2] = strtol(macPart,0,16); macPart[2] = (char)BSSIDstr[9]; macPart[3] = (char)BSSIDstr[10]; slaves[SlaveCnt].peer_addr[3] = strtol(macPart,0,16); macPart[2] = (char)BSSIDstr[12]; macPart[3] = (char)BSSIDstr[13]; slaves[SlaveCnt].peer_addr[4] = strtol(macPart,0,16); macPart[2] = (char)BSSIDstr[15]; macPart[3] = (char)BSSIDstr[16]; slaves[SlaveCnt].peer_addr[5] = strtol(macPart,0,16); 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]; u8 *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((u8*)peer_addr); if (exists) { // Slave already paired. Serial.println("Already Paired"); } else { // Slave not paired, attempt pair int addStatus = esp_now_add_peer((u8*)peer_addr, ESP_NOW_ROLE_CONTROLLER, CHANNEL, NULL, 0); if (addStatus == 0) { // Pair success Serial.println("Pair success"); } else { Serial.println("Pair failed"); } 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++) { u8 *peer_addr = slaves[i].peer_addr; if (i == 0) { // print only for first slave Serial.print("Sending: "); Serial.println(data); } int result = esp_now_send(peer_addr, &data, sizeof(data)); Serial.print("Send Status: "); if (result ==0) { Serial.println("Success " + String(result)); } else { Serial.println("Failed " + String(result)); } delay(100); } } // callback when data is sent from Master to Slave esp_now_send_cb_t OnDataSent(const uint8_t *mac_addr, u8 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 == 0 ? "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); esp_now_register_send_cb([](uint8_t* macaddr, uint8_t status) { printMacAddress(macaddr); static uint32_t ok = 0; static uint32_t fail = 0; if (status == 0) { Serial.println("ESPNOW: SEND_OK"); ok++; } else { Serial.println("ESPNOW: SEND_FAILED"); fail++; } Serial.printf("[SUCCESS] = %lu/%lu \r\n", ok, ok+fail); }); } 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); } ESP32 code adapted from ESP32 ESPNow example: c++ /** ESPNOW - Basic communication - Slave Date: 26th September 2017 Author: Arvind Ravulavaru <https://github.com/arvindr21> */ #include <esp_now.h> #include <WiFi.h> #include <MQTTClient.h> #define CHANNEL 1 /** MQTT client class to access mqtt broker */ MQTTClient mqttClient(2560); /** MQTT broker URL */ static const char * mqttBroker = "xx.xx.xx.xx"; /** MQTT connection id */ static const char * mqttID = "ESP32"; /** MQTT user name */ static const char * mqttUser = "esp32"; /** MQTT password */ static const char * mqttPwd = "PASSWORD"; /** WiFi client class to receive messages from mqtt broker */ WiFiClient mqttReceiver; void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len); // Init ESP Now with fallback void InitESPNow() { if (esp_now_init() == ESP_OK) { Serial.println("ESPNow Init Success"); } else { Serial.println("ESPNow Init Failed"); 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_STA); WiFi.begin("MYWIFI", "MYWIFIPW"); // configure device AP mode configDeviceAP(); // This is the mac address of the Slave in AP Mode Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); // Start connection to MQTT broker // Connect to MQTT broker mqttClient.begin(mqttBroker, mqttReceiver); Serial.println("Connecting to MQTT broker"); int connectTimeout = 0; while (!mqttClient.connect(mqttID, mqttUser, mqttPwd)) { delay(100); connectTimeout++; if (connectTimeout > 10) { // Wait for 1 seconds to connect Serial.println("Can't connect to MQTT broker"); ESP.restart(); } } Serial.println("Connected to MQTT"); // 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(""); mqttClient.publish("/debug","[INFO] Last Packet Recv from: " + tftMsg); mqttClient.publish("/debug","[INFO] Last Packet Recv Data: " + tftMsg); recvMsgNum++; } void loop() { // Chill } Output on Serial from ESP32: ESPNow/Basic/Slave Example AP Config Success. Broadcasting with AP: Slave:24:0A:C4:81:CE:9C AP MAC: 24:0A:C4:81:CE:9D Connecting to MQTT broker [E][WiFiClient.cpp:97] connect(): lwip_connect_r: 113 Connected to MQTT ESPNow Init Success Last Packet Recv from: 5c:cf:7f:01:5a:5d Last Packet Recv Data: 91 Last Packet Recv from: 5c:cf:7f:01:5a:5d Last Packet Recv Data: 92 Last Packet Recv from: 5c:cf:7f:01:5a:5d Last Packet Recv Data: 93 Last Packet Recv from: 5c:cf:7f:01:5a:5d Last Packet Recv Data: 94 Output on Serial from ESP8266: ESPNow/Multi-Slave/Master Example STA MAC: 5C:CF:7F:01:5A:5D ESPNow Init Success Found 6 devices 2: Slave:24:0A:C4:81:CE:9C [24:0A:C4:81:CE:9D] (-55) 1 Slave(s) found, processing.. Processing: 24:A:C4:81:CE:9D Status: Pair success Sending: 1 Send Status: Success 0 {0x24,0xA,0xC4,0x81,0xCE,0x9D}; ESPNOW: SEND_OK [SUCCESS] = 1/1 Output from my MQTT broker: [INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d [INFO] Last Packet Recv Data: 42 [INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d [INFO] Last Packet Recv Data: 43 [INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d [INFO] Last Packet Recv Data: 44 Im using your code to send ESPNow messages between ESP8266 (Master) to ESP32 (Slave) (without connecting to MQTTClient) , set them up on same channel, but only about 25% of the messages reach the ESP32. The weird thing is even if I set them on different channels, it still works and I still get the same result (still around 20-25% of the messages reach the ESP32). Any idea what I am doing wrong here ? Thanks !

-- You are receiving this because you commented. Reply to this email directly or view it on GitHub: #878 (comment)

Change this part of your code:

// Get BSSID => Mac Address of the Slave
char macPart[4];
macPart[0] = '0';
macPart[1] = 'x';

      macPart[2] = (char)BSSIDstr[0];
      macPart[3] = (char)BSSIDstr[1];
      slaves[SlaveCnt].peer_addr[0] = strtol(macPart,0,16);
      macPart[2] = (char)BSSIDstr[3];
      macPart[3] = (char)BSSIDstr[4];
      slaves[SlaveCnt].peer_addr[1] = strtol(macPart,0,16);
      macPart[2] = (char)BSSIDstr[6];
      macPart[3] = (char)BSSIDstr[7];
      slaves[SlaveCnt].peer_addr[2] = strtol(macPart,0,16);
      macPart[2] = (char)BSSIDstr[9];
      macPart[3] = (char)BSSIDstr[10];
      slaves[SlaveCnt].peer_addr[3] = strtol(macPart,0,16);
      macPart[2] = (char)BSSIDstr[12];
      macPart[3] = (char)BSSIDstr[13];
      slaves[SlaveCnt].peer_addr[4] = strtol(macPart,0,16);
      macPart[2] = (char)BSSIDstr[15];
      macPart[3] = (char)BSSIDstr[16];
      slaves[SlaveCnt].peer_addr[5] = strtol(macPart,0,16);
      slaves[SlaveCnt].channel = (uint8_t) channel;

with this code
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];
}
}

Hope it helps

@Bluebrain2000
Copy link

Bluebrain2000 commented Jan 27, 2020

I found a simple solution! :)

My ESP-NOW setup worked for over a year flawlessly, with the slave permanently connected to WiFi.
When I switched my access point, I had no clue why I could not get it working again.
I am using 2 ESP8266 as master and slave.

Finally I could at least figure out what the problem was. The ESP8266 always uses WiFi channel # 1, regardless which channel was configured with esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, wifi_channel, NULL, 0);

configured WiFi channel: 8
ESP_Now init OK
1:0, 2:0, 3:0, cmd:0
sent on WiFi channel 1, took 6844 µs, error=1 (errorcounter:1)
1:0, 2:0, 3:0, cmd:0
sent on WiFi channel 1, took 6489 µs, error=1 (errorcounter:2)
...

"configured WiFi channel: 8" but "sent on WiFi channel 1"

Nothing helped! (at least on the ESP8266)

The solution I found, was to setup a not-connecting WiFi connection:

WiFi.mode(WIFI_STA);
const char* dummy = "abcdefgh";
//         SSID   pass   channel       BSSID  connect
WiFi.begin(dummy, dummy, wifi_channel, false, false);

With the last parameter connect=false, WiFi is only setup but no connection attempts will be made (which would obviously fail with the dummy SSID and password) but this will change the ESP NOW WiFi channel!.

That's it! Now it works with every WiFi channel! :)

configured WiFi channel: 8
ESP_Now init OK
1:0, 2:0, 3:0, cmd:0
sent on WiFi channel 8, took 798 µs, error=0 (errorcounter:0)
1:0, 2:0, 3:0, cmd:0
sent on WiFi channel 8, took 635 µs, error=0 (errorcounter:0)
...

"sent on WiFi channel 8"

And, btw. for those who don't want to hardcode the channel number:
Make a network search for a known SSID and then use this channel:

#define SSID_SEARCH "IoT1"
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.print("scanning WiFi networks for channel of SSID ");
Serial.println(SSID_SEARCH);
//                        async  scan_hidden
int n = WiFi.scanNetworks(false, false);
if(n==0) {
	Serial.println("No networks found. :( Restart in 5 sec.");
	delay(5000);
	ESP.restart();
} else {
	for (int i = 0; i < n; ++i) {
		Serial.print(i + 1);
		Serial.print(": ");
		Serial.print(WiFi.SSID(i));
		Serial.print(" (");
		Serial.print(WiFi.RSSI(i));
		Serial.print(") channel ");
		Serial.println(WiFi.channel(i));
		if(!ssid_found && String(WiFi.SSID(i)) == SSID_SEARCH) {
			ssid_found = true;
			wifi_channel = WiFi.channel(i);
			Serial.print("   ^ FOUND! Using WiFi channel ");
			Serial.println(wifi_channel);
		}
	}
	if(!ssid_found) {
		Serial.println("SSID not found. :( Restart in 5 sec.");
		delay(5000);
		ESP.restart();
	}
}
Serial.print("\n");

const char* dummy = "abcdefgh";
//         SSID   pass   channel       BSSID  connect
WiFi.begin(dummy, dummy, wifi_channel, false, false);

@smartkodian
Copy link

I build up a small test configuration with an ESP8266 sending data over ESPNow and an ESP32 receiving data over ESPNow. Then the ESP32 send the received data over MQTT to an MQTT broker and it works.

But there is one condition:

The Wifi you connect to must be on the same Wifi channel that is used for ESPNow.
In my case I tested with ESPNow sending/receiving on channel 1 and the ESP32 connected to a WiFi which is using channel 1 as well.
If I connect to another WiFi that uses e.g. channel 13, the ESP32 does not receive any ESPNow data anymore.
I tried to change the ESPNow channel to 13, but I didn't get the connection between the ESP8266 and ESP32 to work (with or without a WiFi connection). That might be a limitation on the ESP8266 (???) but I have only one ESP32 to test.
Here is the code that worked for me:
ESP8266 code adapted from ESP32 ESPNow example:

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>
extern "C" {
  #include <espnow.h>
  #include <user_interface.h>
}

/**
   ESPNOW - Basic communication - Master
   Date: 26th September 2017
   Author: Arvind Ravulavaru <https://github.com/arvindr21>
*/

typedef struct esp_now_peer_info {
    u8 peer_addr[6];    /**< ESPNOW peer MAC address that is also the MAC address of station or softap */
    uint8_t channel;                        /**< Wi-Fi channel that peer uses to send/receive ESPNOW data. If the value is 0,
                                                 use the current channel which station or softap is on. Otherwise, it must be
                                                 set as the channel that station or softap is on. */
} esp_now_peer_info_t;

// Global copy of slave
#define NUMSLAVES 20
esp_now_peer_info_t slaves[NUMSLAVES] = {};
int SlaveCnt = 0;

#define CHANNEL 1

void printMacAddress(uint8_t* macaddr) {
  Serial.print("{");
  for (int i = 0; i < 6; i++) {
    Serial.print("0x");
    Serial.print(macaddr[i], HEX);
    if (i < 5) Serial.print(',');
  }
  Serial.println("};");
}

// Init ESP Now with fallback
void InitESPNow() {
  if (esp_now_init() == 0) {
    Serial.println("ESPNow Init Success");
  }
  else {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
}

// 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);
      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
        char macPart[4];
        macPart[0] = '0';
        macPart[1] = 'x';

        macPart[2] = (char)BSSIDstr[0];
        macPart[3] = (char)BSSIDstr[1];
        slaves[SlaveCnt].peer_addr[0] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[3];
        macPart[3] = (char)BSSIDstr[4];
        slaves[SlaveCnt].peer_addr[1] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[6];
        macPart[3] = (char)BSSIDstr[7];
        slaves[SlaveCnt].peer_addr[2] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[9];
        macPart[3] = (char)BSSIDstr[10];
        slaves[SlaveCnt].peer_addr[3] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[12];
        macPart[3] = (char)BSSIDstr[13];
        slaves[SlaveCnt].peer_addr[4] = strtol(macPart,0,16);
        macPart[2] = (char)BSSIDstr[15];
        macPart[3] = (char)BSSIDstr[16];
        slaves[SlaveCnt].peer_addr[5] = strtol(macPart,0,16);

        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];
      u8 *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((u8*)peer_addr);
      if (exists) {
        // Slave already paired.
        Serial.println("Already Paired");
      } else {
        // Slave not paired, attempt pair
        int addStatus = esp_now_add_peer((u8*)peer_addr, ESP_NOW_ROLE_CONTROLLER, CHANNEL, NULL, 0);
        if (addStatus == 0) {
          // Pair success
          Serial.println("Pair success");
        } else {
          Serial.println("Pair failed");
        }
        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++) {
    u8 *peer_addr = slaves[i].peer_addr;
    if (i == 0) { // print only for first slave
      Serial.print("Sending: ");
      Serial.println(data);
    }
    int result = esp_now_send(peer_addr, &data, sizeof(data));
    Serial.print("Send Status: ");
    if (result ==0) {
      Serial.println("Success " + String(result));
    } else {
      Serial.println("Failed " + String(result));
    }
    delay(100);
  }
}

// callback when data is sent from Master to Slave
esp_now_send_cb_t OnDataSent(const uint8_t *mac_addr, u8 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 == 0 ? "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);
  esp_now_register_send_cb([](uint8_t* macaddr, uint8_t status) {
    printMacAddress(macaddr);
    static uint32_t ok = 0;
    static uint32_t fail = 0;
    if (status == 0) {
      Serial.println("ESPNOW: SEND_OK");
      ok++;
    }
    else {
      Serial.println("ESPNOW: SEND_FAILED");
      fail++;
    }
    Serial.printf("[SUCCESS] = %lu/%lu \r\n", ok, ok+fail);
  });
}

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

ESP32 code adapted from ESP32 ESPNow example:

/**
   ESPNOW - Basic communication - Slave
   Date: 26th September 2017
   Author: Arvind Ravulavaru <https://github.com/arvindr21>
*/

#include <esp_now.h>
#include <WiFi.h>
#include <MQTTClient.h>

#define CHANNEL 1

/** MQTT client class to access mqtt broker */
MQTTClient mqttClient(2560);
/** MQTT broker URL */
static const char * mqttBroker = "xx.xx.xx.xx";
/** MQTT connection id */
static const char * mqttID = "ESP32";
/** MQTT user name */
static const char * mqttUser = "esp32";
/** MQTT password */
static const char * mqttPwd = "PASSWORD";
/** WiFi client class to receive messages from mqtt broker */
WiFiClient mqttReceiver;

void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len);

// Init ESP Now with fallback
void InitESPNow() {
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  else {
    Serial.println("ESPNow Init Failed");
    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_STA);
  WiFi.begin("MYWIFI", "MYWIFIPW");
  // configure device AP mode
  configDeviceAP();
  // This is the mac address of the Slave in AP Mode
  Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());

  // Start connection to MQTT broker
  // Connect to MQTT broker
  mqttClient.begin(mqttBroker, mqttReceiver);

  Serial.println("Connecting to MQTT broker");

  int connectTimeout = 0;

  while (!mqttClient.connect(mqttID, mqttUser, mqttPwd)) {
    delay(100);
    connectTimeout++;
    if (connectTimeout > 10) { // Wait for 1 seconds to connect
      Serial.println("Can't connect to MQTT broker");
      ESP.restart();
    }
  }
  Serial.println("Connected to MQTT");

  // 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("");
  mqttClient.publish("/debug","[INFO] Last Packet Recv from: " + tftMsg);
  mqttClient.publish("/debug","[INFO] Last Packet Recv Data: " + tftMsg);
  recvMsgNum++;
}

void loop() {
  // Chill
}

Output on Serial from ESP32:

ESPNow/Basic/Slave Example
AP Config Success. Broadcasting with AP: Slave:24:0A:C4:81:CE:9C
AP MAC: 24:0A:C4:81:CE:9D
Connecting to MQTT broker
[E][WiFiClient.cpp:97] connect(): lwip_connect_r: 113
Connected to MQTT
ESPNow Init Success
Last Packet Recv from: 5c:cf:7f:01:5a:5d
Last Packet Recv Data: 91

Last Packet Recv from: 5c:cf:7f:01:5a:5d
Last Packet Recv Data: 92

Last Packet Recv from: 5c:cf:7f:01:5a:5d
Last Packet Recv Data: 93

Last Packet Recv from: 5c:cf:7f:01:5a:5d
Last Packet Recv Data: 94

Output on Serial from ESP8266:

ESPNow/Multi-Slave/Master Example
STA MAC: 5C:CF:7F:01:5A:5D
ESPNow Init Success

Found 6 devices 
2: Slave:24:0A:C4:81:CE:9C [24:0A:C4:81:CE:9D] (-55)
1 Slave(s) found, processing..
Processing: 24:A:C4:81:CE:9D Status: Pair success
Sending: 1
Send Status: Success 0
{0x24,0xA,0xC4,0x81,0xCE,0x9D};
ESPNOW: SEND_OK
[SUCCESS] = 1/1 

Output from my MQTT broker:

[INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d
[INFO] Last Packet Recv Data: 42
[INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d
[INFO] Last Packet Recv Data: 43
[INFO] Last Packet Recv from: 5c:cf:7f:01:5a:5d
[INFO] Last Packet Recv Data: 44

I followed the same in the example but I have strange result! the MAC address of peer is changed from first discovering and after peer processing..

this is the result!

1: Slave:BC:DD:C2:30:7F:77 [BE:DD:C2:30:7F:77] (-26) 1 Slave(s) found, processing.. Processing: EE:DE:2E:E:FE:7E Status: Already Paired Sending: 3 Send Status: Success 0 {0xEE,0xDE,0x2E,0xE,0xFE,0x7E}; ESPNOW: SEND_FAILED

Any Help please!

Thanks for all

@glush
Copy link

glush commented Jul 24, 2020

I can confirm that Sender -> ESP-Now -> Receiver -> WiFi -> World scheme works only on WiFi channel 1. I made experiment with 2 ESP8266 boards. One is sender and one is receiver. Everything works fine until I tried to start STA connection to WiFi network. Immediatelly after I tried to connect receiver to WiFi it stops receiving packet. So I switch sender to channel 1, recompile and load new sketch. But strange thing. Receiver configured at channel 13 continue receiving packets sending on channel 1. Seems to me Esp-Now works on channel 1 all the time. But may be I'm worng.

@Bluebrain2000
Copy link

@glush see my solution above to set the WiFi channel:
#878 (comment)

@Rot3l
Copy link

Rot3l commented Aug 18, 2020

Hi
I have resolved this problem in another way, I have define two modes: espnow mode or "wifi-client + mqtt" mode/code, when esp32 reboots, it reads a eeprom variable, this tells it what code must execute. So firts it boots in espnow slave mode, then, when it receives a message, burns it in eeprom and change the state variable also in eeprom, and reboots.
Then it wakes up and execute "wifi-client + mqtt" mode/code, reads info from eeprom and sends it. Resets eeprom state variable and reboots again.
Cons: Lost of espnow RX during this period of time; only integer values due to eeprom
Pros: Only a chip; it works!; it's amazing to view the output from this gateway switching :)

If you want to see the code or watch it working, just ask for!

@kevinkessler
Copy link

kevinkessler commented Sep 18, 2020

@glush see my solution above to set the WiFi channel:
#878 (comment)

That doesn't work for me for the ESP32, but this does

esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(channel,WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);

Combine this with the access point and scan that @smartkodian is using above, and everything works no matter what channel you are on (WiFi.channel(i) will return the channel after the scan). It's also a lot easier to use the WiFi.BSSID(i) , which returns a uint8_t pointer, directly in the memcpy of the peer_addr of the esp_now_peer_info_t struct, rather than parse our the string from WiFi.BSSIDstr(i).

@Jacky-gh
Copy link

Jacky-gh commented Dec 2, 2020

This works for me with an esp32 as Master (transmitter) in the Arduino IDE:
Automatically detect the channel of the Slave and use this one for transmission (which can be an arbitrary channel between 1 upto 13).
And as already mentioned: If you want to configure a STAtion on the Slave (Receiver) side as well (.e.g. for MQTT or WebServer) the channel needs to be the same as the one your WiFi router uses (N-1).

Master code (excerpt):

//...
#define PEER_SSID_PREFIX "MyIoT"  // SSID Praefix of the Slaves
#define PRINTSCANRESULTS 1   // 0: no, 1: yes
#define DELETEBEFOREPAIR 0   // 0: no, 1: yes
//...

uint8_t channel_old = 0;

//...

//-------------------------------------------------
// Scan for slaves in Access Point (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");
  } else {
    Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices ");
    for (int i = 0; i < scanResults; ++i) {
      // Print SSID and RSSI and channel for each device found
      String SSID = WiFi.SSID(i);
      int32_t RSSI = WiFi.RSSI(i);
      String BSSIDstr = WiFi.BSSIDstr(i);
      uint8_t channel = WiFi.channel(i);

      if (PRINTSCANRESULTS) {
        Serial.print(i + 1);
        Serial.print(": ");
        Serial.print(SSID);
        Serial.print(" (");
        Serial.print(RSSI);
        Serial.print(")");
        Serial.print(" Chn: ");
        Serial.print(channel);
        Serial.println();
      }
      delay(10);
      // Check if the current device starts with string defined in PEER_SSID_PREFIX
      if (SSID.indexOf(PEER_SSID_PREFIX) == 0) {
        // SSID of interest
        Serial.println("Found a Slave.");
        Serial.print(i + 1);
        Serial.print(": ");
        Serial.print(SSID);
        Serial.print(" [");
        Serial.print(BSSIDstr);
        Serial.print("]");
        Serial.print(" (");
        Serial.print(RSSI);
        Serial.print(")");
        Serial.print(" Chn: ");
        Serial.print(channel);
        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 ) {
            slave.peer_addr[ii] = (uint8_t) mac[ii];
          }
        }

        slave.channel = channel; // use slave channel
        slave.encrypt = 0;       // no encryption

        // Check if channel has changed?
        if(channel != channel_old) {
//        esp_wifi_set_promiscuous(true);
//        esp_wifi_set_channel(channel,WIFI_SECOND_CHAN_NONE);
//        esp_wifi_set_promiscuous(false);
          // Workaround to set channel
          setupDummyAP();
          WiFi.disconnect();
          //Set device in Station mode (STA) to begin with
          //Usually, Station interface is set for CONTROLLER, SoftAP interface for SLAVE AND COMBO.
          WiFi.mode(WIFI_STA);

          channel_old = channel;
        }

        slaveFound = 1;
        // we are planning to have only one slave in this example;
        // Hence, break after we find one, to be a bit efficient
        break;
      }
    }
  }

  if (slaveFound) {
    Serial.println("Slave Found, processing..");
  } else {
    Serial.println("Slave Not Found, trying again.");
  }

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

//...

//-------------------------------------------------
// Workaround: setup a not connecting WiFi AP to change the channel
//-------------------------------------------------
void setupDummyAP() {
  WiFi.disconnect();
  WiFi.mode(WIFI_AP);
  delay(100);
  const char *dummy = "abcdefgh";
  //         SSID ,  PSK ,  channel  , BSSID, connect
  WiFi.softAP(dummy, dummy, slave.channel, 0, false);
  delay(250);

  // DEBUG: print WiFi connection info
  //   Mode, Channel, SSID, Passphrase , BSSID, AP MAC
  //WiFi.printDiag(Serial);
  Serial.print("Channel new: ");
  Serial.println(WiFi.channel());
  delay(100);
}

/-------------------------------------------------
// Setup
//-------------------------------------------------
void setup() {
  Serial.begin(115200);
  Serial.println("ESPNow/Basic/Master Example");

  //WiFiReset();
  WiFi.disconnect();
  //Set device in Station mode (STA) to begin with
  //Usually, Station interface is set for CONTROLLER, SoftAP interface for SLAVE AND COMBO.
  WiFi.mode(WIFI_STA);
  // This is the mac address of the Master in Station mode (STA)
  Serial.print("STA MAC: ");
  Serial.println(WiFi.macAddress());

  // DEBUG:  print WiFi connection info
  //   Mode, Channel, SSID, Passphrase , BSSID, AP MAC
  //WiFi.printDiag(Serial);
  Serial.print("Channel: ");
  Serial.println(WiFi.channel());
  delay(100);

  // Init ESP-Now with a fallback logic
  InitESPNow();
  // Once ESP-Now is successfully initialized, we will register for Send Call Back to
  // get the status of the transmitted packet
  esp_now_register_send_cb(OnDataSent);
}

//-------------------------------------------------
// Loop
//-------------------------------------------------
void loop() {
  // In the loop we scan for slave
  ScanForSlave();
  // If Slave is found, it would be populate in the 'slave' variable
  // We will check if 'slave' variable is defined and then we proceed further
  if (slave.channel) {   // check if slave channel is defined
    // 'slave' is defined
    // Add slave as peer if it has not been added already
    bool isPaired = manageSlave();
    if (isPaired) {
      // pair success or already paired
      // Send data to device
      sendData();
    } else {
      // slave pair failed
      Serial.println("Slave pair failed!");
    }
  }
  else {
    // No slave found to process
  }

  // wait for 10 seconds to run the logic again
  delay(10000);
}

applecargo added a commit to dianaband/forest-all-around that referenced this issue Apr 26, 2022
+ peer book listing (debug)
+ no addressbook/peer list -> all go broadcast!
+ wifi_channel == 1 for later 
(espressif/arduino-esp32#878 (comment))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Stale Issue is stale stage (outdated/stuck)
Projects
None yet
Development

No branches or pull requests