esp_now_register_send_cb(OnDataSent); won't compile

I had a esp now example from this website
working using (3) XAIO ESP32-C3's. This was a couple weeks ago. I started up the arduino IDE yesterday for the first time in a while and it made me sit threw some long updates and now the sender_board.ino doesn't compile:

C:\Users\raweg\dev\Ardiuno\sender_board_2\sender_board_2.ino: In function 'void setup()':
C:\Users\raweg\dev\Ardiuno\sender_board_2\sender_board_2.ino:132:28: error: invalid conversion from 'void (*)(const uint8_t*, esp_now_send_status_t)' {aka 'void (*)(const unsigned char*, esp_now_send_status_t)'} to 'esp_now_send_cb_t' {aka 'void (*)(const wifi_tx_info_t*, esp_now_send_status_t)'} [-fpermissive]
  132 |   esp_now_register_send_cb(OnDataSent);
      |                            ^~~~~~~~~~
      |                            |
      |                            void (*)(const uint8_t*, esp_now_send_status_t) {aka void (*)(const unsigned char*, esp_now_send_status_t)}
In file included from C:\Users\raweg\dev\Ardiuno\sender_board_2\sender_board_2.ino:7:
C:\Users\raweg\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-b66b5448-v1\esp32c3/include/esp_wifi/include/esp_now.h:185:54: note:   initializing argument 1 of 'esp_err_t esp_now_register_send_cb(esp_now_send_cb_t)'
  185 | esp_err_t esp_now_register_send_cb(esp_now_send_cb_t cb);
      |                                    ~~~~~~~~~~~~~~~~~~^~
exit status 1

Compilation error: invalid conversion from 'void (*)(const uint8_t*, esp_now_send_status_t)' {aka 'void (*)(const unsigned char*, esp_now_send_status_t)'} to 'esp_now_send_cb_t' {aka 'void (*)(const wifi_tx_info_t*, esp_now_send_status_t)'} [-fpermissive]
1 Like
/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-esp-now-wi-fi-web-server/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
//#include <Adafruit_Sensor.h>
//#include <DHT.h>

// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 1

// Digital pin connected to the DHT sensor
#define DHTPIN 4  

// Uncomment the type of sensor in use:
//#define DHTTYPE    DHT11     // DHT 11
#define DHTTYPE    DHT22     // DHT 22 (AM2302)
//#define DHTTYPE    DHT21     // DHT 21 (AM2301)

//DHT dht(DHTPIN, DHTTYPE);

//MAC Address of the receiver 
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
float h = 0.02;
float t = 0.01;

//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
    int id;
    float temp;
    float hum;
    int readingId;
} struct_message;

esp_now_peer_info_t peerInfo;

//Create a struct_message called myData
struct_message myData;

unsigned long previousMillis = 0;   // Stores last time temperature was published
//const long interval = 2200;        // Interval at which to publish sensor readings
const long interval = 5200;        // Interval at which to publish sensor readings

unsigned int readingId = 0;

// Insert your SSID
constexpr char WIFI_SSID[] = "extra ssid";

int32_t getWiFiChannel(const char *ssid) {
  if (int32_t n = WiFi.scanNetworks()) {
      for (uint8_t i=0; i<n; i++) {
          if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
              return WiFi.channel(i);
          }
      }
  }
  return 0;
}

float readDHTTemperature(float t) {
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  // Read temperature as Celsius (the default)
  //float t = dht.readTemperature();
  t = t + 0.02;
  if(t > 20)
	  t = 0.01;
  // Read temperature as Fahrenheit (isFahrenheit = true)
  //float t = dht.readTemperature(true);
  // Check if any reads failed and exit early (to try again).
  if (isnan(t)) {    
    Serial.println("Failed to read from DHT sensor!");
    return 0;
  }
  else {
    Serial.println(t);
    return t;
  }
}

float readDHTHumidity(float h) {
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  //float h = dht.readHumidity();
  h = h + 0.01;
  if(h > 20)
	  h = 0.01;
  if (isnan(h)) {
    Serial.println("Failed to read from DHT sensor!");
    return 0;
  }
  else {
    Serial.println(h);
    return h;
  }
}

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
 
void setup() {
  //Init Serial Monitor
  Serial.begin(115200);

  //dht.begin();
 
  // Set device as a Wi-Fi Station and set channel
  WiFi.mode(WIFI_STA);

  int32_t channel = getWiFiChannel(WIFI_SSID);

  WiFi.printDiag(Serial); // Uncomment to verify channel number before
  esp_wifi_set_promiscuous(true);
  esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
  esp_wifi_set_promiscuous(false);
  WiFi.printDiag(Serial); // Uncomment to verify channel change after

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

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // Save the last time a new reading was published
    previousMillis = currentMillis;
    //Set values to send
    myData.id = BOARD_ID;
    t = myData.temp = readDHTTemperature(t);
    h = myData.hum = readDHTHumidity(h);
    myData.readingId = readingId++;
     
    //Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    if (result == ESP_OK) {
      Serial.println("Sent with success");
    }
    else {
      Serial.println("Error sending the data");
    }
  }
}


above is what I'm using for the (2) sender board. I'm supposed to have a couple sensors but the routines that read the sensors just put out some fake values. And that's what gets sent to the receiver board.

Just a WAG, but I would imagine that one of those updates took your ESP32 core platform from 2.x to 3.x. Which involves many, many, breaking changes.

If this is what happened, you can peruse the 2.x to 3.x migration document found somewhere on Espressif's site and rewrite the offending code, or you can roll back to 2.x and continue on.

1 Like

I installed the previous version 1.8.19 and I get the same error:

error: invalid conversion from 'void (*)(const uint8_t*, esp_now_send_status_t)' {aka 'void (*)(const unsigned char*, esp_now_send_status_t)'} to 'esp_now_send_cb_t' {aka 'void (*)(const wifi_tx_info_t*, esp_now_send_status_t)'} [-fpermissive]
  132 |   esp_now_register_send_cb(OnDataSent);

@van_der_decken did not mention to use a different IDE. He suggested to use an older version of th ESP32 board package.

I went to board mgr and for 'ESP Async Webserver' set the version back to 2.1.2 and same error. This was with both versions 2.3.6 and the older one.

this fixed it:

//esp_now_register_send_cb(OnDataSent);
  esp_now_register_send_cb((esp_now_send_cb_t)OnDataSent);

Thank you, I had the same problem and I've fixed it :star_struck:

That's a library in the Library Manager, third icon down the left side of the IDE -- looks like some books. In the Boards Manager, the second icon that looks kinda like an Uno board, the board package is probably esp32 by Espressif Systems.

The board package name is also the top-level name under Tools > Board in the menu. The first menu item also opens the Boards Manager. Under that is each board package. Arduino AVR Boards is installed by default. The currently active board package is indicated in the menu.


The specific board is selected in the sub-menu.

This appears to be a more recent break. Here's the diff, four months ago

- typedef void (*esp_now_send_cb_t)(const uint8_t *mac_addr, esp_now_send_status_t status);
+ typedef void (*esp_now_send_cb_t)(const esp_now_send_info_t *tx_info, esp_now_send_status_t status);

It was first released in ESP-IDF v5.5; listed as the first of several Breaking Changes. (The ESP-IDF Programming Guide no longer contains complete formatted API reference info after v5.3 -- I guess you're supposed to use the link to the header in GitHub.)

esp32 v3.3.0 is based on IDF v5.5.0. That was two weeks ago.

Generally that's akin to fashioning a contraption out of aluminum foil so that you can "plug in" your TV into that oddly triangular outlet next to the washing machine. Note that this also compiles without a warning

  esp_now_register_send_cb((esp_now_send_cb_t)setup);  // don't do this

However, in this specific case, you can get away with it since the new type

typedef wifi_tx_info_t esp_now_send_info_t;

is actually

typedef struct {
    uint8_t *des_addr;           /**< The address of the receive device */
    uint8_t *src_addr;           /**< The address of the sending device */
    wifi_interface_t ifidx;      /**< Interface of sending 80211 tx data */
    uint8_t *data;               /**< The data for 80211 tx, start from the MAC header */
    uint8_t data_len;            /**< The frame body length for 80211 tx, excluding the MAC header */
    wifi_phy_rate_t rate;        /**< Data rate */
    wifi_tx_status_t tx_status;  /**< Status of sending 80211 tx data */
} wifi_tx_info_t;

where the first field is still a pointer to the sent-to MAC address. The cast is the suggested and accepted fix for this same issue in the repo but it's sloppy.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.