
Internet Clock (ESP32 + LCD)
Beginner20 minA desk clock that takes the time from the internet and never needs setting: the ESP32 joins your home Wi-Fi, gets Turkey's time from a time server (NTP) and shows the date, the day and the time with its seconds on the LCD. After a power cut it finds the time again by itself. Ideal as a first ESP32 project: no soldering, no breadboard, just four wires.
Build it step by step in the appWhat you need
1 × ESP32 Development Board (ESP32-WROOM-32)
1 × 16x2 Character LCD Display (with I2C module)
4 × Jumper Wire - Female/Female
Wiring steps
- 1
Connect the LCD's power (GND and VCC)

Do not put the ESP32 on the breadboard: a 30-pin board covers nearly all of it. In this project the board lies on the table and the LCD is connected straight to its pins with four female-female jumper wires. Hold the board with its USB socket facing you; the pin names are printed on the board next to the pins. On the 4-pin header of the I2C module on the back of the LCD, connect GND to the GND pin on the ESP32's right edge, just above 3V3, and VCC to the VIN pin at the bottom of the left edge. VIN gives 5V while the ESP32 is plugged into USB; the LCD's text is clear at 5V.
- ESP32 GND (next to 3V3) → LCD GND (black wire)
- ESP32 VIN (the USB's 5V) → LCD VCC (red wire)
- 2
Connect the I2C wires (SDA and SCL)

Connect the LCD's SDA pin to the ESP32's D21 pin and its SCL pin to D22. These are the pins the ESP32 uses for I2C; if you use other pins, change SDA_PIN and SCL_PIN in the code too. Before you upload the code, write your home Wi-Fi network's name and password into WIFI_NAME and WIFI_PASSWORD in the code, minding capital letters. The ESP32 only joins 2.4 GHz networks; if your router broadcasts only on 5 GHz, it cannot see the network.
- ESP32 D21 → LCD SDA (yellow wire)
- ESP32 D22 → LCD SCL (green wire)
Arduino sketch
// Install from the Library Manager:
// "LiquidCrystal I2C"
// Board: "ESP32 Dev Module"
#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <time.h>
// Your Wi-Fi network's name and password
const char* WIFI_NAME = "Network_Name";
const char* WIFI_PASSWORD = "Password";
// Turkey time: UTC+3, no summer time
const char* TIME_ZONE = "<+03>-3";
// The server that gives the time
const char* NTP_SERVER = "pool.ntp.org";
// The date on screen: day/month/year
const char* DATE_FORMAT = "%d/%m/%Y";
// The days, starting on Sunday
const char* DAYS[] = {"Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat"};
// The ESP32's I2C pins
const int SDA_PIN = 21;
const int SCL_PIN = 22;
// Ask about the password after this (ms)
const unsigned long WIFI_HINT_AFTER = 15000;
// I2C address: 0x27 on most, 0x3F on some
LiquidCrystal_I2C lcd(0x27, 16, 2);
// The second last written on screen
int shownSecond = -1;
void setup() {
Serial.begin(115200);
Wire.begin(SDA_PIN, SCL_PIN);
lcd.init();
lcd.backlight();
lcd.print("Waiting for WiFi");
Serial.print("Connecting to ");
Serial.println(WIFI_NAME);
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (millis() - start > WIFI_HINT_AFTER) {
// No luck: check name, password
lcd.setCursor(0, 1);
lcd.print("Name/password?");
}
}
Serial.println();
Serial.print("Connected, IP: ");
Serial.println(WiFi.localIP());
// The time comes from the net once,
// then the board keeps it itself
configTzTime(TIME_ZONE, NTP_SERVER);
lcd.clear();
lcd.print("Getting time...");
}
void loop() {
struct tm now;
// No time yet: waits 1 s for it
if (!getLocalTime(&now, 1000)) {
Serial.println("No time yet");
return;
}
// Same second: nothing new to write
if (now.tm_sec == shownSecond) {
delay(50);
return;
}
bool first = shownSecond < 0;
shownSecond = now.tm_sec;
char dateText[11];
strftime(dateText, sizeof dateText, DATE_FORMAT, &now);
char timeText[9];
strftime(timeText, sizeof timeText, "%H:%M:%S", &now);
// Line 1: the date and the day
lcd.setCursor(0, 0);
lcd.print(dateText);
lcd.print(" ");
lcd.print(DAYS[now.tm_wday]);
// Line 2: the time, in the middle
lcd.setCursor(4, 1);
lcd.print(timeText);
// To the Serial Monitor: the first
// time, then once a minute
if (first || now.tm_sec == 0) {
Serial.print(dateText);
Serial.print(" ");
Serial.print(DAYS[now.tm_wday]);
Serial.print(" ");
Serial.println(timeText);
}
}
What the Serial Monitor shows
Connecting to HomeNet ..... Connected, IP: 192.168.1.42 No time yet 21/10/2026 Wed 17:45:09 21/10/2026 Wed 17:46:00 21/10/2026 Wed 17:47:00
If a wire is loose
Connecting to HomeNet ....................................................
What you will see
A one-time ESP32 set-up in the Arduino IDE: in File → Preferences, write https://espressif.github.io/arduino-esp32/package_esp32_index.json into "Additional boards manager URLs"; in Tools → Board → Boards Manager search for "esp32" and install "esp32 by Espressif Systems". Then pick "ESP32 Dev Module" and the ESP32's port under Tools → Board, and install "LiquidCrystal I2C" from the Library Manager (a warning about the "AVR architecture" does not matter, it works on the ESP32 too). Upload the code and open the Serial Monitor at 115200 baud. The LCD first says "Waiting for WiFi"; within a few seconds it joins the network and says "Getting time...", then the date and the day appear on the top line and the time, its seconds ticking, on the bottom line. The Serial Monitor prints the first time and then the time once a minute. Once the time has come in, the board keeps it by itself; if the Wi-Fi drops for a while the clock does not stop, and the board corrects the time again every hour. If the dots in the Serial Monitor never end and the LCD's bottom line says "Name/password?", check the network's name and password, and make sure it is a 2.4 GHz network. If the LCD's light is on but there is no text, turn the blue trimmer on the I2C module with a small screwdriver; if it still shows nothing, change 0x27 in the code to 0x3F. If uploading says "Connecting..." and fails, hold the ESP32's BOOT button down while it uploads. If the ESP32 never shows up in the port list, make sure the cable is a data cable and not a charging-only one, and on Windows install the driver for the USB chip on the board (CP2102 or CH340).
In the app, tick off every wire, match the parts to your inventory and pick up where you left off.
Build it step by step in the app