Wednesday, September 17, 2025

QRCode Clock with ESP32C3 Dev Module

-----
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:

 
 
This timekeeping device is cheap and extremely accurate.  
-----

// 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
}

-----