ESPNOW - Numerous 'espnow var was not declared in this scope'

Hello,

I’ve just discovered PlatformIO and wish to thank everyone involved for this great development tool. And to wish God speed to the peoples of Ukraine during these deeply trying times.

My issue is with building ESPNOW code for the ESP-01 board. Compile errors are all centered around 'espnowxxx was not declared in this scope’ errors, it’s as if a header file is missing. But I have included what I think are the correct include files:

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

Please can anyone shed light on these errors. I have successfully uploaded and executed various WiFi examples to this ESP-01 board which all work fine, it’s appears only ESPNOW is presenting a problem.

Many thanks,
Jack.

platformio.ini

; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:esp01_1m]
platform = espressif8266
board = esp01_1m
framework = arduino
monitor_speed = 115200
upload_port = COM5

Code:

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

bool buttonDown = false;
bool ledOn = false;

void formatMacAddress(const uint8_t *macAddr, char *buffer, int maxLength)
{
  snprintf(buffer, maxLength, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
}

void receiveCallback(const uint8_t *macAddr, const uint8_t *data, int dataLen)
{
  // only allow a maximum of 250 characters in the message + a null terminating byte
  char buffer[ESP_NOW_MAX_DATA_LEN + 1];
  int msgLen = min(ESP_NOW_MAX_DATA_LEN, dataLen);
  strncpy(buffer, (const char *)data, msgLen);
  // make sure we are null terminated
  buffer[msgLen] = 0;
  // format the mac address
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);
  // debug log the message to the serial port
  Serial.printf("Received message from: %s - %s\n", macStr, buffer);
  // what are our instructions
  if (strcmp("on", buffer) == 0)
  {
    ledOn = true;
  }
  else
  {
    ledOn = false;
  }
  digitalWrite(2, ledOn);
}

// callback when data is sent
void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status)
{
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);
  Serial.print("Last Packet Sent to: ");
  Serial.println(macStr);
  Serial.print("Last Packet Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void broadcast(const String &message)
{
  // this will broadcast a message to everyone in range
  uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  esp_now_peer_info_t peerInfo = {};
  memcpy(&peerInfo.peer_addr, broadcastAddress, 6);
  if (!esp_now_is_peer_exist(broadcastAddress))
  {
    esp_now_add_peer(&peerInfo);
  }
  esp_err_t result = esp_now_send(broadcastAddress, (const uint8_t *)message.c_str(), message.length());
  // and this will send a message to a specific device
  /*uint8_t peerAddress[] = {0x3C, 0x71, 0xBF, 0x47, 0xA5, 0xC0};
  esp_now_peer_info_t peerInfo = {};
  memcpy(&peerInfo.peer_addr, peerAddress, 6);
  if (!esp_now_is_peer_exist(peerAddress))
  {
    esp_now_add_peer(&peerInfo);
  }
  esp_err_t result = esp_now_send(peerAddress, (const uint8_t *)message.c_str(), message.length());*/
  if (result == ESP_OK)
  {
    Serial.println("Broadcast message success");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_INIT)
  {
    Serial.println("ESPNOW not Init.");
  }
  else if (result == ESP_ERR_ESPNOW_ARG)
  {
    Serial.println("Invalid Argument");
  }
  else if (result == ESP_ERR_ESPNOW_INTERNAL)
  {
    Serial.println("Internal Error");
  }
  else if (result == ESP_ERR_ESPNOW_NO_MEM)
  {
    Serial.println("ESP_ERR_ESPNOW_NO_MEM");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_FOUND)
  {
    Serial.println("Peer not found.");
  }
  else
  {
    Serial.println("Unknown error");
  }
}

void setup()
{
  Serial.begin(115200);
  delay(1000);
  //Set device in STA mode to begin with
  WiFi.mode(WIFI_STA);
  Serial.println("ESPNow Example");
  // Output my MAC address - useful for later
  Serial.print("My MAC Address is: ");
  Serial.println(WiFi.macAddress());
  // shut down wifi
  WiFi.disconnect();
  // startup ESP Now
  if (esp_now_init() == ESP_OK)
  {
    Serial.println("ESPNow Init Success");
    esp_now_register_recv_cb(receiveCallback);
    esp_now_register_send_cb(sentCallback);
  }
  else
  {
    Serial.println("ESPNow Init Failed");
    delay(3000);
    ESP.restart();
  }
  // use the built in button
  pinMode(0, INPUT_PULLUP);
  pinMode(2, OUTPUT);
}

void loop()
{
  if (digitalRead(0))
  {
    // detect the transition from low to high
    if (!buttonDown)
    {
      buttonDown = true;
      // toggle the LED state
      ledOn = !ledOn;
      digitalWrite(2, ledOn);
      // send a message to everyone else
      if (ledOn)
      {
        broadcast("on");
      }
      else
      {
        broadcast("off");
      }
    }
    // delay to avoid bouncing
    delay(500);
  }
  else
  {
    // reset the button state
    buttonDown = false;
  }
}

Build Log:

Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif8266/esp01_1m.html
PLATFORM: Espressif 8266 (3.2.0) > Espressif Generic ESP8266 ESP-01 1M
HARDWARE: ESP8266 80MHz, 80KB RAM, 1MB Flash
PACKAGES:
 - framework-arduinoespressif8266 3.30002.0 (3.0.2)
 - tool-esptool 1.413.0 (4.13) 
 - tool-esptoolpy 1.30000.201119 (3.0.0)
 - toolchain-xtensa 2.100300.210717 (10.3.0)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 35 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <ESP8266WiFi> 1.0
Building in release mode
Compiling .pio\build\esp01_1m\src\main.cpp.o
Compiling .pio\build\esp01_1m\libd82\ESP8266WiFi\ESP8266WiFiGeneric.cpp.o
Compiling .pio\build\esp01_1m\libd82\ESP8266WiFi\ESP8266WiFiGratuitous.cpp.o
Compiling .pio\build\esp01_1m\libd82\ESP8266WiFi\ESP8266WiFiMulti.cpp.o
Compiling .pio\build\esp01_1m\libd82\ESP8266WiFi\ESP8266WiFiSTA-WPS.cpp.o
src\main.cpp: In function 'void receiveCallback(const uint8_t*, const uint8_t*, int)':src\main.cpp:16:15: error: 'ESP_NOW_MAX_DATA_LEN' was not declared in this scope
   16 |   char buffer[ESP_NOW_MAX_DATA_LEN + 1];
      |               ^~~~~~~~~~~~~~~~~~~~
src\main.cpp:18:11: error: 'buffer' was not declared in this scope; did you mean 'setbuffer'?
   18 |   strncpy(buffer, (const char *)data, msgLen);
      |           ^~~~~~
      |           setbuffer
src\main.cpp: At global scope:
src\main.cpp:39:43: error: 'esp_now_send_status_t' has not been declared
   39 | void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status)       
      |                                           ^~~~~~~~~~~~~~~~~~~~~
src\main.cpp: In function 'void sentCallback(const uint8_t*, int)':
src\main.cpp:46:28: error: 'ESP_NOW_SEND_SUCCESS' was not declared in this scope      
   46 |   Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
      |                            ^~~~~~~~~~~~~~~~~~~~
src\main.cpp: In function 'void broadcast(const String&)':
src\main.cpp:53:3: error: 'esp_now_peer_info_t' was not declared in this scope; did you mean 'esp_now_deinit'?
   53 |   esp_now_peer_info_t peerInfo = {};
      |   ^~~~~~~~~~~~~~~~~~~
      |   esp_now_deinit
src\main.cpp:54:11: error: 'peerInfo' was not declared in this scope
   54 |   memcpy(&peerInfo.peer_addr, broadcastAddress, 6);
      |           ^~~~~~~~
src\main.cpp:59:3: error: 'esp_err_t' was not declared in this scope
   59 |   esp_err_t result = esp_now_send(broadcastAddress, (const uint8_t *)message.c_str(), message.length());
      |   ^~~~~~~~~
src\main.cpp:69:7: error: 'result' was not declared in this scope
   69 |   if (result == ESP_OK)
      |       ^~~~~~
src\main.cpp:69:17: error: 'ESP_OK' was not declared in this scope; did you mean 'ERR_OK'?
   69 |   if (result == ESP_OK)
      |                 ^~~~~~
      |                 ERR_OK
src\main.cpp:73:22: error: 'ESP_ERR_ESPNOW_NOT_INIT' was not declared in this scope   
   73 |   else if (result == ESP_ERR_ESPNOW_NOT_INIT)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~
src\main.cpp:77:22: error: 'ESP_ERR_ESPNOW_ARG' was not declared in this scope
   77 |   else if (result == ESP_ERR_ESPNOW_ARG)
      |                      ^~~~~~~~~~~~~~~~~~
src\main.cpp:81:22: error: 'ESP_ERR_ESPNOW_INTERNAL' was not declared in this scope
   81 |   else if (result == ESP_ERR_ESPNOW_INTERNAL)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~
src\main.cpp:85:22: error: 'ESP_ERR_ESPNOW_NO_MEM' was not declared in this scope
   85 |   else if (result == ESP_ERR_ESPNOW_NO_MEM)
      |                      ^~~~~~~~~~~~~~~~~~~~~
src\main.cpp:89:22: error: 'ESP_ERR_ESPNOW_NOT_FOUND' was not declared in this scope
   89 |   else if (result == ESP_ERR_ESPNOW_NOT_FOUND)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~
src\main.cpp: In function 'void setup()':
src\main.cpp:112:25: error: 'ESP_OK' was not declared in this scope; did you mean 'ERR_OK'?
  112 |   if (esp_now_init() == ESP_OK)
      |                         ^~~~~~
      |                         ERR_OK
src\main.cpp:115:30: error: invalid conversion from 'void (*)(const uint8_t*, const uint8_t*, int)' {aka 'void (*)(const unsigned char*, const unsigned char*, int)'} to 'esp_now_recv_cb_t' {aka 'void (*)(unsigned char*, unsigned char*, unsigned char)'} [-fpermissive]
  115 |     esp_now_register_recv_cb(receiveCallback);
      |                              ^~~~~~~~~~~~~~~
      |                              |
      |                              void (*)(const uint8_t*, const uint8_t*, int) {aka void (*)(const unsigned char*, const unsigned char*, int)}
In file included from src\main.cpp:3:
C:\Users\user\.platformio\packages\framework-arduinoespressif8266\tools\sdk\include/espnow.h:50:48: note:   initializing argument 1 of 'int esp_now_register_recv_cb(esp_now_recv_cb_t)'
   50 | int esp_now_register_recv_cb(esp_now_recv_cb_t cb);
      |                              ~~~~~~~~~~~~~~~~~~^~
src\main.cpp:116:30: error: invalid conversion from 'void (*)(const uint8_t*, int)' {aka 'void (*)(const unsigned char*, int)'} to 'esp_now_send_cb_t' {aka 'void (*)(unsigned char*, unsigned char)'} [-fpermissive]
  116 |     esp_now_register_send_cb(sentCallback);
      |                              ^~~~~~~~~~~~
      |                              |
      |                              void (*)(const uint8_t*, int) {aka void (*)(const unsigned char*, int)}
In file included from src\main.cpp:3:
C:\Users\user\.platformio\packages\framework-arduinoespressif8266\tools\sdk\include/espnow.h:47:48: note:   initializing argument 1 of 'int esp_now_register_send_cb(esp_now_send_cb_t)'
   47 | int esp_now_register_send_cb(esp_now_send_cb_t cb);
      |                              ~~~~~~~~~~~~~~~~~~^~
*** [.pio\build\esp01_1m\src\main.cpp.o] Error 1
============================= [FAILED] Took 3.28 seconds =============================The terminal process "C:\Users\user\.platformio\penv\Scripts\platformio.exe 'run'" terminated with exit code: 1.

Terminal will be reused by tasks, press any key to close it.

?

You are using APIs from the Arduino-ESP32 version of the ESPNOW library, ESP-NOW - ESP32 - — ESP-IDF Programming Guide latest documentation.

Can you try ESP8266-based examples? Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE) | Random Nerd Tutorials

[env:esp01_1m]
platform = espressif8266
board = esp01_1m
framework = arduino
monitor_speed = 115200
upload_port = COM5

with src/main.cpp of

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

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    String d;
    bool e;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t 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();
}

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);

  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {

}

compiles fine for me

RAM:   [===       ]  34.5% (used 28256 bytes from 81920 bytes)
Flash: [====      ]  35.3% (used 269013 bytes from 761840 bytes)
Building .pio\build\esp01_1m\firmware.bin
Creating BIN file ".pio\build\esp01_1m\firmware.bin" using "C:\Users\Max\.platformio\packages\framework-arduinoespressif8266\bootloaders\eboot\eboot.elf" and ".pio\build\esp01_1m\firmware.elf"
============== [SUCCESS] Took 11.71 seconds ==============

Can you confirm?

Thank you Maximilian, yes your code example compiles. I have yet to find out if there are incompatibilities in an ESP8266 talking with an ESP32 using ESPNow, e.g. payload max length, etc.

I didn’t realise ESPNow code was more than just including the different header files to make ESP32 code work on ESP8266.

I have not come across documentation on this subject, so any references you can suggest would be welcome.

Thanks again,
Jack.

The ultimate documentation truth is the used header file: Arduino/espnow.h at master · esp8266/Arduino · GitHub

Indeed, no documentation on ESPNOW for Arduino-ESP8266 is listed in Welcome to ESP8266 Arduino Core’s documentation! — ESP8266 Arduino Core 3.0.2 documentation. However, since the core builds on the Espressif NONOS SDK (Arduino/tools/sdk/lib at master · esp8266/Arduino · GitHub), and as such, documentation of ESPNOW on ESP8266 is available through them: Technical Documents | Espressif Systems

Or more directly

^-- Chapter 3.8 “ESP-NOW APIs”.

The extra mile is much appreciated.
A truly complete and useful reply.
:slightly_smiling_face: