// =====================================
// LCD1602 (PARALLEL) + ESP32 NTP CLOCK
// =====================================
#include <WiFi.h>
#include <LiquidCrystal.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// ===============================
// LCD CONFIG (YOUR PINOUT)
// RS, E, D4, D5, D6, D7
// ===============================
LiquidCrystal lcd(0, 4, 16, 17, 5, 18);
// ===============================
// WIFI + NTP CONFIG
// ===============================
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 6 * 3600
#define UTC_OFFSET_DST 0
// ===============================
// WEATHER API
// ===============================
const char* tempApiUrl = "http://api.open-meteo.com/v1/forecast?latitude=23.81&longitude=90.41¤t_weather=true";
const unsigned long TEMP_UPDATE_INTERVAL = 5 * 60 * 1000;
// ===============================
// GLOBAL VARIABLES
// ===============================
float lastTemp = -1000.0;
unsigned long lastTempUpdate = 0;
const char* daysOfWeek[] = {"SUN","MON","TUE","WED","THU","FRI","SAT"};
const char* months[] = {"JAN","FEB","MAR","APR","MAY","JUN",
"JUL","AUG","SEP","OCT","NOV","DEC"};
// Display cache (avoid flicker)
struct DispCache {
char weekDay[4];
uint8_t hour, minute, second;
uint8_t mon, day;
float temperature;
} lastDisplay = {"", 99, 99, 99, 99, 99, -1000.0};
// ===============================
// FUNCTIONS
// ===============================
// Fetch temperature
void fetchTemperature() {
HTTPClient http;
http.begin(tempApiUrl);
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
StaticJsonDocument<512> doc;
if (deserializeJson(doc, payload) == DeserializationError::Ok) {
if (doc["current_weather"]["temperature"]) {
lastTemp = doc["current_weather"]["temperature"];
}
}
}
http.end();
lastTempUpdate = millis();
}
// Print static part (HH:MM)
void printTimeStatic(const struct tm &timeinfo) {
char line1[14];
snprintf(line1, sizeof(line1), "%s - %02d:%02d:",
daysOfWeek[timeinfo.tm_wday],
timeinfo.tm_hour,
timeinfo.tm_min);
lcd.setCursor(0, 0);
lcd.print(line1);
}
// Print seconds only
void printSeconds(uint8_t sec) {
lcd.setCursor(12, 0);
char secStr[3];
snprintf(secStr, sizeof(secStr), "%02d", sec);
lcd.print(secStr);
}
// Print date + temperature
void printDateTemp(const struct tm &timeinfo, float temp) {
char dateStr[9];
snprintf(dateStr, sizeof(dateStr), "%s %2d ",
months[timeinfo.tm_mon],
timeinfo.tm_mday);
char tempStr[8];
if (temp > -100) {
snprintf(tempStr, sizeof(tempStr), "%5.1fC", temp);
} else {
snprintf(tempStr, sizeof(tempStr), " --.-C");
}
lcd.setCursor(0, 1);
lcd.print(dateStr);
lcd.setCursor(8, 1);
lcd.print(tempStr);
}
// ===============================
// SETUP
// ===============================
void setup() {
Serial.begin(115200);
lcd.begin(16, 2);
// Boot message
lcd.setCursor(0, 0);
lcd.print("Connecting WiFi");
lcd.setCursor(0, 1);
lcd.print("Please wait... ");
// WiFi connect
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(300);
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Connected ");
lcd.setCursor(0, 1);
lcd.print("Syncing Time...");
// NTP setup
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
// Initial temp fetch
fetchTemperature();
lastTempUpdate = millis() - TEMP_UPDATE_INTERVAL;
}
// ===============================
// LOOP
// ===============================
void loop() {
struct tm timeinfo;
// Get time
if (!getLocalTime(&timeinfo)) {
lcd.setCursor(0, 0);
lcd.print("NTP Error ");
lcd.setCursor(0, 1);
lcd.print("Retrying... ");
delay(1000);
return;
}
// Update temperature periodically
if (millis() - lastTempUpdate >= TEMP_UPDATE_INTERVAL) {
fetchTemperature();
}
// Update hour/min/day only when changed
if (strcmp(daysOfWeek[timeinfo.tm_wday], lastDisplay.weekDay) != 0 ||
timeinfo.tm_hour != lastDisplay.hour ||
timeinfo.tm_min != lastDisplay.minute) {
printTimeStatic(timeinfo);
strncpy(lastDisplay.weekDay, daysOfWeek[timeinfo.tm_wday], 4);
lastDisplay.hour = timeinfo.tm_hour;
lastDisplay.minute = timeinfo.tm_min;
}
// Update seconds only
if (timeinfo.tm_sec != lastDisplay.second) {
printSeconds(timeinfo.tm_sec);
lastDisplay.second = timeinfo.tm_sec;
}
// Update date/temp only when needed
if (timeinfo.tm_mon != lastDisplay.mon ||
timeinfo.tm_mday != lastDisplay.day ||
abs(lastTemp - lastDisplay.temperature) > 0.1) {
printDateTemp(timeinfo, lastTemp);
lastDisplay.mon = timeinfo.tm_mon;
lastDisplay.day = timeinfo.tm_mday;
lastDisplay.temperature = lastTemp;
}
delay(50);
}