ESP-NOW can't send a string lonher than 6 characters

Hi, is my first project with esp now…so probably the error will be really stupid… i need to build a string with multiple value (in this project i start sending just temperature) and send it rhrough esp now… but if the string is shorter than 6 character i have no problem… with more than six it does not work…

Any sujjestion? thanks a lot :slight_smile:

Those are the sketches

for sender (ESP32)

#include <esp_now.h>
#include <WiFi.h>
float tempC;
String pippo;

// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x5C, 0xCF, 0x7F, 0x55, 0xF6, 0xE1};

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
  String d;
} struct_message;

// Create a struct_message called myData
struct_message myData;

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

#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) */

RTC_DATA_ATTR int bootCount = 0;

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 5 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");

  /*
  Next we decide what all peripherals to shut down/keep on
  By default, ESP32 will automatically power down the peripherals
  not needed by the wakeup source, but if you want to be a poweruser
  this is for you. Read in detail at the API docs
  http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
  Left the line commented as an example of how to configure peripherals.
  The line below turns off all RTC peripherals in deep sleep.
  */
  //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  //Serial.println("Configured all RTC Peripherals to be powered down in sleep");

  // 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);
  
  // Register peer
  esp_now_peer_info_t peerInfo;
  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;
  }

  //get temperature
  gradi();

  //create a complete string to send
  pippo = "http://xxxxxx.000webhostapp.com/ricez_a2.php/?luogo=Brent&temp=" + String(tempC);

  // Set values to send
  
  myData.d = pippo;
  
  // 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(2000);

  /*
  Now that we have setup a wake cause and if needed setup the
  peripherals state in deep sleep, we can now start going to
  deep sleep.
  In the case that no wake up sources were provided but deep
  sleep was started, it will sleep forever unless hardware
  reset occurs.
  */
  Serial.println("Going to sleep now");
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void gradi(){
  int adcVal = analogRead(34);
  // Calculate voltage
  float v = adcVal * 3.3 / 4095;
  // Calculate resistance value of thermistor
  float Rt = 10 * v / (5 - v);
  // Calculate temperature (Kelvin)
  float tempK = 1 / (log(Rt / 10) / 3950 + 1 / (273.15 + 25));
  // Calculate temperature (Celsius)
  tempC = tempK - 273.15;
}


void loop(){
  //This is not going to be called
}

And this for reciver

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


// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
    String d;
} 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("String: ");
  Serial.println(myData.d);
}
 
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() {

}

if is a problem i can add the rest of the string once recived…but i was wander why it doesn’t work is there a limit for string length?

Thank you very much!

You should not be using the String class in your data structure. It dynamically allocates space to hold whatever string (lower case 's') you are sending. When you first create it, it doesn't have any space allocated but your receiver is doing a memcpy() the size of whatever is received.

In the receiver code, try putting in a Serial.println(sizeof(myData)); and you will see it is much smaller than what your are trying to cram into it.

You may be able to use the reserve() function to make it larger before the memcpy(), but there is no guarantee that doing a blind memcpy() into a String object will do the correct thing.

You would be much better off using a regular c-string (array of char) that has a predefined size and make sure all your messages are less than that.

Great suggestion i solved converting with toCharArray() like this :slight_smile:

#include <esp_now.h>
#include <WiFi.h>
float tempC;
String pippo;

// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x5C, 0xCF, 0x7F, 0x55, 0xF6, 0xE1};

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
  char a[85];
} struct_message;

// Create a struct_message called myData
struct_message myData;

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

#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) */

RTC_DATA_ATTR int bootCount = 0;

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 5 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");

  /*
  Next we decide what all peripherals to shut down/keep on
  By default, ESP32 will automatically power down the peripherals
  not needed by the wakeup source, but if you want to be a poweruser
  this is for you. Read in detail at the API docs
  http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
  Left the line commented as an example of how to configure peripherals.
  The line below turns off all RTC peripherals in deep sleep.
  */
  //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  //Serial.println("Configured all RTC Peripherals to be powered down in sleep");

  // 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);
  
  // Register peer
  esp_now_peer_info_t peerInfo;
  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;
  }

  //get temperature
  gradi();

  //create a string with all data
  pippo = "a1.php/?luogo=Brent&temp=" + String(tempC) + "&peso=100.00";
  
  // Set values to send
  pippo.toCharArray(myData.a, 85);  
  Serial.println(myData.a);
  
  // 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(2000);

  /*
  Now that we have setup a wake cause and if needed setup the
  peripherals state in deep sleep, we can now start going to
  deep sleep.
  In the case that no wake up sources were provided but deep
  sleep was started, it will sleep forever unless hardware
  reset occurs.
  */
  Serial.println("Going to sleep now");
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void gradi(){
  int adcVal = analogRead(34);
  // Calculate voltage
  float v = adcVal * 3.3 / 4095;
  // Calculate resistance value of thermistor
  float Rt = 10 * v / (5 - v);
  // Calculate temperature (Kelvin)
  float tempK = 1 / (log(Rt / 10) / 3950 + 1 / (273.15 + 25));
  // Calculate temperature (Celsius)
  tempC = tempK - 273.15;
}


void loop(){
  //This is not going to be called
}

now everithing arrive to esp8266 without problems… next step is to send those char array to Mega2560 connected through serial… i was just serialprinting the chararray and then i used to do readstring() on Mega… but also here there are problems with length…

Do i need to do a char array also here? is there a easy way or i must copy shar by char?
My code on Mega was this

String data;

void setup() {
  // Note the format for setting a serial port is as follows: Serial2.begin(baud-rate, protocol, RX pin, TX pin);
  Serial.begin(115200);
  Serial3.begin(115200);
}
 
void loop() {
 letturaESP();
 delay(20000); 
}

void letturaESP(){
  data="";
  if (Serial3.available()>0)
  {
    data=Serial3.readString();
    Serial.println("La mia stringa è: ");
    Serial.print(data);   
  } 
}

Thank you very much :slight_smile:

Serial.readString() returns the String just read from the Serial port.

BUT, it is much better to NOT use the String class, especially on AVR controllers with very limited memory. Read Robin2s excellent tutorial Serial Input Basics for how to do it properly without Strings.

Thanks. i’ve used his examples…i think it works quite good but there are still problems…i think is fault of the senders…here is the code… if i use serial.println the reciver will recive the char array but with some toublr…
if i use serial.write it doesn’t recive nothing…where am is the error?

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


// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
    char a[85];
} 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.write(myData.a);
  Serial.flush();
}
 
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() {

}

and code of the reciver modified with your suggestions :slight_smile:

const byte numChars = 85;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void setup() {
  // Note the format for setting a serial port is as follows: Serial2.begin(baud-rate, protocol, RX pin, TX pin);
  Serial.begin(115200);
  Serial3.begin(115200);
  Serial2.begin(9600);
  Serial.println("Serialbegin ok");
}
 
void loop() {
 letturaESP();
 delay(20000); 
}

void letturaESP(){
    recvWithEndMarker();
    showNewData();
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
   
    while (Serial3.available() > 0 && newData == false) {
        rc = Serial3.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        //carico();
        newData = false;
    }
}

Sounds like you need a couple of debug statements in there to figure out what you are actually sending.

But i see it when i connect my esp on the serial monitor the result of Serial.println is right.. do i need to use serial.print on esp sender or Serial.write? And how can i check what i send?

Thank you very much :slight_smile:

If the serial monitor is connected, you can't also connect your Mega to the same pins. I'm a bit confused about your connections.

ESP32 -->(wireless)--> ESP8266 -->(Serial)--> Mega

You could always use the SerialTransfer library. It may also be better to use SoftSerial for the ESP8266 and use different pins to connect to the Mega and leave the serial port available for debug

blh64:
ESP32 -->(wireless)--> ESP8266 -->(Serial)--> Mega

Yes this is my connection between the 3 boards

You could always use the SerialTransfer library. It may also be better to use SoftSerial for the ESP8266 and use different pins to connect to the Mega and leave the serial port available for debug

i can connect esp8266 with mega only with Serial3 port becouse im using this board https://usa.banggood.com/Geekcreit-Mega-WiFi-R3-Module-ATmega2560ESP8266-32Mb-Memory-USB-TTL-CH340G-p-1205437.html?cur_warehouse=UK

Wich is a Mega with embedded esp8266 and they comunicate with Serial3 port..

I have uload the sketch on esp8266 and it works the i see what 8266 print through serial..the only problems is communication betwen esp8266 and Mega but is a common communications through serial port..

Thank you very much :slight_smile:

I think i fix it..tomorrow i will debug better..but i think the problem was that esp8266 printed on serial two times while Mega wasn’t reading..so once i reed on Mega i read two strings instead of one..now i have reduced the delay for mega and it seams to work :)! Thank s again for your suggestion you have helped me a lot to find the way :)!