espressif / ESP8266_NONOS_SDK

ESP8266 nonOS SDK
Other
918 stars 533 forks source link

ESP-NOW communication fails between nodes after connecting root node to new router ref:_00D7FyCNM._5007F11kBPf: #325

Open suraj9657 opened 3 years ago

suraj9657 commented 3 years ago

Basic Info This issue complies with the issue POLICY doc. I have read the documentation at readthedocs and the issue is not addressed there. I have tested that the issue is present in current master branch (aka latest git). I have searched the issue tracker for a similar issue. If there is a stack dump, I have decoded it. I have filled out all fields below. Platform Hardware: [ESP-8266] Core Version: [latest git hash or date] Development Env: [Arduino IDE] Operating System: [Windows] Settings in IDE Module: [ESP8266 Nodemcu] Flash Mode: [qio] Flash Size: [4MB] lwip Variant: [v2 Lower Memory] Reset Method: [nodemcu] Flash Frequency: [40Mhz] CPU Frequency: [80Mhz] Upload Using: [SERIAL] Upload Speed: [115200]

Problem Description

ESP-NOW communication fails between nodes after connecting root node to new router. Sometimes ESP-NOW communication works while maintaing router connection, but as soon as the root node is connected to different router communication between node fails.

Below are the steps to reproduce.

program esp8266 nodes with attached code (updating router SSID and password). choose any node at random as root node (nearest to router) and through serial input give any input 3 times to start connection with router(described in code). through serial input check for (delivery message or failed message) outcome of esp-now transmission. This step fails 80% of times. If it connects to router (in step 3) and is successful in delivering message to non-root nodes, if you change the SSID to any other available router or mobile hotspot it connects to router but fails to deliver message to non-root nodes.

[MCVE] Sketch

include

include

define LED 2

const char ssidAp = "username"; //ssid of router const char passwordAp = "password"; //password fro router uint8_t broadcastAddress[] = {0xA8, 0xD9, 0xB3, 0x0D, 0xAA, 0xCE}; //broadcastAddressChanged uint8_t mac[6] {0xA8, 0xD9, 0xB3, 0x0D, 0xAA, 0xCE}; //MAC Address you want to set int counter = 0; bool onFlag = false; uint8_t channelNumber = 0;

typedef struct struct_message { char a[32]; int b; float c; String d; bool e; } struct_message; struct_message myData;

void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { // Callback when data is sent Serial.print("Last Packet Send Status: "); Serial.println(sendStatus == 0 ? "Delivery Success" : "Delivery Fail"); }

void OnDataRecv(uint8_t mac, uint8_t incomingData, uint8_t len) { // Callback when data is received Serial.print("Bytes received: "); Serial.println(len); memcpy(&myData, incomingData, sizeof(myData)); Serial.print("Bytes received: "); Serial.println(len); Serial.print("Char: "); Serial.println(myData.a); Serial.print("Int: "); Serial.println(myData.b); Serial.print("Float: "); Serial.println(myData.c); Serial.print("String: "); Serial.println(myData.d); Serial.print("Bool: "); Serial.println(myData.e); Serial.println(); onFlag =!onFlag; digitalWrite(LED, onFlag); }

bool listNetworks() { Serial.println("scan start"); bool connectionAvailable = false; int n = WiFi.scanNetworks(); // WiFi.scanNetworks will return the number of networks found Serial.println("scan done"); if (n == 0) { Serial.println("no networks found"); } else { Serial.print(n); Serial.println(" networks found"); for (int i = 0; i < n; ++i) { // Print SSID and RSSI for each network found Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i)); Serial.print(" ("); Serial.print(WiFi.RSSI(i)); Serial.print(")"); Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? "." : "*"); Serial.println(WiFi.BSSIDstr(i)); String s = WiFi.BSSIDstr(i); Serial.print("channel "); Serial.println(WiFi.channel(i)); if(WiFi.SSID(i) == ssidAp){ connectionAvailable = true; channelNumber = WiFi.channel(i); erial.print("router channelNumber is "); Serial.print(channelNumber); } } } Serial.println(""); WiFi.scanDelete(); return connectionAvailable; }

void setup() { Serial.begin(115200); pinMode(LED, OUTPUT); WiFi.persistent(false); WiFi.mode(WIFI_STA); WiFi.disconnect(); if (esp_now_init() != 0) { // Init ESP-NOW Serial.println("Error initializing ESP-NOW"); return; } esp_now_set_self_role(ESP_NOW_ROLE_COMBO); // Set ESP-NOW Role esp_now_register_send_cb(OnDataSent); // get the status of Trasnmitted packet // esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 0, NULL, 0); // Register peer esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, channelNumber, NULL, 0); esp_now_register_recv_cb(OnDataRecv); // Register for a callback function that will be called when data is received Serial.print("OLD ESP8266 MAC: "); Serial.println(WiFi.macAddress()); //This will read MAC Address of ESP

wifi_set_macaddr(0, const_cast<uint8*>(mac)); //This line changes MAC adderss of ESP8266

Serial.print("NEW ESP8266 MAC: "); Serial.println(WiFi.macAddress()); //This will read MAC Address of ESP // connectclient(); listNetworks(); // changing channel to ssid channel

}

void connectclient(){ if(listNetworks()){ WiFi.begin(ssidAp, passwordAp, channelNumber); while (WiFi.status() != WL_CONNECTED) { Serial.print('.'); delay(500); } }else{ Serial.println("network not found"); } if(WiFi.status() == WL_CONNECTED){ Serial.println("wifi connected"); } }

void loop() { if(Serial.available()){ //serial input anything to pass myData to peers counter++; String str = Serial.readString(); size_t len = str.length(); uint8_t sbuf[len]; strcpy(myData.a, "THIS IS A CHAR"); myData.b = random(1,20); myData.c = 1.2; myData.d = "Hello"; myData.e = false; esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); if(counter == 2){ //serial second time input anything to change peer channel int a = esp_now_set_peer_channel(broadcastAddress,channelNumber); Serial.print("channel set to "); Serial.println(channelNumber); }else if(counter == 3){ //serial third time input anything to connect node to router Serial.println("connecting wifi router"); connectclient(); } } }

Debug Messages

router channelNumber is 11 Last Packet Send Status: Delivery Success Last Packet Send Status: Delivery Success channel set to 11 Last Packet Send Status: Delivery Success connecting wifi router ................wifi connected Last Packet Send Status: Delivery Fail Last Packet Send Status: Delivery Fail Last Packet Send Status: Delivery Fail

goatzillax commented 8 months ago

esp_now_add_peer either ignores the channel or there is something wrong deeper in the pile.

You'd think they had the channel in there as a parameter because the system was designed to allow the hardware to switch to whatever channel each peer is declared on. But it's just broken.

Aside from that, there doesn't even seem to be a way to set the channel on an ESP8266 apart from associating with a router, which pretty much defeats the purpose in its entirety.

And obviously none of this will play nicely with deep sleep either or any notion of power saving.

So you're pretty much locked to channel 1. If you want your slave to also talk to a router, that means you have to lock your router to channel 1. (Which is going to suck for you if you have a neighbor who is also blasting on channel 1.)

There is a way to kind of get it to work which shows that the ESP8266 can obviously set the channel and blast out an ESP-NOW message under the hood, but it burns too much power and the direct interface just isn't exposed to the user.

Hot garbage.

Edit: in Arduino, you can set the channel with wifi_set_channel(uint8_t). So basically treat esp_now_add_peer like it ignores the channel (because it does) and manually set the channel. So upon first boot, I send a message across all channels to the destination MAC. Whichever succeeds is the channel I save in RTC for subsequent wakeups.