LCD 2x16 display data from API

Hello,
I need your help with my first project with Wemos d1 mini. I wrote an internet watch code which, apart from time, also displays current data on COVID-19 incidence in the country and my province. However, I stopped at a certain point and it's hard for me to move on to fully complete the project.

  • the data in the second line are displayed correctly, but by delving into the if and millis functions, the text blinks with the clock seconds, do you have any idea how to solve it? There was also a problem of synchronizing data with the API, if I add a delay every 5 minutes, the clock also stops.

  • I would like to add a buzzer to the clock that will inform about the change of data downloaded from the API. but I don't know how to bite the subject to convey esp information that the data in api has changed

Thank you for your help.

covid clock.c (9.22 KB)

Hi Mizka,

you are asking for

can you take several hours time to dive into my code to understand my whole code
and then write the additional code that does do...

You will get more help if you point us (the other forum-members) to the line of code where one of your problems is or at least where you estimate the problem could be

best regards

Stefan

only update the covid information on LCD if it was changed.

use something like

oldIinfectedByRegion_14_infectedCount
on a more global level and compare if the new infectedByRegion_14_infectedCount has changed.

by the way, clean up your comments

delay(1000); //Send a request to update every 10 sec (= 10,000 ms)

I think the problem appears on the 195 line when it starts printing api data on the lcd. I probably nest the functions incorrectly and the text changes with seconds. I will be grateful for showing me how to enter the functions correctly. Of course I will correct the code and comments. I left it as a draft, sorry

noiasca:
only update the covid information on LCD if it was changed.

use something like

oldIinfectedByRegion_14_infectedCount
on a more global level and compare if the new infectedByRegion_14_infectedCount has changed.

by the way, clean up your comments

delay(1000); //Send a request to update every 10 sec (= 10,000 ms)

Could you write an example of your use in my code

Hi Miszka,

in line 195 there is a second

curMillis = millis();

which updates curMillis again as it has been updated in line 169
The LCD-object offers placing the cursor to any xy-position
You wrote that the text blinks with the time
if you position the cursor using

lcd.setCursor(x, y);

where "x" "and "y" are the exact positions where to insert updated content
and just overwriting the content that should change the rest of the text should stay there
if it still blinks there might be a command

lcd.clear();

where it shouldn't be

As a general hint: your code will be much more easy to understand if you divide it into several functions.

Have you ver written a function on your own?
here is a tutorial with a very easy example Arduino Functions

You should place all the write to LCD stuff inside such a function

best regards

Stefan

Here is a [untested] cleaned up version that removes so many of the if/else statements so it is a bit easier to follow

/*
  Wiring is simple on Wemos D1 R2
  Just 4 connections:
  5v -> 5v
  Gnd -> Gnd
  SCA -> SCA
  SCL -> SCL

*/

unsigned long curMillis;
unsigned long prevMillis = 0;
const unsigned long displayDuration = 10000UL;
const unsigned long displayBlankDuration = 500UL;

unsigned long prevFetchMillis = 0;
const unsigned long fetchDelay = 300000UL;

enum { INFO, INFECTED, DECEASED, REGION, INFECTED_REGION, DECEASED_REGION, LAST_STATE };
int displayState;

int infected;
int deceased;
int regionInfectedCount;
int regionDeceasedCount;

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiUdp.h>
#include <String.h>
#include <Wire.h>
#include <ArduinoJson.h>
#include <WiFiClientSecure.h>
#include <SSD1306.h>
#include <SSD1306Wire.h>
#include <NTPClient.h>
#include <Time.h>
#include <TimeLib.h>
#include <Timezone.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); //or try 0x3f Create an instance of the lcd screen

// Define NTP properties
#define NTP_OFFSET 60 * 60         // In seconds
#define NTP_INTERVAL 60 * 1000     // In miliseconds
#define NTP_ADDRESS "pool.ntp.org" // change this to whatever pool is closest (see ntp.org)

// Set up the NTP UDP client
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

const char *ssid = "XXXX"; // insert your own ssid such as BTHub4-9X99
const char *password = "XXXX"; // and your wifi password

String date; //create the string for the date which will be printed on the lcd screen below
String t;    // create the string for the time

const char *months[] = {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"};

//void welcome()
//{
//    lcd.setCursor(0, 0);
//    lcd.print("Clock");
//    lcd.setCursor(0, 1);
//    lcd.print("COVID-19");
//
//}
//    delay(5000);

void clearLCDLine(int line)
{
  lcd.setCursor(0, line);
  for (int n = 0; n < 16; n++) // 20 indicates symbols in line. For 2x16 LCD write - 16
  {
    lcd.print(" ");
  }
}

void setup()
{
  Serial.begin(115200); // most ESP-01's use 115200 but this could vary. Included for serial monitor debugging
  timeClient.begin();   // Start the NTP UDP client

  prevFetchMillis = millis() - fetchDelay;  // so we fetch the first time through loop()
  prevMillis = millis() - displayDuration;
  
  ///////////////////// The section below is to connect the esp8266 to your wifi

  int cursorPosition = 0;
  lcd.begin();
  lcd.backlight();
  Wire.begin();
  lcd.print("Polacz");

  lcd.setCursor(0, 0);
  lcd.print("Polacz");
  lcd.setCursor(0, 1);
  lcd.print(ssid);

  // Connect to wifi
  Serial.println("");
  Serial.print("Laczenie z ");
  Serial.print(ssid);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Polaczono z WiFi ");
  Serial.print(WiFi.localIP());
  Serial.println("");

  delay(1000);
  ///////////////////////|end wifi connection set up
}

void loop()
{
  //////////////////////// The first part of the loop is for the internet clock

  curMillis = millis();

  if (WiFi.status() == WL_CONNECTED) //Check WiFi connection status
  {
    refreshTime();
    // Display the date and time
    Serial.println("");
    Serial.print("Local date: ");
    Serial.print(date);
    Serial.println("");
    Serial.print("Local time: ");
    Serial.print(t);

    //lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(t);
    lcd.setCursor(6, 0);
    lcd.print(date);

    // check if it is time to refresh information
    if (curMillis - prevFetchMillis >= fetchDelay)
    {
      fetchData();
      prevFetchMillis = curMillis;
    }

    // check if it is time to blank the line to prepare for next state
    if ((curMillis - prevMillis) >= displayDuration - displayBlankDuration)
    {
      clearLCDLine(1);
    }

    // check if it is time to display the next bit of information
    if ( curMillis - prevMillis >= displayDuration )
    {
      // move to next display state
      prevMillis = curMillis;
      displayState++;
      if(displayState == LAST_STATE) displayState = 0;
      lcd.setCursor(0, 1);
      switch ( displayState ) {
        case INFO:
          lcd.print("Polska COVID-19");
          break;

        case INFECTED:
          lcd.print("Chorych:");
          lcd.setCursor(9, 1);
          lcd.print(infected, DEC);
          break;

        case DECEASED:
          lcd.print("Zgonow:");
          lcd.setCursor(8, 1);
          lcd.print(deceased, DEC);
          break;

        case REGION:
          lcd.print("WIELKOPOLSKIE");
          break;

        case INFECTED_REGION:
          lcd.print("Chorych:");
          lcd.setCursor(9, 1);
          lcd.print(regionInfectedCount, DEC);
          break;

        case DECEASED_REGION:
          lcd.print("Zgonow:");
          lcd.setCursor(8, 1);
          lcd.print(regionDeceasedCount, DEC);
          break;
      }
    }
  }

  else // this part is a step to attempt to connect to wifi again if disconnected
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Polacz");

    //display.display();
    WiFi.begin(ssid, password);
    //display.drawString(0, 24, "Connected.");

    lcd.clear();
    lcd.setCursor(0, 1);
    lcd.print("Polacz.");

    delay(1000);
  }

  delay(1000); //Send a request to update every 10 sec (= 10,000 ms)
} //end void loop


void refreshTime()
{
  date = ""; // clear the variables
  t = "";

  // update the NTP client and get the UNIX UTC timestamp
  timeClient.update();
  unsigned long epochTime = timeClient.getEpochTime();

  // convert received time stamp to time_t object
  time_t local, utc;
  utc = epochTime;

  // Then convert the UTC UNIX timestamp to local time
  //TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2};  //UTC - 5 hours - change this as needed
  // TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -60};   //UTC - 6 hours - change this as needed
  // Timezone usEastern(usEDT, usEST);
  // local = usEastern.toLocal(utc);

  TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 60}; //Central European Summer Time
  TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 0};   //Central European Standard Time
  Timezone CE(CEST, CET);
  local = CE.toLocal(utc);

  // now format the Time variables into strings with proper names for month, day etc
  date += day(local);
  date += ".";
  date += months[month(local) - 1];
  date += ".";
  date += year(local);

  // format the time to 12-hour format with AM/PM and add seconds. t (time) is made up of the variables below which are then printed as a string
  if (hour(local) < 10)
    t += " ";
  t += hour(local);
  t += ":";
  if (minute(local) < 10) // add a zero if minute is under 10
    t += "0";
  t += minute(local);
  // t += ":";
  //        if (second(local) < 10)
  //            t += "0";
  //        t += second(local);
  //t += ampm[isPM(local)];

}

void fetchData()
{
  HTTPClient http;
  http.begin("http://api.apify.com/v2/key-value-stores/3Po6TV7wTht4vIEid/records/LATEST?disableRedirect=true");
  int httpCode = http.GET();
  if (httpCode > 0)
  {
    const size_t capacity = JSON_ARRAY_SIZE(16) + 16 * JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 1080;
    DynamicJsonDocument doc(capacity);
    deserializeJson(doc, http.getString());
    JsonArray infectedByRegion = doc["infectedByRegion"];

    // Parameters
    infected = doc["infected"];
    deceased = doc["deceased"];

    JsonObject infectedByRegion_14 = infectedByRegion[14];
    //const char *infectedByRegion_14_region = infectedByRegion_14["region"];       // "wielkopolskie"
    regionInfectedCount = infectedByRegion_14["infectedCount"];
    regionDeceasedCount = infectedByRegion_14["deceasedCount"];
  }
  http.end(); //Close connection
}

blh64:
Here is a [untested] cleaned up version that removes so many of the if/else statements so it is a bit easier to follow

/*

Wiring is simple on Wemos D1 R2
  Just 4 connections:
  5v -> 5v
  Gnd -> Gnd
  SCA -> SCA
  SCL -> SCL

*/

unsigned long curMillis;
unsigned long prevMillis = 0;
const unsigned long displayDuration = 10000UL;
const unsigned long displayBlankDuration = 500UL;

unsigned long prevFetchMillis = 0;
const unsigned long fetchDelay = 300000UL;

enum { INFO, INFECTED, DECEASED, REGION, INFECTED_REGION, DECEASED_REGION, LAST_STATE };
int displayState;

int infected;
int deceased;
int regionInfectedCount;
int regionDeceasedCount;

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiUdp.h>
#include <String.h>
#include <Wire.h>
#include <ArduinoJson.h>
#include <WiFiClientSecure.h>
#include <SSD1306.h>
#include <SSD1306Wire.h>
#include <NTPClient.h>
#include <Time.h>
#include <TimeLib.h>
#include <Timezone.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); //or try 0x3f Create an instance of the lcd screen

// Define NTP properties
#define NTP_OFFSET 60 * 60        // In seconds
#define NTP_INTERVAL 60 * 1000    // In miliseconds
#define NTP_ADDRESS "pool.ntp.org" // change this to whatever pool is closest (see ntp.org)

// Set up the NTP UDP client
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

const char *ssid = "XXXX"; // insert your own ssid such as BTHub4-9X99
const char *password = "XXXX"; // and your wifi password

String date; //create the string for the date which will be printed on the lcd screen below
String t;    // create the string for the time

const char *months[] = {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"};

//void welcome()
//{
//    lcd.setCursor(0, 0);
//    lcd.print("Clock");
//    lcd.setCursor(0, 1);
//    lcd.print("COVID-19");
//
//}
//    delay(5000);

void clearLCDLine(int line)
{
  lcd.setCursor(0, line);
  for (int n = 0; n < 16; n++) // 20 indicates symbols in line. For 2x16 LCD write - 16
  {
    lcd.print(" ");
  }
}

void setup()
{
  Serial.begin(115200); // most ESP-01's use 115200 but this could vary. Included for serial monitor debugging
  timeClient.begin();  // Start the NTP UDP client

prevFetchMillis = millis() - fetchDelay;  // so we fetch the first time through loop()
  prevMillis = millis() - displayDuration;
 
  ///////////////////// The section below is to connect the esp8266 to your wifi

int cursorPosition = 0;
  lcd.begin();
  lcd.backlight();
  Wire.begin();
  lcd.print("Polacz");

lcd.setCursor(0, 0);
  lcd.print("Polacz");
  lcd.setCursor(0, 1);
  lcd.print(ssid);

// Connect to wifi
  Serial.println("");
  Serial.print("Laczenie z ");
  Serial.print(ssid);

WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Polaczono z WiFi ");
  Serial.print(WiFi.localIP());
  Serial.println("");

delay(1000);
  ///////////////////////|end wifi connection set up
}

void loop()
{
  //////////////////////// The first part of the loop is for the internet clock

curMillis = millis();

if (WiFi.status() == WL_CONNECTED) //Check WiFi connection status
  {
    refreshTime();
    // Display the date and time
    Serial.println("");
    Serial.print("Local date: ");
    Serial.print(date);
    Serial.println("");
    Serial.print("Local time: ");
    Serial.print(t);

//lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(t);
    lcd.setCursor(6, 0);
    lcd.print(date);

// check if it is time to refresh information
    if (curMillis - prevFetchMillis >= fetchDelay)
    {
      fetchData();
      prevFetchMillis = curMillis;
    }

// check if it is time to blank the line to prepare for next state
    if ((curMillis - prevMillis) >= displayDuration - displayBlankDuration)
    {
      clearLCDLine(1);
    }

// check if it is time to display the next bit of information
    if ( curMillis - prevMillis >= displayDuration )
    {
      // move to next display state
      prevMillis = curMillis;
      displayState++;
      if(displayState == LAST_STATE) displayState = 0;
      lcd.setCursor(0, 1);
      switch ( displayState ) {
        case INFO:
          lcd.print("Polska COVID-19");
          break;

case INFECTED:
          lcd.print("Chorych:");
          lcd.setCursor(9, 1);
          lcd.print(infected, DEC);
          break;

case DECEASED:
          lcd.print("Zgonow:");
          lcd.setCursor(8, 1);
          lcd.print(deceased, DEC);
          break;

case REGION:
          lcd.print("WIELKOPOLSKIE");
          break;

case INFECTED_REGION:
          lcd.print("Chorych:");
          lcd.setCursor(9, 1);
          lcd.print(regionInfectedCount, DEC);
          break;

case DECEASED_REGION:
          lcd.print("Zgonow:");
          lcd.setCursor(8, 1);
          lcd.print(regionDeceasedCount, DEC);
          break;
      }
    }
  }

else // this part is a step to attempt to connect to wifi again if disconnected
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Polacz");

//display.display();
    WiFi.begin(ssid, password);
    //display.drawString(0, 24, "Connected.");

lcd.clear();
    lcd.setCursor(0, 1);
    lcd.print("Polacz.");

delay(1000);
  }

delay(1000); //Send a request to update every 10 sec (= 10,000 ms)
} //end void loop

void refreshTime()
{
  date = ""; // clear the variables
  t = "";

// update the NTP client and get the UNIX UTC timestamp
  timeClient.update();
  unsigned long epochTime = timeClient.getEpochTime();

// convert received time stamp to time_t object
  time_t local, utc;
  utc = epochTime;

// Then convert the UTC UNIX timestamp to local time
  //TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2};  //UTC - 5 hours - change this as needed
  // TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -60};  //UTC - 6 hours - change this as needed
  // Timezone usEastern(usEDT, usEST);
  // local = usEastern.toLocal(utc);

TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 60}; //Central European Summer Time
  TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 0};  //Central European Standard Time
  Timezone CE(CEST, CET);
  local = CE.toLocal(utc);

// now format the Time variables into strings with proper names for month, day etc
  date += day(local);
  date += ".";
  date += months[month(local) - 1];
  date += ".";
  date += year(local);

// format the time to 12-hour format with AM/PM and add seconds. t (time) is made up of the variables below which are then printed as a string
  if (hour(local) < 10)
    t += " ";
  t += hour(local);
  t += ":";
  if (minute(local) < 10) // add a zero if minute is under 10
    t += "0";
  t += minute(local);
  // t += ":";
  //        if (second(local) < 10)
  //            t += "0";
  //        t += second(local);
  //t += ampm[isPM(local)];

}

void fetchData()
{
  HTTPClient http;
  http.begin("http://api.apify.com/v2/key-value-stores/3Po6TV7wTht4vIEid/records/LATEST?disableRedirect=true");
  int httpCode = http.GET();
  if (httpCode > 0)
  {
    const size_t capacity = JSON_ARRAY_SIZE(16) + 16 * JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 1080;
    DynamicJsonDocument doc(capacity);
    deserializeJson(doc, http.getString());
    JsonArray infectedByRegion = doc["infectedByRegion"];

// Parameters
    infected = doc["infected"];
    deceased = doc["deceased"];

JsonObject infectedByRegion_14 = infectedByRegion[14];
    //const char *infectedByRegion_14_region = infectedByRegion_14["region"];      // "wielkopolskie"
    regionInfectedCount = infectedByRegion_14["infectedCount"];
    regionDeceasedCount = infectedByRegion_14["deceasedCount"];
  }
  http.end(); //Close connection
}

Thank you for your work! The program works as I wanted. Your code will help me learn programming. I will study it.
Now I'm thinking how to add an alarm buzzer. I was thinking about adding if infected! = Infected tone buzzer. It's a good idea? But where to implement the function

miszka:
Thank you for your work! The program works as I wanted. Your code will help me learn programming. I will study it.
Now I'm thinking how to add an alarm buzzer. I was thinking about adding if infected! = Infected tone buzzer. It's a good idea? But where to implement the function

It depends on when you want the buzzer to sound. Do you want it to sound whenever the variable infected changes? Whenever the variable regionInfectedCount changes? Both? something else?

Also, what sort of tone? Buzz for 1 second, 10 seconds, forever? This will also affect how you should implement this.

Most likely, you will need to keep track of the previous value of whatever variable and use another timer to keep track of how long the buzzer is on and then turn it off. Look at the StateChangeExample (File->Examples->02.Digital->StateChangeDetection) to see how you would detect this change

Look at the BlinkWithoutDelay example to see how to time something (very similar to the current program)

I would like the buzzer to turn on when the infected variable changes. Sound would have been short, 10 seconds.

I will read the examples you gave. Thank you for your time.