esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
15.98k stars 13.34k forks source link

Doing a Wifi scan makes ESP-NOW receiving unreliable afterwards #8690

Open AndreKR opened 1 year ago

AndreKR commented 1 year ago

Basic Infos

Platform

Settings in IDE

Problem Description

To reproduce this, you need two ESP8266.

Load the first one with a sketch that continuously sends ESP-NOW broadcasts, like this one:

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <espnow.h>
uint8_t broadcastAddress[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

void setup()
{
  Serial.begin(115200);
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  wifi_set_channel(6);
  esp_now_init();
  delay(10);
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
}  

void loop()
{
  Serial.printf("Channel: %u\n", wifi_get_channel());
  int data = 1234;
  esp_now_send(broadcastAddress, (uint8_t*)&data, sizeof(data));
  delay(500);
}

Load the second one with a sketch that displays a text when an ESP-NOW message is received, like this one:

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

void on_espnow_receive(uint8_t *mac_addr, uint8_t *data, uint8_t len) {
  Serial.printf("Received %u bytes from ", len);
  for (uint8_t b = 0; b < 6 ; b++)
    Serial.printf("%02hhX", mac_addr[b]);
  Serial.println();
}

void on_scan_done(void *arg, STATUS status) {}

void setup() {
  delay(3000);
  Serial.begin(115200);
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);

  // struct scan_config config = {0};
  // wifi_station_scan(&config, on_scan_done);

  wifi_set_channel(6);
  esp_now_init();
  delay(10);
  Serial.printf("Channel: %u\n", wifi_get_channel());
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_recv_cb(on_espnow_receive);
}

void loop() {
  delay(1000);
}

If you now run the receiver, in the Serial Monitor you'll see many received messages, just as expected:

Received 4 bytes from ...
Received 4 bytes from ...
Received 4 bytes from ...

Now uncomment the two commented lines in the receiver sketch:

  struct scan_config config = {0};
  wifi_station_scan(&config, on_scan_done);

You can also call WiFi.scanNetworks() instead of wifi_station_scan(&config, on_scan_done), it has the same effect.

If you then run the receiver again, you'll still get a message from time to time, but much much fewer, almost every message is lost.

Received 4 bytes from ...
TD-er commented 1 year ago

Have you also tried to set the channel again after scanning is done? I have noticed the actual channel set to WiFi may remain at the last channel used, when scanning.

By the way, I am surprised to see you're using wifi_set_channel in STA mode anyway. In STA mode setting the channel should be ignored as you can only do this in AP mode or in promiscuous mode.

ESP-NOW does have several rather tricky issues regarding the channel. A peer is stored internally with its MAC and channel. Thus when a package is received by a node, it may reply to the known MAC/channel of this peer. When a peer was added while the channel was off, it may try to hop between channels a lot. I got the feeling it may still every now and then receive ESP-NOW packets sent to channel X while the ESP is set to channel Y. But this is probably more due to bad antenna filtering. Anyway, ESP-NOW and WiFi channels is a really tricky combination.

AndreKR commented 1 year ago

Have you also tried to set the channel again after scanning is done?

I think I did, but since I didn't include it in the minimal example, I will try it again and add it.

By the way, I am surprised to see you're using wifi_set_channel in STA mode anyway.

There were issues with that in the past, but I'm absolutely sure that with the current version of the Arduino core setting the channel in STA mode works. It's only meaningful for ESP-NOW though because as soon as you actually connect to a Wifi the channel of the Wifi will take precedence. I'm also sure that you have to switch to STA mode for ESP-NOW to work.

A peer is stored internally with its MAC and channel.

I stored all my peers with channel 0, which means no channel switching should be happening. I felt like having devices on different channels just complicates matters even more than they already are with ESP-NOW.

Anyway, ESP-NOW and WiFi channels is a really tricky combination.

That's actually how I found this issue, the scheme I tried to implement was: I have a "server" and a "client" device and the server is connected to Wifi. When a client starts up, it scans the Wifi to set the channel to the same channel the server is on and then uses ESP-NOW for the rest of the communication because it's more battery-friendly than normal Wifi. Because of this issue here, I switched to a different scheme: Now when the client starts up it goes through the channels in a loop and sends broadcast messages and when the server receives one, it answer with a message containing its own channel. It works quite well. It has the additional advantage that it's even more battery-friendly and the client don't need to be in Wifi range. All around this bug helped my come up with a better solution, thank you bug. :)

ESP-NOW in general feels quite tricky, mostly because it's closed source and the documentation is garbage.

TD-er commented 1 year ago

I'm also sure that you have to switch to STA mode for ESP-NOW to work.

Nope. As a matter of fact, ESP-NOW does work perfectly fine using the AP interface. You need to use the MAC associated with the AP interface though.

I stored all my peers with channel 0, which means no channel switching should be happening. I felt like having devices on different channels just complicates matters even more than they already are with ESP-NOW.

I may have to test this myself. I for sure don't want to use several channels, but I did notice that some boards actually start communicating over different channels until I realized this was the last scanned channel.

ESP-NOW in general feels quite tricky, mostly because it's closed source and the documentation is garbage.

Can't agree more! Documentation was next to non existent when I started implementing it and I still have not merged my code into the main repository of my project as it still feels "too flaky".

AndreKR commented 1 year ago

Nope. As a matter of fact, ESP-NOW does work perfectly fine using the AP interface.

Ah yes, it works with AP, too. It just doesn't work without setting a mode at all, that's what I wanted to say.

I haven't tested whether there are any differences in power consumption or else between those modes. Does it start sending beacons right away when I set AP mode?

TD-er commented 1 year ago

AP mode doesn't do anything other than guaranteed not going to "radio sleep". So it is much more "available" to send data to.