ESP-NOW reliability - random 1 to 10 second delays

haunt_jR
Posts: 1
Joined: Mon Aug 31, 2020 11:45 am

ESP-NOW reliability - random 1 to 10 second delays

Postby haunt_jR » 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).
  1. /*
  2.  * ESP-NOW test, based on sending ON and OFF commands,as triggered by a GPIO pin
  3.  * TRANSMITTER
  4. */
  5.  
  6. #include <esp_now.h>
  7. #include <WiFi.h>
  8.  
  9. //MAC address of the other ESP32
  10. uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};  //Receiver
  11.  
  12. bool sendStatus;
  13. int curONstatus;
  14. int inputStatus;
  15. int ON_command;
  16. int incoming_ID;
  17. int inputPin=13;
  18.  
  19. //Send/Receive Structure
  20. typedef struct struct_message {
  21.     int command;         //an integer for the command.  For this test 0=OFF, 1=ON
  22.     long command_ID;  //used as a unique ID for command receipt confirmation
  23. } struct_message;
  24.  
  25. struct_message MyReadings;
  26. struct_message incomingReadings;    
  27.  
  28. // ESP-NOW Callback when data is sent
  29. void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  30.   sendStatus=status;
  31.   }
  32.  
  33. // ESP-NOW Callback when data is received
  34. void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  35.   memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
  36.   ON_command = incomingReadings.command;
  37.   incoming_ID=incomingReadings.command_ID;
  38. }
  39.  
  40. void setup()
  41. {
  42.   //Set up ESP-NOW
  43.   WiFi.mode(WIFI_STA);  // Initialize WiFi (needed for ESP-NOW)
  44.  
  45.   //disable sleep mode
  46.   WiFi.setSleep(false);    
  47.  
  48.   if (esp_now_init() != ESP_OK) {
  49.     //Serial.println("Error initializing ESP-NOW");
  50.     return;
  51.   }
  52.  
  53.   esp_now_register_send_cb(OnDataSent);
  54.   esp_now_peer_info_t peerInfo;
  55.   memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  56.   peerInfo.channel = 11;  
  57.   peerInfo.encrypt = false;
  58.  
  59.   if (esp_now_add_peer(&peerInfo) != ESP_OK){
  60.    // Serial.println("Failed to add peer");
  61.    return;
  62.   }
  63.  
  64.   // Register for a callback function that will be called when data is received
  65.   esp_now_register_recv_cb(OnDataRecv);
  66.  
  67.   //setup GPIO
  68.   pinMode(inputPin, INPUT_PULLUP);
  69. }  //end setup()  
  70.  
  71. void loop()
  72. {
  73.   //get input pin
  74.    inputStatus=!digitalRead(inputPin); //invert it
  75.  
  76.   if (curONstatus!=inputStatus){  //look for a change in value
  77.     // send data to receiver.  This is blocking, and will loop until successful.    
  78.     MyReadings.command = inputStatus;
  79.     MyReadings.command_ID++;  //increment the command count
  80.     while (incoming_ID!=MyReadings.command_ID){  //loop until the response matches the send value
  81.       esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &MyReadings, sizeof(MyReadings));
  82.       delay(5);  //put in a delay to wait for a response from the receiver.
  83.                  //this prevents the transmitter from sending multiple times
  84.                  //a forum post said that the ESP32/ESP-NOW had a ~3 ms max rate
  85.     }
  86.     // < this is where I put in code that collected ON/OFF metrics >
  87.     curONstatus=inputStatus;  //reset the flag for the next loop
  88.   }
  89.  
  90.   // < this is where I put in code to display metrics on the OLED display >
  91.  
  92.   delay(5);  // delay before the next attempt
  93. }  //end loop
Receiver Code
  1. /*
  2.  * ESP-NOW test, based on sending ON and OFF commands,as triggered by a GPIO pin
  3.  * RECEIVER
  4.  * OLED code and ON/OFF metrics collection removed
  5. */
  6.  
  7. #include <esp_now.h>
  8. #include <WiFi.h>
  9.  
  10. //MAC address of the other ESP32
  11. uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF6, 0xFF, 0xFF};  //Transmitter
  12.  
  13. //Send/Receive Structure
  14. typedef struct struct_message {
  15.     int command;         //an integer for the command.  For this test 0=OFF, 1=ON
  16.     long command_ID;  //used as a unique ID for command receipt confirmation
  17. } struct_message;
  18.  
  19. struct_message MyReadings;
  20. struct_message incomingReadings;
  21.  
  22. //variables to keep track of ON and OFF metrics
  23. int ON_command=0;  //the command from the transmitter
  24. int curONstatus=0;
  25. long incoming_counter;
  26.  
  27. void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  28.   memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
  29.   ON_command = incomingReadings.command;
  30.   incoming_counter= incomingReadings.command_ID;
  31.  
  32.   //Echo back the same data using ESP-NOW send
  33.   MyReadings.command = ON_command;
  34.   MyReadings.command_ID= incoming_counter;
  35.   esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &MyReadings, sizeof(MyReadings));
  36. }
  37.  
  38. void setup()
  39. {
  40.   WiFi.mode(WIFI_STA);  // Initialize WiFi (needed for ESP-NOW)
  41.   //disable sleep mode
  42.   WiFi.setSleep(false);
  43.  
  44.   if (esp_now_init() != ESP_OK) {
  45.     // Serial.println("Error initializing ESP-NOW");
  46.     return;
  47.   }
  48.  
  49.   // Register peer
  50.   esp_now_peer_info_t peerInfo;
  51.   memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  52.   peerInfo.channel = 11;  
  53.   peerInfo.encrypt = false;
  54.    
  55.   // Add peer        
  56.   if (esp_now_add_peer(&peerInfo) != ESP_OK){
  57.     //Serial.println("Failed to add peer");
  58.     return;
  59.   }
  60.   // Register for a callback function that will be called when data is received
  61.   esp_now_register_recv_cb(OnDataRecv);
  62.  
  63.   //initialize the OLED display
  64.   //display.init();
  65. }  
  66.  
  67. void loop()
  68. {  
  69.   // < this is where I put in code that collected ON/OFF metrics
  70.   //   and display metrics on the OLED display >
  71.   delay(5);  // delay before loop
  72. }  //end loop

Who is online

Users browsing this forum: No registered users and 83 guests