All projects
Hardware2026

Smart Alarm

An ESP32 bedside alarm clock that tracks your sleep with an onboard accelerometer and wakes you during light sleep instead of at a fixed time. I designed the whole thing: firmware, sleep-staging model, schematic, and PCB.

Everything runs on the ESP32 itself. No phone, no cloud, no app.

Part 1 · Firmware and interface
A ten-screen menu system covering alarm, smart alarm, sleep data, weather, and settings, all driven by one rotary encoder and one button. The home face pulls NTP time and a 5-day OpenWeatherMap forecast, and repaints only the digits that actually changed, so the display never flickers. Alarm, smart-wake, and snooze settings live in EEPROM and reload on boot.
ESP32ArduinoTFT_eSPISPII2CEEPROM
Finished Smart Alarm PCB showing time, date, weather and alarm status
The finished board. Home screen: NTP time, date, live weather, and alarm status, all flicker-free.
Paging the menus, opening Sleep Data, and dropping into sleep mode, all on one encoder and one button.
Part 2 · Sleep tracking and on-device ML
An MPU-6050 clipped to the mattress logs motion to an SD card at 2 Hz. Every 30 seconds the device pulls 21 statistical features off a ring buffer, scores that window as light or deep sleep, and writes it back out, so the morning hypnogram survives a reboot. I trained a Random Forest on eight hand-labelled nights, roughly 420,000 raw samples, and exported it to C to run entirely on-chip.
Pythonscikit-learnmicromlgenMPU-6050SD / CSV
Sleep Data screen with a two-lane hypnogram and light/deep totals
The Sleep Data screen: time asleep, a two-lane hypnogram, and light/deep totals, read back off the SD card.
Part 3 · Schematic and PCB
The first version lived on two breadboards with the display taped to the front. Once the pinout stopped changing I redrew it in Altium as a two-layer board, with every peripheral broken out to a labelled header so modules stay swappable, and had it fabricated. Same firmware, considerably less wire.
Altium DesignerSchematic CapturePCB Layout
The original two-breadboard prototype running the same firmware
Where it started. Same firmware, same home screen, considerably more wire.
Altium schematic split into passive, active, and microcontroller blocks
The schematic, organised into passive components, active components, and the ESP32 itself.
Two-layer PCB layout with labelled peripheral headers
Two-layer layout. Every peripheral breaks out to a labelled header so modules stay swappable.
3D render of the assembled PCB
The 3D render of the assembled board, before it went out for fabrication.
Highlights
Rings early at the first stretch of light sleep inside a window you choose, at one of three sensitivity levels, and falls back to the exact alarm time if that moment never comes
The Random Forest hit 65% accuracy but only 0.19 recall on deep sleep, so I did not ship it as the displayed stage. Mattress motion alone barely separates deep from light: median peak deviation was 140 versus 142
Shipped an actigraphy-style sleep-cycle model instead, using ~90 minute cycles where any movement forces light sleep. It produces 20 to 27% deep sleep, in line with published norms, and the Random Forest vote is still logged every window so the comparison stays honest
Roughly 1,100 lines of firmware plus a 1.4 MB generated classifier, which is why the board needs the 3 MB huge_app partition instead of the default 1.3 MB one
A 150 ms debounce plus a 400 ms hard lockout on the back button, and an external pull-up on the input-only encoder pin. Both problems surfaced on the breadboard and went straight into the schematic
SD files open once on entering sleep mode and close once on exit. An earlier version reopened them on every write and corrupted the card, so that rule is now enforced by the architecture