ESP32 CYD with LVGL: Digital Clock with Time and Date

In this guide, you’ll learn how to turn your ESP32 Cheap Yellow Display (CYD) board into a digital clock that displays time and date using LVGL (Light Versatile Graphics Library). We’ll use the WorldTimeAPI to get the current time and date. The ESP32 will be programmed using Arduino IDE.

ESP32 CYD with LVGL: Digital Clock with Time and Date

New to the ESP32 Cheap Yellow Display? Start here: Getting Started with ESP32 Cheap Yellow Display Board – CYD (ESP32-2432S028R).

Project Overview

In this project, we’ll display the time and date from the WorldTimeAPI on the ESP32 CYD board. The time and date will be displayed on text labels.

ESP32 CYD Cheap Yellow Display LVGL Digital Clock Time and Date Demonstration Screen

To get an accurate date and time for your timezone, we’ll use the WorldTimeAPI. To get the time from the API, the ESP32 needs to connect to the internet, so you need to have a router in your surroundings so that the ESP32 can connect to it.

Prerequisites

Before proceeding, make sure you follow the next prerequisites. You must follow all steps, otherwise, your project will not work.

1) Parts Required

For this project, you need the following parts

2) Install ESP32 Boards in Arduino IDE

Arduino IDE 2 Logo

We’ll program the ESP32 using Arduino IDE. Make sure you have the ESP32 boards installed. Follow the next tutorial:

3) Get familiar with the ESP32 Cheap Yellow Display

The ESP32-2432S028R development board has become known in the maker community as the “Cheap Yellow Display” or CYD for short. This development board, whose main chip is an ESP32-WROOM-32 module, comes with a 2.8-inch TFT touchscreen LCD, a microSD card interface, an RGB LED, and all the required circuitry to program and apply power to the board.

ESP32 Cheap Yellow Display CYD Board ESP32-2432S028R front

If this is your first time using the ESP32 Cheap Yellow Display, make sure to follow our getting started guide:

4) Install TFT and LVGL Libraries

LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library that provides a wide range of easy-to-use graphical elements for your microcontroller projects that require a graphical user interface (GUI).

LVGL new logo

Follow the next tutorial to install and configure the required libraries to use LVGL for the ESP32 Cheap Yellow Display using Arduino IDE.

5) Install ArduinoJson Library

For this project, you need to install the ArduinoJSON library to handle the JSON response when you make a request to the WorldTimeAPI.

In the Arduino IDE, go to Sketch > Include Library > Manage Libraries. Search for ArduinoJSON and install the library by Benoit Blanchon. We’re using version 7.0.4. We recommend using the same version.

ESP32 CYD Digital Clock: Display Date and Time – Arduino Code

The following code will create two text labels with the current time and date. Before uploading the code to your board, you need to insert your network credentials so that the ESP32 can connect to the internet to get the time and date. You also need to insert your timezone.

/*  Rui Santos & Sara Santos - Random Nerd Tutorials - https://RandomNerdTutorials.com/esp32-cyd-lvgl-digital-clock/  |  https://RandomNerdTutorials.com/esp32-tft-lvgl-digital-clock/
    THIS EXAMPLE WAS TESTED WITH THE FOLLOWING HARDWARE:
    1) ESP32-2432S028R 2.8 inch 240Ă—320 also known as the Cheap Yellow Display (CYD): https://makeradvisor.com/tools/cyd-cheap-yellow-display-esp32-2432s028r/
      SET UP INSTRUCTIONS: https://RandomNerdTutorials.com/cyd-lvgl/
    2) REGULAR ESP32 Dev Board + 2.8 inch 240x320 TFT Display: https://makeradvisor.com/tools/2-8-inch-ili9341-tft-240x320/ and https://makeradvisor.com/tools/esp32-dev-board-wi-fi-bluetooth/
      SET UP INSTRUCTIONS: https://RandomNerdTutorials.com/esp32-tft-lvgl/
    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

/*  Install the "lvgl" library version 9.2 by kisvegabor to interface with the TFT Display - https://lvgl.io/
    *** IMPORTANT: lv_conf.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***
    *** YOU MUST USE THE lv_conf.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***
    FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https://RandomNerdTutorials.com/cyd-lvgl/ or https://RandomNerdTutorials.com/esp32-tft-lvgl/   */
#include <lvgl.h>

/*  Install the "TFT_eSPI" library by Bodmer to interface with the TFT Display - https://github.com/Bodmer/TFT_eSPI
    *** IMPORTANT: User_Setup.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***
    *** YOU MUST USE THE User_Setup.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***
    FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https://RandomNerdTutorials.com/cyd-lvgl/ or https://RandomNerdTutorials.com/esp32-tft-lvgl/   */
#include <TFT_eSPI.h>

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Specify the timezone you want to get the time for: https://worldtimeapi.org/api/timezone
// Timezone example for Portugal: "Europe/Lisbon"
const char* timezone = "Europe/Lisbon";

// Store date and time
String current_date;
String current_time;

// Store hour, minute, second
static int32_t hour;
static int32_t minute;
static int32_t second;
bool sync_time_date = false;

#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320

#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];

// If logging is enabled, it will inform the user about what is happening in the library
void log_print(lv_log_level_t level, const char * buf) {
  LV_UNUSED(level);
  Serial.println(buf);
  Serial.flush();
}

String format_time(int time) {
  return (time < 10) ? "0" + String(time) : String(time);
}

static lv_obj_t * text_label_time;
static lv_obj_t * text_label_date;

static void timer_cb(lv_timer_t * timer){
  LV_UNUSED(timer);
  second++;
  if(second > 59) {
    second = 0;
    minute++;
    if(minute > 59) {
      minute = 0;
      hour++;
      sync_time_date = true;
      Serial.println(sync_time_date);
      Serial.println("\n\n\n\n\n\n\n\n");
      if(hour > 23) {
        hour = 0;
      }
    }
  }

  String hour_time_f = format_time(hour);
  String minute_time_f = format_time(minute);
  String second_time_f = format_time(second);

  String final_time_str = String(hour_time_f) + ":" + String(minute_time_f) + ":"  + String(second_time_f);
  //Serial.println(final_time_str);
  lv_label_set_text(text_label_time, final_time_str.c_str());
  lv_label_set_text(text_label_date, current_date.c_str());
}

void lv_create_main_gui(void) {
  // Get the time and date from WorldTimeAPI
  while(hour==0 && minute==0 && second==0) {
    get_date_and_time();
  }
  Serial.println("Current Time: " + current_time);
  Serial.println("Current Date: " + current_date);

  lv_timer_t * timer = lv_timer_create(timer_cb, 1000, NULL);
  lv_timer_ready(timer);

  // Create a text label for the time aligned center
  text_label_time = lv_label_create(lv_screen_active());
  lv_label_set_text(text_label_time, "");
  lv_obj_align(text_label_time, LV_ALIGN_CENTER, 0, -30);
  // Set font type and size
  static lv_style_t style_text_label;
  lv_style_init(&style_text_label);
  lv_style_set_text_font(&style_text_label, &lv_font_montserrat_48);
  lv_obj_add_style(text_label_time, &style_text_label, 0);

  // Create a text label for the date aligned center
  text_label_date = lv_label_create(lv_screen_active());
  lv_label_set_text(text_label_date, current_date.c_str());
  lv_obj_align(text_label_date, LV_ALIGN_CENTER, 0, 40);
  // Set font type and size
  static lv_style_t style_text_label2;
  lv_style_init(&style_text_label2);
  lv_style_set_text_font(&style_text_label2, &lv_font_montserrat_30);
  lv_obj_add_style(text_label_date, &style_text_label2, 0); 
  lv_obj_set_style_text_color((lv_obj_t*) text_label_date, lv_palette_main(LV_PALETTE_GREY), 0);
}

void get_date_and_time() {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;

    // Construct the API endpoint
    String url = String("http://worldtimeapi.org/api/timezone/") + timezone;
    http.begin(url);
    int httpCode = http.GET(); // Make the GET request

    if (httpCode > 0) {
      // Check for the response
      if (httpCode == HTTP_CODE_OK) {
        String payload = http.getString();
        //Serial.println("Time information:");
        //Serial.println(payload);
        // Parse the JSON to extract the time
        JsonDocument doc;
        DeserializationError error = deserializeJson(doc, payload);
        if (!error) {
          const char* datetime = doc["datetime"];          
          // Split the datetime into date and time
          String datetime_str = String(datetime);
          int splitIndex = datetime_str.indexOf('T');
          current_date = datetime_str.substring(0, splitIndex);
          current_time = datetime_str.substring(splitIndex + 1, splitIndex + 9); // Extract time portion
          hour = current_time.substring(0, 2).toInt();
          minute = current_time.substring(3, 5).toInt();
          second = current_time.substring(6, 8).toInt();
        } else {
          Serial.print("deserializeJson() failed: ");
          Serial.println(error.c_str());
        }
      }
    } else {
      Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str());
      sync_time_date = true;
    }
    http.end(); // Close connection
  } else {
    Serial.println("Not connected to Wi-Fi");
  }
}

void setup() {
  String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
  Serial.begin(115200);
  Serial.println(LVGL_Arduino);

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nConnected to Wi-Fi network with IP Address: ");
  Serial.println(WiFi.localIP());
  
  // Start LVGL
  lv_init();
  // Register print function for debugging
  lv_log_register_print_cb(log_print);

  // Create a display object
  lv_display_t * disp;
  // Initialize the TFT display using the TFT_eSPI library
  disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
  lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
  
  // Function to draw the GUI
  lv_create_main_gui();
}

void loop() {
  // Get the time and date from WorldTimeAPI
  if(sync_time_date) {
    sync_time_date = false;
    get_date_and_time();
    while(hour==0 && minute==0 && second==0) {
      get_date_and_time();
    }
  }
  lv_task_handler();  // let the GUI do its work
  lv_tick_inc(5);     // tell LVGL how much time has passed
  delay(5);           // let this time pass
}

View raw code

How Does the Code Work?

Let’s take a look at how to get time and date from the API and update the text labels with the current values. Alternatively, you can skip to the Demonstration section.

Including Libraries

You need to include the lvgl.h and the TFT_eSPI.h libraries to communicate and display text on the screen.

#include <lvgl.h>
#include <TFT_eSPI.h>

You need to include the WiFi, HTTPClient, and the ArduinoJson libraries to make HTTP requests and handle JSON data.

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

Insert Your Credentials and Timezone

In the following lines, you must insert your network credentials so that the ESP32 can connect to your router.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Set your timezone in the timezone variable at the beginning of the code (list of all available timezones).

const char* timezone = "Europe/Lisbon";

Declaring Other Variables

Create some auxiliary variables to hold the date and time values.

// Store date and time
String current_date;
String current_time;

// Store hour, minute, second
static int32_t hour;
static int32_t minute;
static int32_t second;
bool sync_time_date = false;

Global Text Labels

We create two global LVGL text label objects, so that we can access them inside all functions later on.

static lv_obj_t * text_label_time;
static lv_obj_t * text_label_date;

setup()

In the setup(), include the following lines for debugging. These will print the version of LVGL that you’re using. You must be using version 9.

String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);

Connect to the Internet

To connect the ESP32 to the internet we use the following code.

// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.print("\nConnected to Wi-Fi network with IP Address: ");
Serial.println(WiFi.localIP());

Initialize the LVGL Library

Initialize the LVGL Library by calling the lv_init() function in the setup().

// Start LVGL
lv_init();

Register Debugging Function

Register your log_print() function declared previously as a function associated with debugging LVGL.

// Register print function for debugging
lv_log_register_print_cb(log_print);

Create a Display Object

To write to the display, you must create a display object first. You need to do this in all your LVGL sketches. The following lines will create an LVGL display object called disp with the screen width, screen height, and drawing buffer defined earlier.

// Create a display object
lv_display_t * disp;
// Initialize the TFT display using the TFT_eSPI library
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);

Drawing the GUI

The LVGL library works asynchronously. You must call the function to draw on the display in the setup(). Then, everything works with events and callbacks. The code will always be listening for events in the background. When something happens, it will run the callback function associated with the event. You don’t need to check for any events in the loop().

Throughout most of our examples, the function that will draw to the screen will be called lv_create_main_gui(). Then, inside that function, we’ll add the instructions to build the interface.

// Function to draw the GUI
lv_create_main_gui();

get_date_and_time()

When we initialize the screen, we call the get_date_and_time() function to get the latest date and time from the WorldTimeAPI. Then, we store the values in some auxiliary variables that will be used to display them on the screen.

void get_date_and_time() {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;

    // Construct the API endpoint
    String url = String("http://worldtimeapi.org/api/timezone/") + timezone;
    http.begin(url);
    int httpCode = http.GET(); // Make the GET request

    if (httpCode > 0) {
      // Check for the response
      if (httpCode == HTTP_CODE_OK) {
        String payload = http.getString();
        //Serial.println("Time information:");
        //Serial.println(payload);
        // Parse the JSON to extract the time
        JsonDocument doc;
        DeserializationError error = deserializeJson(doc, payload);
        if (!error) {
          const char* datetime = doc["datetime"];          
          // Split the datetime into date and time
          String datetime_str = String(datetime);
          int splitIndex = datetime_str.indexOf('T');
          current_date = datetime_str.substring(0, splitIndex);
          current_time = datetime_str.substring(splitIndex + 1, splitIndex + 9); // Extract time portion
          hour = current_time.substring(0, 2).toInt();
          minute = current_time.substring(3, 5).toInt();
          second = current_time.substring(6, 8).toInt();
        } else {
          Serial.print("deserializeJson() failed: ");
          Serial.println(error.c_str());
        }
      }
    } else {
      Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str());
      sync_time_date = true;
    }
    http.end(); // Close connection
  } else {
    Serial.println("Not connected to Wi-Fi");
  }
}

Preparing the GUI

Before drawing the main GUI, we start by calling the API to get the latest time and date.

void lv_create_main_gui(void) {
  // Get the time and date from WorldTimeAPI
  while(hour==0 && minute==0 && second==0) {
    get_date_and_time();
  }
(...)

Timer

To update the time and date text labels on the screen, we can create an LVGL timer that will run a specific function periodically. In this case, we’ll update it every 1 second. Create an LVGL timer called timer and assign the timer_cb callback function.

lv_timer_t * timer = lv_timer_create(timer_cb, 1000, NULL);
lv_timer_ready(timer);

Time Text Label

To create a text label, we can call the LVGL function lv_label_create() and pass as argument where we want to display the text. We want to add it to the current screen (lv_screen_active()).

// Create a text label for the time aligned center
text_label_time = lv_label_create(lv_screen_active());

After creating the text label, we can set its text by using the lv_label_set_text() function that accepts as arguments the text label we’re referring to and the text we want to add to that label. In our case, we’re setting it to empty at the beginning.

lv_label_set_text(text_label_time, "");

The following lines align the text label. You can use the lv_obj_align() function. Pass as arguments, the LVGL object, the alignment and x and y offsets in pixels.

lv_obj_align(text_label_time, LV_ALIGN_CENTER, 0, -30);

To style our text label, we’ll start by creating an object of type lv_style_t called style_text_label. This kind of object is used to apply styles to LVGL objects.

static lv_style_t style_text_label;

After creating the style, we initialize it using the lv_style_init() function and pass as argument our text label style (style_text_label).

lv_style_init(&style_text_label);

Then, we can set the font type and size using the lv_style_set_text_font() function. We pass as argument the style object we’re referring to and the font type. Finally, we apply the style.

lv_style_set_text_font(&style_text_label, &lv_font_montserrat_48);
lv_obj_add_style(text_label_time, &style_text_label, 0);

Date Text Label

A similar procedure is applied to create the text_label_date.

 // Create a text label for the date aligned center
text_label_date = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_date, current_date.c_str());
lv_obj_align(text_label_date, LV_ALIGN_CENTER, 0, 40);
// Set font type and size
static lv_style_t style_text_label2;
lv_style_init(&style_text_label2);
lv_style_set_text_font(&style_text_label2, &lv_font_montserrat_30);
lv_obj_add_style(text_label_date, &style_text_label2, 0); 
lv_obj_set_style_text_color((lv_obj_t*) text_label_date, lv_palette_main(LV_PALETTE_GREY), 0);

Timer Callback Function

The timer_cb function runs every one second. Each time the callback function runs, we increment one second, every 60 seconds one minute and every 60 minutes one hour.

static void timer_cb(lv_timer_t * timer){
  LV_UNUSED(timer);
  second++;
  if(second > 59) {
    second = 0;
    minute++;
    if(minute > 59) {
      minute = 0;
      hour++;
      sync_time_date = true;
      Serial.println(sync_time_date);
      Serial.println("\n\n\n\n\n\n\n\n");
      if(hour > 23) {
        hour = 0;
      }
    }
  }
(...)

We use these auxiliary variable to prepare the String that will be displayed on the text labels.

String hour_time_f = format_time(hour);
String minute_time_f = format_time(minute);
String second_time_f = format_time(second);

String final_time_str = String(hour_time_f) + ":" + String(minute_time_f) + ":"  + String(second_time_f);

Set the text labels to the current time and date:

lv_label_set_text(text_label_time, final_time_str.c_str());
lv_label_set_text(text_label_date, current_date.c_str());

loop()

In the loop(), you can add any other tasks that you need your ESP32 to do like in any regular Arduino sketch. In our case, we will check if it’s necessary to sync the date and time with the WorldTimeAPI every hour.

void loop() {
  // Get the time and date from WorldTimeAPI
  if(sync_time_date) {
    sync_time_date = false;
    get_date_and_time();
    while(hour==0 && minute==0 && second==0) {
      get_date_and_time();
    }
  }
  lv_task_handler();   // let the GUI do its work
  lv_tick_inc(5);         // tell LVGL how much time has passed
  delay(5);                 // let this time pass
}

Demonstration

Upload the code to your board. Go to Tools > Board and select ESP32 > ESP32 Dev Module. Then, select the right COM port in Tools > Port.

If you see an Error like this: “Sketch too big” during the uploading process, in Arduino IDE go to Tools > Partition scheme > choose anything that has more than 1.4MB APP, for example: “Huge APP (3MB No OTA/1MB SPIFFS“.

Select Huge App Partion Scheme Arduino IDE Tools Menu

Finally, click the upload button.

Arduino IDE 2 Upload Button

After a few seconds, the time and date will be displayed on the screen as shown in the picture below.

ESP32 CYD Cheap Yellow Display LVGL Digital Clock Time Date

The ESP32 will not keep the time perfectly with its internal clock. During our tests, after one hour it usually incurs a 20 to 40 seconds delay. Every hour we make a new HTTP request to the WorldTimeAPI to sync the time and date.

Wrapping Up

In this tutorial, you learned to display date and time on the Cheap Yellow Display (CYD) board using the LVGL library.

We hope you found this tutorial useful. We’re preparing more guides about this board, so stay tuned. If you would like to learn more about creating graphical user interfaces using the LVGL library with the ESP32, check out our latest eBook:

Other guides you might like reading:

To learn more about the ESP32, make sure to take a look at our resources:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

36 thoughts on “ESP32 CYD with LVGL: Digital Clock with Time and Date”

  1. The demo seems too big: I get the following error (having set up lv_conf.h and User_Setup.h as directed)

    Sketch uses 1442985 bytes (110%) of program storage space. Maximum is 1310720 bytes.
    Global variables use 63016 bytes (19%) of dynamic memory, leaving 264664 bytes for local variables. Maximum is 327680 bytes.
    Sketch too big; see support.arduino.cc/hc/en-us/articles/360013825179 for tips on reducing it.
    text section exceeds available space in board

    Compilation error: text section exceeds available space in board

    Reply
    • Exactly… When using Wi-Fi with LVGL, you usually need to use:

      If you see an Error like this: “Sketch too big” during the uploading process, in Arduino IDE go to Tools > Partition scheme > choose anything that has more than 1.4MB APP, for example: “Huge APP (3MB No OTA/1MB SPIFFS“.

      We describe that step in the guide.

      Glad it worked!

      Reply
      • Hello Rui, I’m using version 2.3.3 and the Partition scheme option is not appearing, even checking the image you placed, in this new version it is practically only half full, could you tell me where this option might be?

        Reply
  2. Hi, can you help please?
    I have loaded the code for the clock and all works fine for about 50 mins and then the display freezes and won’t update of it’s own accord. Could this be an issue related to the code refreshing to accommodate the 20 to 40 sec delay, i.e. if it fails to connect it just freezes. Any thoughts please?
    Love your channel and projects, thanks and regards
    Bryan

    Reply
    • Hello Bryan,
      I think the API might have failed to GET the time and date… It’s a free API so is not perfect and sometimes might block some requests. You might need to add a delay in the loop() section to make less requests when it fails, after line 205 you can add:
      delay(10000);

      Reply
      • Hi Rui
        Thanks for your reply, I’ve tried adding the 10secs delay in the LOOP as you suggested but the same problem still exists. Do you think a 20 secs delay may help, or is there an alternative site to request the time info from?
        Again, many thanks and kind regards
        Bryan

        Reply
      • Hi Rui
        Thanks for your reply. I have tried adding the 10 secs delay but sadly it made no difference, I then increased it to 20 secs but also with no luck. Could it be that the API has failed, at their end, and is not allowing repeated requests, although the initial request gets the correct date and time? Is there an alternative date/time location to request from?
        Many thanks
        Bryan

        Reply
  3. As an addendum to my mail above I have started the CYD Clock program and the serial monitor showed a clean start with the date and time obtained (at 08:46). Having left the serial monitor connected the software tried to connect again at 09:00 and reports back, every 20 secs, that “GET request failed error: connection refused”. This has been happening continuously for the last 25 mins. Please can you suggest where the fault may be. My internet connection hasn’t failed, everything else internet wise is running perfectly.
    Many thanks and kind regards
    Bryan

    Reply
  4. Thank you for this tutorial.
    Is there a way to modify the code so that the date is displayed in the european format ? (dd/mm/yyyy)

    Reply
    • I just made the following changes:
      added these near the time ones
      static int32_t year;
      static int32_t month;
      static int32_t day;

      and the following code at the bottom of ‘timer_cb’
      lv_label_set_text(text_label_time, final_time_str.c_str());
      String year_date_f = String(year);
      String month_date_f = String(month);
      String day_date_f = String(day);
      String final_date_str = String(day_date_f) + “-” + String(month_date_f) + “-” + String(year_date_f);
      //lv_label_set_text(text_label_date, current_date.c_str());
      lv_label_set_text(text_label_date, final_date_str.c_str());

      Reply
  5. Seems better to treat the WorldTimeAPI requests like an NTP server (NTP would be a better place to pull from anyway IMHO) – you don’t want to clobber that service/server with requests for a clock. This project would benefit from a local battery backed RTC like an NXP PCF2131 which is a nano-power RTC with an internal 32.768kHz TCXO.

    This way you get the second counter pretty much right-on-the-money, and it stores the other important stuff internally (date, time, day of week, day of year, etc.) so that can be pulled up right away at boot time even without going out to the internet. One can also enable local touch time date setting for internet-denied setup.

    I did something similar for a fish tank light running on an ESP32-S3 touch display kit – I use a cheap GPS receiver to pull location and UTC, then use the Timezone Arduino library from Jack Christensen to convert to local time. This updates the local RTC and then refreshes the sync to the GPS time standard every 24 hours. I had wired in the 1PPS output from the GPS receiver and configures the RTC to output 1PPS – with the intention of “training” the local oscillator to a long-integration GPS time, but never got around to it. From the local time and position, I can calculate a rough approximation of the atmosphere and light angle with Raleigh scattering to create a sunrise/sunset which is “reasonable” (the fish doesn’t complain) which drives 4x PWM outputs (RGB-W).

    Reply
  6. There is a capacitive touch version of the CYD. Can the Capacitive version be swapped in for the Resistive version? I think they use different touch drivers?, so I assume no. But if that is the case is it a big lift to switch over to the Capacitive version?

    ESP32-2432S028R ILI9341 Resistive Touch Screen 240×320
    ESP-WROOM-32 Capacitive Touch Screen TFT LCD Module 320×480 ST7796 ESP32-3248S035C

    Reply
    • The capacitive works in a different way and requires a different touch library.
      We don’t have instructions for the capacitive display at the moment.
      Regards,
      Sara

      Reply
  7. I installed ArduinoJason as instructed by the posted sketch for this program.

    I get a Compilation Terminated Error Message:

    In file included from C:\Users\Jerry Renken\Desktop\R Nerd\RN ESP32 and CYD Tutorials from the Web\CYD Tutorials\CYD_Digital_Clock_with_Time_and_Date/ArduinoJson.h:9,
    from C:\Users\Jerry Renken\Desktop\R Nerd\RN ESP32 and CYD Tutorials from the Web\CYD Tutorials\CYD_Digital_Clock_with_Time_and_Date\CYD_Digital_Clock_with_Time_and_Date.ino:59:
    C:\Users\Jerry Renken\Desktop\R Nerd\RN ESP32 and CYD Tutorials from the Web\CYD Tutorials\CYD_Digital_Clock_with_Time_and_Date/ArduinoJson.hpp:11:10: fatal error: ArduinoJson/Configuration.hpp: No such file or directory
    11 | #include “ArduinoJson/Configuration.hpp”
    | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    compilation terminated.
    exit status 1

    Compilation error: ArduinoJson/Configuration.hpp: No such file or directory

    The portion of my sketch with the include statements:

    #include <lvgl.h>

    #include <TFT_eSPI.h>

    #include <WiFi.h>
    #include <HTTPClient.h>
    #include <ArduinoJson.h>

    #include <ArduinoJson/Configuration.hpp>

    // #include <Configuration.hpp>

    What is going on? How can I fix this problem?

    Reply
  8. I’m having trouble changing the color of text. I’m trying to update the color of the Date Text to Red as follows:

    lv_obj_set_style_text_color((lv_obj_t*) text_label_date, lv_palette_main(LV_PALETTE_RED), 0);

    However, the color of the date on the display becomes blue. Any ideas why the colors don’t match what I’m trying to set them to?

    Reply
      • Thank you. Uncommenting #define TFT_INVERSION_ON in the TFT_eSPI User_setup.h did the trick.

        I also added the following in lv_create_main_gui to use a black background instead of white.

        //Set Background Color
        lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x000000), LV_PART_MAIN);

        Thanks so much for the tutorial. First time programming an ESP32 from scratch although I’ve used prebuilt binaries from others. I’ve played around a bit with the code to substitute a configTime function to update the time from an NTP server instead of the Worldtime API and I’ve reformatted the text to see Day of the Week on line 1, date on line 2 in the format 12 Sep 2024 and the time in AM/PM format on line 3. I also disconnect from WiFi after updating the time and only reconnect about once a day to update the time from NTP.

        Next thing to do is to make DST corrections automatic, maybe using the Timezone library.

        Reply
  9. Thank you for publishing this project. As this is my first time working with ESP 32 I purchased the eBooks “Learn ESP32 with Arduino IDE” and “Learn LVGL” to get started.
    I changed the font color and the screen color. Is there another font zise than “montserrat_48 ” that I can install to provide me with a larger display of the time?

    Reply
  10. First of all: thank you a lot for both, the eBooks and these examples…
    Nevertheless I have a problem, i can’t fix! I would like to switch off/dim the backlight after a certain amount of time. Unfortunately this doesn’t work. Directly after having switched off the backlight, it is automatically switch on again.
    Can you tell me how to fix this?
    Regards,
    Gerhard

    Reply
    • Hi. Another half day and the error is found. As usual, the problem was sitting right in front of the computer. Sorry for the unnecessary question…

      If anyone is interested:
      Backlight ON: digitalWrite(TFT_BL, HIGH);
      Backlight OFF: digitalWrite(TFT_BL, LOW);
      TFT_BL already exists and comes from the TFT driver.
      By the way: dimming via PWM works just as well…

      Regards,
      Gerhard

      Reply
    • I don’t know the “best” way how to add dimming/backlight-control.
      I think you can do this within the loop-function, the timer-callback function, or if you add touchscreen-functionality, within the touchscreen-event-handler.

      Changing the brightness can be done by calling
      analogWrite(TFT_BL, ); with 0<=DUTY<=255
      or
      digitalWrite(TFT_BL, <true|false>);

      I would suggest to set the brightness to its maximum value on an input event.
      If nothing else is going on, the brightness could be slowly reduced in the loop() or timer_cb() to a minimum value.

      Reply
  11. I’ve been trying to compile a clock program for a week now.
    I’m using Arduino 2.3.3, I’ve installed libraries
    with the numbers in the article. I get an error:lv_log_register_print_cb’ was not declared in this scope .

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.