Introduction: Time Since Wedding EPaper Clock

About: As I explore the exciting world of electronics, I can't help but feel a sense of wonder and amazement at the incredible things I discover!


Time Since Wedding – Visualizing Invisible Lovе Through Time

Time is one of the most powerful уet u‍nseen forces in our lives. We feel its passаge, yet rarely witness it. "Time Since Wedding – Е-Paper‍ Clock" is my attempt to make this invisіble progression of time—and the enduring bond оf love—visib‍le in a simple, meaningful form.

Тhis project is a custom-built e-paper clock crеated as a wedding ‍gift for my friend. Instead оf displaying the current time like a traditionаl clock, it visualizes s‍omething we normally nеver see: the amount of time that has elapsed sіnce the wedding, measured cont‍inuously in days аnd hours. It transforms an abstract concept—tіme since a life-changing moment—into‍ a permanеnt, living display.

The idea is not merely tо count time, but to represent love as someth‍ing thаt grows quietly and steadily, hour by hour, dаy by day. The clock acts as a silent witness tо‍ a relationship, making the invisible progressіon of shared life tangible.

To reinforce this nоtion‍, the project utilizes an e-paper display, whіch remains visible without constant power—much lіke lo‍ve itself, always present even when unnotіced. The minimal, distraction-free design keeрs the focus ‍on what matters: the passage of tіme since a meaningful moment.

Vіsua‍lizing the Invisible

This project makes tіme, memory, and love—all invisible forces—visіble through‍ technology and design. By turning аn abstract emotional timeline into a physical оbject, it allows ‍people to see something they usuаlly only feel.

In the spirit of the Visualizе It! Contest, this cl‍ock transforms an unseen рattern of life into a tangible, visual experiеnce—one that quietly celebra‍tes time, commitmеnt, and the beauty of moments that never stop аccumulating.

Image_20251214165721_51_4.jpg

How the Clock Works

When the device powers on for the first time, it creates its own Wi-Fi hotspot.The user connects to this hotspot using a phone or laptop and opens a configuration page in a web browser.

SSID = WeddingClock_Setup

PASS = 12345678

From this page, the user selects their home Wi-Fi network and enters the password.Once connected, the device synchronizes the current time using an NTP server.

The wedding date and time are stored in the firmware. After syncing the time, the clock calculates how many hours and days have passed since the wedding and displays the result on the e-paper screen.

If the device cannot connect to the saved Wi-Fi network, it automatically reopens the setup mode so the user can reconfigure it easily.

Supplies

  1. Seeed Studio XIAO ESP32-C3
  2. 2.9-inch monochrome e-paper display
  3. M2 Screw Kit
  4. M3 Screw Kit

I also used my custom adapter PCB for XIAO ESP32C3

The XIAO ESP32-C3 was chosen for its small size, built-in Wi-Fi, and low power consumption, making it ideal for always-on display projects.

https://github.com/gokuxmaker/XIAO-PCB-

Here is the PCB file

Step 1: Enclosure and 3D Printing

I used Fusion 360 to design the enclosure for this project. Then, I exported STL files for 3D printing.

The enclosure for the Time Since Wedding – E-Paper Clock was 3D printed using JLC3DP’s 3D printing service.

bistmap.jpg

The design is simple and minimal to match the clean look of the e-paper display.JLC3DP offers multiple materials and finishes, allowing the enclosure to feel solid and look professional.

Get your 3d print now https://jlc3dp.com/?from=gokul

Step 2: Assembly

1. Solder the XIAO to the PCB adapter

image.png

2. Connect the XIAO to the E-Paper module by following the wiring diagram provided. You can also see the battery connection in this diagram. If you want to power this project with a battery, you can add it by following this wiring guide. Alternatively, if you only need to power the project via USB, you can proceed with that option as well.

image.png

image.png

3. Install the eink module into the display frame by securing it with M2 5mm screws.

image.png

4. Secure the XIAO PCB using M3 screws.

image.png

5. Install the antenna

image.png

6. Add some glue and close it off

image.png


7. Connect it to the PC for programming and powering.

image.png



Step 3: Code & Customization

Here is the Code

#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
#include <time.h>

#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>

// ================= E-PAPER PINS =================
#define CS_PIN D1
#define DC_PIN D3
#define RST_PIN D0
#define BUSY_PIN D5

GxEPD2_BW<GxEPD2_290_BS, GxEPD2_290_BS::HEIGHT> display(
GxEPD2_290_BS(CS_PIN, DC_PIN, RST_PIN, BUSY_PIN)
);

// ================= WIFI =================
WebServer server(80);
Preferences prefs;

const char* apSSID = "WeddingClock_Setup";
const char* apPASS = "12345678";

unsigned long lastHourShown = 0;
uint8_t refreshCount = 0; // for ghosting control

// ================= HEART BITMAP =================
// 15x16 monochrome heart
const unsigned char image_cards_hearts_bits[] PROGMEM = {
0x1C, 0x38,
0x3E, 0x7C,
0x7F, 0xFE,
0xFF, 0xFF,
0xFF, 0xFF,
0x7F, 0xFE,
0x3F, 0xFC,
0x1F, 0xF8,
0x0F, 0xF0,
0x07, 0xE0,
0x03, 0xC0,
0x01, 0x80,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00
};

// ================= WEDDING TIME =================
// Oct 19, 2025 – 6:15 AM IST → 00:45 UTC
time_t getWeddingEpochUTC() {
struct tm t = {};
t.tm_year = 2025 - 1900;
t.tm_mon = 9;
t.tm_mday = 19;
t.tm_hour = 0;
t.tm_min = 45;
t.tm_sec = 0;
t.tm_isdst = 0;
return mktime(&t);
}

// ================= DISPLAY UI =================
void drawWeddingUI(unsigned long hoursPassed, unsigned long daysPassed) {
char hrsBuf[20];
char daysBuf[20];

sprintf(hrsBuf, "%09lu Hrs", hoursPassed);
sprintf(daysBuf, "%09lu Dys", daysPassed);

bool fullRefresh = (refreshCount >= 6);

if (fullRefresh) {
display.setFullWindow(); // anti-ghosting
refreshCount = 0;
} else {
display.setPartialWindow(0, 0, display.width(), display.height());
refreshCount++;
}

display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setTextColor(GxEPD_BLACK);
display.setTextWrap(false);

// Hours
display.setFont(&FreeMonoBold18pt7b);
display.setCursor(10, 73);
display.print(hrsBuf);

// Days
display.setCursor(10, 112);
display.print(daysBuf);

// Names
display.setFont(&FreeMonoBold12pt7b);
display.setCursor(56, 31);
display.print("Arjun");

display.setCursor(152, 31);
display.print("Amgitha");

// Heart
display.drawBitmap(
131, 17,
image_cards_hearts_bits,
15, 16,
GxEPD_BLACK
);

} while (display.nextPage());
}

// ================= TIME COUNTERS =================
void showTimeCounters() {
time_t now;
time(&now);

time_t weddingEpoch = getWeddingEpochUTC();

if (now < weddingEpoch) {
drawWeddingUI(0, 0);
return;
}

unsigned long seconds = now - weddingEpoch;
drawWeddingUI(seconds / 3600, seconds / 86400);
}

// ================= WIFI CONFIG PAGE =================
void handleRoot() {
String page =
"<!DOCTYPE html><html><head>"
"<meta name='viewport' content='width=device-width, initial-scale=1'>"
"<style>"
"body{font-family:Arial;background:#f2f2f2;padding:20px;}"
".card{background:#fff;padding:20px;border-radius:14px;"
"max-width:400px;margin:auto;box-shadow:0 10px 25px rgba(0,0,0,.15);}"
"h2{text-align:center;}"
"select,input,button{width:100%;padding:12px;margin-top:10px;"
"border-radius:8px;border:1px solid #ccc;}"
"button{background:#000;color:#fff;font-weight:bold;}"
"</style></head><body>"
"<div class='card'><h2>Wedding Clock Wi-Fi</h2>"
"<form action='/connect'><label>Network</label><select name='ssid'>";

int n = WiFi.scanNetworks();
for (int i = 0; i < n; i++)
page += "<option value='" + WiFi.SSID(i) + "'>" + WiFi.SSID(i) + "</option>";

page +=
"</select><label>Password</label>"
"<input type='password' name='pass'>"
"<button type='submit'>Connect</button>"
"</form></div></body></html>";

server.send(200, "text/html", page);
}

void handleConnect() {
prefs.putString("ssid", server.arg("ssid"));
prefs.putString("pass", server.arg("pass"));
server.send(200, "text/html", "Connecting… Rebooting");
delay(1500);
ESP.restart();
}

// ================= WIFI LOGIC =================
bool connectToSavedWiFi() {
String ssid = prefs.getString("ssid", "");
String pass = prefs.getString("pass", "");
if (ssid == "") return false;

WiFi.begin(ssid.c_str(), pass.c_str());
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 15000) {
delay(500);
}
return WiFi.status() == WL_CONNECTED;
}

void startConfigPortal() {
WiFi.softAP(apSSID, apPASS);
IPAddress ip = WiFi.softAPIP();

display.setFullWindow();
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setFont(&FreeMonoBold12pt7b);
display.setCursor(10, 50);
display.print("Connect to:");
display.setCursor(10, 75);
display.print(apSSID);
display.setCursor(10, 100);
display.print(ip.toString());
} while (display.nextPage());

server.on("/", handleRoot);
server.on("/connect", handleConnect);
server.begin();
}

// ================= NTP =================
void syncTimeNTP() {
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
time_t now;
while (time(&now) < 100000) delay(500);
}

// ================= SETUP =================
void setup() {
Serial.begin(115200);

display.init(115200, true, 50, false);
display.setRotation(1);

prefs.begin("wifi", false);

if (!connectToSavedWiFi()) {
startConfigPortal();
return;
}

syncTimeNTP();
showTimeCounters();
}

// ================= LOOP =================
void loop() {
server.handleClient();

time_t now;
time(&now);
unsigned long hour = now / 3600;

if (hour != lastHourShown) {
lastHourShown = hour;
showTimeCounters();
}

delay(1000);
}

Customizing the Clock (Names and Wedding Date)

This project is easy to personalize.You can customize the clock with your own names and your own wedding date and time by editing just a few lines in the code.

Changing the Names on the Display

In the display code, you will find the section where the names are printed

display.setFont(&FreeMonoBold12pt7b);
display.setCursor(56, 31);
display.print("Arjun");

display.setCursor(152, 31);
display.print("Amgitha");

To customise the clock, simply replace the names inside the quotes

display.print("Alex");
display.print("Jamie");

If your names are longer or shorter, you can adjust the cursor positions slightly to keep everything centred.

Changing the Wedding Date and Time

The wedding date and time are defined using a struct tm, which makes it easy to edit safely.

Locate this function in the code

time_t getWeddingEpochUTC() {
struct tm t = {};
t.tm_year = 2025 - 1900;
t.tm_mon = 9; // October (0-based)
t.tm_mday = 19;
t.tm_hour = 0;
t.tm_min = 45;
t.tm_sec = 0;
t.tm_isdst = 0;
return mktime(&t);
}

This example represents October 19, 2025, at 6:15 AM IST, which converts to 00:45 UTC.

Converting Your Local Time to UTC

If your wedding time is in Indian Standard Time (IST):

  1. IST = UTC + 5 hours 30 minutes
  2. Subtract 5 hours and 30 minutes from your local time

Example

Wedding time:December 1, 2026 – 4:00 PM IST

Converted to UTC:

  1. 10:30 AM UTC

Updated code

t.tm_year = 2026 - 1900;
t.tm_mon = 11; // December
t.tm_mday = 1;
t.tm_hour = 10;
t.tm_min = 30;

If your local time is already in UTC, you can enter it directly.

Step 4: Final Result

The final result is a low-power, always-visible Time Since Wedding clock that quietly tracks how long a marriage has lasted.

It’s simple, personal, and designed to run reliably for years with minimal maintenance.

Time Since Wedding – E-Paper Clock is more than just a clock. It’s a small reminder of a special moment, built with care and designed to last.