/*
ESP32 + ILI9341 240x320 TFT — Digital Clock
AI Centre Nandurbar | Arvind Patil
Real-hardware build (Arduino IDE).
Same logic as the Wokwi sketch — only the WiFi credentials differ.
Libraries required (Library Manager):
- Adafruit GFX Library
- Adafruit ILI9341
- Adafruit BusIO
Wiring (adjust pins to your board if different):
CS -> GPIO5
DC -> GPIO2
RST -> GPIO4
SCK -> GPIO18
MOSI -> GPIO23
MISO -> GPIO19
LED -> 3V3
VCC -> 3V3
GND -> GND
*/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <WiFi.h>
#include <time.h>
#define TFT_CS 5
#define TFT_DC 2
#define TFT_RST 4
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// ---- navy/gold palette (RGB565) ----
#define COL_BG 0x0006
#define COL_PANEL 0x10A2
#define COL_GOLD 0xFEA0
#define COL_GOLD_DK 0xC5A0
#define COL_WHITE 0xFFFF
#define COL_GREY 0x8410
// ---- Set your real WiFi credentials here ----
const char* ssid = "Airtel_air_6035";
const char* password = "air26289";
const long gmtOffset_sec = 19800; // IST UTC+5:30
const int daylightOffset_sec = 0;
bool timeSynced = false;
unsigned long fallbackMillisAtBoot = 0;
const char* days[] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
const char* daysMr[] = {"रविवार","सोमवार","मंगळवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"};
const char* mons[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
String lastTimeStr = "";
String lastDateStr = "";
bool colonOn = true;
void drawFrame() {
tft.fillScreen(COL_BG);
tft.drawRect(6, 6, 228, 308, COL_GOLD_DK);
tft.drawRect(8, 8, 224, 304, COL_GOLD_DK);
tft.setTextColor(COL_GOLD);
tft.setTextSize(2);
tft.setCursor(28, 22);
tft.print("AI CENTRE NANDURBAR");
tft.drawFastHLine(16, 46, 208, COL_GOLD_DK);
tft.setTextColor(COL_GREY);
tft.setTextSize(1);
tft.setCursor(70, 54);
tft.print("DIGITAL CLOCK");
}
void drawWifiBadge() {
int x = 176, y = 14;
tft.fillRect(x, y, 40, 14, COL_PANEL);
tft.setTextSize(1);
tft.setTextColor(timeSynced ? COL_GOLD : COL_GREY);
tft.setCursor(x + 2, y + 3);
tft.print(timeSynced ? "NTP" : "OFF");
}
void getNowStruct(struct tm &timeinfo) {
if (timeSynced) {
getLocalTime(&timeinfo);
} else {
unsigned long elapsedSec = (millis() - fallbackMillisAtBoot) / 1000;
time_t t = 1700000000 + elapsedSec;
localtime_r(&t, &timeinfo);
}
}
void drawClockFace() {
struct tm timeinfo;
getNowStruct(timeinfo);
char timeBuf[9];
snprintf(timeBuf, sizeof(timeBuf), "%02d:%02d:%02d",
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
String timeStr = String(timeBuf);
if (!colonOn) {
timeStr.setCharAt(2, ' ');
timeStr.setCharAt(5, ' ');
}
char dateBuf[24];
snprintf(dateBuf, sizeof(dateBuf), "%02d %s %04d",
timeinfo.tm_mday, mons[timeinfo.tm_mon], timeinfo.tm_year + 1900);
String dateStr = String(dateBuf);
tft.setTextSize(4);
if (lastTimeStr != "") {
tft.setTextColor(COL_BG);
tft.setCursor(18, 110);
tft.print(lastTimeStr);
}
tft.setTextColor(COL_WHITE);
tft.setCursor(18, 110);
tft.print(timeStr);
lastTimeStr = timeStr;
tft.setTextSize(2);
tft.fillRect(16, 160, 208, 40, COL_BG);
tft.setTextColor(COL_GOLD);
int wIdx = timeinfo.tm_wday;
tft.setCursor(60, 162);
tft.print(days[wIdx]);
tft.setCursor(60, 184);
tft.print(daysMr[wIdx]);
if (lastDateStr != dateStr) {
tft.fillRect(16, 214, 208, 20, COL_BG);
tft.setTextSize(2);
tft.setTextColor(COL_GREY);
tft.setCursor(40, 216);
tft.print(dateStr);
lastDateStr = dateStr;
}
tft.setTextSize(1);
tft.setTextColor(COL_GOLD_DK);
tft.setCursor(58, 290);
tft.print("Arvind Patil / Ysz4");
drawWifiBadge();
}
void connectWiFi() {
WiFi.begin(ssid, password);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 15000) {
delay(250);
}
if (WiFi.status() == WL_CONNECTED) {
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org", "time.nist.gov");
struct tm timeinfo;
if (getLocalTime(&timeinfo, 5000)) {
timeSynced = true;
}
}
if (!timeSynced) {
fallbackMillisAtBoot = millis();
}
}
void setup() {
Serial.begin(115200);
tft.begin();
tft.setRotation(0);
drawFrame();
connectWiFi();
}
unsigned long lastTick = 0;
void loop() {
if (millis() - lastTick >= 500) {
colonOn = !colonOn;
drawClockFace();
lastTick = millis();
}
}