This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
Every alarm clock punishes laziness.
It rings at the same minute whether you slept like a log or stared at the ceiling until 3 a.m. Then it hands you a snooze button, so you can chop your last half hour into nine-minute pieces of broken sleep. Snooze, snooze, snooze.
Sloth Clock ๐ฆฅ rewards it.
It's a bedside sloth built on one Arduino UNO Q. A 60 GHz radar watches how you actually slept, through the blanket, with no camera and no wearable. If the night was rough, or it's raining outside (a microphone listens for rain, keeping only sound features, never audio), it lets you stay in bed longer: up to 30 minutes, decided early, and never past the time you must be up. No morning run in the rain anyway. Then it wakes you the way a sloth would want, slowly: a sunrise climbs the LED matrix, a soft chime follows, and Gemma 3 1B, running on the clock itself, tells you why you got the lie-in:
06:45. Good morning, dear. Your sleep was a bit restless, so I've given you a longer rest.
That's a real message, written by the model on the board, offline.

The cardboard sloth: the UNO Q's LED matrix shows through the front, the radar on top faces the bed, and the no-glow e-paper card shows the morning.
TL;DR
- ๐ก Senses: a 60 GHz mmWave radar reads breathing, heart rate and restlessness, and a small microphone listens for rain. No camera, no wearable, nothing to charge.
- ๐งฎ Decides: plain code scores the night and picks the alarm, inside health limits it cannot break.
- ๐ Acts: an LED-matrix sunrise, a chime, a Gemma-written note, and an e-paper card.
- ๐ One Arduino UNO Q, fully offline. No phone, no cloud, no account, no API key.
Lazy, but only the safe kind
Sleeping in is the easiest feature in the world to get wrong. So the sloth has rules it cannot break:
| Rule | |
|---|---|
| ๐ค Restless night (score below 60) | +15 min |
| ๐ง๏ธ Raining outside | +15 min |
| ๐งฑ Never more than | +30 min in total |
| โฐ Never past | your "must be up by" time |
| ๐ซ Snooze | does not exist |
| ๐ Two days in a row | no, unless last night was very poor (score below 40) |
| ๐คท Not enough radar data | normal alarm, and an honest "not sure" |
They're hard-coded in one small file, not settings. Future sleepy me does not get a vote.
Slow and steady, all the way down
The theme isn't just the name. Every part of the clock is slow on purpose, and that's exactly what makes it reliable:
| Part | Slow | Why slow is fine |
|---|---|---|
| ๐ Wake-up | A sunrise that climbs the LED matrix, then a soft chime | Nobody wants to wake up to a fire alarm |
| ๐ง Gemma 3 1B | ~4.4 tokens/s on the board's Arm CPU, 20โ38 s per note | The decision is made 45 minutes before the alarm, so the model has 70ร the time it needs |
| ๐ช Your to-do list | One tiny step a day (5, 15 or 30 min) | Slow and steady is how a sloth gets anywhere |
Demo
The video shows a full run: a 6-minute demo nap (tossing and turning on purpose), the decision (+15 min, restless night, score 33), the sunrise, the chime, and Gemma's note. Demo mode exists because you shouldn't have to sleep eight hours to see an alarm clock work. That would be a little too on-theme.
It sees you breathe. Here's the live page while I lie still, then while I hold my breath for a few seconds:

Breathing 15/min, heart rate 63 bpm, movement near zero. Nothing touches me.

Holding my breath: the breathing rate drops from about 15 to 2.5 per minute, then recovers.
The whole page, on any phone or laptop on the same network:

Live readings, the night score with every term, the alarm decision and the wake note, all served by the UNO Q itself.
The decision, with every rule shown:

Alarm 06:45 (usual 06:30, must be up by 07:00): +15 min, because the night scored 33 out of 100.
Code
Abhinavkrishna3211
/
Sloth-Clock
A bedside sloth on Arduino UNO Q: a 60 GHz radar watches your sleep, the alarm gives you extra minutes when itโs safe, and a no-glow e-paper card moves procrastinated jobs forward one tiny step a day. Fully offline.
Sloth Clock ๐ฆฅ
Slow and steady wins the morning.
Most alarm clocks punish you for being tired. Sloth Clock does the opposite: it watches how you slept, and if the night was rough, it lets you sleep in, safely. Then it asks for the smallest possible step on the job you keep putting off. Not the whole job. One tiny step.
Laziness, done properly, is a strategy. Rest when you need it, move a little every day, never panic That is how a sloth gets where it is going.
Everything runs offline on one Arduino UNO Q. No cloud, no account, no camera, no wearable.
The three lazy things it does for you
1. It lets you sleep in, and it earns that right
A 60 GHz mmWave radar on the nightstand reads breathing, heart rate and restlessness through the blanket In the morning the board scores the night. Aโฆ
| Path | What lives there |
|---|---|
app/sketch/sketch.ino |
STM32: radar line parser, 10 s rows, LED-matrix face and sunrise, chime, button, backup alarm |
app/python/ |
Linux: SQLite, night score, alarm decision, Gemma notes + validator, tiny-step engine, web page |
firmware/ |
The radar kit's XIAO ESP32C6 and the e-paper card's XIAO ESP32-S3 |
tests/ |
Decision, validator, night score and on-board Gemma tests |
docs/measurements.md |
Every number in this post, with date, setup and trials |
MIT licensed.
How I Built It
Hardware

Everything in the clock. Top left: the XIAO ePaper Display Board EE04 with the 7.5" e-paper panel. Left, top to bottom: the round INMP441 microphone, the green PAM8403 amplifier, and the small cavity speaker for the chime. Bottom: the 60 GHz radar in its case, and the Arduino UNO Q.
| Part | Job |
|---|---|
| Arduino UNO Q (4 GB) | The whole brain: an STM32U585 microcontroller and a Qualcomm QRB2210 running Linux, on one board |
| Seeed MR60BHA2 60 GHz mmWave kit | Breathing, heart rate, presence and movement, without contact |
| Seeed XIAO ePaper Display Board EE04 + 7.5" 800ร480 panel | The no-glow card |
| PAM8403 amplifier + small cavity speaker | The soft chime, driven by a tone from the STM32 |
| INMP441 microphone | Listens for rain. The STM32 keeps only a few sound features, never audio |
Everything runs from USB: low voltage, no mains, nothing that heats up or moves. And the enclosure? Cardboard. I don't have a 3D printer, so the sloth lives in a box I cut and taped in an evening. Lazy and free.

The Arduino UNO Q: Linux and an STM32 on one board, with the 8ร13 LED matrix that draws the sunrise.

The 60 GHz radar on top of the sloth, tilted down toward the bed.

The 7.5" e-paper panel and the XIAO ePaper Display Board EE04 that drives it. Even on the desk it shows the morning: wake up 06:45, "+15 min of slow morning, never later than 07:00", the month, what's coming up, today's tiny step and the note. And a sloth hanging from a garland of lights.

One-sheet wiring: the chime on D3, the button on D2, and the radar and card talking to the board.
Why the UNO Q, specifically
An alarm clock is a strange mix of jobs. Part of it must be hard real time: the alarm must ring and the button must work. Part of it is heavy and slow: a language model. Most boards make you pick one.
The UNO Q is two computers on one board, and Sloth Clock gives each the job it's good at:
| โก STM32U585 (real time) | ๐ง QRB2210 (Linux) | |
|---|---|---|
| Sense | Parse every radar line, count bad ones, build a 10 s summary row | Store rows in SQLite |
| Think | Night score, alarm decision with hard limits, Gemma 3 1B | |
| Act | LED-matrix sunrise, chime, button, backup alarm | Validate every note, serve the web page, update the card |
They talk over the Arduino Bridge. Each summary row is a handful of integers, and its largest possible message is 33 bytes, well under the Bridge's 256-byte limit.
That split is what makes it a trustworthy alarm clock:
- ๐ The button lives on the microcontroller, so it works even while Linux is busy running a model.
- โฐ The microcontroller has a backup alarm. If Linux ever misses the alarm, the STM32 rings on its own.
- ๐ฐ๏ธ No model is on the critical path. If Gemma is slow, down or wrong, a plain template is used and the alarm still rings on time.
The night score is explainable, not magic
score = 100 โ (restless % + 0.5 ร irregular-breathing % + 10 ร long awakenings)
Each term is a share of the minutes observed, so a 6-minute demo nap and a full night use the same scale. The page shows every term, so you can see exactly why you did or didn't get your lie-in.
Gemma only words things. Code decides everything.
This was the most interesting part. A 1B model is lovely at sounding warm and bad at facts, and an alarm clock that lies about what time it is is worse than no alarm clock. So:
- Code makes the decision and writes the reason in plain words.
- Gemma only rephrases it in a sleepy, kind sloth's voice.
-
A validator checks every note before you see it:
- every number and time must appear in the decision record (
6:45is one time, not 6 and 45, and2:10โ3:30is a range, not a minus sign) - number words count too ("twenty" is a number)
- no "snooze", and no "extra time" if the alarm didn't move
- every number and time must appear in the decision record (
- Code writes the wake time at the front. The model never copies it.
- One retry with a stricter prompt, then a template. Something honest always comes out.
Every rule exists because the model broke it. In one early test, on two nights where the alarm had not moved at all, Gemma cheerfully said "I've given you a little extra time" ๐ . Each failure became a validator rule and a test.
On the board, across 10 different decision records:
| Prompt version | โ Valid first try | ๐ Valid after retry | ๐ Template |
|---|---|---|---|
| Model writes the time itself | 4 / 10 | 1 / 10 | 5 / 10 |
| Code writes the time, model writes the reason | 8 / 10 | 2 / 10 | 0 / 10 |
No wrong number got through. What the validator can't catch: in one retry, the model turned "you slept badly, but you already slept in yesterday" into "you've already had a restful sleep". Every number was right, but the meaning wasn't. Rules can check facts. They can't fully check feelings.
One tiny step a day
You type the job you keep avoiding. Gemma splits its first step into three sizes (5, 15 and 30 minutes), a checker rejects anything with invented numbers, and each morning the card shows one step. After a bad night, it shows the tiniest one. Rest counts too.
The open-source AI at the core
- ๐ง Gemma 3 1B (open weights, QAT Q4_0 GGUF): wake notes and step splitting.
- โ๏ธ llama.cpp
llama-serveron the UNO Q's Arm CPU: 3 threads, no GPU, no internet, started at boot. - ๐งฉ Arduino App Lab: one app made of a Python container, the MCU sketch and the web UI.
- ๐งฎ TabPFN v2 (open tabular foundation model): guesses which step size you'll actually finish, with a small numpy fallback built in. Tested on synthetic data so far, since real mornings take time to collect.
- ๐ก Seeed's open mmWave library and Seeed_GFX on the two XIAOs.
| Measured on the UNO Q | Result |
|---|---|
| Gemma generation | 4.42โ4.45 tok/s |
| First token, cold prompt | 2.4 s |
| Wake note, including retries | 20โ38 s |
| Alarm decision + health limits | 12 / 12 test cases |
| Note validator | 20 / 20 test cases |
| Sketch size | 97 KB flash (12%), 44 KB RAM (16%) |
| Radar vs manual breath count + reference heart rate | ~80โ90% |
Every number here is logged in docs/measurements.md with date, setup and trials.
What it can't do (yet)
I'd rather say this than have you find it:
- Radar accuracy: about 80โ90% against a manual breath count and a reference heart rate in my tests. That's enough to tell a restless night from a calm one, but not enough for medicine. The movement number still jumps too easily, so calibration is next.
- Rain bonus: it passes my tests at home, but it hasn't lived through a full monsoon of real mornings yet. A loud fan or a shower could still fool it.
- It's a comfort device, not a medical one.
My Agent Session
I built Sloth Clock with Claude Code as my coding agent. Here's how we split the work:
| ๐ง Me | ๐ค Claude Code |
|---|---|
| The idea, and the safe-laziness rules | Wrote most of the Python app, the STM32 sketch and the two XIAO firmwares |
| Picking, wiring and placing the hardware | Wrote the tests and the note validator, one rule per failure I found |
| Flashing, testing and every measurement on the board | Debugged from the logs and readings I sent back |
| Deciding what ships, and what the post claims | Kept docs/measurements.md and the progress notes up to date |
The best part: every time Gemma broke a rule on the board, I pasted the bad note back, and the agent turned it into a validator rule and a test. That loop is why no wrong number got through.
Why Does Open Innovation Matter?
Because this device lives in your bedroom, watching you breathe. ๐๏ธ
- ๐ Your data never leaves the nightstand. No audio, no camera, and no raw radar waveform is stored anywhere. Only small rows go into a file on the board: a breathing rate, a heart rate and a movement number every 10 seconds. That's health data. With a closed API, every wake note would be a little report about your night sent to someone else's server.
- ๐ It works offline. An alarm can't depend on the internet, a server, or an API key that expires. The radar is wired straight to the clock, and nothing leaves the room. If the Wi-Fi dies at 3 a.m., the sloth doesn't notice.
- ๐ธ It costs nothing to run. No tokens, no subscription. A year of wake notes costs $0.
- ๐ I can swap the model. It's one GGUF file and one command line. When a better small open model comes out, the clock gets better without asking anyone's permission.
- ๐ I can read every layer: the radar library, the inference server, the model. When something broke, I could find out why.
A closed model could write a slightly nicer sentence. It couldn't do it on a nightstand, offline, for free, without learning when you sleep.
The Lazy Payoff
- ๐ด Up to 30 more minutes of sleep on exactly the mornings you need it, with zero risk of being late.
- ๐ง Zero decisions before coffee. No more bargaining with a snooze button, half asleep. The sloth already did the maths.
- โ Zero effort to track sleep. No wearable to charge, no app to open, no button at bedtime. The laziest sleep tracker is the one you never touch.
- ๐ช Progress without willpower. One tiny step a day, and a smaller one after a bad night.
Prize Categories
- Best Use of Arduino: the whole agent lives on one Arduino UNO Q, and each half does the job it's built for. It senses with a 60 GHz radar: the STM32 parses every line and builds 33-byte summary rows. It decides on Linux: night score, alarm logic with hard health limits, and Gemma 3 1B running on the board, offline. It acts on the STM32: the LED-matrix sunrise, the chime through a PAM8403 and a small speaker, the button, and a backup alarm that rings even if Linux doesn't. The two halves talk over the Arduino Bridge, packaged as one App Lab app. The STM32 also carries a register-level I2S driver and a hand-written FFT for the INMP441 microphone (the core has no I2S library or CMSIS-DSP), so the microcontroller itself listens for rain and passes on only a few numbers, never audio.
- Best Use of Gemma: Gemma 3 1B runs on the board through llama.cpp, offline. It writes every wake note and splits avoided jobs into tiny steps. Code writes the facts, and a validator checks every number Gemma writes: 10 / 10 notes valid on the board (8 on the first try, 2 after one retry), 0 wrong numbers through.