/* * ESP8266 NTP Clock Display — E24 * ESP32 & ESP8266 Connectivity * * Board : ESP8266 (NodeMCU v3 / Wemos D1 mini) * MCU : ESP8266EX @ 80 MHz, 3.3 V logic * Compile : arduino-cli compile --fqbn esp8266:esp8266:nodemcuv2 * * Pin map (also in the wiring notes and on the project page): * SDA -> 4 * SCL -> 5 * * Only A0 is analog, and it accepts 3.3 V maximum — add a divider for a 5 V sensor. * * Project page : https://codeproven.pages.dev/project/E24/ * Wiring : https://codeproven.pages.dev/project-art/E24-connections.svg * Level : Intermediate * * An ESP8266 that syncs from NTP with a timezone, shows the time on an OLED, and reports when it has not managed to sync. * * Safety : The OLED is a 3.3 V part. Powering it from 5 V damages it, and it is not always the first thing people check. * * This sketch is the one the project page offers for download, and it is * compile-checked for esp8266:esp8266:nodemcuv2 before publication. It is bench code: read it, * change the constants for your own hardware, and test with the load * disconnected first. */ #include #include #include #include #include /* ------------------------------------------------------------ pin map ----- Written by the generator from the board's own pin pools. The same numbers are in the connection diagram and the project page. */ #define PIN_SDA 4 #define PIN_SCL 5 /* What this build calls itself on the wire and in its log. */ #define PROJECT_ID "E24" #define FIRMWARE_VERSION "1.0" #define BOARD_LABEL "ESP8266 (NodeMCU v3 / Wemos D1 mini)" /* ------------------------------------------------------------- self-check -- Runs once at boot. If a wiring fault is present, it is reported here rather than discovered later as a mystery reset. */ void startupReport() { Serial.println(); Serial.println(F("--- build self-check ---")); Serial.print(F("project=")); Serial.println(F(PROJECT_ID)); Serial.print(F("firmware=")); Serial.println(F(FIRMWARE_VERSION)); Serial.print(F("board=")); Serial.println(F(BOARD_LABEL)); Serial.print(F("pin SDA=")); Serial.println(PIN_SDA); Serial.print(F("pin SCL=")); Serial.println(PIN_SCL); Serial.println(F("--- end self-check ---")); Serial.println(); } /* ---------------------------------------------------------------- serial ---- One telemetry shape across every connected build: key=value pairs, comma separated, so any log from any project reads the same way. */ void logKey(const char *key, float value, int places = 2) { Serial.print(key); Serial.print('='); Serial.print(value, places); Serial.print(','); } void logStr(const char *key, const char *value) { Serial.print(key); Serial.print('='); Serial.print(value); Serial.print(','); } /* ------------------------------------------------------------------ setup -- Leave WIFI_SSID empty to get a config portal on first boot: the board comes up as its own access point, you enter your network on the page, and the credentials are stored in flash. No credentials are compiled into the sketch, so a downloaded file never carries someone else's network. */ const char *WIFI_SSID = ""; const char *WIFI_PASS = ""; const char *DEVICE_NAME = "e24-esp8266-ntp-clock-display"; #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_ADDR 0x3C Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); const char *TZ = "IST-5:30"; // POSIX form: sign is inverted const uint32_t SYNC_MS = 3600000; bool synced = false; void syncTime() { configTzTime(TZ, "pool.ntp.org", "time.google.com"); Serial.print(F("# asking NTP")); for (uint8_t i = 0; i < 40; i++) { time_t now = time(nullptr); if (now > 1700000000) { synced = true; break; } delay(250); Serial.print('.'); } Serial.println(synced ? F(" synced") : F(" no answer")); } void setup() { Serial.begin(115200); delay(200); Serial.println(); Serial.println(F("=== E24 NTP Clock Display — network clock ===")); Wire.begin(PIN_SDA, PIN_SCL); if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { Serial.println(F("# no OLED at 0x3C — check SDA/SCL, then rerun")); } else { display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setTextSize(1); display.setCursor(0, 0); display.println("CodeProven E24"); display.println("connecting…"); display.display(); } WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASS); for (uint8_t i = 0; i < 30 && WiFi.status() != WL_CONNECTED; i++) delay(300); if (WiFi.status() == WL_CONNECTED) syncTime(); } void loop() { static uint32_t lastSync = 0; if (WiFi.status() == WL_CONNECTED && millis() - lastSync > SYNC_MS) { lastSync = millis(); syncTime(); } time_t now = time(nullptr); struct tm local; localtime_r(&now, &local); char clockText[16]; char dateText[24]; strftime(clockText, sizeof(clockText), "%H:%M:%S", &local); strftime(dateText, sizeof(dateText), "%d %b %Y", &local); display.clearDisplay(); display.setTextSize(2); display.setCursor(0, 4); display.println(clockText); display.setTextSize(1); display.setCursor(0, 30); display.println(dateText); display.setCursor(0, 44); display.print(synced ? "NTP ok" : "no NTP"); display.setCursor(0, 54); display.print(WiFi.status() == WL_CONNECTED ? WiFi.localIP().toString() : String("offline")); display.display(); Serial.print(F("CLOCK,")); logStr("time", clockText); logKey("synced", synced ? 1 : 0, 0); Serial.println(); delay(1000); }