ESP32 "Stack smashing protect failure!" When sending specific SMS

Hello all,

I am working on a project for which I intended to use an arduino nano EVERY because of its large memory, unfortunately I fried it while attempting to resolve voltage drop issues. I had a ESP32 laying around so I'm using that to replace the Every and I'm currently adapting the sketches to it.

I've run into a frustrating issues with the SMS alerts the sketch is supposed to send. The sketch sends an SMS alert when a flow sensor has counted over 300mL of fluid or when a float switch/reed switch is opened, an SMS alerts when a DS18B20 reads a temperature below 45 degrees Fahrenheit, and an SMS alert when the battery percent level is below 20%. It also posts data via dweet to a dashboard every 60 seconds.

I had zero issues with this using the nano every, but there is one issue i'm facing when using the ESP32. the SMS alerts for full and temperature get sent without issue, but when the low battery SMS is sent, the serial monitor reads:

19:03:17.157 -> 	---> 19.00 [%] BATTERY LOW!
19:03:19.065 -> Sent text alert!
19:03:19.065 -> 
19:03:19.065 -> Stack smashing protect failure!
19:03:19.111 -> 
19:03:19.111 -> abort() was called at PC 0x400e6090 on core 1
19:03:19.111 -> 
19:03:19.111 -> ELF file SHA256: 0000000000000000
19:03:19.111 -> 
19:03:19.111 -> Backtrace: 0x40085c10:0x3ffb1ed0 0x40085e85:0x3ffb1ef0 0x400e6090:0x3ffb1f10 0x400d1495:0x3ffb1f30 0x400d1a72:0x3ffb1f70 0x400d5181:0x3ffb1fb0 0x40086e95:0x3ffb1fd0
19:03:19.111 -> 
19:03:19.111 -> Rebooting...

the peculiarity is that this issue only happens for the battery SMS function, and never for any other function . The percent is calculated using MultiMap() function and is declared as an int, while tempF is declared a float and totalMililitres is declared as unsigned long. I changed percent to a float and it still does the same thing

I've attached my code in this thread, would really appreciate some feedback and assistance

thanks!

// For SIM7000 cellular shield
#include "Adafruit_FONA.h" // https://github.com/botletics/SIM7000-LTE-Shield/tree/master/Code
#include <SoftwareSerial.h>
#include <OneWireNg.h>
#include <DallasTemperature.h>
#include <Adafruit_ADS1X15.h>
#include <MultiMap.h>
#define ONE_WIRE_BUS 4
Adafruit_ADS1115 ads;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;
// For SIM7000 shield
#define FONA_PWRKEY 6
#define FONA_RST 7
#define FONA_TX 10 // Microcontroller RX
#define FONA_RX 11 // Microcontroller TX

#define SIMCOM_7000
#define PROTOCOL_HTTP_GET         // Generic

#define LED 13

// Using SoftwareSerial
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;

Adafruit_FONA_LTE fona = Adafruit_FONA_LTE();

#define samplingRate 60000UL // The time in between posts, in millis

uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);
char imei[16] = {0}; // Use this for device ID
char replybuffer[255]; // Large buffer for replies
uint8_t type;
unsigned long counter = 0;

bool bat = false;
bool opened = false;
bool cold = false;

char volBuff[12];
char tempBuff[12];
char batBuff[12];

char URL[300];  // Make sure this is long enough for your request URL
char body[200]; // Only need this is you're doing an HTTP POST request

//const int FLOWSWITCH = 2; // Use pin 2 to wake up the Uno/Mega
const int  buttonPin = 3;
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button




const char * phone_number = "+18000000006"; // Include country code, only numbe

const char * text_message1 = " mL FULL!"; // Change to suit your needs
const char * text_messageV = volBuff;

const char * text_message3 = " % BATTERY LOW!";
const char * text_messageB = batBuff;

const char * text_message2 = "*F FREEZING!"; // Change to suit your needs
const char * text_messageF = tempBuff;


int flowPin = 2;    //This is the input pin on the Arduino
double flowRate;    //This is the value we intend to calculate.
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;

volatile int count; //This integer needs to be set as volatile to ensure it updates correctly during the interrupt process.
float tempC;
float tempF;
float tLimit = 45.0;


/**************************************************** Battery stuf **************************************************/
int R1 = 27, R2 = 10; // 10k and 27k
float dividerRatio; // pre-calculate in setup
float calibrationFactor = 1.000; // calibrate  if needed
int in[] = {
  10000, 12000, 12500, 12800, 12900, 13000, 13100, 13200, 13300, 13400, 13600, 14600, 14900
};                                                                                         // [13] IN holds the mV inputs
int out [] = {
  0, 9, 14, 17, 20, 30, 40, 70, 90, 99, 100, 110, 120
};                                                                                       // [13] OUT holds the percentage outputs
float bLimit = 20;
int Val;
/*********************************************************************************************************************/

void setup() {

  Serial.begin(115200);
  //  while (!Serial) delay(1); // Wait for serial, for debug
  Serial.println(F("*** Burgalert 7000 ***"));

  dividerRatio = (R1 + R2) / R1;
  ads.setGain(GAIN_ONE);
  ads.begin();

  pinMode(flowPin, INPUT);           //Sets the pin as an input
  attachInterrupt(digitalPinToInterrupt(flowPin), Flow, RISING);
  flowRate          = 0.0;
  totalMilliLitres  = 0;
  //pinMode(BUTTON, INPUT); // For the interrupt wake-up to work

#ifdef LED
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
#endif

  pinMode(FONA_RST, OUTPUT);
  digitalWrite(FONA_RST, HIGH); // Default state

  pinMode(FONA_PWRKEY, OUTPUT);
  pinMode(buttonPin, INPUT);
  powerOn(true); // Power on the module
  moduleSetup(); // Establish first-time serial comm and print IMEI

  fona.setFunctionality(1); // AT+CFUN=1
  fona.setNetworkSettings(F("hologram")); // For Hologram SIM card, change appropriately

  // Perform first-time GPS/GPRS setup if the shield is going to remain on,
  // otherwise these won't be enabled in loop() and it won't work!
#ifndef turnOffShield

#if !defined(SIMCOM_3G) && !defined(SIMCOM_7500) && !defined(SIMCOM_7600)
  // Disable GPRS just to make sure it was actually off so that we can turn it on
  if (!fona.enableGPRS(false)) Serial.println(F("Failed to disable GPRS!"));

  // Turn on GPRS
  while (!fona.enableGPRS(true)) {
    Serial.println(F("Failed to enable GPRS, retrying..."));
    delay(2000); // Retry every 2s
  }
  Serial.println(F("Enabled GPRS!"));
#endif
#endif


  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  //  Serial.print("Parasite power is: ");
  //  if (sensors.isParasitePowerMode()) Serial.println("ON");
  //  else Serial.println("OFF");

  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");

  //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();

  // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
  sensors.setResolution(insideThermometer, 9);

  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC);
  Serial.println();
}

void loop()
{
  int adc0 = ads.readADC_SingleEnded(0);
  float battVoltage = ads.computeVolts(adc0) * dividerRatio * calibrationFactor;
  float battVolt = battVoltage * 3.7;
  int battmV = (battVolt * 1000) + 30;
  Val = battmV;
  int percent;
  percent =  multiMap(Val, in, out, 13);
  Serial.println("-----------------------------------------------------------");
  Serial.print("Battery voltage: "); Serial.print(battVoltage, 3); Serial.print("  "); Serial.print("AIN0: "); Serial.print(adc0 ); Serial.print(" BatVolt: "); Serial.println(battVolt, 3);
  Serial.print("Battery mV: "); Serial.println(battmV);
  Serial.print("Battery level [%]: "); Serial.println(percent);
  delay(1000);
  dtostrf(percent, 1, 2, batBuff);
  delay(1000);

  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  printTemperature(insideThermometer); // Use a simple function to print out the data
  tempC = sensors.getTempCByIndex(0);
  tempF = (tempC * 1.8) + 32;
  dtostrf(tempF, 1, 2, tempBuff);

  count = 0;      // Reset the counter so we start counting from 0 again
  delay (1000);   //Wait 1 second

  // noInterrupts(); //Disable the interrupts on the Arduino
  // Only send SMS if the switch was closed
  //Start the math
  flowRate = (count * 2.25);        //Take counted pulses in the last second and multiply by 2.25mL
  flowRate = flowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
  flowRate = flowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute
  totalMilliLitres += flowRate;
  buttonState = digitalRead(buttonPin);
  Serial.println(flowRate);         //Print the variable flowRate to Serial
  Serial.println(totalMilliLitres);
  dtostrf(totalMilliLitres, 1, 2, volBuff);
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  if (millis() - counter > samplingRate) {
    PostData ();
    counter = millis ();
  }


  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  if (buttonState == HIGH && lastButtonState == LOW || totalMilliLitres > 300 && totalMilliLitres - flowRate <= 300) {
    opened = false;
    lastButtonState = buttonState;
    FullSMS ();
  }


  if (tempF < tLimit && cold == false) {
    ColdSMS ();
    cold = true;
  }
  else if (tempF > tLimit + 2.0 && cold == true) {
    cold = false;
  }
  if (percent < bLimit && bat == false) {
    batSMS ();
    bat = true;
  }
}



// Power on/off the module
void powerOn(bool state) {
  if (state) {
    Serial.println(F("Turning on SIM7000..."));
    digitalWrite(FONA_PWRKEY, LOW);
    delay(100); // Turn on module
    digitalWrite(FONA_PWRKEY, HIGH);
    delay(4500); // Give enough time for the module to boot up before communicating with it
  }
  else {
    Serial.println(F("Turning off SIM7000..."));
    fona.powerDown(); // Turn off module
  }
}

void moduleSetup() {
  // SIM7000 takes about 3s to turn on and SIM7500 takes about 15s
  // Press Arduino reset button if the module is still turning on and the board doesn't find it.
  // When the module is on it should communicate right after pressing reset

  // Software serial:
  fonaSS.begin(115200); // Default SIM7000 shield baud rate

  Serial.println(F("Configuring to 9600 baud"));
  fonaSS.println("AT+IPR=9600"); // Set baud rate
  delay(100); // Short pause to let the command run
  fonaSS.begin(9600);
  if (! fona.begin(fonaSS)) {
    Serial.println(F("Couldn't find FONA"));
    while (1); // Don't proceed if it couldn't find the device
  }

  // Hardware serial:
  /*
    fonaSerial->begin(115200); // Default SIM7000 baud rate

    if (! fona.begin(*fonaSerial)) {
    DEBUG_PRINTLN(F("Couldn't find SIM7000"));
    }
  */

  // The commented block of code below is an alternative that will find the module at 115200
  // Then switch it to 9600 without having to wait for the module to turn on and manually
  // press the reset button in order to establish communication. However, once the baud is set
  // this method will be much slower.
  /*
    fonaSerial->begin(115200); // Default LTE shield baud rate
    fona.begin(*fonaSerial); // Don't use if statement because an OK reply could be sent incorrectly at 115200 baud

    Serial.println(F("Configuring to 9600 baud"));
    fona.setBaudrate(9600); // Set to 9600 baud
    fonaSerial->begin(9600);
    if (!fona.begin(*fonaSerial)) {
    Serial.println(F("Couldn't find modem"));
    while(1); // Don't proceed if it couldn't find the device
    }
  */

  type = fona.type();
  Serial.println(F("FONA is OK"));
  Serial.print(F("Found "));
  switch (type) {
    case SIM800L:
      Serial.println(F("SIM800L")); break;
    case SIM800H:
      Serial.println(F("SIM800H")); break;
    case SIM808_V1:
      Serial.println(F("SIM808 (v1)")); break;
    case SIM808_V2:
      Serial.println(F("SIM808 (v2)")); break;
    case SIM5320A:
      Serial.println(F("SIM5320A (American)")); break;
    case SIM5320E:
      Serial.println(F("SIM5320E (European)")); break;
    case SIM7000:
      Serial.println(F("SIM7000")); break;
    case SIM7070:
      Serial.println(F("SIM7070")); break;
    case SIM7500:
      Serial.println(F("SIM7500")); break;
    case SIM7600:
      Serial.println(F("SIM7600")); break;
    default:
      Serial.println(F("???")); break;
  }

  // Print module IMEI number.
  uint8_t imeiLen = fona.getIMEI(imei);
  if (imeiLen > 0) {
    Serial.print("Module IMEI: "); Serial.println(imei);
  }
}

bool netStatus() {
  int n = fona.getNetworkStatus();

  Serial.print(F("Network status ")); Serial.print(n); Serial.print(F(": "));
  if (n == 0) Serial.println(F("Not registered"));
  if (n == 1) Serial.println(F("Registered (home)"));
  if (n == 2) Serial.println(F("Not registered (searching)"));
  if (n == 3) Serial.println(F("Denied"));
  if (n == 4) Serial.println(F("Unknown"));
  if (n == 5) Serial.println(F("Registered roaming"));

  if (!(n == 1 || n == 5)) return false;
  else return true;

}

void Flow()
{
  count++; //Every time this function is called, increment "count" by 1
}

void FullSMS () {
  char message3[20];

  strcpy(message3, volBuff);
  strcat(message3, text_message1);

  pinMode(FONA_RST, OUTPUT);
  digitalWrite(FONA_RST, HIGH); // Default state
  pinMode(FONA_PWRKEY, OUTPUT);
  pinMode(buttonPin, INPUT);
  powerOn(true); // Power on the module
  moduleSetup(); // Establish first-time serial comm and print IMEI

  fona.setNetworkSettings(F("hologram")); // For Hologram SIM card, change appropriately
  while (!netStatus()) {
    Serial.println(F("Failed to connect to cell network, retrying..."));
    delay(2000); // Retry every 2s
  }
  Serial.println(F("Connected to cell network!"));

  // Send a text to your phone!
  if (!fona.sendSMS(phone_number, message3)) {
    Serial.println(F("Failed to send text!"));
  }
  else {
    Serial.println(F("Sent text alert!"));
  }
}


void ColdSMS () {
  char message[20];

  strcpy(message, tempBuff);
  strcat(message, text_message2);
  pinMode(FONA_RST, OUTPUT);
  digitalWrite(FONA_RST, HIGH); // Default state
  pinMode(FONA_PWRKEY, OUTPUT);

  powerOn(true); // Power on the module
  moduleSetup(); // Establish first-time serial comm and print IMEI

  fona.setNetworkSettings(F("hologram")); // For Hologram SIM card, change appropriately
  while (!netStatus()) {
    Serial.println(F("Failed to connect to cell network, retrying..."));
    delay(2000); // Retry every 2s
  }
  Serial.println(F("Connected to cell network!"));

  // Send a text to your phone!
  if (!fona.sendSMS(phone_number, message)) {
    Serial.println(F("Failed to send text!"));
  }
  else {
    Serial.println(F("Sent text alert!"));
  }
}

void batSMS () {
  char message2[20];

  strcpy(message2, batBuff);
  strcat(message2, text_message3);
  pinMode(FONA_RST, OUTPUT);
  digitalWrite(FONA_RST, HIGH); // Default state
  pinMode(FONA_PWRKEY, OUTPUT);

  powerOn(true); // Power on the module
  moduleSetup(); // Establish first-time serial comm and print IMEI

  fona.setNetworkSettings(F("hologram")); // For Hologram SIM card, change appropriately
  while (!netStatus()) {
    Serial.println(F("Failed to connect to cell network, retrying..."));
    delay(2000); // Retry every 2s
  }
  Serial.println(F("Connected to cell network!"));

  // Send a text to your phone!
  if (!fona.sendSMS(phone_number, message2)) {
    Serial.println(F("Failed to send text!"));
  }
  else {
    Serial.println(F("Sent text alert!"));
  }
}
void printTemperature(DeviceAddress deviceAddress)
{
  // method 1 - slower
  //Serial.print("Temp C: ");
  //Serial.print(sensors.getTempC(deviceAddress));
  //Serial.print(" Temp F: ");
  //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit

  // method 2 - faster
  float tempC = sensors.getTempC(deviceAddress);
  if (tempC == DEVICE_DISCONNECTED_C)
  {
    Serial.println("Error: Could not read temperature data");
    return;
  }
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

void PostData ()
{
  // If the shield was already on, no need to re-enable
#if defined(turnOffShield) && !defined(SIMCOM_3G) && !defined(SIMCOM_7500) && !defined(SIMCOM_7600)
  // Disable GPRS just to make sure it was actually off so that we can turn it on
  if (!fona.enableGPRS(false)) Serial.println(F("Failed to disable GPRS!"));

  // Turn on GPRS
  while (!fona.enableGPRS(true)) {
    Serial.println(F("Failed to enable GPRS, retrying..."));
    delay(2000); // Retry every 2s
  }
  Serial.println(F("Enabled GPRS!"));
#endif

  // Post something like temperature and battery level to the web API
  // Construct URL and post the data to the web API

  // Format the floating point numbers



  // Also construct a combined, comma-separated location array
  // (many platforms require this for dashboards, like Adafruit IO):
  //sprintf(locBuff, "%s,%s,%s,%s", speedBuff, latBuff, longBuff, altBuff); // This could look like "10,33.123456,-85.123456,120.5"

  // Construct the appropriate URL's and body, depending on request type
  // In this example we use the IMEI as device ID

#ifdef PROTOCOL_HTTP_GET
  // GET request

  counter = 0; // This counts the number of failed attempts tries

#if defined(SIMCOM_3G) || defined(SIMCOM_7500) || defined(SIMCOM_7600)
  // You can adjust the contents of the request if you don't need certain things like speed, altitude, etc.
  sprintf(URL, "GET /dweet/for/%s?temp=%s&bat=%s&vol=%s HTTP/1.1\r\nHost: dweet.io\r\n\r\n",
          imei, tempBuff, batBuff, volBuff);

  // Try a total of three times if the post was unsuccessful (try additional 2 times)
  while (counter < 3 && !fona.postData("www.dweet.io", 443, "HTTPS", URL)) { // Server, port, connection type, URL
    Serial.println(F("Failed to complete HTTP/HTTPS request..."));
    counter++; // Increment counter
    delay(1000);
  }
#else
  sprintf(URL, "http://dweet.io/dweet/for/%s?temp=%s&bat=%s&vol=%s", imei, tempBuff, batBuff, volBuff);

  while (counter < 3 && !fona.postData("GET", URL)) {
    Serial.println(F("Failed to post data, retrying..."));
    counter++; // Increment counter
    delay(1000);
  }
#endif

#elif defined(PROTOCOL_HTTP_POST)
  // You can also do a POST request instead

  counter = 0; // This counts the number of failed attempts tries

#if defined(SIMCOM_3G) || defined(SIMCOM_7500) || defined(SIMCOM_7600)
  sprintf(body, "{\"lat\":%s,\"long\":%s}\r\n", latBuff, longBuff); // Terminate with CR+NL
  sprintf(URL, "POST /dweet/for/%s HTTP/1.1\r\nHost: dweet.io\r\nContent-Length: %i\r\n\r\n", imei, strlen(body));

  while (counter < 3 && !fona.postData("www.dweet.io", 443, "HTTPS", URL, body)) { // Server, port, connection type, URL
    Serial.println(F("Failed to complete HTTP/HTTPS request..."));
    counter++; // Increment counter
    delay(1000);
  }
#else
  sprintf(URL, "http://dweet.io/dweet/for/%s", imei);
  sprintf(body, "{\"lat\":%s,\"long\":%s}", latBuff, longBuff);

  // Let's try a POST request to thingsboard.io
  // Please note this can me memory-intensive for the Arduino Uno
  // and may not work. You might have to split it up into a couple requests
  // and send part of the data in one request, and the rest in the other, etc.
  // Perhaps an easier solution is to swap out the Uno with an Arduino Mega.
  /*
    const char * token = "qFeFpQIC9C69GDFLWdAv"; // From thingsboard.io device
    sprintf(URL, "http://demo.thingsboard.io/api/v1/%s/telemetry", token);
    sprintf(body, "{\"lat\":%s,\"long\":%s,\"speed\":%s,\"head\":%s,\"alt\":%s,\"temp\":%s,\"batt\":%s}", latBuff, longBuff,
          speedBuff, headBuff, altBuff, tempBuff, battBuff);
    //  sprintf(body, "{\"lat\":%s,\"long\":%s}", latBuff, longBuff); // If all you want is lat/long
  */

  while (counter < 3 && !fona.postData("POST", URL, body)) {
    Serial.println(F("Failed to complete HTTP POST..."));
    counter++;
    delay(1000);
  }
#endif


#endif

  //Only run the code below if you want to turn off the shield after posting data
#ifdef turnOffShield
  // Disable GPRS
  // Note that you might not want to check if this was successful, but just run it
  // since the next command is to turn off the module anyway
  if (!fona.enableGPRS(false)) Serial.println(F("Failed to disable GPRS!"));

  // Turn off GPS
  if (!fona.enableGPS(false)) Serial.println(F("Failed to turn off GPS!"));

  // Power off the module. Note that you could instead put it in minimum functionality mode
  // instead of completely turning it off. Experiment different ways depending on your application!
  // You should see the "PWR" LED turn off after this command
  //  if (!fona.powerDown()) Serial.println(F("Failed to power down FONA!")); // No retries
  counter = 0;
  while (counter < 3 && !fona.powerDown()) { // Try shutting down
    Serial.println(F("Failed to power down FONA!"));
    counter++; // Increment counter
    delay(1000);
  }
#endif

  // Alternative to the AT command method above:
  // If your FONA has a PWRKEY pin connected to your MCU, you can pulse PWRKEY
  // LOW for a little bit, then pull it back HIGH, like this:
  //  digitalWrite(PWRKEY, LOW);
  //  delay(600); // Minimum of 64ms to turn on and 500ms to turn off for FONA 3G. Check spec sheet for other types
  //  delay(1300); // Minimum of 1.2s for SIM7000
  //  digitalWrite(PWRKEY, HIGH);

  // Shut down the MCU to save power
#ifndef samplingRate
  Serial.println(F("Shutting down..."));
  delay(5); // This is just to read the response of the last AT command before shutting down
  MCU_powerDown(); // You could also write your own function to make it sleep for a certain duration instead
#else
  //  // The following lines are for if you want to periodically post data (like GPS tracker)
  //  Serial.print(F("Waiting for ")); Serial.print(samplingRate); Serial.println(F(" seconds\r\n"));
  //  delay(samplingRate * 1000UL); // Delay

  // Only run the initialization again if the module was powered off
  // since it resets back to 115200 baud instead of 4800.
#ifdef turnOffShield
  fona.powerOn(FONA_PWRKEY); // Powers on the module if it was off previously
  moduleSetup();
#endif

#endif
}

// Turn off the MCU completely. Can only wake up from RESET button
// However, this can be altered to wake up via a pin change interrupt
//void MCU_powerDown() {
//  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
//  ADCSRA = 0; // Turn off ADC
//  power_all_disable ();  // Power off ADC, Timer 0 and 1, serial interface
//  sleep_enable();
//  sleep_cpu();
//}

Hello

Your buffer is too small for "XX.XX % BATTERY LOW!"

changed the buffer for message2 from 20 to 25, it works! You're a genius thank you! :smiley: