0

First of all, sorry if anything isn't well explained; this is my first time asking for help on Stack Overflow. I have an ESP8266 connected to a DHT11 temp/humidity sensor and an ILI9341 TFT-LCD screen to display the data I receive from the NTP server and OpenWeatherMap. I noticed that after a while of normal running it just resets due to what I believe is a shortage of memory (caused by OpenWeatherMap). I tried inspecting the error it gives when it resets and it has something to do with a "Panic" mode of the ESP8266's, although I never managed to get a copy of what it spits out.

I'm asking this question because I'm planning to add a weather forecast section, but when I tried to add the piece of code needed to get the forecast data, it just crashed right off the bat everytime it turned on.

Down here is the code for you to inspect, in case anything is wrong with the Json part, which I believe is the culprit for this, as I'm new to working with the ArduinoJson library, although I got my head around it.

#include <DHT.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ILI9341esp.h>
#include <ESP8266WiFi.h>
#include <time.h>
#include <Adafruit_GFX.h>
#include <ArduinoJson.h>

#define TFT_MISO D6
//#define TFT_LED 3.3V (change to IO pin if you want the screen to be toggled on/off)
#define TFT_SCK D5
#define TFT_MOSI D7
#define TFT_DC D2
#define TFT_RESET D3
#define TFT_CS D8
#define DHTPIN D1
#define DHTTYPE DHT11
#define WIFI_SSID "MY_SSID"
#define WIFI_PASS "MY_PASS"
#define TX_LED D0

WiFiClient client;
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
DHT dht(DHTPIN, DHTTYPE);

int wifitries = 0;
int timezone = 2 * 3600; //when time changes change this from 2 to 1
int dst = 0;
float t = 0.0;
float h = 0.0;
const long interval = 15000;
int elapsed_t = 0;
String APIKEY = "someapikey";
String CityID = "somecityid";
char servername[] = "api.openweathermap.org";
String result;
String weatherDescription = "";
String weatherDesc;
String weatherID;
int Temperature;
int Humidity;
char* tem = "  ";
char* hum = "  ";
char* temp = "  ";
char* humi = "  ";

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(TX_LED, OUTPUT);
  digitalWrite(TX_LED, HIGH);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);
  tft.begin();
  configTime(timezone, dst, "pool.ntp.org", "it.pool.ntp.org");
  dht.begin();

  WiFi.disconnect();
  delay (3000);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.println();
  Serial.println ("Connecting to TP-LINK_DD1E61");

  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.println("Connecting to ");
  tft.println("TP-LINK_DD1E61");
  while ((!(WiFi.status() == WL_CONNECTED))) {
    Serial.print(".");
    wifitries++;
    tft.setTextSize(1);
    tft.print(".");
    delay(300);
  }
  if (wifitries = 15) {
    wifitries = 0;
    WiFi.disconnect();
    delay (3000);
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    while ((!(WiFi.status() == WL_CONNECTED))) {
      Serial.print(".");
      wifitries++;
      tft.setTextSize(1);
      tft.print(".");
      delay(300);
    }
  }
  if (WiFi.status() == WL_CONNECTED) {
    tft.setTextSize(2);
    tft.println();
    tft.println("Connected to ");
    tft.println("TP-LINK_DD1E61");
    delay(500);
    tft.fillScreen(ILI9341_BLACK);
  }

  while (!time(nullptr)) {
    Serial.print("*");
    delay(300);
  }

  tft.drawLine(0, 18, 320, 18, ILI9341_WHITE);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  tft.setCursor(0, 135);
  tft.print("TEMPO");
  tft.setCursor(20, 25);
  tft.println("TEMPERATURA");
  tft.println();
  tft.println();
  tft.setCursor(215, 25);
  tft.println("UMIDITA'");
  tft.setTextSize(1);
  tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
  tft.setCursor(0, 52);
  tft.print("INTERNO");
  tft.setCursor(0, 87);
  tft.print("ESTERNO");

  delay(1000);
  DHT_read();
  getWeatherData();
  displayConditions(Temperature, Humidity, weatherDescription);
}

void DHT_read() {
  float newT = dht.readTemperature();
  if (isnan(newT)) {
    Serial.println("Failed to read from DHT sensor!");
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(109, 43);
    tft.print("!");
  }
  else {
    int t = newT;

    if (t >= 10) {
      char* temp = "  ";
      sprintf(temp, "%02d", t);
    }
    else {
      char* temp = "  ";
      sprintf(temp, "%01d", t);
      tft.setTextColor(ILI9341_BLACK);
      tft.setTextSize(2);
      tft.setCursor(79, 43);
      tft.print("0");
    }

    Serial.print("Temperature: ");
    Serial.print(temp);
    Serial.println();
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    tft.setCursor(67, 43);
    tft.print(temp);
    tft.setCursor(92, 40);
    tft.setTextSize(1);
    tft.print("o");
    tft.setCursor(99, 43);
    tft.setTextSize(2);
    tft.print("C");
    tft.setTextColor(ILI9341_BLACK);
    tft.setCursor(109, 43);
    tft.print("!");
  }
  float newH = dht.readHumidity();
  if (isnan(newH)) {
    Serial.println("Failed to read from DHT sensor!");
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(287, 43);
    tft.print("!");
  }
  else {
    int h = newH;

    if (h >= 10 && h <= 99) {
      char* humi = "  ";
      sprintf(humi, "%02d", h);
      tft.setTextColor(ILI9341_BLACK);
      tft.setTextSize(2);
      tft.setCursor(261, 43);
      tft.print("0");
    }
    else if (h = 100) {
      char* humi = "  ";
      sprintf(humi, "%03d", h);
    }
    else {
      char* humi = "  ";
      sprintf(humi, "%01d", h);
      tft.setTextColor(ILI9341_BLACK);
      tft.setTextSize(2);
      tft.setCursor(261, 43);
      tft.print("0");
    }

    Serial.print("Humidity: ");
    Serial.print(humi);
    Serial.println();
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
    tft.setCursor(237, 43);
    tft.print(humi);
    tft.setCursor(277, 43);
    tft.print("%");
    tft.setTextColor(ILI9341_BLACK);
    tft.setCursor(287, 43);
    tft.print("!");
  }
}

void screen() {
  time_t now = time(nullptr);
  struct tm* p_tm = localtime(&now);

  char* day = "  ";
  sprintf(day, "%02d", p_tm->tm_mday);

  tft.setCursor(192, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(day);

  tft.setCursor(217, 0);
  tft.print("/");

  char* month = "  ";
  sprintf(month, "%02d", p_tm->tm_mon + 1);

  tft.setCursor(231, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(month);

  tft.setCursor(256, 0);
  tft.print("/");

  char* year = "    ";
  sprintf(year, "%04d", p_tm->tm_year + 1900);

  tft.setCursor(268, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(year);

  char* hour = "  ";
  sprintf(hour, "%02d", p_tm->tm_hour);

  tft.setCursor(0, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(hour);

  tft.setCursor(22, 0);
  tft.print(":");

  char* minute = "  ";
  sprintf(minute, "%02d", p_tm->tm_min);

  tft.setCursor(34, 0);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.print(hour);



}

void getWeatherData() {
  if (client.connect(servername, 80))
  { //starts client connection, checks for connection
    client.println("GET /data/2.5/weather?id=" + CityID + "&units=metric&APPID=" + APIKEY + "&lang=it");
    client.println("Host: api.openweathermap.org");
    client.println("User-Agent: ArduinoWiFi/1.1");
    client.println("Connection: close");
    client.println();
  }
  else {
    Serial.println("connection failed");        //error message if no client connect
    Serial.println();
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(0, 220);
    tft.print("CONNESSIONE FALLITA");
  }

  while (client.connected() && !client.available())
    delay(1);                                          //waits for data
  while (client.connected() || client.available())
  { //connected or data available
    char c = client.read();                     //gets byte from ethernet buffer
    result = result + c;
  }

  client.stop();                                      //stop client
  result.replace('[', ' ');
  result.replace(']', ' ');
  Serial.print(result);
  Serial.println();
  char jsonArray [result.length() + 1];
  result.toCharArray(jsonArray, sizeof(jsonArray));
  jsonArray[result.length() + 1] = '\0';
  DynamicJsonBuffer json_buf(3584); //was 4096
  JsonObject &root = json_buf.parseObject(jsonArray); //

  if (!root.success())
  {
    Serial.println("parseObject() failed");
    tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    tft.setCursor(109, 78);
    tft.print("!");
    tft.setCursor(287, 78);
    tft.print("!");

  }
  else {
    tft.setTextColor(ILI9341_BLACK);
    tft.setCursor(109, 78);
    tft.print("!");
    tft.setCursor(287, 78);
    tft.print("!");
  }

  float temperature = root["main"]["temp"];
  float humidity = root["main"]["humidity"];
  String weather = root["weather"]["main"];
  String description = root["weather"]["description"];
  String id = root["weather"]["id"];
  weatherDescription = description;
  Temperature = temperature;
  Humidity = humidity;
  weatherID = id;

  result = "";  //to clean memory and keep it from running out of space
}

void displayConditions(int Temperature, int Humidity, String weatherDescription) {
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

  if (Temperature >= 10) {
    char* tem = "  ";
    sprintf(tem, "%02d", Temperature);
  }
  else {
    char* tem = "  ";
    sprintf(tem, "%01d", Temperature);
    tft.setTextColor(ILI9341_BLACK);
    tft.setTextSize(2);
    tft.setCursor(79, 78);
    tft.print("0");
  }

  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setCursor(67, 78);
  tft.print(tem);
  tft.setCursor(92, 75);
  tft.setTextSize(1);
  tft.print("o");
  tft.setCursor(99, 78);
  tft.setTextSize(2);
  tft.print("C");

  if (Humidity >= 10 && Humidity <= 99) {
    char* hum = "  ";
    sprintf(hum, "%02d", Humidity);
    tft.setTextColor(ILI9341_BLACK);
    tft.setTextSize(2);
    tft.setCursor(261, 78);
    tft.print("0");
  }
  else if (Humidity = 100) {
    char* hum = "  ";
    sprintf(hum, "%03d", Humidity);
  }
  else {
    char* hum = "  ";
    sprintf(hum, "%01d", Humidity);
    tft.setTextColor(ILI9341_BLACK);
    tft.setTextSize(2);
    tft.setCursor(261, 78);
    tft.print("0");
  }

  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setCursor(237, 78);
  tft.print(hum);
  tft.setCursor(277, 78);
  tft.print("%");

  if (weatherDesc != weatherDescription) {
    weatherDesc = weatherDescription;
    tft.fillRect(0, 150, 320, 240, ILI9341_BLACK);
    tft.setCursor(0, 150);
    tft.print(weatherDescription);
  }
  else {
    tft.setCursor(0, 150);
    tft.print(weatherDescription);
  }
}


void loop() {
  screen();
  if (millis() > elapsed_t + interval) {
    elapsed_t = millis();
    getWeatherData();
    DHT_read();
    displayConditions(Temperature, Humidity, weatherDescription);
    Serial.print("Free heap: ");
    Serial.print(ESP.getFreeHeap());
    Serial.println();
  }
  if (ESP.getFreeHeap() < 1000) {
    ESP.reset();
  }
}

EDIT This is the payload I get from running the code:

        {"coord":{"lon":longitude,"lat":latitude},
        "weather": {"id":800,"main":"Clear","description":"cielo sereno","icon":"01d"} ,"base":"stations",
    "main":{"temp":16.56,"feels_like":13.87,"temp_min":13.33,"temp_max":20,"pressure":1022,"humidity":38},
    "visibility":10000,
    "wind":{"speed":1.5,"deg":80},
    "clouds":{"all":0},"dt":1586590775,
"sys":{"type":1,"id":6776,"country":"IT","sunrise":1586579815,"sunset":1586627707},
    "timezone":7200,"id":city_id,"name":"city_name","cod":city_code}
GoTVm
  • 31
  • 6
  • You do over allocated a lot for the `DynamicJsonBuffer json_buf(3584)`, according to the payload send back from the API you used, the json_buf only need about 800 bytes. However, it is not the cultprit for the heap fragmentation. I will explain why when I have time later. – hcheung Apr 10 '20 at 14:04
  • Add reading sensor data to this project https://github.com/ThingPulse/esp8266-weather-station-color/ from yours truly and you're done ;-) As for processing JSON I propose you look into https://github.com/squix78/json-streaming-parser. By streaming data you don't have to allocate a fixed amount of memory. – Marcel Stör Apr 11 '20 at 08:02

2 Answers2

0

First of all, you do over-allocated quite a bit for the DynamicJsonBuffer json_buf(3584), according to the payload send back from the API you used, the json_buf would only need less than 800 bytes, so DynamicJsonBuffer json_buf(800) would be more than sufficient. You can use ArduinoJson Assistant to calculate the buffer size required by copying and pasting the json payload into the input box on the page.

Over-size ArduinoJson buffer however is not the cultprit for the heap fragmentation that you are facing. One of the problem that String class caused heap fragmentation come from String concatenation, and this is what happen to your case. String concatenation gives Arduino users the capability of put two strings together like in JavaScript or Pyhton, String temp = "Temperature=" + String(temperature)+" Celsius". However, this statement along generates 5 heap allocations (not 4) even though you only want the final one.

In your code, you declare a global variable result and you are doing String concatenation in your function.

String result;

// later in your function

void getWeatherData() {

  // at part of your function

  while (client.connected() || client.available())
  { //connected or data available
    char c = client.read();                //gets byte from ethernet buffer
    result = result + c;
  }

  // at end of your function  

  result = "";  //to clean memory and keep it from running out of space
}

When you do concatenation, the original allocation for your global variable result may no longer have enough space for the concatenated variable, so it create a temporary heap and do the concatenation, and then eventually put the result back to a newly allocated memory for result on the heap, leaving a hole at the heap for the original result variable. What make this worst is that this is happening for each iteration of the while loop. This is why even some of the heap allocations get free-up at the end of function, it does not necessary will be re-usable (think of a piece of cheese with a lot of holes on it).

BTW, your code:

result = "";  //to clean memory and keep it from running out of space

never really free up the memory allocation. This is another common misunderstanding.

Short term fix - Use String locally

Having said that, String class is not always the evil if you know what's going on and how to use it. One of the quick fix for your problem (as I don't have time to optimise the code for you) is to use it locally within the function and do not use the global variable for the String result;. I did a quick test, by removing the global variable result and declare as a "throw-away" local variable within the getWeatherData() function, the free heap memory stabilised and no longer caused crash. When you use String class within a function, it does not leave a hole in the overall heap space, but get free up at the end of the function.

// String result; //comment the global variable out

void getWeatherData() {

  String result;    //declare it as a local variable

  while (client.connected() || client.available())
  { //connected or data available
    char c = client.read();           //gets byte from ethernet buffer
    result = result + c;
  }

  //result = "";  //this is not necessary and does not free up heap
}

Long term fix - Don't use String class

For a better fix, do not use String concatenation within the while loop. Here is the version without using String class, and quite a bit clean up for eliminating the unnecessary global variables (also some re-factoring some of the repetitive codes).

#include <Arduino.h>
#include <DHT.h>
#include <ESP8266WiFi.h>
#include <time.h>
#include <ArduinoJson.h>
#include <Adafruit_Sensor.h>
// #include <Adafruit_ILI9341esp.h>
// #include <Adafruit_GFX.h>

#define TFT_MISO D6
//#define TFT_LED 3.3V (change to IO pin if you want the screen to be toggled on/off)
#define TFT_SCK D5
#define TFT_MOSI D7
#define TFT_DC D2
#define TFT_RESET D3
#define TFT_CS D8

#define DHTPIN D1
#define DHTTYPE DHT11

#define WIFI_SSID "wifi-ssid"
#define WIFI_PASS "wifi-password"
#define TX_LED D0

WiFiClient client;
// Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
DHT dht(DHTPIN, DHTTYPE);

int timezone = 2 * 3600; //when time changes change this from 2 to 1
int dst = 0;

const unsigned long interval = 15000;
unsigned long elapsed_t = 0;

const char APIKEY[] = "open-weather-api-key";  //replace with actual api-key
const char CityID[] = "cityID";  //replace with actual city ID
char servername[] = "api.openweathermap.org";

void displayConditions(int Temperature, int Humidity, char *weatherDescription) {
  // tft.setTextSize(2);
  // tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);

  char tem[3] = {0};
  if (Temperature >= 10) {
    sprintf(tem, "%02d", Temperature);
  }
  else {
    sprintf(tem, "%01d", Temperature);
    // tft.setTextColor(ILI9341_BLACK);
    // tft.setTextSize(2);
    // tft.setCursor(79, 78);
    // tft.print("0");
  }

  // tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  // tft.setCursor(67, 78);
  // tft.print(tem);
  // tft.setCursor(92, 75);
  // tft.setTextSize(1);
  // tft.print("o");
  // tft.setCursor(99, 78);
  // tft.setTextSize(2);
  // tft.print("C");

  char hum[4] = {0};
  if (Humidity >= 10 && Humidity <= 99) {
    sprintf(hum, "%02d", Humidity);
    // tft.setTextColor(ILI9341_BLACK);
    // tft.setTextSize(2);
    // tft.setCursor(261, 78);
    // tft.print("0");
  }
  else if (Humidity == 100) {
    sprintf(hum, "%03d", Humidity);
  }
  else {
    sprintf(hum, "%01d", Humidity);
    // tft.setTextColor(ILI9341_BLACK);
    // tft.setTextSize(2);
    // tft.setCursor(261, 78);
    // tft.print("0");
  }

  // tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  // tft.setCursor(237, 78);
  // tft.print(hum);
  // tft.setCursor(277, 78);
  // tft.print("%");

  static char weatherDesc[10];
  if (strcmp(weatherDesc, weatherDescription) != 0) {
    strcpy(weatherDesc, weatherDescription);
    // tft.fillRect(0, 150, 320, 240, ILI9341_BLACK);
    // tft.setCursor(0, 150);
    // tft.print(weatherDescription);
  }
  else {
    // tft.setCursor(0, 150);
    // tft.print(weatherDescription);
  }
}

void DHT_read() {

  float newT = dht.readTemperature();
  float newH = dht.readTemperature();
  if (isnan(newT) || isnan(newH)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    // tft.setTextSize(2);
    // tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    // tft.setCursor(109, 43);
    // tft.print("!");
    // tft.setCursor(287, 43);
    // tft.print("!");
    return;
  }
  char condition[] = "";
  displayConditions((int)newT, (int)newH, condition);
}

void screen() {
  char timeNow[20];
  time_t now = time(nullptr);
  struct tm* p_tm = localtime(&now);

  strftime(timeNow, 20, "%H:%M  %d:%m:%Y", p_tm);
  Serial.println(timeNow);
  // tft.setCursor(0, 0);
  // tft.setTextSize(2);
  // tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  // tft.print(timeNow);
}

void getWeatherData() {

  if (client.connect(servername, 80))
  { //starts client connection, checks for connection
    char buff[110];
    char getString[] = "GET /data/2.5/weather?id=%s&units=metric&APPID=%s&lang=it";
    sprintf(buff, getString, CityID, APIKEY);
    client.println(buff);
    client.println(F("Host: api.openweathermap.org"));
    client.println(F("User-Agent: ArduinoWiFi/1.1"));
    client.println(F("Connection: close"));
    client.println();
  }
  else {
    Serial.println(F("connection failed"));        //error message if no client connect
    Serial.println();
    // tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    // tft.setCursor(0, 220);
    // tft.print(F("CONNESSIONE FALLITA"));
    return;
  }

  while (client.connected() && !client.available())
    delay(1);                                          //waits for data

  char result[800];
  int i = 0;
  while (client.connected() || client.available())
  { //connected or data available
    result[i++] = (char)client.read();
  }

  client.stop();                                      //stop client
  result[strlen(result) + 1] = '\0';
  Serial.println(result);

  DynamicJsonBuffer json_buf(800); //was 4096
  JsonObject &root = json_buf.parseObject(result); //

  if (!root.success())
  {
    Serial.println(F("parseObject() failed"));
    // tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    // tft.setCursor(109, 78);
    // tft.print("!");
    // tft.setCursor(287, 78);
    // tft.print("!");
    return;
  }

  // tft.setTextColor(ILI9341_BLACK);
  // tft.setCursor(109, 78);
  // tft.print("!");
  // tft.setCursor(287, 78);
  // tft.print("!");

  char weatherDescription[10] = {0};
  strcpy(weatherDescription, (const char*)root["weather"][0]["main"]);
  weatherDescription[strlen(weatherDescription) + 1] = '\0';

  int temperature = (int)root["main"]["temp"];
  int humidity = (int)root["main"]["humidity"];
  int weatherID = root["weather"][0]["id"];    //this was not used anywhere in the program

  displayConditions(temperature, humidity, weatherDescription);
}



void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(TX_LED, OUTPUT);
  digitalWrite(TX_LED, HIGH);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(115200);
  // tft.begin();
  // dht.begin();

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.println (F("Connecting to TP-LINK_DD1E61"));

  // tft.setRotation(3);
  // tft.fillScreen(ILI9341_BLACK);
  // tft.setTextSize(2);
  // tft.println(F("Connecting to "));
  // tft.println(F("TP-LINK_DD1E61"));
  while (WiFi.status() != WL_CONNECTED) {
   Serial.print(".");
   // tft.setTextSize(1);
   // tft.print(".");
   delay(300);
  }

  // query the ntp should be only after the establish of wifi connection
  configTime(timezone, dst, "pool.ntp.org", "it.pool.ntp.org");
  while (!time(nullptr)) {
   Serial.print("*");
   delay(300);
  }

  Serial.println(F("Connceted"));
  // tft.setTextSize(2);
  // tft.println();
  // tft.println(F("Connected to "));
  // tft.println(F("TP-LINK_DD1E61"));
  // delay(500);
  // tft.fillScreen(ILI9341_BLACK);

  // tft.drawLine(0, 18, 320, 18, ILI9341_WHITE);
  // tft.setTextSize(2);
  // tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  // tft.setCursor(0, 135);
  // tft.print("TEMPO");
  // tft.setCursor(20, 25);
  // tft.println(F("TEMPERATURA"));
  // tft.println();
  // tft.println();
  // tft.setCursor(215, 25);
  // tft.println(F("UMIDITA'"));
  // tft.setTextSize(1);
  // tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
  // tft.setCursor(0, 52);
  // tft.print(F("INTERNO"));
  // tft.setCursor(0, 87);
  // tft.print(F("ESTERNO"));

}

void loop() {
  screen();
  if (millis() > elapsed_t + interval) {
    elapsed_t = millis();
    getWeatherData();
    DHT_read();
    // displayConditions(Temperature, Humidity, weatherDescription);
    Serial.print("Free heap: ");
    Serial.print(ESP.getFreeHeap());
    Serial.println();
  }
  delay(1000);  // only update the time once per second
 }

You can learn more about "The Evils of Arduino Strings" in more details. I hope my example will help you to learn something on how to manage the memory and avoid of using String class.

hcheung
  • 3,377
  • 3
  • 11
  • 23
  • Okay, I started by completely removing the APIKEY and CityID String variables: I only called them once, so I'd rather straight up type them in the getWeatherData() function. What I actually quite fail to understand is the part about having result be an array `(result[i++] = c;)`. Anyway, I tried declaring result in the getWeatherData() function, so it becomes a local variable. I will tell you how it goes, thanks for now. – GoTVm Apr 10 '20 at 17:23
  • I update my answer by posting a version without using String class for your reference. I did quite some re-write/re-factor to clean up the code. The code running well over night without any crash or over use of heap. BTW, I don't have the tft display, so most of the codes for tft display are comment out. Hope you will learn something from the code. Good luck and have fun with it. – hcheung Apr 11 '20 at 03:51
  • BTW, I believe that both ntp and open weather server cache the request, so there is no point to query the server so often (15s), maybe you should change it to 1 minute (and update time for every 1s). – hcheung Apr 11 '20 at 03:53
-1

You are right with the Json part, but before that some tips:

  • Never post your logins/api keys/passwords - I removed them from the code
  • replace

    if (millis() > elapsed_t + interval) {

with (does the same but is rollover safe)

if (millis() - elapsed_t > interval) {

Now t oArduinoJson -this lib is for your use "bloated" try to manually parse the string -if you post a real stringIcould show you how to. And get rid of String class

  String APIKEY = "someapikey";
  String CityID = "somecityid";
  char servername[] = "api.openweathermap.org"; // GOOD example of how to avoid String class
  String result;
  String weatherDescription = "";
  String weatherDesc;
  String weatherID;

String class fractures the heap and causes usually the esp8266/esp32 to crash after some time. The free heap check doesn't help - there is enough heap but its fractured so long Strings could not be processed correctly. There is no garbage collection to solve this issue on micro controllers.

Codebreaker007
  • 2,911
  • 1
  • 10
  • 22
  • First of all, thanks for removing my private data, I seriously did not think of doing that beforehand. Thank you very much. I will try the millis thing, but as to the string I should post, what string should I post? The data I get from OpenWeatherMap? – GoTVm Apr 10 '20 at 15:31
  • Yes the json you decode with ArduinoJson (before posting check for personal data and if overwrite it with other characters of the same type) – Codebreaker007 Apr 10 '20 at 20:50
  • This is the payload I get from running the code: `{"coord":{"lon":longitude,"lat":latitude},"weather": {"id":800,"main":"Clear","description":"cielo sereno","icon":"01d"} ,"base":"stations","main":{"temp":16.56,"feels_like":13.87,"temp_min":13.33,"temp_max":20,"pressure":1022,"humidity":38},"visibility":10000,"wind":{"speed":1.5,"deg":80},"clouds":{"all":0},"dt":1586590775,"sys":{"type":1,"id":6776,"country":"IT","sunrise":1586579815,"sunset":1586627707},"timezone":7200,"id":city_id,"name":"city_name","cod":city_code}` – GoTVm Apr 11 '20 at 07:41