NTP internet clock
A desk clock that sets itself from the internet and handles daylight saving on its own. Big digits and the date on a small OLED.
Wiring
| From | To board | Note |
|---|---|---|
| OLED VCC | 3V3 | |
| OLED GND | GND | |
| OLED SDA | GPIO 21 | |
| OLED SCL | GPIO 22 |
Tested on this board
Not run on this board yet. Treat the wiring and code as a first draft.
Firmware, Arduino sketch for ESP32 Dev Module
// NTP clock: Wi-Fi sets the time, the TZ rule handles daylight saving.
#include <WiFi.h>
#include <Wire.h>
#include <time.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const char* WIFI_SSID = "your-network";
const char* WIFI_PASS = "your-password";
// POSIX time zone rule. US Eastern shown; more examples in the project notes.
const char* TZ_RULE = "EST5EDT,M3.2.0,M11.1.0";
Adafruit_SSD1306 display(128, 64, &Wire, -1);
int lastMinute = -1;
void message(const char* text) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 28);
display.print(text);
display.display();
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 not found at 0x3C");
for (;;) delay(1000);
}
message("Joining Wi-Fi...");
Serial.printf("wifi joining %s\n", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(250);
Serial.printf("wifi ok %s\n", WiFi.localIP().toString().c_str());
message("Setting the time...");
configTzTime(TZ_RULE, "pool.ntp.org", "time.google.com");
struct tm now;
while (!getLocalTime(&now, 10000)) Serial.println("waiting for NTP");
char text[48];
strftime(text, sizeof text, "%a %d %b %Y %H:%M:%S %Z", &now);
Serial.printf("time synced: %s\n", text);
}
void loop() {
struct tm now;
if (!getLocalTime(&now, 100)) return;
char hhmm[6], ss[3], date[20];
strftime(hhmm, sizeof hhmm, "%H:%M", &now);
strftime(ss, sizeof ss, "%S", &now);
strftime(date, sizeof date, "%a %d %b %Y", &now);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(3);
display.setCursor(4, 12);
display.print(hhmm);
display.setTextSize(2);
display.setCursor(100, 19);
display.print(ss);
display.setTextSize(1);
display.setCursor(4, 50);
display.print(date);
if (WiFi.status() != WL_CONNECTED) display.print(" *"); // still keeping time, just not syncing
display.display();
if (now.tm_min != lastMinute) {
lastMinute = now.tm_min;
char line[48];
strftime(line, sizeof line, "%H:%M:%S %a %d %b %Y %Z", &now);
Serial.println(line);
}
delay(200);
}Wiring
| From | To board | Note |
|---|---|---|
| OLED VCC | 3V3 | |
| OLED GND | GND | |
| OLED SDA | GPIO 8 | |
| OLED SCL | GPIO 9 |
Tested on this board
Not run on this board yet. Treat the wiring and code as a first draft.
Firmware, Arduino sketch for ESP32S3 Dev Module
// NTP clock: Wi-Fi sets the time, the TZ rule handles daylight saving.
#include <WiFi.h>
#include <Wire.h>
#include <time.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const char* WIFI_SSID = "your-network";
const char* WIFI_PASS = "your-password";
// POSIX time zone rule. US Eastern shown; more examples in the project notes.
const char* TZ_RULE = "EST5EDT,M3.2.0,M11.1.0";
Adafruit_SSD1306 display(128, 64, &Wire, -1);
int lastMinute = -1;
void message(const char* text) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 28);
display.print(text);
display.display();
}
void setup() {
Serial.begin(115200);
Wire.begin(8, 9);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 not found at 0x3C");
for (;;) delay(1000);
}
message("Joining Wi-Fi...");
Serial.printf("wifi joining %s\n", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(250);
Serial.printf("wifi ok %s\n", WiFi.localIP().toString().c_str());
message("Setting the time...");
configTzTime(TZ_RULE, "pool.ntp.org", "time.google.com");
struct tm now;
while (!getLocalTime(&now, 10000)) Serial.println("waiting for NTP");
char text[48];
strftime(text, sizeof text, "%a %d %b %Y %H:%M:%S %Z", &now);
Serial.printf("time synced: %s\n", text);
}
void loop() {
struct tm now;
if (!getLocalTime(&now, 100)) return;
char hhmm[6], ss[3], date[20];
strftime(hhmm, sizeof hhmm, "%H:%M", &now);
strftime(ss, sizeof ss, "%S", &now);
strftime(date, sizeof date, "%a %d %b %Y", &now);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(3);
display.setCursor(4, 12);
display.print(hhmm);
display.setTextSize(2);
display.setCursor(100, 19);
display.print(ss);
display.setTextSize(1);
display.setCursor(4, 50);
display.print(date);
if (WiFi.status() != WL_CONNECTED) display.print(" *"); // still keeping time, just not syncing
display.display();
if (now.tm_min != lastMinute) {
lastMinute = now.tm_min;
char line[48];
strftime(line, sizeof line, "%H:%M:%S %a %d %b %Y %Z", &now);
Serial.println(line);
}
delay(200);
}Wiring
| From | To board | Note |
|---|---|---|
| OLED VCC | 3V3 | |
| OLED GND | GND | |
| OLED SDA | GPIO 6 | |
| OLED SCL | GPIO 7 |
Tested on this board
Not run on this board yet. Treat the wiring and code as a first draft.
Firmware, Arduino sketch for ESP32C3 Dev Module
// NTP clock: Wi-Fi sets the time, the TZ rule handles daylight saving.
#include <WiFi.h>
#include <Wire.h>
#include <time.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const char* WIFI_SSID = "your-network";
const char* WIFI_PASS = "your-password";
// POSIX time zone rule. US Eastern shown; more examples in the project notes.
const char* TZ_RULE = "EST5EDT,M3.2.0,M11.1.0";
Adafruit_SSD1306 display(128, 64, &Wire, -1);
int lastMinute = -1;
void message(const char* text) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 28);
display.print(text);
display.display();
}
void setup() {
Serial.begin(115200);
Wire.begin(6, 7);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 not found at 0x3C");
for (;;) delay(1000);
}
message("Joining Wi-Fi...");
Serial.printf("wifi joining %s\n", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(250);
Serial.printf("wifi ok %s\n", WiFi.localIP().toString().c_str());
message("Setting the time...");
configTzTime(TZ_RULE, "pool.ntp.org", "time.google.com");
struct tm now;
while (!getLocalTime(&now, 10000)) Serial.println("waiting for NTP");
char text[48];
strftime(text, sizeof text, "%a %d %b %Y %H:%M:%S %Z", &now);
Serial.printf("time synced: %s\n", text);
}
void loop() {
struct tm now;
if (!getLocalTime(&now, 100)) return;
char hhmm[6], ss[3], date[20];
strftime(hhmm, sizeof hhmm, "%H:%M", &now);
strftime(ss, sizeof ss, "%S", &now);
strftime(date, sizeof date, "%a %d %b %Y", &now);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(3);
display.setCursor(4, 12);
display.print(hhmm);
display.setTextSize(2);
display.setCursor(100, 19);
display.print(ss);
display.setTextSize(1);
display.setCursor(4, 50);
display.print(date);
if (WiFi.status() != WL_CONNECTED) display.print(" *"); // still keeping time, just not syncing
display.display();
if (now.tm_min != lastMinute) {
lastMinute = now.tm_min;
char line[48];
strftime(line, sizeof line, "%H:%M:%S %a %d %b %Y %Z", &now);
Serial.println(line);
}
delay(200);
}Parts
| Quantity | Part | Where to buy |
|---|---|---|
| 1× | ESP32 dev board | Buy at Amazon |
| 1× | 0.96 inch SSD1306 OLED, I2C, address 0x3C | |
| 4× | Jumper wires |
Amazon buy links may include an Associates tag, and this site may earn a commission from qualifying Amazon purchases at no extra cost to you. Adafruit links are direct.
Libraries
WiFi (built in), Adafruit SSD1306, Adafruit GFX Library
Load it
- In the Arduino IDE, install the esp32 board package and pick the board named above the sketch.
- Install the libraries listed above from the Library Manager.
- Paste the sketch, choose the board's port and upload. Hold BOOT if the upload stalls at Connecting.
- Close the IDE's serial monitor, then open the bench here to watch the output.
Field notes
- Change TZ_RULE for your time zone. Examples: Central US "CST6CDT,M3.2.0,M11.1.0", Pacific US "PST8PDT,M3.2.0,M11.1.0", UK "GMT0BST,M3.5.0/1,M10.5.0", Central Europe "CET-1CEST,M3.5.0,M10.5.0/3", Japan "JST-9".
- The ESP32 re-syncs with the time servers about once an hour. If Wi-Fi drops, the clock keeps running on its own crystal and a * appears after the date.
- Set WIFI_SSID and WIFI_PASS first. The ESP32 only joins 2.4 GHz networks.
Not tested yet
- Not tested on hardware yet. Compiles for every board listed with Arduino-ESP32 core 3.3.12.
Built it? Send a build report with your board and what the serial port printed. Working reports become the "Tested on this board" entries above.