SoftwareSerial Not Reliable?

You can do that, but if you get the sizes wrong you code will crash, which makes debugging difficult.
You can improve your chances by passing both the string address AND its size and then using strlcpy and strlcat to work on them see strlcpy_strlcat.ino for an example sketch on how to use them.
This will protect you if you get the size wrong for the number of chars you are adding and not crash your sketch so you can still print debug msgs.
OR
You can use my SafeString library to create the globals which have a number of advantages
I) the SafeString carries around the char[ ] size to check there is enough space for the next add
ii) SafeString has similar functions to String so converting to SafeString is more straight forward
iii) SafeString will give you detailed error msgs when you try to push too much into them.
The downside is that SafeString objects take a bit more memory than just a char[ ], and you don't have a lot of spare memory. If SafeStrings work then great otherwise you are back to raw char[ ]'s
OR
using a board with more RAM (see the suggestion from @TomGeorge above)
Can you just move everything to the ESP8266? Or are you short of pins?

Here the previous sketch I posted, but partially converted to use SafeString.

// download SafeString V4.1.5+ library from the Arduino Library manager or from
// https://www.forward.com.au/pfod/ArduinoProgramming/SafeString/index.html
#include "SafeString.h"

//https://www.youtube.com/watch?v=4vKxGHGYOtI&t=103s
//#define SCROLL
#define DISPLAY_TEMPERATURES //display pool and air temperatures as well as time & date

#define USE_SOFTWARESERIAL

#ifdef USE_SOFTWARESERIAL
// SERIAL_IO redefines Arduino.h:54  #define SERIAL_IO  0x0
// that won't help
#define SERIAL_IO Serial1
#else
#define SERIAL_IO Serial
#endif

#define MAXLEN 60
#ifdef USE_SOFTWARESERIAL
#include <SoftwareSerial.h>
#endif
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
//Gnd
//Vcc
//SDA(A4)
//SCL(A5)
//-------------Clock variables-----------
unsigned long refmillis, currenthour;
int Time[6]; //currenthour_10's,currenthour_1's,currentminute_10's,currentminute_1's
//String str_currentTime = "", str_currentDate = "", str_pooltemp = "", str_airtemp = "", str_wakeupTime = "";
// not a problem is these are not correct SafeString will print a detailed error msg
cSF(str_currentTime, 20);
cSF(str_currentDate, 20);
cSF(str_pooltemp, 10);
cSF(str_airtemp, 10);
cSF(str_wakeupTime, 10);


// add reserve( ) in setup for these globals
int buzzPin = 8, alarmdone = 0;
// make period and duration arrays to get compile to work
int period[] = {500, 594, 500, 594, 707, 594, 707, 594, 530, 500, 594};
int duration[] = {1000, 1000, 1000, 1000, 250, 500, 250, 500, 500, 1000, 1000};
//------------esp01 variables ----------------------------------------------------
#ifdef USE_SOFTWARESERIAL
SoftwareSerial SERIAL_IO(6, 7); // RX, TX
#endif
// leave these as Strings because that is just convenient
String AP = "*****"; // AP NAME
String PASS = "***********"; // AP PASSWORD
String API = "***********"; // Write API KEY
String HOST = "api.thingspeak.com";
String PORT = "80";

cSF(str_time, 100); //looks like 87 is enough
int toggle = 0;
int countTimeCommand = 0;
boolean found = false;
const unsigned long delaymillis = 120000UL; //120 sec
unsigned long startmillis;
//--------------LCD variables ---------------
int LCDcol = 0;
#ifdef SCROLL
const unsigned long delaydisplaymillis = 500UL;
#else
const unsigned long delaydisplaymillis = 6000UL;
#endif
unsigned long startdisplaymillis;
//--------------Big Display-------------------
// Define the bit patters for each of our custom chars. These
// are 5 bits wide and 8 dots deep
uint8_t custChar[8][8] = {
  {31, 31, 31, 0, 0, 0, 0, 0}, // Small top line - 0
  {0, 0, 0, 0, 0, 31, 31, 31}, // Small bottom line - 1
  {31, 0, 0, 0, 0, 0, 0, 31}, // Small lines top and bottom -2
  {0, 0, 7, 7, 7, 7, 0, 0}, // colon dot -3
  {31, 31, 31, 31, 31, 31, 15, 7}, // Left bottom chamfer full - 4
  {28, 30, 31, 31, 31, 31, 31, 31}, // Right top chamfer full -5
  {31, 31, 31, 31, 31, 31, 30, 28}, // Right bottom chamfer full -6
  {7, 15, 31, 31, 31, 31, 31, 31}, // Left top chamfer full -7
};
// Define our numbers 0 thru 9
// 254 is blank and 255 is the "Full Block"
uint8_t bigNums[10][6] = {
  {7, 0, 5, 4, 1, 6}, //0
  {0, 5, 254, 1, 255, 1}, //1
  {0, 2, 5, 7, 1, 1}, //2
  {0, 2, 5, 1, 1, 6}, //3
  {7, 1, 255, 254, 254, 255}, //4
  {7, 2, 0, 1, 1, 6}, //5
  {7, 2, 0, 4, 1, 6}, //6
  {0, 0, 5, 254, 7, 254}, //7
  {7, 2, 5, 4, 1, 6}, //8
  {7, 2, 5, 1, 1, 6}, //9
};

void setup() {
  // put your setup code here, to run once:
  // Only start Serial if using USE_SOFTWARESERIAL
#ifdef USE_SOFTWARESERIAL
  Serial.begin(115200);
  for (int i = 10; i > 0; i--) {
    delay(500);
    Serial.print(i); Serial.print(' ');
  }
  Serial.println(F("Started "));
  SafeString::setOutput(Serial);   // <<<<<<<<<<   send error messages to Serial
#endif
  //  str_currentTime.reserve(20); // padded to 16 in Clock( ) so 20 should be fine
  //  str_currentDate.reserve(20); // padded to 16 in getresults1 so 20 should be fine
  //  str_pooltemp.reserve(10);
  //  str_airtemp.reserve(10);
  //  str_wakeupTime.reserve(10);

  pinMode(buzzPin, OUTPUT);
  digitalWrite(buzzPin, LOW);
  lcd.init(); // initialize the lcd
  lcd.init();
  lcd.backlight();
  delay(500);
  lcd.home();
  lcd.clear();
  for (size_t cnt = 0; cnt < sizeof(custChar) / 8; cnt++)
  {
    lcd.createChar(cnt, custChar[cnt]);
  }
  initClock(0, 0, 0, &refmillis); //init Time to midnite
  SERIAL_IO.begin(9600);

  while (found == false)
  {
    sendCommand("AT", 5, "OK");
    sendCommand("AT+CWMODE=1", 5, "OK");
    sendCommand("AT + CWJAP = \"" + AP + "\",\"" + PASS + "\"", 50, "OK");
    sendCommand("AT+CIPMUX=1", 5, "OK");
  }
  startmillis = millis() - delaymillis;
  startdisplaymillis = millis() - delaydisplaymillis;
}

void loop()
{
  if (SafeString::errorDetected()) {
    // one of the toInt() failed
    SafeString::Output.println("one if the toInt( ) failed");
  }
  //--------------- Get info from Internet ---------
  if ((millis() - startmillis) >= delaymillis)
  {
    while (SERIAL_IO.available() > 0) SERIAL_IO.read(); //start with an MT softwareserial buffer before sending GET's
    if (toggle == 3)
    {
      getresults1(str_time, 1423291L, 1, str_wakeupTime, "", 0); //get wakupTime
      toggle = 0;
    }
    else if (toggle == 2)
    {
      getresults1(str_time, 1418147L, 1, str_airtemp, "AIR", 1); //get airtemp
      toggle = 3;
    }
    else if (toggle == 1)
    {
      getresults1(str_time, 1418147L, 4, str_pooltemp, "EAU", 1); //get pooltemp
      toggle = 2;
    }
    else if (toggle == 0)
    {
      getresults(str_time); //getTime & date
      parseResults(str_time, str_currentDate, &refmillis);
#ifdef DISPLAY_TEMPERATURES
      toggle = 1;
#endif
    }
#ifdef USE_SOFTWARESERIAL
    Serial.println(str_time);
#endif
    SERIAL_IO.println(F("\n\r"));
    startmillis = millis();
  }
  //-------------------- Run the Clock ----------------------------------------------
  Clock(str_currentTime, refmillis, &currenthour, Time); //update time of day Clock
  //  if (str_wakeupTime == str_currentTime.substring(0, 5)) //alarm if active
  cSF(sfWake, 5);
  str_currentTime.substring(sfWake, 0, 5);
  if (str_wakeupTime == sfWake) //alarm if active
  {
    if (alarmdone == 0)
    {
      Miles(period, duration);
      alarmdone = 1;
    }
  }
  else
  {
    alarmdone = 0;
  }
  //----------------Take care of LCD display -----------------------------------------
  if (((int)currenthour > 21) || ((int)currenthour < 9)) //During sleeptime, only show currentTime on big display
    // if (0)
  {
    LCDbig(Time);
  }
  else //During waketime, show currentTime, currentDate, pooltemp, and airtemp on small display
  {
    LCDsmall(&startdisplaymillis, &LCDcol, str_currentTime, str_currentDate, str_pooltemp, str_airtemp, str_wakeupTime);
  }
} //void loop()

void initClock(unsigned long valhour, unsigned long valminute, unsigned long valsecond, unsigned long *Refmillis)
{
  *Refmillis = millis() - ((valhour * 3600L + valminute * 60L + valsecond)) * 1000L; //reference to 0h/0m/0s
}

//int Clock(String *currentTime, unsigned long Refmillis, unsigned long *Currenthour, int *TIme)
// nothing returned from this method
void Clock(SafeString &currentTime, unsigned long Refmillis, unsigned long *Currenthour, int *TIme)
{
  unsigned long deltamillis, currentminute, currentsecond;
  int siz, i;
  deltamillis = (millis() - Refmillis) % ((unsigned long)(60L * 60L * 24L) * 1000L);
  *Currenthour = deltamillis / 3600000L;
  deltamillis -= *Currenthour * 3600000L;
  currentminute = deltamillis / 60000L;
  deltamillis -= currentminute * 60000L;
  currentsecond = deltamillis / 1000L;
  currentTime = "";// clear to start with
  twoDigits(currentTime, *Currenthour);
  currentTime += ":";
  twoDigits(currentTime, currentminute);
  currentTime += ":";
  twoDigits(currentTime, currentsecond);
  siz = currentTime.length();
  if (siz < 16) for (i = 0; i < 16 - siz; i++) currentTime += (" "); // padd it
  TIme[0] = *Currenthour / 10;
  TIme[1] = *Currenthour % 10;
  TIme[2] = currentminute / 10;
  TIme[3] = currentminute % 10;
  TIme[4] = currentsecond / 10;
  TIme[5] = currentsecond % 10;
}

void Miles(int *Period, int *Duration)
{
  int i, j;
  unsigned long tIme;
  for (j = 0; j < 2; j++)
  {
    for (i = 0; i < 11; i++) //song duration=19sec
    {
      tIme = 0ul;
      while (tIme < 1000ul * Duration[i])
      {
        digitalWrite(buzzPin, HIGH);
        delayMicroseconds(Period[i]);
        digitalWrite(buzzPin, LOW);
        delayMicroseconds(Period[i]);
        tIme += (2 * Period[i]);
      }
    }
    delay(1000);
  }
  digitalWrite(buzzPin, LOW);
}

void LCDbig(int *tIme)
{
  printBigNum(tIme[0], 0, 0);
  lcd.setCursor(3, 0);
  lcd.print(' ');
  lcd.setCursor(3, 1);
  lcd.print(' ');
  printBigNum(tIme[1], 4, 0);
  if (tIme[5] % 2 == 0) //blink the : every second
  {
    lcd.setCursor(7, 0);
    lcd.print((char)3); //:
    lcd.setCursor(7, 1);
    lcd.print((char)3); //:
  }
  else
  {
    lcd.setCursor(7, 0);
    lcd.print(' '); //blank
    lcd.setCursor(7, 1);
    lcd.print(' '); //blank
  }
  lcd.setCursor(8, 0);
  lcd.print(' ');
  lcd.setCursor(8, 1);
  lcd.print(' ');
  printBigNum(tIme[2], 9, 0);
  lcd.setCursor(12, 0);
  lcd.print(' ');
  lcd.setCursor(12, 1);
  lcd.print(' ');
  printBigNum(tIme[3], 13, 0);

}

// -----------------------------------------------------------------
// Print big number over 2 lines, 3 colums per half digit
// -----------------------------------------------------------------
void printBigNum(int number, int startCol, int startRow) {
  // Position cursor to requested position (each char takes 3 cols plus a space col)
  lcd.setCursor(startCol, startRow);
  // Each number split over two lines, 3 chars per line. Retrieve character
  // from the main array to make working with it here a bit easier.
  uint8_t thisNumber[6];
  for (int cnt = 0; cnt < 6; cnt++) {
    thisNumber[cnt] = bigNums[number][cnt];
  }
  // First line (top half) of digit
  for (int cnt = 0; cnt < 3; cnt++) {
    lcd.print((char)thisNumber[cnt]);
  }
  // Now position cursor to next line at same start column for digit
  lcd.setCursor(startCol, startRow + 1);
  // 2nd line (bottom half)
  for (int cnt = 3; cnt < 6; cnt++) {
    lcd.print((char)thisNumber[cnt]);
  }
}

void LCDsmall(unsigned long *Startdisplaymillis, int *lcdcol, SafeString &STR_currentTime, SafeString &STR_currentDate, SafeString &STR_pooltemp, SafeString &STR_airtemp, SafeString &str_wakeupTIME)
{
  //  String Message, line2;
  cSF(Message, 24); // 24?? not a problem SafeString will tell us if this is too small
  cSF(line2, 24);
  int Msglength;
  lcd.setCursor(0, 0);
  if (str_wakeupTIME.length() > 0)
  {
    //    lcd.print(STR_currentTime.substring(0, 8) + " " + str_wakeupTIME);
    cSF(sfPrint, 20);
    STR_currentTime.substring(sfPrint, 0, 8);
    sfPrint += " ";
    sfPrint += str_wakeupTIME;
    lcd.print(sfPrint);
  }
  else lcd.print(STR_currentTime); //Line0
  Message = "";
  Message += STR_currentDate; //16 characters
  Message += STR_pooltemp; //8 characters or 0
  Message += STR_airtemp; //8 characters or 0
  if (Message.length() == 24) Message += " "; //16 or 32 characters only  // <<<<<<<<<< odd
  Msglength = Message.length();
  Message += STR_currentDate; //needed for scrolling
  //line2 = Message.substring(*lcdcol, *lcdcol + 16);
  Message.substring(line2, *lcdcol, *lcdcol + 16);
  lcd.setCursor(0, 1);
  lcd.print(line2); //Line2 scrolls or alternates
  if ((millis() - *Startdisplaymillis) >= delaydisplaymillis) //Line1
  {
#ifdef SCROLL
    *lcdcol += 1; //scroll
#else
    *lcdcol += 16; //alternate
#endif
    if (*lcdcol >= Msglength) *lcdcol = 0;
    *Startdisplaymillis = millis();
  }
}

void getresults(SafeString &Str_time) //get time of day from Internet
{
  cSF(getData, 100, "GET https://api.thingspeak.com/apps/thinghttp/send_request?api_key=5R0NJ8SL2DSEAGQA");
  char c = ' ';
  //String Str_time = "";
  Str_time = ""; // clear to start with
  int countcomma = 0;
  unsigned long waitTime, startTime;
  sendCommand("AT+CIPSTART=0,\"TCP\",\"" + HOST + "\"," + PORT, 15, "OK");
  sendCommand("AT+CIPSEND=0," + String(getData.length() + 4), 4, ">");
  SERIAL_IO.println(getData);  // no need for a String here
  SERIAL_IO.println(F("\n\r"));
  //Typical Response From esp-01
  //Recv 87 bytes
  //SEND OK
  //+IPD,0,32:11:23:32 AM, Friday 14, May 20210,CLOSED

  waitTime = 10000UL;
  startTime = millis();
  while ((c != ':') && ((millis() - startTime) <= waitTime)) //remove unwanted initial characters
  {
    if (SERIAL_IO.available() > 0)
    {
      c = SERIAL_IO.read();
    }
  }
  waitTime = 1000UL;
  startTime = millis();
  c = ' ';
  while ((countcomma != 3) && ((millis() - startTime) <= waitTime)) //get time,date characters up to 3 ','
  {
    if (SERIAL_IO.available() > 0)
    {
      c = SERIAL_IO.read();
      Str_time.concat(c);
      if (c == ',') countcomma++;
    }
  }
  // return Str_time;
}

void getresults1(SafeString &str_res, long int channelID, int fieldno, SafeString &str_out, const char* str_label, int temperatureresult)
{
  char c = ' ';
  cSF(getData, 80, "GET https://api.thingspeak.com/channels/");
  getData += channelID;
  getData += "/fields/";
  getData += fieldno;
  getData += ".json?results=3";
  String Str_time, Str_temp = "";// ,str_res
  str_res = ""; // clear to start with
  int i, countcolons = 0, siz, iter;
  unsigned long waitTime, startTime;
  sendCommand("AT+CIPSTART=0,\"TCP\",\"" + HOST + "\"," + PORT, 15, "OK");
  sendCommand("AT+CIPSEND=0," + String(getData.length() + 4), 4, ">");
  SERIAL_IO.println(getData);
  SERIAL_IO.println(F("\n\r"));
  waitTime = 10000UL;
  startTime = millis();
  c = ' ';
  while ((c != '[') && ((millis() - startTime) <= waitTime)) //remove until [ start of feed
  {
    if (SERIAL_IO.available() > 0)
    {
      c = SERIAL_IO.read();
    }
  }
  for (iter = 0; iter < 3; iter++)
  {
    waitTime = 1000UL;
    startTime = millis();
    c = ' ';
    countcolons = 0;
    while ((countcolons != 5) && ((millis() - startTime) <= waitTime)) //remove until field3
    {
      if (SERIAL_IO.available() > 0)
      {
        c = SERIAL_IO.read();
        if (c == ':') countcolons++;
      }
    }
    waitTime = 1000UL;
    startTime = millis();
    c = ' ';
    Str_time = "";
    while ((c != '}') && ((millis() - startTime) <= waitTime)) //get data = "xxxxx"} or null}
    {
      if (SERIAL_IO.available() > 0)
      {
        c = SERIAL_IO.read();
        Str_time.concat(c);
      }
    }
    if (Str_time.substring(0, 1) != "n") Str_temp = Str_time; //Copy if field is not null. The last (most recent) valid field will be used.
  } //for (iter=0;iter<3;iter++) next feed
  if (Str_temp.length() != 0)
  {
    siz = Str_temp.length();
    String tmpStr = Str_temp.substring(1, siz - 2);
    str_res = tmpStr.c_str();
  }
  if (str_res.length() != 0)
  {
    if (temperatureresult)
    {
      str_out = str_label;
      str_out += " ";
      float tempFloat = 0.0;
      str_res.toFloat(tempFloat);
      str_out += round(tempFloat);
      str_out += "C";
      siz = str_out.length();
      if (siz < 8) for (i = 0; i < 8 - siz; i++) str_out += " ";
    }
    else
    {
      int str_resInt = 0;
      str_res.toInt(str_resInt);
      //      if (str_res.toInt() < 0) str_out = "";  // 0 could indicate error in toInt()
      if (str_resInt < 0) str_out = "";  // 0 could indicate error in toInt()
      else {
        str_out = "";
        twoDigits(str_out, str_resInt / 100);
        str_out += ":";
        twoDigits(str_out, str_resInt % 100);
      }
    }
  }
  //return str_res;
}

void parseResults(SafeString &Str_time, SafeString &str_CurrentDate, unsigned long *refMillis)
{
  int i = 0, j = 0, len,  startindx = 0, hashcode, siz;  //newTime[3],
  // if newTime[3] not initialized here, then when used below may get garbage
  int newTime[3] = {0, 0, 0};
  //String str_temp,
  cSF(str_temp, 6);
  //String parsechars = ":: , , ";
  cSF(parsechars, 7, ":: , , ");
  //
  // typical String to parse is:  11:23:32^AM,^Friday^14,^May^20210,CLOSED
  //
  //      substring(startindx,i) pchar[j]  found    what
  //      -----------------------------------------------
  //                    0     2     :  0    11      hour
  //                    3     5     :  1    23      minute
  //                    6     8     ^  2    32      second
  //                    9     12    ^  3    AM,     AM/PM
  //                    13    19    ^  4    Friday  day name
  //                    20    22    ,  5    14      day date
  //                    23    23    ^  6    -       nothing
  //                    24    27    ^  7    May     month
  //                    28    33    ,  8    20210   year
  //                                ^  9

  len = Str_time.length();
  if ((len >= 10) && (len < MAXLEN)) //parsing the received string newTime values in [hours,minutes,seconds], Day, Date, Month, Year
  {
    while (i < len)
    {
      if (Str_time.charAt(i) == parsechars.charAt(j))
      {
        switch (j)
        {
          case 0:
            // newTime[j] = (Str_time.substring(startindx, i)).toInt(); break; //get hour,minute,seconds
            Str_time.substring(str_temp, startindx, i);
            str_temp.toInt(newTime[j]);
            break;
          case 1:
            //newTime[j] = (Str_time.substring(startindx, i)).toInt(); break; //get hour,minute,seconds
            Str_time.substring(str_temp, startindx, i);
            str_temp.toInt(newTime[j]);
            break;
          case 2:
            //newTime[j] = (Str_time.substring(startindx, i)).toInt(); break; //get hour,minute,seconds
            Str_time.substring(str_temp, startindx, i);
            str_temp.toInt(newTime[j]);
            break;
          case 3:
            //str_temp = Str_time.substring(startindx, i - 1);
            Str_time.substring(str_temp, startindx, i - 1);
            if (str_temp.charAt(0) == 'P') //change to 24-hour format
            {
              if (newTime[0] != 12) newTime[0] += 12;
            }
            else
            {
              if (newTime[0] == 12) newTime[0] -= 12;
            }
            break;
          case 4:
            // str_temp = Str_time.substring(startindx, i); //get day
            Str_time.substring(str_temp, startindx, i);
            //get day of the week
            hashcode = codeString(str_temp);
            switch (hashcode)
            {
              case 13760: str_CurrentDate = "Lun "; break; //Mon
              case 13280: str_CurrentDate = "Mar "; break; //Tue
              case 13440: str_CurrentDate = "Mer "; break; //Wed
              case 13984: str_CurrentDate = "Jeu "; break; //Thu
              case 13088: str_CurrentDate = "Ven "; break; //Fri
              case 14208: str_CurrentDate = "Sam "; break; //Sat
              case 12864: str_CurrentDate = "Dim "; break; //Sun
              default: break; //do nothing
            }
            break;
          case 5: {
              //twoDigits(str_CurrentDate, (Str_time.substring(startindx, i)).toInt()); break; //get day date (1-31)
              Str_time.substring(str_temp, startindx, i);
              int dayDate = 0;
              str_temp.toInt(dayDate);
              twoDigits(str_CurrentDate, dayDate);
            }
          case 6: break;
          case 7:
            //str_temp = Str_time.substring(startindx, i); //get month
            Str_time.substring(str_temp, startindx, i);
            //get Month
            hashcode = codeString(str_temp);
            switch (hashcode)
            {
              case 13760: str_CurrentDate += "/01/"; break; //Jan
              case 13376: str_CurrentDate += "/02/"; break; //Feb
              case 14016: str_CurrentDate += "/03/"; break; //Mar
              case 12864: str_CurrentDate += "/04/"; break; //Apr
              case 14304: str_CurrentDate += "/05/"; break; //May
              case 12992: str_CurrentDate += "/06/"; break; //Jun
              case 12928: str_CurrentDate += "/07/"; break; //Jul
              case 13600: str_CurrentDate += "/08/"; break; //Aug
              case 13824: str_CurrentDate += "/09/"; break; //Sep
              case 12672: str_CurrentDate += "/10/"; break; //Oct
              case 13120: str_CurrentDate += "/11/"; break; //Nov
              case 14240: str_CurrentDate += "/12/"; break; //Dec
              default: break; //do nothing
            }
            break;
          case 8: {
              //str_CurrentDate += Str_time.substring(startindx, i - 1); break; //get year (4 digits)
              Str_time.substring(str_temp, startindx, i);
              int yearDate = 0;
              str_temp.toInt(yearDate);
              twoDigits(str_CurrentDate, yearDate);
            }
          default: break; //do nothibg
        } // switch(j)
        j++;
        startindx = i + 1;
      } //if (Str_time.charAt(i) == parsechars.charAt(j))
      i++;
    } //while (i<len)
    initClock(newTime[0], newTime[1], newTime[2], refMillis);  // <<<<<<< warning about newTime[ ] not being initialized
    siz = str_CurrentDate.length();
    if (siz < 16) for (i = 0; i < 16 - siz; i++) str_CurrentDate += " ";
  } //if ((len>=10)&&(len<MAXLEN))
}

int codeString(SafeString &in)
{
  int res = 0;
  for (int i = 0; i < 3; i++) res = ((in[i] << 5) + res) ^ res;
  return res;
}
//String twoDigits(unsigned long val)
// add two digits to outString
void twoDigits(SafeString &outString, unsigned long val)
{
  //String outString, str_val;
  //String str_val(val);
  //if (str_val.length() == 1) outString += "0";
  if (val < 10) {
    outString += "0";
  }
  outString += val;
  //return (outString);
}

// readReplay should be char* NOT a char
//void sendCommand(String command, int maxTime, char readReplay) {
void sendCommand(SafeString &command, int maxTime, const char* readReplay) {
  sendCommand(command.c_str(), maxTime, readReplay);
}
void sendCommand(String &command, int maxTime, const char* readReplay) {
  sendCommand(command.c_str(), maxTime, readReplay);
}
void sendCommand(const char* command, int maxTime, const char* readReplay) {
  found = false;
  while (countTimeCommand < (maxTime * 1))
  {
    SERIAL_IO.println(command);
    if (SERIAL_IO.find((uint8_t*)readReplay)) //ok
    {
      found = true;
      break;
    }
    countTimeCommand++;
  }
  countTimeCommand = 0;
}

BUT
looks to me like you are very close to running out of RAM.
Try running this and check for SafeString Error msgs. A zero length SafeString indicates available memory is <128bytes.
See my previous post for how to get around that check.

[Mod edit]
Inappropriate comments removed.
@J-M-L please use more temperate language, appropriate for a technical support forum, and show some respect for other posters, even if you don't agree with them. Thank you.
[End of mod edit]

And as memory is low there is an incentive to be cautious and not add extra libraries requiring more ram than necessary.

The problem is with low memory you will not allow any more then you think you need. Hence the likely hood of buffer overflow is increased.
If you get buffer overflow you will most likely crash you sketch at that point or elsewhere.

Well that’s about design

You won’t crash if you test. You will have to handle edge cases and devise a strategy for when you can’t complete some task because memory was low.

If this happens too frequently and code has been optimized for memory then it’s time to get better hardware.

I think you have this around the wrong way, "You will crash when you test" if you do not allow enough space in the char[ ]s and use strcpy/strcat.

As I mentioned in by post #30, you can avoid crashes by using strlcpy and strlcat, BUT you need to carry around the char[ ] size yourself and pass it to every method the adds to that array.

Here is an example of a crash when the char[ ] was not sized correctly
This crash happened in testing. Which is my point really.

As was foretold in post #5, battle bas been joined.

Basically, it comes down to this: you need to manage your RAM Any Which Way You Can and opinions vary as to how that should be done.

No... you test BEFORE doing stupid things and thus don't crash. Of course it means you need to know the size of the buffers. Then the programmer of course needs to decide what happens in that case and how to recover.

I defer to you. You are a far better programmer than I will ever be. I test to find the stupid things I have coded.

LOL, you know what I mean as you do it in your library. You test for space available before concatenating etc...

Ohh.. Yes I agree, BUT all the solution code posted here on the forum just uses strcpy/strcat and does not include any such testing code so that was my expectation of any solutions offered using char[ ], hence the comment. The of' quoted Serial Basics being a case in point, although in that case the buffer is sized to avoid the need, but that is not made clear anywhere in the text leaving the reader with the impression that it is OK to just use strcpy without checks.

we agree it's not OK to not test if you are not sure it won't overflow (gee, lots of negative !)

I think we agree as well that even though a library would "not do the stupid stuff and crash" (because it was developed in the right way and is doing the test), the programer should still check for proper completion of the request and decide what to do if the ask failed.

So it's a matter of testing before, or testing after - but in any case it's about testing when necessary.

No I don't agree with that, I might be sure today, but a change in a global buffersize or global string or a change in the method call order / code path could change that tomorrow.
I would say you should test always where the operation is happening with the arguments you have there at hand. So, for example, by using strlcpy or strlcat

Thanx. Tell me please what you mean by "passing a String as reference".

that's what was suggested here (#17)

In your code you had examples like

Where you passed a String pointer String*. No copies there.
A String reference is declared as String & instead of String *
It is really a pointer like String * BUT in your code you can use it like String.
e.g.

int Clock(String &currentTime, unsigned long Refmillis, unsigned long *Currenthour, int *TIme) {
 . . . 
  currentTime = twoDigits(*Currenthour) + ":" + twoDigits(currentminute)+ ":" + twoDigits(currentsecond);
  siz = currentTime.length();

Note the currentTime->length() is not written as currentTime.length().

So using a String & (reference) the code looks you are using a normal String but works like a String*, i.e. updates the result, but without having to use -> everywhere.

Depending on how you use them, String objects can be The Good, The Bad and The Ugly. There are several ways to do apparently innocuous things that end up calling the copy constructor and if you do so enough, your horse is headed down the trail to Ugly town.

That call by reference helps with avoiding one of those constructors being called. It's just one more thing you need to know before you have a chance to use Strings without problems.

Anyway, I removed several of the String * arguments of my functions and accessed them in these functions as global variables. I also used long String manipulations outside the functions. My freeMemory() now shows 276 bytes instead of 127. The compiler shows 56% progmem 63% Ram instead of 56% and 62%. It's been running for several hours with no bugging even tho' I'm using SoftwareSerial. I'll let it run all night to see if there's a little surprise waiting for me in the morning. Yeah, those big Strings can be pretty violent inside of functions. I'll post my new code here.

//https://www.youtube.com/watch?v=4vKxGHGYOtI&t=103s
//#define SCROLL
#define DISPLAY_TEMPERATURES //display pool and air temperatures as well as time & date
#define USE_SOFTWARESERIAL
#ifdef USE_SOFTWARESERIAL
#define SERIAL Serial1
#else
#define SERIAL Serial
#endif
#define MAXLEN 60 
#ifdef USE_SOFTWARESERIAL
#include <SoftwareSerial.h>
#endif
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
//Gnd 
//Vcc 
//SDA(A4) 
//SCL(A5) 
//-------------Clock variables-----------
unsigned long refmillis,currenthour;
int Time[6]; //currenthour_10's,currenthour_1's,currentminute_10's,currentminute_1's
String str_currentTime="", str_currentDate="", str_pooltemp="", str_airtemp="", str_wakeupTime="";
int buzzPin=8,alarmdone=0;
int period[]={500,594,500,594,707,594,707,594,530,500,594};
int duration[]={1000,1000,1000,1000,250,500,250,500,500,1000,1000};
//------------esp01 variables ----------------------------------------------------
#ifdef USE_SOFTWARESERIAL
SoftwareSerial SERIAL(6, 7); // RX, TX
#endif
String AP = "************";       // AP NAME
String PASS = "************"; // AP PASSWORD
String API = "************";   // Write API KEY
String HOST = "api.thingspeak.com";
String PORT = "80";
String str_time="";
String getData="";
int toggle=0;
int countTimeCommand=0; 
boolean found = false; 
const unsigned long delaymillis=12000UL; //120 sec
unsigned long startmillis;
extern char *__brkval;
//--------------LCD variables ---------------
int LCDcol=0;
#ifdef SCROLL
const unsigned long delaydisplaymillis=500UL;
#else
const unsigned long delaydisplaymillis=6000UL;
#endif 
unsigned long startdisplaymillis;
//--------------Big Display-------------------
// Define the bit patters for each of our custom chars. These
// are 5 bits wide and 8 dots deep
const uint8_t custChar[8][8] = {
  {31, 31, 31, 0, 0, 0, 0, 0},      // Small top line - 0
  {0, 0, 0, 0, 0, 31, 31, 31},      // Small bottom line - 1
  {31, 0,  0, 0, 0,  0,  0, 31},    // Small lines top and bottom -2
  {0, 0, 7, 7, 7, 7,  0, 0},        // colon dot -3
  {31, 31, 31, 31, 31, 31, 15, 7},  // Left bottom chamfer full - 4
  {28, 30, 31, 31, 31, 31, 31, 31}, // Right top chamfer full -5
  {31, 31, 31, 31, 31, 31, 30, 28}, // Right bottom chamfer full -6
  {7, 15, 31, 31, 31, 31, 31, 31},  // Left top chamfer full -7
};
// Define our numbers 0 thru 9
// 254 is blank and 255 is the "Full Block"
const uint8_t bigNums[10][6] = {
  {7, 0, 5, 4, 1, 6},         //0
  {0, 5, 254, 1, 255, 1},     //1
  {0, 2, 5, 7, 1, 1},         //2
  {0, 2, 5, 1, 1, 6},         //3
  {7, 1, 255, 254, 254, 255}, //4
  {7, 2, 0, 1, 1, 6},         //5
  {7, 2, 0, 4, 1, 6},         //6
  {0, 0, 5, 254, 7, 254},     //7
  {7, 2, 5, 4, 1, 6},         //8
  {7, 2, 5, 1, 1, 6},         //9
};

void setup() {
  // put your setup code here, to run once:
#ifdef USE_SOFTWARESERIAL
  Serial.begin(115200);
#endif
  pinMode(buzzPin,OUTPUT);
  digitalWrite(buzzPin,LOW);
  lcd.init();                      // initialize the lcd
  lcd.init();
  lcd.backlight();
  delay(500);
  lcd.home();
  lcd.clear();
  for (int cnt = 0; cnt < sizeof(custChar) / 8; cnt++) 
  {
    lcd.createChar(cnt, custChar[cnt]);
  }  
  initClock(0, 0, 0, &refmillis); //init Time to midnite
  SERIAL.begin(9600);
  
  while (found==false)
  {
    sendCommand1("AT",5,"OK");
    sendCommand1("AT+CWMODE=1",5,"OK");
    sendCommand1(("AT+CWJAP=\""+ AP +"\",\""+ PASS +"\"").c_str(),50,"OK");
    sendCommand1("AT+CIPMUX=1",5,"OK");
  }
  startmillis=millis()-delaymillis; 
  startdisplaymillis=millis()-delaydisplaymillis; 
}

void loop() 
{
//--------------- Get info from Internet ---------  
  if ((millis()-startmillis)>=delaymillis)
  {
    while (SERIAL.available()>0) SERIAL.read(); //start with an MT softwareserial buffer before sending GET's
    if (toggle==3)
    {
      getData="GET https://api.thingspeak.com/channels/";
      getData+="1423291";
      getData+="/fields/";
      getData+="1";
      getData+=".json?results=3";
      sendCommand1(("AT+CIPSTART=0,\"TCP\",\""+ HOST +"\","+ PORT).c_str(),15,"OK");
      sendCommand1(("AT+CIPSEND=0," +String(getData.length()+4)).c_str(),4,">");
      getresults1(&str_wakeupTime,"",0); //get wakupTime
#ifdef USE_SOFTWARESERIAL
      Serial.println(str_wakeupTime);
#endif
      toggle=0;
    }        
    else if (toggle==2)
    {
      getData="GET https://api.thingspeak.com/channels/";
      getData+="1418147";
      getData+="/fields/";
      getData+="1";
      getData+=".json?results=3";
      sendCommand1(("AT+CIPSTART=0,\"TCP\",\""+ HOST +"\","+ PORT).c_str(),15,"OK");
      sendCommand1(("AT+CIPSEND=0," +String(getData.length()+4)).c_str(),4,">");
      getresults1(&str_airtemp,"AIR",1); //get airtemp
#ifdef USE_SOFTWARESERIAL
      Serial.println(str_airtemp);
#endif
      toggle=3;      
    }
    else if (toggle==1)
    {
      getData="GET https://api.thingspeak.com/channels/";
      getData+="1418147";
      getData+="/fields/";
      getData+="4";
      getData+=".json?results=3";
      sendCommand1(("AT+CIPSTART=0,\"TCP\",\""+ HOST +"\","+ PORT).c_str(),15,"OK");
      sendCommand1(("AT+CIPSEND=0," +String(getData.length()+4)).c_str(),4,">");
      getresults1(&str_pooltemp,"EAU",1); //get pooltemp
#ifdef USE_SOFTWARESERIAL
      Serial.println(str_pooltemp);
#endif
      toggle=2;
    }
    else if (toggle==0)
    {
      getData="GET https://api.thingspeak.com/apps/thinghttp/send_request?api_key=5R0NJ8SL2DSEAGQA";
      sendCommand1(("AT+CIPSTART=0,\"TCP\",\""+ HOST +"\","+ PORT).c_str(),15,"OK");
      sendCommand1(("AT+CIPSEND=0," +String(getData.length()+4)).c_str(),4,">");
      getresults(); //getTime & date
      parseResults(&refmillis);
#ifdef USE_SOFTWARESERIAL
      Serial.println(str_currentDate);
#endif
#ifdef DISPLAY_TEMPERATURES
      toggle=1;
#endif
    }
    SERIAL.println("\n\r");
    startmillis=millis();
  }
//-------------------- Run the Clock ----------------------------------------------
  Clock(&str_currentTime, refmillis, &currenthour, Time); //update time of day Clock
  if (str_wakeupTime==str_currentTime.substring(0,5)) //alarm if active
  {
    if (alarmdone==0)
    {
      Miles(period, duration);
      alarmdone=1;
    }
  }
  else
  { 
    alarmdone=0;
  }
//----------------Take care of LCD display -----------------------------------------
  if (((int)currenthour>21)||((int)currenthour<9)) //During sleeptime, only show currentTime on big display
//  if (0)
  {
    LCDbig(Time);
  }
  else //During waketime, show currentTime, currentDate, pooltemp, and airtemp on small display
  {
    LCDsmall(&startdisplaymillis,&LCDcol,&str_currentTime,&str_currentDate,&str_pooltemp,&str_airtemp,&str_wakeupTime);
  }
} //void loop()

void initClock(unsigned long valhour, unsigned long valminute, unsigned long valsecond, unsigned long *Refmillis)
{
  *Refmillis = millis() - ((valhour * 3600L + valminute * 60L + valsecond)) * 1000L; //reference to 0h/0m/0s
}

int Clock(String *currentTime, unsigned long Refmillis, unsigned long *Currenthour, int *TIme)
{
  unsigned long deltamillis,currentminute,currentsecond;
  int siz, i;
  deltamillis = (millis() - Refmillis) % ((unsigned long)(60L * 60L * 24L) * 1000L);
  *Currenthour = deltamillis / 3600000L;
  deltamillis -= *Currenthour * 3600000L;
  currentminute = deltamillis / 60000L;
  deltamillis-= currentminute * 60000L;
  currentsecond = deltamillis / 1000L;
  *currentTime = twoDigits(*Currenthour) + ":" + twoDigits(currentminute)+ ":" + twoDigits(currentsecond);
  siz = currentTime->length();
  if (siz<16) for (i = 0; i < 16 - siz; i++) *currentTime += (" ");
  TIme[0] = *Currenthour / 10; 
  TIme[1] = *Currenthour % 10;
  TIme[2] = currentminute / 10;
  TIme[3] = currentminute % 10;
  TIme[4] = currentsecond / 10;
  TIme[5] = currentsecond % 10;
}

void Miles(int *Period,int *Duration)
{
  int i,j;
  long long tIme;
  for (j=0;j<2;j++)
  {
    for (i=0;i<11;i++) //song duration=19sec
    {
      tIme=0L;
      while (tIme<(long long)1000*(long long)Duration[i])
      {
        digitalWrite(buzzPin,HIGH);
        delayMicroseconds(Period[i]);
        digitalWrite(buzzPin,LOW);
        delayMicroseconds(Period[i]);
        tIme+=(2*Period[i]);
      }
    }
    delay(1000);
  } 
  digitalWrite(buzzPin,LOW); 
}

void LCDbig(int *tIme)
{
  printBigNum(tIme[0], 0, 0);
  lcd.setCursor(3,0);
  lcd.print(' ');
  lcd.setCursor(3,1);
  lcd.print(' ');
  printBigNum(tIme[1], 4, 0);
  if (tIme[5]%2==0) //blink the : every second
  {
    lcd.setCursor(7,0); 
    lcd.print((char)3); //:
    lcd.setCursor(7,1);
    lcd.print((char)3); //:
  }
  else
  {
    lcd.setCursor(7,0); 
    lcd.print(' '); //blank
    lcd.setCursor(7,1);
    lcd.print(' '); //blank
  }
  lcd.setCursor(8,0);
  lcd.print(' ');
  lcd.setCursor(8,1);
  lcd.print(' ');
  printBigNum(tIme[2], 9, 0);
  lcd.setCursor(12,0);
  lcd.print(' ');
  lcd.setCursor(12,1);
  lcd.print(' ');
  printBigNum(tIme[3], 13, 0);
}

// -----------------------------------------------------------------
// Print big number over 2 lines, 3 colums per half digit
// -----------------------------------------------------------------
void printBigNum(int number, int startCol, int startRow) {
  // Position cursor to requested position (each char takes 3 cols plus a space col)
  lcd.setCursor(startCol, startRow);
  // Each number split over two lines, 3 chars per line. Retrieve character
  // from the main array to make working with it here a bit easier.
  uint8_t thisNumber[6];
  for (int cnt = 0; cnt < 6; cnt++) {
    thisNumber[cnt] = bigNums[number][cnt];
  }
  // First line (top half) of digit
  for (int cnt = 0; cnt < 3; cnt++) {
    lcd.print((char)thisNumber[cnt]);
  }
  // Now position cursor to next line at same start column for digit
  lcd.setCursor(startCol, startRow + 1);
  // 2nd line (bottom half)
  for (int cnt = 3; cnt < 6; cnt++) {
    lcd.print((char)thisNumber[cnt]);
  }
}

void LCDsmall(unsigned long *Startdisplaymillis,int *lcdcol,String *STR_currentTime,String *STR_currentDate,String *STR_pooltemp,String *STR_airtemp,String *str_wakeupTIME)
{
    String Message,line2;
    int Msglength;
    lcd.setCursor(0, 0);
    if (str_wakeupTIME->length()>0)
    {
      lcd.print(STR_currentTime->substring(0,8)+"   "+*str_wakeupTIME);
    }
    else lcd.print(*STR_currentTime); //Line0
    Message="";
    Message+=*STR_currentDate; //16 characters
    Message+=*STR_pooltemp; //8 characters or 0
    Message+=*STR_airtemp; //8 characters or 0
    if (Message.length()==24) Message+="        ";//16 or 32 characters only
    Msglength = Message.length();
    Message+=*STR_currentDate; //needed for scrolling
    line2=Message.substring(*lcdcol,*lcdcol+16);
    lcd.setCursor(0,1);
    lcd.print(line2); //Line2 scrolls or alternates
    if ((millis()-*Startdisplaymillis)>=delaydisplaymillis) //Line1
    {      
#ifdef SCROLL
      *lcdcol+=1; //scroll
#else
      *lcdcol+=16; //alternate
#endif
      if (*lcdcol >= Msglength)  *lcdcol=0;
      *Startdisplaymillis=millis(); 
    }  
}

void getresults() //get time of day from Internet
{
  char c=' ';  
  int countcomma=0;
  unsigned long waitTime,startTime; 
  str_time="";
  SERIAL.println(getData);
  SERIAL.println("\n\r");
//Typical Response From esp-01
//Recv 87 bytes
//SEND OK
//+IPD,0,32:11:23:32 AM,  Friday 14, May 20210,CLOSED

  waitTime=10000UL;
  startTime=millis();
  while ((c!=':')&&((millis()-startTime)<=waitTime)) //remove unwanted initial characters
  {
    if (SERIAL.available()>0)
    {
      c=SERIAL.read();
    }
  }
  waitTime=1000UL;
  startTime=millis();
  c=' ';
  while ((countcomma!=3)&&((millis()-startTime)<=waitTime)) //get time,date characters up to 3 ','
  {
    if (SERIAL.available()>0)
    {
      c=SERIAL.read();
      str_time.concat(c);
      if (c==',') countcomma++;
    }
  }
}

void getresults1(String *str_out,String str_label,int temperatureresult)
{
  char c=' ';  
  String Str_temp="",str_res="";
  int i,countcolons=0,siz,iter;
  unsigned long waitTime,startTime;  
  SERIAL.println(getData);
  SERIAL.println("\n\r");
  waitTime=10000UL;
  startTime=millis();
  c=' ';
  while ((c!='[')&&((millis()-startTime)<=waitTime)) //remove until [ start of feed
  {
    if (SERIAL.available()>0)
    {
      c=SERIAL.read();
    }
  }
  for (iter=0;iter<3;iter++)
  {
    waitTime=1000UL;
    startTime=millis();
    c=' ';
    countcolons=0;
    while ((countcolons!=5)&&((millis()-startTime)<=waitTime)) //remove until field3
    {
      if (SERIAL.available()>0)
      {
        c=SERIAL.read();
        if (c==':') countcolons++;
      }
    }
    waitTime=1000UL;
    startTime=millis();
    c=' ';
    str_time="";
    while ((c!='}')&&((millis()-startTime)<=waitTime)) //get data = "xxxxx"} or null}
    {
      if (SERIAL.available()>0)
      {
        c=SERIAL.read();
        str_time.concat(c);
      }
    }
    if (str_time.substring(0,1)!="n") Str_temp=str_time; //Copy if field is not null. The last (most recent) valid field will be used.
  } //for (iter=0;iter<3;iter++) next feed
  if (Str_temp.length()!=0) 
  {
    siz = Str_temp.length();
    str_res=Str_temp.substring(1,siz-2);
  }
  if (str_res.length()!=0)
  {
    if (temperatureresult)
    { 
      *str_out=str_label+" "+String(round(str_res.toFloat()))+"C";
      siz=str_out->length();
      if (siz<8) for (i=0;i<8-siz;i++) *str_out+=" ";
    }
    else
    {
      if (str_res.toInt()<0) *str_out="";
      else *str_out=twoDigits(str_res.toInt()/100)+":"+twoDigits(str_res.toInt()%100);
    }
  }
  return str_res;
}

void parseResults(unsigned long *refMillis)
{
  int i=0,j=0,len,newTime[3],startindx=0,hashcode,siz;
  String str_temp,parsechars="::   ,  , "; 
  //
  // typical String to parse is:  11:23:32^AM,^Friday^14,^May^20210,CLOSED
  // 
  //      substring(startindx,i) pchar[j]  found    what
  //      ----------------------------------------------- 
  //                    0     2     :  0    11      hour
  //                    3     5     :  1    23      minute
  //                    6     8     ^  2    32      second
  //                    9     12    ^  3    AM,     AM/PM
  //                    13    19    ^  4    Friday  day name
  //                    20    22    ,  5    14      day date
  //                    23    23    ^  6    -       nothing
  //                    24    27    ^  7    May     month
  //                    28    33    ,  8    20210   year
  //                                ^  9
  
  len=str_time.length();
  if ((len>=10)&&(len<MAXLEN)) //parsing the received string newTime[] values in [hours,minutes,seconds], Day, Date, Month, Year
  {
    while (i<len) 
    {
      if (str_time.charAt(i) == parsechars.charAt(j)) 
      {
        switch (j)
        {
	        case 0: newTime[j]=(str_time.substring(startindx,i)).toInt(); break;//get hour,minute,seconds
	        case 1: newTime[j]=(str_time.substring(startindx,i)).toInt(); break;//get hour,minute,seconds
          case 2: newTime[j]=(str_time.substring(startindx,i)).toInt(); break;//get hour,minute,seconds
          case 3: str_temp=str_time.substring(startindx,i-1);
                  if (str_temp.charAt(0) == 'P') //change to 24-hour format
                  {
                     if (newTime[0]!=12) newTime[0]+=12; 
                  }
                  else
                  {
                    if (newTime[0]==12) newTime[0]-=12;
                  }
                  break;
          case 4: str_temp=str_time.substring(startindx,i); //get day
                  //get day of the week
                  hashcode=codeString(str_temp);
                  switch (hashcode)
                  {
                    case 13760: str_currentDate="Lun "; break;//Mon 
                    case 13280: str_currentDate="Mar "; break;//Tue 
                    case 13440: str_currentDate="Mer "; break;//Wed 
                    case 13984: str_currentDate="Jeu "; break;//Thu 
                    case 13088: str_currentDate="Ven "; break;//Fri 
                    case 14208: str_currentDate="Sam "; break;//Sat 
                    case 12864: str_currentDate="Dim "; break;//Sun 
                    default: break; //do nothing
                  }
                  break;
          case 5: str_currentDate+=twoDigits((str_time.substring(startindx,i)).toInt()); break; //get day date (1-31)
          case 6: break;
          case 7: str_temp=str_time.substring(startindx,i); //get month
                  //get Month
                  hashcode=codeString(str_temp);
                  switch (hashcode)
                  {
                    case 13760: str_currentDate+="/01/"; break;//Jan
                    case 13376: str_currentDate+="/02/"; break;//Feb
                    case 14016: str_currentDate+="/03/"; break;//Mar
                    case 12864: str_currentDate+="/04/"; break;//Apr
                    case 14304: str_currentDate+="/05/"; break;//May
                    case 12992: str_currentDate+="/06/"; break;//Jun
                    case 12928: str_currentDate+="/07/"; break;//Jul
                    case 13600: str_currentDate+="/08/"; break;//Aug
                    case 13824: str_currentDate+="/09/"; break;//Sep
                    case 12672: str_currentDate+="/10/"; break;//Oct
                    case 13120: str_currentDate+="/11/"; break;//Nov
                    case 14240: str_currentDate+="/12/"; break;//Dec
                    default: break; //do nothing 
                  }
                  break;
          case 8: str_currentDate+=str_time.substring(startindx,i-1); break; //get year (4 digits)
          default: break; //do nothibg
        }  // switch(j)     
        j++;
        startindx=i+1;
      } //if (str_Time->charAt(i) == parsechars.charAt(j))
      i++;
    } //while (i<len)
    initClock(newTime[0],newTime[1],newTime[2],refMillis);
    siz = str_currentDate.length();
    if (siz<16) for (i = 0; i < 16 - siz; i++) str_currentDate += " ";
  } //if ((len>=10)&&(len<MAXLEN))
}

int codeString(String in)
{
  int res=0;
  for (int i=0;i<3;i++) res = ((in[i] << 5) + res) ^ res;
  return res;
}
String twoDigits(unsigned long val)
{
  String outString, str_val;
  str_val = String(val);
  if (str_val.length() == 1)
    outString = "0" + str_val;
  else
    outString = str_val;
  return (outString);
}

void sendCommand1(char command[], int maxTime, char readReplay[]) {
  found=false;
#ifdef USE_SOFTWARESERIAL
  Serial.println(freeMemory());
#endif
  while(countTimeCommand < (maxTime*1))
  {
    SERIAL.println(command);
    if(SERIAL.find(readReplay))//ok
    {
      found = true;
      break;
    }
    countTimeCommand++;
  }
  countTimeCommand = 0;
}

int freeMemory() {
  char top;
  return __brkval ? &top - __brkval : &top - __malloc_heap_start;
}

(edited your post to remove your credentials..)

good cleaning up work !

you can probably save a bit more as you have duplicated strings like
getData="GET https://api.thingspeak.com/channels/";

In that case adding reserve(..) in the setup for these globals can avoid having them move on the heap and causing RAM fragmentation.

Taming Arduino Strings has a StringReserveCheck class that will tell you if your reserve was large enough to avoid moving it on the heap.
With your memory limitations you will want to set the minimum reserve that does not result in the String being re-allocated to a different location leaving a hole behind.