SimpleTimer question - calling multiple functions

I have the following code which I have adapted for my needs and it works well.

But it has the dreaded “delay” functions, which I am trying to replace with timers as a practice exercise.

Hardware is :
Wemos D1 mini
Lolin 1.44" TFT
DHT12 sensor

It reads indoor temp/humidity/pressure from the DHT12, and outdoor reading from openweathermap.org

//Wifi weather station v3.0.0
//
//Credit to educ8s.tv for the json code
//http://educ8s.tv/esp8266-weather-display/
//
//v3.0.0 just shows location and web weather.
//Added DHT indoor temp and humidity sensor
//
//updated v3.0.0 to work with SimpleTimer interval rather than delay

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>  // use 5.xx.xx stable (not BETAS's - causes compile errors).
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SimpleTimer.h>    //timer
#include <WEMOS_DHT12.h>

//Setup tft pins
#define TFT_RST -1 //for TFT I2C Connector Shield V1.0.0 and TFT 1.4 Shield V1.0.0
#define TFT_CS D4  //for TFT I2C Connector Shield V1.0.0 and TFT 1.4 Shield V1.0.0
#define TFT_DC D3  //for TFT I2C Connector Shield V1.0.0 and TFT 1.4 Shield V1.0.0

//Setup display name as tft
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);


//Setup DHT temp and humidity sensor
DHT12 indoor;


//Setup simple timer
SimpleTimer timer;

const char* ssid     = "";      // SSID of local network
const char* password = "";   // Password on network
String APIKEY = "";  
String CityID = ""; //


WiFiClient client;
char servername[]="api.openweathermap.org";  // remote server we will connect to
String result;

int  counter = 60;
String weatherDescription ="";
String weatherLocation = "";
String Country;
float Temperature;
float Humidity;
float Pressure;


void setup()
{
  Serial.begin(115200);
  int cursorPosition=0;
  
  tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab
  tft.setRotation(3);           //where 0=0; 1=90; 2=180; 3=270degrees
  tft.fillScreen(ST77XX_BLACK); //clears screen with black page
  tft.setTextSize(2);           //same text size for whole sketch this time
  tft.setTextColor(ST77XX_WHITE);
  tft.setCursor(0, 0);
  tft.println("Connecting");
  Serial.println("Connecting");
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    tft.setCursor(cursorPosition,2); 
    tft.print(".");
    cursorPosition++;
  }
 
  tft.fillScreen(ST77XX_BLACK); 
  tft.setCursor(0, 0);
  tft.print("Connected!");
  Serial.println("Connected");
  delay(1000);


  //Setup timers
  timer.setInterval(2000L, displayWeather);     //Setup a function to be called every 2 seconds
  timer.setInterval(2000L, displayConditions);  //Setup a function to be called every 2 seconds
  
}

void loop()
{

     //timer.run(); // Initiates SimpleTimer
    
     if(counter == 60) //Get new data every 10 minutes
    {
      counter = 0;
      displayGettingData();
      delay(1000);
      getWeatherData();
    }else
    {
      counter++;

      timer.run(); // Initiates SimpleTimer
      //displayWeather(weatherLocation,weatherDescription);
      //delay(2000);
      //displayConditions(Temperature,Humidity,Pressure);
      //delay(2000);
    }
}

void getWeatherData() //client function to send/receive GET request data.
{
  if (client.connect(servername, 80)) {  //starts client connection, checks for connection
    client.println("GET /data/2.5/weather?id="+CityID+"&units=metric&APPID="+APIKEY);
    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();
  }

  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.println(result);

char jsonArray [result.length()+1];
result.toCharArray(jsonArray,sizeof(jsonArray));
jsonArray[result.length() + 1] = '\0';

StaticJsonBuffer<1024> json_buf;
JsonObject &root = json_buf.parseObject(jsonArray);
if (!root.success())
{
  Serial.println("parseObject() failed");
}

String location = root["name"];
String country = root["sys"]["country"];
float temperature = root["main"]["temp"];
float humidity = root["main"]["humidity"];
String weather = root["weather"]["main"];
String description = root["weather"]["description"];
float pressure = root["main"]["pressure"];

weatherDescription = description;
weatherLocation = location;
Country = country;
Temperature = temperature;
Humidity = humidity;
Pressure = pressure;

}

// PAGE 1of2
void displayWeather(String location,String description)
{
  tft.fillScreen(ST77XX_BLACK);
  tft.setCursor(0,0);
  tft.setTextColor(ST77XX_WHITE);
  tft.print(location);
  tft.print(", ");
  tft.println(Country);
  tft.println("");
  tft.println("Currently:");
  tft.print(description);
}


//PAGE 2of2
void displayConditions(float Temperature,float Humidity, float Pressure)
{

    tft.fillScreen(ST77XX_BLACK); //clears screen with black page
    tft.setTextSize(2);           //same text size for whole sketch this time
    tft.setTextColor(ST77XX_WHITE);
    tft.setCursor(0, 0);
    tft.println("Indoor");

    if(indoor.get()==0); //reads indoor sensor

    int hin = (indoor.humidity);   //can calibrate sensors here e.g.  float hin = (indoor.humidity + 1.5); 
    float tin = (indoor.cTemp); 
      
    //INDOOR DHT SENSOR
    // if (hin==0 || hin > 100)  //optional way to incur error message if humidity sensor faulty or not connected.
    if (isnan(hin) || isnan(tin)) 
   {
    tft.setTextColor(ST7735_RED);  //write green on black background to remove old print
    tft.setCursor(0,16);
    tft.print("Error in");
  } 
    else
  {
     tft.setTextColor(ST7735_GREEN);  //write green on black background to remove old print
     tft.setCursor(0,16);
     tft.print("Temp:");
     tft.print(String(tin, 1));  
     tft.print("c");

     tft.setTextColor(ST7735_CYAN);  //write cyan on black background to remove old print
     tft.setCursor(0,32);
     tft.print("Humid:");
     tft.print(int(hin));  // use int for whole number so it fits on screen better
     tft.print("%");
  }

    //OUTDOOR WEB WIFI WEATHER
    tft.setTextColor(ST77XX_WHITE);
    tft.setCursor(0, 64);
    tft.println("Outdoor");

    tft.setTextColor(ST7735_GREEN);  //write green on black background to remove old print
    tft.setCursor(0,80);
    tft.print("Temp:");
    tft.print(Temperature,1);
    tft.print("c");

    tft.setTextColor(ST7735_CYAN);  //write cyan on black background to remove old print
    tft.setCursor(0,96);
    tft.print("Humid:");
    tft.print(Humidity,0);
    tft.print("%");
      
    tft.setTextColor(ST7735_YELLOW);  //write red on black background to remove old print
    tft.setCursor(0,112);
    tft.print("mBar:");
    tft.print(Pressure,0);
}


void displayGettingData()
{
  tft.fillScreen(ST77XX_BLACK);
  tft.setCursor(0,0);
  tft.println("Getting");
  tft.print("data....");
}

As you can see the I’ve had a go at changing to timer method and commented out the two delays.

It gives errors when compiling:

“WiFi_WeatherDisplay_877_v3.0.0_indoor_timer:84:42: error: invalid conversion from ‘void ()(String, String)’ to 'timer_callback {aka void ()()}’ [-fpermissive]”
"error: initializing argument 2 of ‘int SimpleTimer::setInterval(long int, timer_callback)’ [-fpermissive]
int setInterval(long d, timer_callback f);"

I think it’s because when the function is called the original way , it declares the values of (weatherLocation,weatherDescription) and (Temperature,Humidity,Pressure).

  1. Is it actually worth changing from delay to timer method?
  2. Any other comments on the code - improvements/suggestions?

Thanks

Anyone? :slight_smile:

The displayWeather() function expects to be passed 2 Strings but you are not providing any. No promises that it will work, but remove the argument list from the function and ensure that the data to be display is available as global variables.

UKHeliBob:
The displayWeather() function expects to be passed 2 Strings but you are not providing any. No promises that it will work, but remove the argument list from the function and ensure that the data to be display is available as global variables.

Thanks!

I did try changing:

*timer.setInterval(2000L, displayWeather); *

to

*timer.setInterval(2000L, displayWeather(weatherLocation,weatherDescription)); *

but it caused more errors. I will have a little go at making global variables.

At the end of the day the delays are not so bad in this simple weather station :slight_smile:

  1. Is it actually worth changing from delay to timer method?

If you want your sketch to stay responsive: yes.

  1. Any other comments on the code - improvements/suggestions?

Try to keep comments telling what the code actually is doing:

    if(counter == 60) //Get new data every 10 minutes

displayWeather() and displayConditions() must not have any parameters if you want them to be called by the SimpleTimer library.

pylon:
If you want your sketch to stay responsive: yes.

Try to keep comments telling what the code actually is doing:

    if(counter == 60) //Get new data every 10 minutes

displayWeather() and displayConditions() must not have any parameters if you want them to be called by the SimpleTimer library.

Thanks for the advice pylon! :slight_smile:

A timer callback function CANNOT have ANY arguments. It must be a void function with NO arguments.

Regards,
Ray L.