• Latency and Reliability Testing

    Jake Wachlin03/16/2019 at 21:07 4 comments

    Using a modified version of my basic example of ESP-NOW usage, I tested latency and reliability of this networking strategy. 

    The basic setup was that one device would send a message to another and start a timer. The receiving device would immediately send the message back to the original sender. Once the original device receives the echoed message, it stops the timer and records how long it took. An error counter is incremented if the message did not complete the round trip. I added padding bytes to the basic message format so that I could test sending messages of various sizes. I tested this for 1000 messages (sent at 5hz) with the two devices right next to each other on a desk (about 4 inches away), and with the devices across the room (about 128 inches away).

    This testing was performed in my apartment in a city, so the 2.4GHz spectrum is very full. I used WiFi channel 1, and did not choose it intelligently (e.g. based on the power there.) I don't expect anyone else to be able to get the exact same results, but this can be used as a guideline.

    The latency overall was good. The round trip latency is shown here, which includes some parsing/processing time. The latency for devices farther away seems to be slightly higher than for closer devices. The main concern with devices farther away seems to be the error rate. I expect this latency would be worse with encryption enabled.

    The error rate seen in this testing is surprisingly high, and increases quickly as the devices are moved apart. Unidirectional error rate is shown here, which is the half missed messages (since this test uses a round trip approach). If you plan to send important messages using ESP-NOW, you may want to incorporate some resend-until-confirmed-received setup to your firmware. Direct messaging instead of broadcasting may be more reliable, but that was not tested.

  • ESP-Now Introduction

    Jake Wachlin03/16/2019 at 19:31 4 comments

    I'd like to begin this log by noting that I am not a networking expert, so if something I say here is wrong, I'd love to know. At the same time, I know there are many people using the ESP32 who also are not networking experts and just need a working example they can modify to get multiple devices talking to each other. This work examines the example I developed and some of the issues I ran into while making it. The example allows one ESP32 device to blink an LED on another ESP32 device wirelessly, with no configuration (but also no security.) In the GIF below, the ESP32 device on the right acts as a sender, and the ESP32 on the left receives the messages and toggles its LED when it does. Note that "sender" and "receiver" only relate to my example. ESP-NOW supports two-way communication with no such designations.

    First, I recommend reading the documentation that Espressif provides about ESP-NOW. It will provide an overview of what ESP-NOW is. If you are not a networking person, a lot of the technical details probably don't mean a lot. But, as builders of things, many of us just want easy to use microcontrollers that can easily talk wirelessly to other microcontrollers. ESP-NOW can be used for that.

    My example is built on the concept of sending some arbitrary payload to all ESP32 devices within range, without security. To send to all devices, use the broadcast MAC address, which is all 0xFF.

    static uint8_t broadcast_mac[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

    We then define some payload to send. You can change this to whatever you want, as long as it is less than 250 bytes long, since that is the maximum size of the ESP-NOW data body. For my example, I include an address index and a counter. For another project of mine, I plan to build in some ad-hoc message addressing using this address index. The counter here is simply to monitor  how reliable the connection is.

    typedef struct __attribute__((packed)) esp_now_msg_t
      uint32_t address;
      uint32_t counter;
      // Can put lots of things here...
    } esp_now_msg_t;

     My example uses the Arduino ESP32 interface, which makes using the ESP32 very easy. Within the Arduino "setup" routine, I simply set up the Serial connection, the LED, and call my ESP-NOW setup function.

    void setup() {

    Within the network_setup function, I initialize  ESP-NOW using Espressifs API, as well as linking callback functions that are called upon sending or receiving of data. First, you must but the device into station mode, and disconnect WiFi (WiFi is likely not connected, but this is here in case it will be brought into someone else's code which uses WiFi also). 

    static void network_setup(void)
      //Puts ESP in STATION MODE

    Next, the "esp_now_init" function is called. This is Espressif's API. My code does not try to recover if it fails, but you may want to act upon the returned value.

      if (esp_now_init() != 0)

     The next step is critical, at least for how I wanted to use ESP-NOW. The other basic examples I've seen for this either require you to hardcode the MAC addresses of the other devices on your network into the firmware, or share the MAC addresses in a process where each "slave" node enters soft-AP mode, the master connects to it, and receives the MAC address, then switches into ESP-NOW mode. That feels very clunky and could span the air with large numbers of SSIDs only used for configuration. Instead, I set it up so all messages are broadcast to all other devices on the network. You can develop an ad-hoc addressing layer on top if you want. This ensures you can add a device to the network without knowing anything about the other devices.

      esp_now_peer_info_t peer_info;
      peer_info.channel = WIFI_CHANNEL;
      memcpy(peer_info.peer_addr, broadcast_mac, 6);
      peer_info.ifidx = ESP_IF_WIFI_STA;
      peer_info.encrypt = false;
    Read more »