This is a DIY sunrise alarm clock built around a Raspberry Pi Zero 2 W, a Waveshare e-paper display, and a Shelly Duo RGBW light bulb. It shows the time on an always-on e-ink display, plays alarm sounds through small speakers, and gradually brightens a light before the alarm goes off. Everything is controlled by physical components such as rotary encoders, toggle switches, and custom circuits.
Features
- Always-on e-paper display with no glow at night
- Gradual sunrise effect using a Shelly Duo RGBW bulb
- Alarm playback from local sound files or Spotify playlists
- Physical controls: rotary encoders, snooze button, and toggle switch
- Sunrise timing and settings stored persistently in JSON
- Automatic startup on boot using systemd
- Works offline once configured
Hardware
- Microcontroller: Raspberry Pi Zero 2 W
- Display: Waveshare 3.7 inch e-paper (black and white model)*
- Audio DAC: Adafruit Speaker Bonnet
- Extended 40 pin stacking header*
- Speakers: Two 4 Ω 3 W full-range speakers connected to bonnet terminals
- Light: Shelly DUO RGBW E27*
- Rotary Encoder for menu navigation
- 10k Ohm Potentiometer for volume control
- MCP3008 chip plus breakout board and jumper cables*
- Toggle Switch for shelly light toggle on and off
- Momentary push button for snooze
- Power Supply: 5 V 2 A USB adapter
- RTC DS3231

Hardware Notes
- The model of the waveshare display is important, not only due to the layout of the screen codes, but also because the bigger displays take much longer to refresh and they do not all have the same codes to refresh the screen. This display refreshes relatively quickly and has partial and full refresh commands available.
- The Adafruit Speaker Bonnet must be installed first. Use an extended 40-pin stacking header so GPIO pins remain accessible.
- I wrote my code for the RGBW model for the sunrise effect from orange to white. The white only bulb will also work (going from warm to white and increasing brightness) but you will have to change the code yourself
- Detailed MCP3008 wiring guide
GPIO Wiring
| Hardware Component | Signal | GPIO |
|---|---|---|
| E-Paper Display | RST | 27 |
| DC | 22 | |
| CS | 8 | |
| BUSY | 5 | |
| PWR | 12 | |
| MOSI | 10 | |
| SCLK | 11 | |
| Rotary Encoder (Menu) | CLK | 17 |
| DT | 25 | |
| SW | 23 | |
| Snooze Button | 24 | |
| Toggle Switch (Light) | 16 | |
| MCP3008 (ADC) | CLK | 11 |
| DOUT | 9 | |
| DIN | 10 | |
| CS |
7 | |
| RTC Module | SDA | 2 |
| SCL | 3 |
Software Overview
The code is structured into a few key files that manage different parts of the system. All of the code can be found on my GitHub here.
-
final.py– Main program, menu system, and alarm logic -
alarm.py– Alarm class and JSON persistence -
light_control.py– Controls Shelly bulb and sunrise effect -
spotify_service.pyandauth.py– Spotify integration via SpotDL (music downloader) -
icons.py– Bitmap assets for the e-paper interface -
run-alarm.sh– Systemd launch script -
alarm_settings.json– Persistent alarm configuration -
epdconfig.py– Part of the Waveshare display setup (edit GPIO pins as needed)
Setup Notes
Before running the clock, configure your Spotify credentials in auth.py if you plan to integrate playlists, and enter your Shelly bulb IP address in light_control.py. Assign a static IP to your Shelly device to prevent connection issues.
For testing, run:
python3 /data/app/final.py
Sound Files
Alarm sounds should be placed in /Music/alarm-sounds/ as .wav files. The current code expects these names:
- classic.wav
- ambient.wav
- guitar.wav
-
nature.wav
You can replace or add your own audio files as long as they’re in the same format and location.
Enclosure

The enclosure was built by hand from scrap materials. The front panel is 3.5 mm plywood, and behind it is thin tackboard that holds the mounted components. It’s not the tidiest build inside, but it does the job well!