Nothing is more frustrating than needing the time and not having a watch, but watches can be expensive and boring so we programed this ~$2.00 USD ESP32C3 Dev Module with on-board OLED to provide the time in a low cost and interesting way.
Oh, to make it work you also need a smart phone....
-----
After uploading the source code below you will get a QRCode on the OLED that conveniently provides a second by second account of the time which you can read from your smart phone camera. Here's the demo:
// QRCode Clock
// QRCode on OLED is updated each second
// time the time of day as HH:MM:SS in 24 hr format.
//
// Board (~$4) is ESP32C3 Dev Module with onboard OLED.
//
// Details at: https://www.whiskeytangohotel.com/
// SEPT 2025
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <WiFi.h>
#include "time.h"
#include "QRCodeGenerator.h"
// WiFi credentials
const char* ssid = "YOURSSID";
const char* password = "YOURWIFIPASSWORD";
const char* ntpServer = "pool.ntp.org";
// A few Google searches led me to this:
U8G2_SSD1306_72X40_ER_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
void setup() {
Wire.begin(5, 6); // I2C
Wire.setClock(100000); // slow for stability
delay(200); // power-up delay
u8g2.begin();
// Connecting WiFi status screen
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x10_tr);
u8g2.drawStr(0, 15, "Connecting...");
u8g2.sendBuffer();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
configTzTime("CST6CDT,M3.2.0/2,M11.1.0/2", ntpServer); //Central Time
}
void loop() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
delay(2000);
return;
}
// Format time string (HH:MM:SS) 24 hour time
char timeStr[16];
strftime(timeStr, sizeof(timeStr), "%H:%M:%S", &timeinfo);
// Generate QR code
QRCode qrcode;
const uint8_t qrVersion = 3; // 29x29 QRCode
uint8_t qrcodeData[qrcode_getBufferSize(qrVersion)];
qrcode_initText(&qrcode, qrcodeData, qrVersion, 0, timeStr);
// Scale/Center QRCode to fit 64x32 OLED but remember QRCodes are square
int scale = 1; // keep modules square
int width = qrcode.size * scale;
int height = qrcode.size * scale;
int xOffset = (64 - width) / 2;
int yOffset = (32 - height) / 2;
// Draw QRCode to OLED
u8g2.clearBuffer();
for (uint8_t y = 0; y < qrcode.size; y++) {
for (uint8_t x = 0; x < qrcode.size; x++) {
if (qrcode_getModule(&qrcode, x, y)) {
u8g2.drawBox(xOffset + x * scale, yOffset + y * scale, scale, scale);
}
}
}
u8g2.sendBuffer();
delay(1000); // refresh once per second
}
-----