Weather Station's code crashing after some hours ( ARDUINOMEGA2560+SIM808+MYSQL)

Hello everyone,
I am developing a project to build a weather station with an Arduino MEGA 2560, with the following components: rain gauge, anenometer, windsock, BME280 and Sht20 sensors. In addition, it also sends data to a MYSQL database via the SIM808 module every 10 minutes. My code is running normally. The problem is that after around 15/20 hours running it just crashes and stops to send data to the database. If I reset the arduino mechanically it sends the data again, but this is not ideal, because the project is installed in a distant place and does not pay off to visit it every 15 hours to unlocked it. Do you guys know how to solve this problem? I'm new to the Arduino’s world, so I know my code isn't perfect but at least it's working. I was looking to make the code a little more dynamic or add something like a watchdog to restart every time the program crashes. Can you guy help me to do something like that?

The code:

#include <SoftwareSerial.h>
#include "DFRobot_SHT20.h"
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)


#define TINY_GSM_MODEM_SIM808


#include <TinyGsmClient.h>



SoftwareSerial gprsSerial(10, 11);


Adafruit_BME280 bme; // I2C

// Constants definitions anem.
const float pi = 3.14159265;           // Numero pi
int period = 5000;               // Tempo de medida(miliseconds) 5000
int radius = 147;      // Raio do anemometro(mm)


// Variable definitions ANENOMETRO

unsigned int counter = 0; // magnet counter for sensor
unsigned int RPM = 0;          // Revolutions per minute
float speedwind = 0;         // Wind speed (Km/h)

//Const def Pluviômetro

#define INTERRUPT_INPUT 3
 
volatile int pulse_counter_ISR;
int pulse_counter;


// Const def biruta

int pin=0;  // A0 entrada do biruta *
float valor =0;
int Winddir =0;



DFRobot_SHT20    sht20;


void setup(){   


Serial.begin(4800);
 gprsSerial.begin(4800);
 

  gprsSerial.flush();
  Serial.flush();

  // attach or detach from GPRS service
  gprsSerial.println("AT+CGATT?");
  delay(100);
  toSerial();

    // bearer settings
  gprsSerial.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
  delay(2000);
  toSerial();

  // bearer settings
  gprsSerial.println("AT+SAPBR=3,1,\"APN\",\"taif\"");
  delay(2000);
  toSerial();

  // bearer settings
  gprsSerial.println("AT+SAPBR=0,1");
  delay(2000);
  gprsSerial.println("AT+SAPBR=1,1");
  delay(2000);
  toSerial();
   


    //pluviometro
  digitalWrite(INTERRUPT_INPUT, HIGH); // activate internal pull-up, so normally input is HIGH
  attachInterrupt(INTERRUPT_INPUT - 2, interrupt_handler, FALLING); // count on FALLING edge

  //bme280
     
    bool status;
    status = bme.begin(); 

   

  // Anemômetro
  pinMode(2, INPUT);  // Entrada anemometro *
  digitalWrite(2, HIGH);  //internall pull-up active

  //sensorsolo

    sht20.initSHT20();                                  // Init SHT20 Sensor

   

}



// Calculo da velocidade wind  *************
void windvelocity(){
  speedwind = 0;
  counter = 0; 
  attachInterrupt(0, addcount, RISING);
  unsigned long millis();       
  long startTime = millis();
  while(millis() < startTime + period) {
  }
   
}


void RPMcalc(){
  RPM=((counter)*60)/(period/1000);  // Calculate revolutions per minute (RPM)
}


void SpeedWind(){
  speedwind = (((4 * pi * radius * RPM)/60) / 1000);  // Calculate wind speed on khm/
 
}

void addcount(){
  counter++;
}

// Fim calculo veloc wind 



void loop()
{ 
 
 
// PLUVIOMETRO

    noInterrupts(); // disable interrupts
    pulse_counter=pulse_counter_ISR; // copy volatile variable into normal variable
    pulse_counter_ISR=0; // reset ISR counter
    interrupts(); // enable interrupts

// Ler anemometro

 windvelocity();
 RPMcalc();
 SpeedWind();

// Ler biruta
String Direc;
valor = analogRead(pin)* (5.0 / 1023.0);

if (valor <= 0.58) {
Winddir = 315;
Direc= "SUDESTE ----> NOROESTE";
}
else if (valor <= 0.65) {
Winddir = 270;
Direc= "LESTE ----> OESTE";
}
else if (valor <= 0.75) {
Winddir = 225;
Direc ="NORDESTE ----> SUDOESTE";
}
else if (valor <= 0.9) {
Winddir = 180;
Direc= "NORTE ----> SUL";
}
else if (valor <= 1.1) {
Winddir = 135;
Direc= "NOROESTE ----> SUDESTE";
}
else if (valor <= 1.3) {
Winddir = 90;
Direc= "OESTE ----> LESTE";
}
else if (valor <= 1.7) { 
Winddir = 45;
Direc= "SUDOESTE ----> NORDESTE";
}
else { 
Winddir = 000;
Direc = "SUL ----> NORTE";
}

float humd = sht20.readHumidity();                  // Read Humidity
float temp = sht20.readTemperature();               // Read Temperature


// initialize http service
   gprsSerial.println("AT+HTTPINIT");
   delay(2000);
   toSerial();

// set http param value
   gprsSerial.print("AT+HTTPPARA=\"URL\",\"MEUSERVIDOR//write_data.php?data1=");
   gprsSerial.print(getBME('C'));

   gprsSerial.print("&data2=");
   gprsSerial.print(getBME('K'));

   gprsSerial.print("&data3=");
   gprsSerial.print(getBME('H'));

   gprsSerial.print("&data4=");
   gprsSerial.print(getBME('P'));

   gprsSerial.print("&data5=");
   gprsSerial.print(getBME('A'));

   gprsSerial.print("&data6=");
   gprsSerial.print(speedwind);

   gprsSerial.print("&data7=");
   gprsSerial.print(Direc);

   gprsSerial.print("&data8=");
   gprsSerial.print(temp);

   gprsSerial.print("&data9=");
   gprsSerial.print(humd);

   gprsSerial.print("&data10=");
   gprsSerial.print(pulse_counter*0.25);

   gprsSerial.println("\"");
   delay(2000);
   toSerial();

   // set http action type 0 = GET, 1 = POST, 2 = HEAD
   gprsSerial.println("AT+HTTPACTION=0");
   delay(6000);
   toSerial();

   // read server response
   gprsSerial.println("AT+HTTPREAD");
   delay(1000);
   toSerial();

   gprsSerial.println("");
   gprsSerial.println("AT+HTTPTERM");
   toSerial();
   delay(300);

   gprsSerial.println("");
   delay(600000);

   
 
   
}

void toSerial()
{
  while(gprsSerial.available()!=0)
  {
    Serial.write(gprsSerial.read());
  }
}

float getBME(char type)
{
   // Robojax.com BME280 Code
  float value;
    float temp = bme.readTemperature();// read temperature
    float pressure = bme.readPressure() / 100.0F; // read pressure
    float rel_hum = bme.readHumidity();// read humidity
    float alt =bme.readAltitude(SEALEVELPRESSURE_HPA);// read altitude
   if(type =='F')
   {
    value = temp *9/5 + 32;//convert to Fahrenheit
   }else if(type =='K')
   {
    value = temp + 273.15;//convert to Kelvin
   }else if(type =='H')
   {
    value = rel_hum;//return relative humidity
   }else if(type =='P')
   {
    value = pressure;//return pressure
   }else if(type =='A')
   {
    value = alt;//return approximate altitude
   }else{
    value = temp;// return Celsius
   }
   return value;
}//getBME

void interrupt_handler()
{
  pulse_counter_ISR = pulse_counter_ISR + 1;
}

 void printDegree()
{
   // Robojax.com Code
    Serial.print("\xC2");
    Serial.print("\xB0"); 
}

PHP CODE ON SERVER

<?php
    // Prepare variables for database connection
   $servername = "myserver";
$database = "mydb";
$username = "myuser";
$password = "mypsw";
// Create connection
$conn = mysqli_connect($servername, $username, $password, $database);
// Check connection
if (!$conn) {
    die("Connection failed: " . mysqli_connect_error());
}
    // Prepare the SQL statement
    $sql = "INSERT INTO Dados_Estacao(TempC,TempK,UR,Pressao,Altitude,VV,Direc,Temp_solo,Umidade_solo,Precip) VALUES ('".$_GET["data1"]."','".$_GET["data2"]."','".$_GET["data3"]."','".$_GET["data4"]."','".$_GET["data5"]."','".$_GET["data6"]."','".$_GET["data7"]."','".$_GET["data8"]."','".$_GET["data9"]."','".$_GET["data10"]."')";

if ($conn->query($sql) === TRUE) {
    echo "New record created successfully";
} else {
    echo "Error: " . $sql . "
" . $conn->error;
}

How is it powered?

ieee488:
How is it powered?

With a 12V sealed battery and a 100W solar panel, and also I put a tensor regulator on the charger controller's output to distribute exactly 10V to both Arduino and SIM module

Do you know that it has crashed? Or is it simply that no more ethernet data is received? Put in some serial prints so you can tell the difference.

wildbill:
Do you know that it has crashed? Or is it simply that no more ethernet data is received? Put in some serial prints so you can tell the difference.

I ran before with several serial prints and I realized the program was crashing. When the problem is with the server connection, after some time, the program gets the connection enable again and keeps sending the data, I lose some data but is a minor problem. An example of what I saw happening on the serial monitor is when I used serial prints like these one:

Serial.println();
    
    Serial.print("Temperature Celsius = ");
    Serial.print(getBME('C'));
    printDegree();
    Serial.print("C \n\r"); 
    Serial.print("Temperature Kelvin = ");
    Serial.print(getBME('K'));
    Serial.println("K ");       


    Serial.print("Pressure = ");
    Serial.print(getBME('P'));
    Serial.println(" hPa ");


    Serial.print("Humidity = ");
    Serial.print(getBME('H'));
    Serial.println("% ");

    
    Serial.print("Approx. Altitude =");
    Serial.print(getBME('A'));
    Serial.println(" m ");

    
   
    Serial.print("Direcao = ");
    Serial.print(Direc);

    Serial.print("\n\r");


    Serial.print("Veloc = ");
    Serial.print(speedwind);
    Serial.println(" m/s ");


    Serial.print("Time:");
    Serial.print(millis());
    Serial.print("\n\r");
    Serial.print(" Temperatura do solo:");
    Serial.print(temp, 1);
    Serial.print("C\n\r");
    Serial.print(" UR do solo:");
    Serial.print(humd, 1);
    Serial.print("%\n\r");

    
    Serial.print(" Precipitação:");
    Serial.print(pulse_counter*0.25);
    Serial.print(" mm ");
    Serial.print("\n\r");

    Serial.println();

and after some loops, it just stops to print all the requests and just crash and stop the looping. I imagine something like this is happening now as well...

look for the use of "String" in the "loop".

Paul

Are you talking about the String Direc; that I declared inside the loop ?? I just fixed that by declaring it globally, but I still don't think this will be enough to stop crashing my code. Do you have any ideia how to set a watchdog to this case, so I can be sure my code will reset if it crashes?

edsfernandes:
Are you talking about the String Direc; that I declared inside the loop ?? I just fixed that by declaring it globally, but I still don't think this will be enough to stop crashing my code. Do you have any ideia how to set a watchdog to this case, so I can be sure my code will reset if it crashes?

Yes. Every time you move something into the String, and new String is created. Eventually, no more memory is available for the new String. The Arduino convention is to use "string" which is terminated with a /0, null.

Paul

Does this happen when declaring floats inside the loop as well ?

No. Floats are ALWAYS 4 bytes long, never changes. Strings, on the other hand, are apt to change in length every time something is moved into one. At a minimum, a String consists of a length(integer) and the text.

Paul

No, it's just things that are dynamically allocated on the heap, like String objects. They're catastrophically dangerous on an Arduino because they have so little RAM.

However, in this case, l'm not convinced that Strings are hurting you. I would replace them with plain old c strings just out of principle, but I don't actually think it would help.