A clock that doesn't show numbers. Every minute, it displays a literary quote that mentions the current time, like "seventeen minutes past ten," "almost exactly at midnight," and so on, with the time phrase emphasized
The code here is tested to work on a CrowPanel ESP32 4.2" e-paper display.
The idea is inspired by Litclock project and the quote database is taken from this awesome project.
- Syncs real time over WiFi via NTP at boot, then keeps time locally
- Matches the current
HH:MMagainst a quotes database and displays one that mentions that exact time - Randomly picks among multiple quotes for the same minute, where available
- Time phrase within the quote is emphasized: bigger font where the display's fixed font sizes allow it, underlined always
- Quote text is dynamically sized (24px / 16px / 12px) and word-wrapped depending on length, so short quotes render big and long ones still fit without truncation
- Header shows the current weekday/month/day; footer shows book title and author, right-aligned
- Partial e-paper refresh once per minute — no unnecessary full-screen flashing
- Reconnects WiFi automatically if the connection drops
- Elecrow CrowPanel ESP32 4.2" E-Paper HMI Display (400×300, SSD1683 driver, ESP32-S3-WROOM-1-N8R8)
- USB-C cable + any 5V USB wall adapter for continuous power (this is a clock and it needs to stay powered)
- Optional: 2.2–3.7V Li-Po battery via the board's BAT connector, if you want it cordless (not required, and not optimized for battery life in this version — see Known Limitations)
literary_clock/
├── literary_clock.ino — main sketch
├── EPD.cpp / EPD.h — e-paper driver (from Elecrow's own library)
├── EPD_GUI.cpp / EPD_GUI.h — drawing/text primitives
├── EPD_SPI.cpp / EPD_SPI.h — low-level SPI/pin definitions
├── EPD_font.h — built-in bitmap fonts (ASCII only)
└── quotes_data.h — quotes compiled into a flash-resident C array
tools/
└── csv_to_header.py — converts a quotes CSV into quotes_data.h
data/
└── quotes.csv — source quotes (see CSV Format below)
Download the AppImage (Linux) or installer for your OS from arduino.cc.
File → Preferences → Additional Boards Manager URLs, add:
https://espressif.github.io/arduino-esp32/package_esp32_index.json
Then Tools → Board → Boards Manager, search esp32, install the latest stable release by Espressif Systems (avoid pre-release versions).
With the board connected via USB-C, set under Tools:
- Board: ESP32S3 Dev Module
- Port: whichever
/dev/ttyUSB*or COM port appears - Flash Size: 8MB
- PSRAM: OPI PSRAM
- Partition Scheme: Huge APP (3MB No OTA/1MB SPIFFS) — required, since the quotes data alone is ~1.4MB and won't fit in the default partition scheme
Open literary_clock/literary_clock.ino and fill in near the top:
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";Note: the ESP32 only supports 2.4GHz WiFi, not 5GHz.
If you're not in the IST timezone, also update:
const long gmtOffset_sec = 19800; // UTC+5:30
const int daylightOffset_sec = 0;Select the port, hit upload. First boot will connect to WiFi, sync time, and start refreshing once a minute.
quotes_data.h is generated from a pipe-delimited (|) CSV with six columns and no header row:
HH:MM|bold phrase|quote text|book title|author|nsfw flag (YES/NO)
Example:
00:00|midnight|"And almost exactly at midnight, the Count's patience was rewarded."|A Gentleman in Moscow|Amor Towles|NO
bold phrasemust appear verbatim (case-insensitive) inside the quote text — it's matched at runtime to find and emphasize the time reference.- Rows flagged
nsfw=YESare skipped during conversion. - The display's built-in font is ASCII-only, so
tools/csv_to_header.pytransliterates accented characters (é→e) and substitutes a few characters that would otherwise be silently dropped (en/em dashes →-, ° →deg, £ →GBP, ¼ →1/4, ø →o).
To regenerate after editing your CSV:
python3 tools/csv_to_header.pyThis reads data/quotes.csv and writes literary_clock/quotes_data.h. Re-upload the sketch afterward.
For full coverage, aim for at least one quote per minute of the day (1440 total) — the sketch falls back to a random quote if no exact match is found for the current minute, which is a fine safety net but shouldn't be the common case.
- Font sizing: the display's font only supports fixed sizes (8/12/16/24/48px). The sketch measures each quote and picks the largest of {24, 16, 12} that will actually fit the content area without overflowing, word-wrapping at word boundaries.
- Bold time phrase: where a valid bigger font size exists one step up (12→16, 16→24), it's used; the 24px tier has no safe bigger option (48px would overflow multi-word phrases off-screen), so it relies on the underline alone. The underline is applied at every tier for visual consistency.
- Quote lookup: on each minute change, every quote matching the current
HH:MMis collected, and one is picked at random.
- Quote repetition: quote selection for a given minute is independent random each time — there's no memory of what was shown previously, so the same quote can occasionally repeat on consecutive days. Adding a "don't repeat the last one shown at this minute" check (or a full rotation) would be a natural improvement.
- Extreme-length quotes: 3 out of 4794 quotes in the reference dataset are long enough to slightly truncate at the smallest font tier (losing roughly the last 1–3% of the text). Negligible in practice, but worth knowing about if you add unusually long quotes of your own.
- No deep sleep / battery optimization: the board is expected to stay on continuous USB/wall power. Running on battery would need sleep-between-refreshes logic, which isn't implemented here.
- No weather or other widgets: left out by design to keep the display focused on the quote.
If the screen never updates and stays on the factory demo image, check that you're building from the correct example tree in Elecrow's own repo — their GitHub repo actually ships two different low-level display init sequences for what look like two hardware revisions of this same board, and using the wrong one causes the BUSY pin to hang indefinitely with no visible error. This project's EPD.cpp is confirmed working against the non-"green sticker" (example/arduino/) tree. If you're pulling library files fresh from Elecrow's repo rather than using this repo's copies, make sure you're consistent about which tree you copy from.
- Display driver library and example code: Elecrow
- Quotes: excerpts from their respective copyrighted books — author and title are displayed alongside each quote. Quotes came from Litclock project
MIT License
