OnDataSent callback function only gets called sometimes

Hello everyone, i have 3 Adafruit QT PY ESP32S2 boards that i am using ESP-NOW with to communicate with each other (two boards that gets the temperature using a DS18B20 sensor and sends it to one board that displays the temperature on a screen). I have got it to work but the callback function OnDataSent only gets called sometimes and the if-statement that checks if it got sent on line 128 says success even if the receiver is not getting any power.

Here is the code that doesn't work

#include <esp_now.h>
#include <WiFi.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Adafruit_NeoPixel.h>

#define NUMPIXELS 1 // How many neopixels i have

// Create a pixels instance to use the built in neopixel on the Adafruit QT PY ESP32-S2 with u.FL connector
Adafruit_NeoPixel pixels(NUMPIXELS, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);

// Data wire is plugged into pin 4 on the ESP32
#define ONE_WIRE_BUS 18

// Setup a oneWire instance to communicate with any OneWire devices
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 10          /* Time ESP32 will go to sleep (in seconds) */

// The recievers MAC address
uint8_t broadcastAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
  int id;  // must be unique for each sender board
  int size;
  int temp;
  int test;
} struct_message;

// Create a struct_message called readings
struct_message readings;

// Create peer interface
esp_now_peer_info_t peerInfo;

// 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");

  // Checks if the send was a success
  if (status == ESP_NOW_SEND_SUCCESS) {
    Serial.println("Delivery Success");
    pixels.fill(0x00FF00); // Turn the neopixel green
    pixels.show();
  } else {
    Serial.println("Delivery Fail");
    pixels.fill(0xFF0000); // Turn the neopixel red
    pixels.show();
  }

  delay(500); // Delay so that you can see the neopixel color
}

void setup() {
  // Init Serial Monitor
  Serial.begin(9600);
  Serial.setDebugOutput(true);
  delay(2000);
#if defined(NEOPIXEL_POWER)
  // If this board has a power control pin, we must set it to output and high
  // in order to enable the NeoPixels. We put this in an #if defined so it can
  // be reused for other boards without compilation errors
  pinMode(NEOPIXEL_POWER, OUTPUT);
  digitalWrite(NEOPIXEL_POWER, HIGH);
#endif

  pixels.begin();            // INITIALIZE NeoPixel strip object (REQUIRED)
  pixels.setBrightness(20);  // not so bright

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

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

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Transmitted packet
  esp_now_register_send_cb(OnDataSent); // I think this is where the problem is but i don't know what else the problem could be

  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;

  // Add peer
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }

  sensors.begin();  // IC Default 9 bit.

  //Print the wakeup reason for ESP32
  // print_wakeup_reason();

  // Set values to send
  sensors.requestTemperatures();  // Send the command to get temperatures

  readings.id = 1; // Set the id of the sender board
  readings.test = 1; // A test variable
  readings.temp = sensors.getTempCByIndex(0); // Get the temperature in °C

  // Checks if the temperature is -127, if it is then the wiring is probably incorrect
  if (readings.temp == -127.00) {
    Serial.println("Failed to read from DS18B20.");
  } else {
    Serial.println("Successfully read from DS18B20.");
  }

  readings.size = sizeof(readings); // Set readings.size to be the size of readings

  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&readings, sizeof(readings));

  // Checks if the data was sent with success (but even if the reciever is offline it still shows "Sent with success!")
  if (result == ESP_OK) {
    Serial.printf("Sent with success! %u bytes\n", readings.size);
  } else {
    Serial.println("Error sending the data");
  }

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 10 seconds
  */
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
  // esp_sleep_enable_ext0_wakeup(GPIO_NUM_17, 1);

  Serial.println("Going to sleep now");
  Serial.flush(); // Flush the Serial monitor (idk what it is used for)
  esp_deep_sleep_start(); // Go in to sleep
}

void loop() {
  // We will never get here
}

And here is the code that does work but i don't wanna use

#include <esp_now.h>
#include <WiFi.h>
#include <Adafruit_NeoPixel.h>

#define NUMPIXELS 1 // How many neopixels i have

// Create a pixels instance to use the built in neopixel on the Adafruit QT PY ESP32-S2 with u.FL connector
Adafruit_NeoPixel pixels(NUMPIXELS, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);

#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 10          /* Time ESP32 will go to sleep (in seconds) */

// The recievers MAC address
uint8_t broadcastAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // Yes i changed this when i uploaded the code to the real MAC address

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

// Create a struct_message called readings
struct_message readings;

// Create peer interface
esp_now_peer_info_t peerInfo;

// 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( ? "Delivery Success" : "Delivery Fail");
  if (status == ESP_NOW_SEND_SUCCESS) {
    Serial.println("Delivery Success");
    pixels.fill(0x00FF00);
    pixels.show();
    delay(500);
  } else {
    pixels.fill(0xFF0000);
    pixels.show();
    delay(500);
  }
}

void setup() {
  // Init Serial Monitor
  Serial.begin(9600);

  pixels.begin();            // INITIALIZE NeoPixel strip object (REQUIRED)
  pixels.setBrightness(20);  // not so bright

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

  // 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); // It works here, the OnDataSend callback function gets called

  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;

  // Add peer
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }

  // Set values to send
  strcpy(myData.a, "THIS IS A CHAR");
  myData.b = random(1, 20);
  myData.c = 1.2;
  myData.d = false;

  // 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");
  }

  delay(1000);

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 10 seconds
  */
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
  // esp_sleep_enable_ext0_wakeup(GPIO_NUM_17, 1);

  Serial.println("Going to sleep now");
  Serial.flush(); // Flush the Serial monitor (idk what it is used for)
  esp_deep_sleep_start(); // Go in to sleep
}

void loop() {
  // We will never get here
}

Any ideas of what makes it so that OnDataSent only gets called sometimes?
Thank you.

There is a difference between successfully sent and successfully received by someone else. That code just tells you it was successfully sent out into the ether.

You probably shouldn't have delay() or print calls in it. I found an example on github that states:

/* ESPNOW sending or receiving callback function is called in WiFi task.
 * Users should not do lengthy operations from this task. Instead, post
 * necessary data to a queue and handle it from a lower priority task. */

espnow_example_main.c

I don't think that is the problem, because the OnDataSent function in the code that works does have print() and delay() calls in it:

// 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( ? "Delivery Success" : "Delivery Fail");
  if (status == ESP_NOW_SEND_SUCCESS) {
    Serial.println("Delivery Success");
    pixels.fill(0x00FF00);
    pixels.show();
    delay(500);
  } else {
    pixels.fill(0xFF0000);
    pixels.show();
    delay(500);
  }

I also tried changing the code from:

// 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");

  // Checks if the send was a success
  if (status == ESP_NOW_SEND_SUCCESS) {
    Serial.println("Delivery Success");
    pixels.fill(0x00FF00); // Turn the neopixel green
    pixels.show();
  } else {
    Serial.println("Delivery Fail");
    pixels.fill(0xFF0000); // Turn the neopixel red
    pixels.show();
  }

  delay(500); // Delay so that you can see the neopixel color
}

To:

// 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");

  // Checks if the send was a success
  if (status == ESP_NOW_SEND_SUCCESS) {
    Serial.println("Delivery Success");
    pixels.fill(0x00FF00);
    pixels.show();
    delay(500);
  } else {
    pixels.fill(0xFF0000);
    pixels.show();
    delay(500);
  }

  // delay(500); // Delay so that you can see the neopixel color
}

This is still very good advise that you shouldn't ignore:

1 Like

Sorry for not replying to any messages. I was on my boat for a month and then forgot about this. Anyways I did get it to work, how tho, I don't know. I just uploaded the code and it worked as expected.

But thanks for the replies :heart:

As the saying goes "Problems that go away on their own will come back on their own". Usually at an inconvenient time.

You are using the broadcast mac-adress FF FF FF FF FF and that is causing that the
ondatasent callback says always success. Even with unpowered receiver
You must use the mac-adress of the receiver

Inside onDataSend you should only copy the status to a global variable set a flag that OnDataSend was called and then do all the rest from loop() especially the neopixel stuff

I only set the mac-address to FF FF FF FF FF when i uploaded the code here to this post. In the real code the MAC-address is correct

important information.

anyway transferring data to neopixels is a have and fast bitbanging that causes high processor-load. As I have written; change your code that inside OnDataSent does only copy the status to a global variable and set a flag that OnDataSent occured and then check in loop() if this flag is set. If it is set do all the neopixel stuff from loop().

best regards Stefan

I don't need to do any of that because it works now, but thanks anyway.

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