Jay Y. Lee

PomoPlayer

A portable pomodoro timer with a music player built in, running on an M5Stack Core2. Flip it over like an hourglass to start a session.

On the benchMusic & audio · Firmware · Software

Reference

The two things I want during focused work are a timer and music, and I did not want them to be two devices or two apps. So it is one handheld: it plays from a microSD card while the timer runs, goes quiet on breaks, and syncs its library and session stats with a server at home over Wi-Fi.

The interaction is physical rather than menu-driven. Flip it over like an hourglass to start. Put it face down to pause. The IMU handles both, so you never have to look at it to use it.

Hardware and stack

BoardM5Stack Core2: ESP32, touch display, speaker, microSD, MPU6886 IMU, Wi-Fi and Bluetooth
FirmwarePlatformIO with the Arduino framework, LVGL for the interface
AudioMP3 and OGG off the card, out to the speaker or Bluetooth headphones
ServerSelf-hosted FastAPI: playlists, file sync, session stats, auto-ingest
LayoutMonorepo: firmware/, server/, docs/

Timer faces

Five, selectable: digital, hourglass sand, ring, analog, and a candle that burns down. The hourglass is the one that made the flip gesture obvious.

These are the face designs at the display's real resolution of 320 by 240. They are drawings, not captures off the device, because the firmware currently boots to a splash screen and nothing else. They will be replaced with real screens once there are real screens to photograph.

Digital face
Digital. The default, and the only one that is legible across a room.
Hourglass face
Hourglass sand. Draining top to bottom, which is what suggested the flip gesture.
Ring face
Ring. Mint means the session is over and this is a break.
Analog face
Analog. A swept wedge for elapsed time.
Candle face
Candle. Burns down over the session and gutters at the end.

Where it is

Phase 0, scaffolding. The firmware boots to a splash screen on real hardware, the server answers a health check, and CI builds both halves on every push. Nothing is playing music yet.

Log

Splash screen boots on real hardware

The firmware builds and flashes to the Core2 and comes up to a splash screen. Not much to look at, but it closes the loop on toolchain, partition layout and board config, which is the part that usually eats the first week.

Partition table is custom for the 16 MB flash, since the stock layouts do not leave enough room for the app plus LVGL plus a filesystem.

CI building both halves

One pipeline builds the firmware with PlatformIO and runs the server tests, so a change that breaks either one fails immediately.

Worth doing this early on a monorepo with two completely different toolchains. The alternative is finding out weeks later that the firmware has not compiled since some unrelated change to the Python side.