ESP32 IoT Clock: Sync Time from the Internet (No RTC)
Build a precise, self-updating IoT clock with an ESP32 that syncs time from a free internet API — no RTC module, no drift, just smart code and perfect timing.
Components and supplies
1
esp32-c3 with built in OLED
1
Wemos D1 clone (ESP-12F)
Apps and platforms
1
arduino IDE
Project description
Code
Internet clock displaying current time in Serial Monitor
cpp
With daily time resync from the internet
1#include <ESP8266WiFi.h> 2#include <WiFiClientSecure.h> 3#include <time.h> 4 5const char* ssid = "Dziubym"; 6const char* password = "Mikigosia1"; 7 8WiFiClientSecure client; 9 10 11unsigned long getUnixTimestamp() { 12 client.setInsecure(); // Skip certificate validation 13 14 if (client.connect("aisenseapi.com", 443)) { 15 client.println("GET /services/v1/timestamp HTTP/1.1"); 16 client.println("Host: aisenseapi.com"); 17 client.println("Connection: close"); 18 client.println(); 19 20 while (client.connected() || client.available()) { 21 String line = client.readStringUntil('\n'); 22 if (line.indexOf("timestamp") >= 0) { 23 int start = line.indexOf(":") + 1; 24 int end = line.indexOf("}", start); 25 unsigned long timestamp = line.substring(start, end).toInt(); 26 client.stop(); 27 return timestamp; 28 } 29 } 30 client.stop(); 31 } 32 return 0; // return 0 if failed 33} 34 35 36unsigned long startUnix = 0; // reference Unix time (Y) 37unsigned long lastSyncMillis = 0; // millis() at last update (U) 38unsigned long currentUnix = 0; 39unsigned long lastDisplayedSecond = 0; 40bool syncedToday = false; // replaces lastSyncCheck 41struct tm *timeInfo = localtime((time_t*)&startUnix); 42 43void setup() { 44 Serial.begin(9600); 45 delay(2000); 46 Serial.println("Connecting to WiFi..."); 47 delay(2000); 48 Serial.println("Connecting to WiFi..."); 49 WiFi.begin(ssid, password); 50 while (WiFi.status() != WL_CONNECTED) { 51 delay(500); 52 Serial.print("."); 53 } 54 Serial.println("\nWiFi connected."); 55 56 startUnix = getUnixTimestamp(); // get reference time (Y) 57 lastSyncMillis = millis(); // mark sync moment (U) 58 59 if (startUnix > 0) { 60 Serial.print("Initial Unix time: "); 61 Serial.println(startUnix); 62 } else { 63 Serial.println("Failed to get Unix timestamp."); 64 } 65} 66 67void loop() { 68 69 unsigned long elapsedSec = (millis() - lastSyncMillis) / 1000; 70 unsigned long currentUnix = startUnix + elapsedSec; 71 72 if (elapsedSec != lastDisplayedSecond) { // new second tick 73 lastDisplayedSecond = elapsedSec; 74 75 // Convert Unix → human-readable 76 time_t now = currentUnix; 77 tm *timeInfo = localtime(&now); // use gmtime for UTC 78 char buffer[30]; 79 strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeInfo); 80 81 Serial.print("Time: "); 82 Serial.print(buffer); 83 Serial.print(" syncedToday:"); 84 Serial.println(syncedToday); 85 86 } 87 88 // Sync every day at 1:00 AM 89 //struct tm *t = localtime((time_t*)¤tUnix); 90 if (timeInfo->tm_hour == 18 && timeInfo->tm_min == 25 && !syncedToday) { 91 Serial.println("1:00 AM reached — syncing time from internet..."); 92 unsigned long newUnix = getUnixTimestamp(); 93 if (newUnix > 0) { 94 startUnix = newUnix; 95 lastSyncMillis = millis(); 96 Serial.println("Time updated successfully."); 97 syncedToday = true; 98 } else { 99 Serial.println("Time update failed."); 100 } 101 delay(1000); // avoid multiple triggers within the same second 102 } 103 // Reset the sync flag at 1:01 AM 104 if (timeInfo->tm_hour == 18 && timeInfo->tm_min == 26) { 105 syncedToday = false; 106 } 107}
IOT clock on ESP32-C3 diplaying time on built-in OLED
cpp
With daily time resync from the internet
1#include <Arduino.h> 2#include <WiFi.h> 3#include <WiFiClientSecure.h> 4#include <U8g2lib.h> 5#include <Wire.h> 6#include <time.h> 7 8// ---- WiFi settings ---- 9const char* ssid = "Dziubym"; 10const char* password = "Mikigosia1"; 11 12// ---- OLED pins ---- 13#define SDA_PIN 5 14#define SCL_PIN 6 15U8G2_SSD1306_72X40_ER_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 16 17// ---- HTTPS client ---- 18WiFiClientSecure client; 19 20// ---- Timekeeping variables ---- 21unsigned long startUnix = 0; 22unsigned long lastSyncMillis = 0; 23unsigned long lastDisplayedSecond = 0; 24bool syncedToday = false; // replaces lastSyncCheck 25struct tm *timeInfo = localtime((time_t*)&startUnix); 26 27// ---- Draw a message on OLED ---- 28void drawOLEDMessage(const char* msg) { 29 30 u8g2.clearBuffer(); 31 u8g2.setDrawColor(1); 32 u8g2.setFont(u8g2_font_5x8_tr); 33 u8g2.drawStr(0, 12, msg); 34 u8g2.sendBuffer(); 35} 36 37// ---- Get Unix timestamp from API ---- 38unsigned long getUnixTimestamp() { 39 drawOLEDMessage("Fetching time..."); // display while fetching 40 41 client.setInsecure(); // skip certificate check 42 if (client.connect("aisenseapi.com", 443)) { 43 client.println("GET /services/v1/timestamp HTTP/1.1"); 44 client.println("Host: aisenseapi.com"); 45 client.println("Connection: close"); 46 client.println(); 47 48 while (client.connected() || client.available()) { 49 String line = client.readStringUntil('\n'); 50 if (line.indexOf("timestamp") >= 0) { 51 int start = line.indexOf(":") + 1; 52 int end = line.indexOf("}", start); 53 unsigned long timestamp = line.substring(start, end).toInt(); 54 client.stop(); 55 return timestamp; 56 } 57 } 58 client.stop(); 59 } 60 return 0; // failed 61} 62 63// ---- Draw time/date on OLED ---- 64void drawTimeDisplay(time_t currentUnix) { 65 tm *timeInfo = localtime(¤tUnix); 66 67 char timeStr[9]; // "HH:MM:SS" 68 snprintf(timeStr, sizeof(timeStr), "%02d:%02d:%02d", 69 timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec); 70 71 char dateStr[20]; // "Wed Oct15 2025" 72 strftime(dateStr, sizeof(dateStr), "%a %b%d %Y", timeInfo); 73 74 u8g2.clearBuffer(); 75 u8g2.setDrawColor(1); 76 u8g2.setFont(u8g2_font_5x8_tr); 77 u8g2.drawStr(0, 8, dateStr); 78 79 u8g2.setDrawColor(1); 80 u8g2.drawBox(0, 16, 72, 24); 81 82 u8g2.setDrawColor(0); 83 u8g2.setFont(u8g2_font_logisoso16_tf); 84 u8g2.drawStr(0, 36, timeStr); 85 u8g2.sendBuffer(); 86} 87 88// ---- Setup ---- 89void setup() { 90 Wire.begin(SDA_PIN, SCL_PIN); 91 u8g2.begin(); 92 93 drawOLEDMessage("Connecting WiFi..."); 94 WiFi.begin(ssid, password); 95 while (WiFi.status() != WL_CONNECTED) { 96 delay(300); 97 } 98 drawOLEDMessage("WiFi connected"); 99 100 // Initial sync 101 startUnix = getUnixTimestamp(); 102 lastSyncMillis = millis(); 103 104 if (startUnix > 0) { 105 drawOLEDMessage("Time synced"); 106 delay(1000); 107 } else { 108 drawOLEDMessage("Sync failed"); 109 delay(1000); 110 } 111} 112 113// ---- Loop ---- 114void loop() { 115 unsigned long nowMs = millis(); 116 unsigned long elapsedSec = (nowMs - lastSyncMillis) / 1000; 117 unsigned long currentUnix = startUnix + elapsedSec; 118 119 // Get local time struct 120 time_t now = currentUnix; 121 struct tm *timeInfo = localtime(&now); 122 123 // Display update once per second 124 if (elapsedSec != lastDisplayedSecond) { 125 lastDisplayedSecond = elapsedSec; 126 drawTimeDisplay(currentUnix); 127 } 128 129 130 // Sync every day at 1:00 AM 131 //struct tm *t = localtime((time_t*)¤tUnix); 132 if (timeInfo->tm_hour == 6 && timeInfo->tm_min == 18 && !syncedToday) { 133 drawOLEDMessage("Daily sync..."); 134 delay(2000); 135 unsigned long newUnix = getUnixTimestamp(); 136 if (newUnix > 0) { 137 startUnix = newUnix; 138 lastSyncMillis = millis(); 139 drawOLEDMessage("Sync OK"); 140 delay(2000); 141 } else { 142 drawOLEDMessage("Sync failed"); 143 delay(2000); 144 } 145 syncedToday = true; 146 } 147 148 // Reset the sync flag at 1:01 AM 149 if (timeInfo->tm_hour == 6 && timeInfo->tm_min == 19) { 150 syncedToday = false; 151 } 152 153 delay(50); 154}
Testing Unix time conversion to Human readable format
cpp
Test performed for a sample Unix timestamp
1#include <time.h> 2 3void setup() { 4 Serial.begin(9600); 5 delay(1000); 6 Serial.println(""); 7 delay(3000); 8 9 // Friday, 20 October 2023 16:00:00 10 time_t now = 1697817600; 11 struct tm *timeInfo = gmtime(&now); 12 13 char buffer[30]; 14 strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeInfo); 15 Serial.println(buffer); // Output: "2023-10-20 00:00:00" 16 17 Serial.printf("Hour: %d, Minute: %d, Second: %d\n", 18 timeInfo->tm_hour, 19 timeInfo->tm_min, 20 timeInfo->tm_sec); 21} 22void loop (){}
Get current time from the internet in Unix time format
cpp
Getting current time from the internet Api
1#include <ESP8266WiFi.h> 2#include <WiFiClientSecure.h> 3 4const char* ssid = "Dziubym"; 5const char* password = "Mikigosia1"; 6 7WiFiClientSecure client; 8 9// Function to get Unix timestamp from API 10unsigned long getUnixTimestamp() { 11 client.setInsecure(); // Skip certificate validation 12 13 if (client.connect("aisenseapi.com", 443)) { 14 client.println("GET /services/v1/timestamp HTTP/1.1"); 15 client.println("Host: aisenseapi.com"); 16 client.println("Connection: close"); 17 client.println(); 18 19 while (client.connected() || client.available()) { 20 String line = client.readStringUntil('\n'); 21 Serial.println(line); 22 if (line.indexOf("timestamp") >= 0) { 23 int start = line.indexOf(":") + 1; 24 int end = line.indexOf("}", start); 25 unsigned long timestamp = line.substring(start, end).toInt(); 26 client.stop(); 27 return timestamp; 28 } 29 } 30 client.stop(); 31 } 32 33 return 0; // return 0 if failed 34} 35 36void setup() { 37 Serial.begin(9600); 38 WiFi.begin(ssid, password); 39 40 Serial.print("Connecting to WiFi"); 41 while (WiFi.status() != WL_CONNECTED) { 42 delay(500); 43 Serial.print("."); 44 } 45 Serial.println("\nWiFi connected"); 46 47 unsigned long timestamp = getUnixTimestamp(); 48 delay(3000); 49 if (timestamp > 0) { 50 Serial.print("Unix time: "); 51 Serial.println(timestamp); 52 } else { 53 Serial.println("Failed to get Unix timestamp."); 54 } 55} 56 57void loop() { 58 // Empty - only run once in setup 59}
Comments
Only logged in users can leave comments