日本語版: README.ja.md
A presentation remote built on the M5Stack StopWatch.
It shows the remaining time large on the round AMOLED, advances your slides with a swipe, and buzzes in your hand as the clock runs down.
Every talk brings the same two problems at the same moment: "how much time is left?" and "next slide, please." Each one takes only a second — but it is a second spent looking away from your audience. This project settles both of them with a single device that sits in your palm — nothing to swap hands, no clock to hunt for on the desk.
Nothing to install on the host. The device pairs as a standard BLE HID keyboard: no driver, no companion app, no background service. Pair it once and start your slideshow.
- Swipe to change slides — brush right across the screen for the next slide, left to go back. It sends real arrow keys, so it works with anything driven by the keyboard: PowerPoint, Keynote, Google Slides, PDF viewers (keys are configurable)
- Remaining time you don't have to read — the ring drains clockwise from 12 o'clock. You take in the area, not the digits
- Warnings you can see coming — the remaining arc is split at your alert thresholds and colored green → amber → red. The place where the color changes is your next warning, so "a buzz is coming up soon" is obvious at a glance
- A nudge in your palm — vibration at 5 minutes left, 1 minute left, or wherever you like: one short buzz for the first threshold, two for the second, and a long pattern at time-up. Just holding it is enough to feel it, and the room hears nothing
- Carry it whichever way suits you — keep it in your hand, run a strap through it, or use the magnets in the back to clip it onto a shirt pocket like a badge. That last one keeps both hands free: a quick glance down is all it takes to check the time
- Your finish time, not just a countdown —
NOW 14:32/END 15:02. Knowing what time you must finish is often easier to act on than minutes remaining, and it lines up with the clock on the wall - Elapsed and total on one line —
ELAPSED 12:34 / 30:00tells you how long you have been talking and how long you were given - Overtime counts up — at zero the display doesn't freeze; it counts upward in
red next to
TIME UP, so you know exactly how far over you are - Configured on the watch itself — talk length and warning times are edited in
mm:ssand stored in flash. The rim dial catches with a short buzz on every five-minute mark, so you can land on15:00without staring at the screen - Wi-Fi only at boot — it syncs over NTP, writes the time into the built-in RTC, and switches Wi-Fi off. Easy on the battery, and the clock keeps working in venues with no Wi-Fi at all
- Power-aware, but readable — auto-dims after 5 s idle and wakes on touch. Tap the bulb icon to pin it bright (it turns on by itself when you plug in USB). Battery level shows on-screen and in the host's Bluetooth panel
Here is the path from a fresh device to your first talk. For the timer and slide control you only need to flash and pair — the Wi-Fi step is optional and only affects the clock display.
Open M5Burner, find M5WatchClicker under the StopWatch category, and press Burn.
Entering download mode: hold the power button for about 2 seconds until the green LED lights, then start the flash.
To build it yourself, see Development.
On boot the Bluetooth icon blinks, waiting to pair. Select M5WatchClicker in your computer's Bluetooth settings (the icon goes solid once connected). After the first pairing it reconnects by itself every time you power on.
It shows up as an ordinary keyboard, so there is no driver or app to install. Start your slideshow and brush left or right across the screen to move between slides.
Swipe up or down to open the settings screen (only while the timer is stopped). Three items, top to bottom: TIME (talk length) / ALERT 1 / ALERT 2.
- Tap the item you want to change (a short press of both buttons also moves the selection)
- Adjust with BtnA (−) / BtnB (+). Hold a button and the step grows: 1 s → 5 s → 15 s → 1 min → 5 min
- For big jumps, trace around the outer rim — 10-second steps, with a small buzz and a catch on every five-minute mark
- To silence a warning, tap the ON/OFF button at the right of that item
- Swipe up or down to save and return to the timer
Settings are stored on the device and survive a power cycle. See Settings screen for the details.
Configure Wi-Fi if you want the NOW / END and date displays. The timer and
slide control work fine without it.
- Get a serial connection ready on your computer (115200 baud — M5Burner's serial
monitor,
screen, CoolTerm, anything) - Hold BtnA while powering on. The screen shows
WiFi SETUP - At the
SSID>prompt type your SSID and press Enter, then your password atPASSWORD> - Once saved it connects, fetches the time over NTP, and writes it into the built-in RTC
The credentials stay on the device, so every later boot syncs automatically. Press BtnB if you want to skip the setup and boot normally.
The NTP / RTC labels near the bottom of the screen tell you whether the sync
worked (see Reading the screen).
The buttons behave like an ordinary stopwatch: the right one runs it, the left one clears it. Reset is a long press so that a mis-tap can never cost you your elapsed time.
| Action | Result |
|---|---|
| Swipe right | Next slide |
| Swipe left | Previous slide |
| BtnB (right) | Start / stop |
| Hold BtnA (left) | Reset (re-applies the configured talk length) |
| Hold both buttons | Reset (same) |
| Swipe up / down | Open settings (disabled while the timer runs) |
| BtnB (after time-up) | Stop / resume the overtime counter |
Vertical swipes are ignored on purpose while the timer runs: a slightly crooked page-turn swipe should never drop you into a settings screen mid-talk.
Open it with an up or down swipe. Three items: talk length / alert 1 / alert 2.
| Action | Result |
|---|---|
| BtnA / BtnB | Decrease / increase (hold to accelerate) |
| Tap an item | Select it |
| Both buttons, short press | Next item |
| Trace the outer rim (dial) | Clockwise increases, counter-clockwise decreases |
| Tap the ON/OFF button at the right | Enable / disable that alert |
| Swipe up / down | Save and return to the timer |
There is no digit to choose. Values read as mm:ss, but all you select is the
item. Hold a button and the step grows automatically — 1 s → 5 s → 15 s → 1 min
→ 5 min — and any step larger than one second snaps to a round value (12:47
+1 min → 13:00). The step in effect is shown under the value.
Use the dial for big moves. Trace around the rim and the value follows; one
full turn spans the whole range (90 minutes for the talk length, the talk length
itself for alerts), with an arc on the rim showing where you are. It moves in
10-second steps and catches with a short buzz on every five-minute mark —
a physical detent you can feel, so you can stop on 15:00 without looking. Keep
turning and it moves on. Use the buttons for one-second trimming.
There are no [-] [+] buttons in the middle of the screen: a stray finger should not change a value, so fine adjustment lives on the physical buttons. The area outside the item boxes is mostly dial, so make the save-and-return swipe from on top of an item box.
Consistency check: if a warning is later than the talk itself, or alert 2 is earlier than alert 1, the offending item turns red and you cannot leave until it is fixed. The firmware never silently rewrites what you typed.
- Ring — remaining time, draining clockwise from 12 o'clock, split into colored zones at your alert thresholds (green → amber → red)
- NOW / END — current time and projected finish time (hidden if no clock is available)
- ELAPSED — elapsed time / configured talk length
- Top line — the date before you start,
PAUSEwhile paused,TIME UPafter the deadline (nothing while running) - Digit and ring color — green (normal) → amber (past alert 1) → red (past alert 2)
- Battery — green, red at 20 % or below, with the percentage underneath. A lightning bolt (⚡) overlays it while USB is connected
- Bluetooth — blinking = pairing / waiting, solid = connected
- Wi-Fi — blinking = syncing, solid = synced, dim = not configured, dim red = sync failed (Wi-Fi is switched off after syncing)
- NTP / RTC (right of the Wi-Fi icon) — where the clock came from.
NTPlit = boot-time sync succeeded,RTClit = running on the built-in RTC, both gray = no time available (clock and date stay hidden) - Bulb (below the Bluetooth icon) — tap to toggle "never dim". While lit (yellow) the screen stays bright. Plugging in USB turns it on and unplugging turns it off, but a tap afterwards always wins — including dimming while powered
Changes made in the on-device settings screen are stored as this file on the
device's LittleFS. With a development environment you can also write the whole
file at once with pio run -t uploadfs.
After flashing with M5Burner the file does not exist yet, so the device starts with defaults. Talk length and warnings are set from the settings screen and Wi-Fi from the serial console — both are saved on the device, so there is no need to edit this file by hand.
{
"presentation_sec": 1800,
"alerts": [
{ "before_sec": 300, "enabled": true },
{ "before_sec": 60, "enabled": true }
],
"swipe_keys": { "next": "RIGHT", "prev": "LEFT" },
"brightness": 80,
"dim_brightness": 10,
"wifi": { "ssid": "", "password": "" },
"ntp": { "server": "pool.ntp.org", "timezone": "JST-9" },
"date_locale": "ja"
}| Key | Description |
|---|---|
presentation_sec |
Talk length in seconds. 10 s – 90 min |
alerts[].before_sec |
Seconds remaining when the alert fires. List them earliest first |
alerts[].enabled |
Whether that alert is active |
swipe_keys.next |
Key sent by a right swipe (next slide). Default RIGHT |
swipe_keys.prev |
Key sent by a left swipe (previous slide). Default LEFT |
Available keys: RIGHT LEFT UP DOWN PAGE_UP PAGE_DOWN SPACE ENTER |
|
brightness |
Normal screen brightness (%) |
dim_brightness |
Brightness after 5 s of inactivity (%) |
wifi.ssid / wifi.password |
Wi-Fi used for time sync. Empty means no sync |
ntp.server |
NTP server (default pool.ntp.org) |
ntp.timezone |
POSIX TZ string (default JST-9) |
date_locale |
Date language. ja (default) = 2026/07/29(水) / en = 2026-07-29 (Wed) |
You can list three or more alerts. Vibration counts are assigned automatically:
one short buzz for the earliest, two for the next, and so on, with a long
pattern × (number of alerts + 1) at time-up.
If the file is missing or corrupt, defaults are restored automatically (30 min / 5 min / 1 min).
Wi-Fi connects only at boot: it fetches the time over NTP, writes it to the built-in RTC, and disconnects. Because it never stays connected, the battery cost is limited to startup, and the clock keeps running from the RTC afterwards — so the display still works in venues without Wi-Fi.
If you would rather not keep a password in config.json in plain text, hold
BtnA while powering on. The screen shows WiFi SETUP and you can type the SSID
and password over the serial console (115200 baud). What you enter is saved to the
config.json on the device.
pio device monitor # open this first, then power on while holding BtnA
⚠️ Thewififields in the repository'sdata/config.jsonare intentionally empty. If you fill in your own credentials, take care not togit committhem.
To build it yourself you need PlatformIO.
Shared board settings come from a submodule (config/), so clone with
--recursive.
git clone --recursive https://github.com/3110/M5WatchClicker.git
cd M5WatchClickerIf you forgot --recursive, fetch it afterwards:
git submodule update --init --recursivepio run # build
pio run -t upload # flash the firmware
pio run -t uploadfs # write data/config.json to LittleFS
pio device monitor # serial monitor (115200)
./tests/run_tests.sh # host tests (verify logic on your PC)Entering download mode: hold the power button for about 2 seconds until the green LED lights, then run
upload.
Timer, input, and alert logic run as plain host builds against a mocked M5Unified, so 24 behavioral scenarios are verified on a laptop in about a second. GitHub Actions runs those tests plus a full firmware build on every push.
