ESP-NOW reliability - random 1 to 10 second delays
Posted: Mon Aug 31, 2020 2:48 pm
Summary: ESP-NOW transmit-receive pair works great, except for occasional ~1 second delays
Hi:
I am using ESP-NOW and two MELIFE ESP-WROOM-32 boards to send a simple ON/OFF trigger from one board to the other. It reads a GPIO input pin on the Transmit board, and sets a GPIO output pin on the Receiver board.
Using the example code, it didn't take me long to get it working, but I was getting a LOT of inconsistency in transmission success.
So, I used comments on this forum to improve reliability.
1) I included a message acknowledgement to confirm when the data is there
The transmitted message includes a message counter, which is incremented on each update
The Receiver receive callback includes sending the message back to the Transmitter.
The Transmitter will keep retransmitting until it sees that the confirmation message has the current counter
I put in a 5 ms delay in the re-transmission loop to minimize traffic
2) I added WiFi.setSleep(false) to the ESP-NOW setup, to prevent the device from going to sleep.
(This was a HUGE improvement).
3) I eliminated all Serial.print statements, and used the built in OLED display for debug and displaying the metrics.
4) I changed power supplies for both boards (plugging into my PC gave me the occasional brownout)
In general, I am now getting great performance. When testing with a 2 second external counter (with a 0.1 second ON, 1.9 second OFF cycle), 99.7% of the pulses are sent and confirmed within 50 ms, and 99.98% are sent and confirmed within 100ms. But in my last test, this still left me with 127 responses over 12 hours that took over 100ms, with at least one with over 1.5 seconds. In earlier tests, it was over 10 seconds. This was using Channel 1, which is also used by my home wifi. I did this on purpose, since I can't control the wifi usage at the site I will be using this.
For my application, it would be really bad to miss a transmission by a second or more. Even once.
Does any one know of any other settings I should look at, which would completely eliminate this delay? Or is this just the nature of using a wifi channel?
Transmitter code (with some of my metric collection code removed to make it smaller).
Receiver Code
Hi:
I am using ESP-NOW and two MELIFE ESP-WROOM-32 boards to send a simple ON/OFF trigger from one board to the other. It reads a GPIO input pin on the Transmit board, and sets a GPIO output pin on the Receiver board.
Using the example code, it didn't take me long to get it working, but I was getting a LOT of inconsistency in transmission success.
So, I used comments on this forum to improve reliability.
1) I included a message acknowledgement to confirm when the data is there
The transmitted message includes a message counter, which is incremented on each update
The Receiver receive callback includes sending the message back to the Transmitter.
The Transmitter will keep retransmitting until it sees that the confirmation message has the current counter
I put in a 5 ms delay in the re-transmission loop to minimize traffic
2) I added WiFi.setSleep(false) to the ESP-NOW setup, to prevent the device from going to sleep.
(This was a HUGE improvement).
3) I eliminated all Serial.print statements, and used the built in OLED display for debug and displaying the metrics.
4) I changed power supplies for both boards (plugging into my PC gave me the occasional brownout)
In general, I am now getting great performance. When testing with a 2 second external counter (with a 0.1 second ON, 1.9 second OFF cycle), 99.7% of the pulses are sent and confirmed within 50 ms, and 99.98% are sent and confirmed within 100ms. But in my last test, this still left me with 127 responses over 12 hours that took over 100ms, with at least one with over 1.5 seconds. In earlier tests, it was over 10 seconds. This was using Channel 1, which is also used by my home wifi. I did this on purpose, since I can't control the wifi usage at the site I will be using this.
For my application, it would be really bad to miss a transmission by a second or more. Even once.
Does any one know of any other settings I should look at, which would completely eliminate this delay? Or is this just the nature of using a wifi channel?
Transmitter code (with some of my metric collection code removed to make it smaller).
- /*
- * ESP-NOW test, based on sending ON and OFF commands,as triggered by a GPIO pin
- * TRANSMITTER
- */
- #include <esp_now.h>
- #include <WiFi.h>
- //MAC address of the other ESP32
- uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //Receiver
- bool sendStatus;
- int curONstatus;
- int inputStatus;
- int ON_command;
- int incoming_ID;
- int inputPin=13;
- //Send/Receive Structure
- typedef struct struct_message {
- int command; //an integer for the command. For this test 0=OFF, 1=ON
- long command_ID; //used as a unique ID for command receipt confirmation
- } struct_message;
- struct_message MyReadings;
- struct_message incomingReadings;
- // ESP-NOW Callback when data is sent
- void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
- sendStatus=status;
- }
- // ESP-NOW Callback when data is received
- void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
- memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
- ON_command = incomingReadings.command;
- incoming_ID=incomingReadings.command_ID;
- }
- void setup()
- {
- //Set up ESP-NOW
- WiFi.mode(WIFI_STA); // Initialize WiFi (needed for ESP-NOW)
- //disable sleep mode
- WiFi.setSleep(false);
- if (esp_now_init() != ESP_OK) {
- //Serial.println("Error initializing ESP-NOW");
- return;
- }
- esp_now_register_send_cb(OnDataSent);
- esp_now_peer_info_t peerInfo;
- memcpy(peerInfo.peer_addr, broadcastAddress, 6);
- peerInfo.channel = 11;
- peerInfo.encrypt = false;
- if (esp_now_add_peer(&peerInfo) != ESP_OK){
- // Serial.println("Failed to add peer");
- return;
- }
- // Register for a callback function that will be called when data is received
- esp_now_register_recv_cb(OnDataRecv);
- //setup GPIO
- pinMode(inputPin, INPUT_PULLUP);
- } //end setup()
- void loop()
- {
- //get input pin
- inputStatus=!digitalRead(inputPin); //invert it
- if (curONstatus!=inputStatus){ //look for a change in value
- // send data to receiver. This is blocking, and will loop until successful.
- MyReadings.command = inputStatus;
- MyReadings.command_ID++; //increment the command count
- while (incoming_ID!=MyReadings.command_ID){ //loop until the response matches the send value
- esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &MyReadings, sizeof(MyReadings));
- delay(5); //put in a delay to wait for a response from the receiver.
- //this prevents the transmitter from sending multiple times
- //a forum post said that the ESP32/ESP-NOW had a ~3 ms max rate
- }
- // < this is where I put in code that collected ON/OFF metrics >
- curONstatus=inputStatus; //reset the flag for the next loop
- }
- // < this is where I put in code to display metrics on the OLED display >
- delay(5); // delay before the next attempt
- } //end loop
- /*
- * ESP-NOW test, based on sending ON and OFF commands,as triggered by a GPIO pin
- * RECEIVER
- * OLED code and ON/OFF metrics collection removed
- */
- #include <esp_now.h>
- #include <WiFi.h>
- //MAC address of the other ESP32
- uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF6, 0xFF, 0xFF}; //Transmitter
- //Send/Receive Structure
- typedef struct struct_message {
- int command; //an integer for the command. For this test 0=OFF, 1=ON
- long command_ID; //used as a unique ID for command receipt confirmation
- } struct_message;
- struct_message MyReadings;
- struct_message incomingReadings;
- //variables to keep track of ON and OFF metrics
- int ON_command=0; //the command from the transmitter
- int curONstatus=0;
- long incoming_counter;
- void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
- memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
- ON_command = incomingReadings.command;
- incoming_counter= incomingReadings.command_ID;
- //Echo back the same data using ESP-NOW send
- MyReadings.command = ON_command;
- MyReadings.command_ID= incoming_counter;
- esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &MyReadings, sizeof(MyReadings));
- }
- void setup()
- {
- WiFi.mode(WIFI_STA); // Initialize WiFi (needed for ESP-NOW)
- //disable sleep mode
- WiFi.setSleep(false);
- if (esp_now_init() != ESP_OK) {
- // Serial.println("Error initializing ESP-NOW");
- return;
- }
- // Register peer
- esp_now_peer_info_t peerInfo;
- memcpy(peerInfo.peer_addr, broadcastAddress, 6);
- peerInfo.channel = 11;
- peerInfo.encrypt = false;
- // Add peer
- if (esp_now_add_peer(&peerInfo) != ESP_OK){
- //Serial.println("Failed to add peer");
- return;
- }
- // Register for a callback function that will be called when data is received
- esp_now_register_recv_cb(OnDataRecv);
- //initialize the OLED display
- //display.init();
- }
- void loop()
- {
- // < this is where I put in code that collected ON/OFF metrics
- // and display metrics on the OLED display >
- delay(5); // delay before loop
- } //end loop