/*
ESP32-C3 Super Mini + MAX7219 (4x cascaded 8x8, 32x8 total)
IoT Clock for India — NTP synced to IST (UTC +5:30)
Board: ESP32-C3 Super Mini
Display: MAX7219 dot matrix, 4 modules cascaded (32 columns x 8 rows)
Wiring (MAX7219 -> ESP32-C3 Super Mini):
VCC -> 5V (or 3V3 if module regulator allows; prefer 5V from USB)
GND -> GND
DIN -> GPIO7
CS -> GPIO10
CLK -> GPIO4
Library required: MD_MAX72XX by majicDesigns
(Sketch > Include Library > Manage Libraries > search "MD_MAX72XX")
Also needs MD_Parola (optional, used here for text/scroll) and SPI (built-in)
Author signature block preserved per house style:
Arvind Patil / AI Centre Nandurbar / Ysz4 / HansaScript
*/
#include <WiFi.h>
#include <time.h>
#include <SPI.h>
#include <MD_MAX72xx.h>
#include <MD_Parola.h>
// ---------- WiFi credentials ----------
const char* WIFI_SSID = "Airtel_arvi_6035";
const char* WIFI_PASSWORD = "air26289";
// ---------- NTP / IST settings ----------
const char* NTP_SERVER = "pool.ntp.org";
const long GMT_OFFSET_SEC = 5 * 3600 + 1800; // IST = UTC +5:30
const int DST_OFFSET_SEC = 0; // India does not observe DST
// ---------- MAX7219 wiring ----------
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4 // 4 x 8x8 = 32x8
#define CLK_PIN 4 // GPIO4 -> CLK
#define DATA_PIN 7 // GPIO7 -> DIN
#define CS_PIN 10 // GPIO10 -> CS
MD_Parola display = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
// ---------- Display modes ----------
enum ClockMode { MODE_TIME, MODE_DATE, MODE_SCROLL };
ClockMode currentMode = MODE_TIME;
bool use24h = true;
unsigned long lastSwitch = 0;
const unsigned long MODE_INTERVAL_MS = 8000; // auto-cycle every 8s (set to 0 to disable)
char buf[64];
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to WiFi");
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 20000) {
delay(400);
Serial.print(".");
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.print("WiFi connected. IP: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("WiFi connect failed — will keep retrying in background.");
}
}
void syncNTP() {
configTime(GMT_OFFSET_SEC, DST_OFFSET_SEC, NTP_SERVER);
Serial.print("Waiting for NTP time sync");
struct tm timeinfo;
int attempts = 0;
while (!getLocalTime(&timeinfo) && attempts < 20) {
Serial.print(".");
delay(500);
attempts++;
}
Serial.println();
if (attempts < 20) {
Serial.println("NTP sync OK (IST).");
} else {
Serial.println("NTP sync failed — check WiFi/internet.");
}
}
void formatTimeString(struct tm &t, char *out, size_t outLen) {
int h = t.tm_hour;
const char *suffix = "";
if (!use24h) {
suffix = (h >= 12) ? " P" : " A";
h = h % 12;
if (h == 0) h = 12;
}
if (use24h) {
snprintf(out, outLen, "%02d:%02d:%02d", h, t.tm_min, t.tm_sec);
} else {
snprintf(out, outLen, "%02d:%02d:%02d%s", h, t.tm_min, t.tm_sec, suffix);
}
}
void formatDateString(struct tm &t, char *out, size_t outLen) {
snprintf(out, outLen, "%02d-%02d-%04d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900);
}
void updateDisplay() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
display.displayText("NO SYNC", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
display.displayAnimate();
return;
}
if (currentMode == MODE_TIME) {
formatTimeString(timeinfo, buf, sizeof(buf));
display.displayText(buf, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
display.displayAnimate();
} else if (currentMode == MODE_DATE) {
formatDateString(timeinfo, buf, sizeof(buf));
display.displayText(buf, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
display.displayAnimate();
} else if (currentMode == MODE_SCROLL) {
char t1[16], t2[16];
formatTimeString(timeinfo, t1, sizeof(t1));
formatDateString(timeinfo, t2, sizeof(t2));
snprintf(buf, sizeof(buf), "%s %s ", t1, t2);
if (display.displayAnimate()) {
display.displayText(buf, PA_LEFT, 60, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}
}
}
void setup() {
Serial.begin(115200);
delay(300);
Serial.println("\nESP32-C3 Super Mini + MAX7219 — IST IoT Clock");
Serial.println("Arvind Patil / AI Centre Nandurbar / Ysz4 / HansaScript");
display.begin();
display.setIntensity(6); // 0 (dim) - 15 (max brightness)
display.displayClear();
display.displayText("BOOT", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
display.displayAnimate();
connectWiFi();
syncNTP();
display.displayClear();
}
void loop() {
// Re-attempt WiFi reconnect silently if dropped
if (WiFi.status() != WL_CONNECTED) {
WiFi.reconnect();
}
// Auto-cycle display modes (optional)
if (MODE_INTERVAL_MS > 0 && millis() - lastSwitch > MODE_INTERVAL_MS) {
lastSwitch = millis();
currentMode = (ClockMode)((currentMode + 1) % 3);
display.displayClear();
}
updateDisplay();
delay(currentMode == MODE_SCROLL ? 20 : 200);
}