Press "Enter" to skip to content

How to Create an Alarm Clock with a Raspberry Pi

Tired of using your phone as an alarm?

How many times have you heard that same awful ringtone and then turned it off accidentally when you meant to hit snooze?

Using the steps outlined in this Raspberry Pi project, you’ll create your own alarm clock that can play any song you want and can be turned off or snoozed using a physical button.

If you’re new to the Pi, you may want to go over my GPIO pin introduction and breadboard tutorial first to familiarize yourself with these tools.

Benefits of a Raspberry Pi alarm clock

The Raspberry Pi can function much better as an alarm clock than your phone. For example, with this alarm clock you can:

  • Play any song or sound you want
  • Use high-quality speakers
  • Keep the “off” button across the room
  • Turn the alarm off remotely if needed
  • Schedule it to auto-dismiss after some time
  • Programmatically set/adjust the volume
  • Create a complex schedule

If you have trouble getting yourself out of bed in the morning, this gives you a sandbox to try out different things and see what works for you.

You can customize the snooze duration, increase the volume every 2 minutes, change the tune to a more urgent song after a few snoozes, or even play a recording of yourself saying to “get out of bed already!”

The possibilities are endless with a Raspberry Pi powered alarm clock.

What you’ll make

This project is going to focus on the functionality of the alarm clock. That means you’ll have a song scheduled to play every morning and a button you can click to snooze or press-and-hold to turn off.

I’ll be wrapping up the project with a breadboard still in use at the end, but you could take things further by soldering the components together, 3D printing a case, or even adding a clock with a 4-digit LED.

alarm clock build
The alarm clock prototype

I might update this project in the future with these additions, but for now, here’s how to create the prototype for a custom Raspberry Pi alarm clock.

If you come up with a cool variation, make sure to share your notes and a photo in the comments below!

What you’ll need

In addition to your Raspberry Pi, you’ll need a handful of electronics components:

  • 2 M-F jumper wires (dupont cables)
  • 1 M-M jumper wire
  • 1 tactile button
  • 1 resistor (1,000Ω)
  • 1 breadboard
  • A speaker

The speaker you can get anywhere, but for the other components, I recommend getting an electronics starter kit. The REXQualis Complete Starter Kit is my top recommendation, but any of them will work.

How to create the alarm clock

The alarm clock needs to do three things to be fully operational:

  1. Play a song on repeat
  2. Schedule the song to play on specific days & times
  3. Snooze/turn off with the press of a button

The very first thing we’ll do is get some audio playing on command, and to do that, we need to start by connecting a speaker.

Before you connect the speaker, run the following commands to update your OS and all of the installed packages on your Pi.

sudo apt update
sudo apt upgrade

It’s always a good idea to run these commands before installing new packages or making changes to your Pi.

Connect a speaker

Getting audio to output properly to your speakers can be kind of a pain, so let’s tackle that first.

In my case, I’ll be using a Bose Color SoundLink. It uses a 3.5mm cable for the audio and USB 2.0 for power.

If you have a monitor connected to your Pi already, the audio is likely configured to output via HDMI. To change the audio output device, right-click on the speaker icon in the start bar and select “Analog” as the output device.

select analog output

I also needed to reboot my Pi for this to work properly via the terminal.

While you could connect to a Bluetooth speaker, your speaker might turn itself off or disconnect from the Pi after a period of inactivity, so it’s not the best solution for a 24/7 alarm clock.

Additionally, using a USB cable to charge the speaker is fine, but using it for the audio can take some more work. The Pi expects audio to be output via the 3.5mm jack (analog) or through the HDMI connection.

In the end, using the analog port (3.5mm) is the simplest way to get audio playing to a speaker, and it also ensures great sound quality.

Next, we’ll test a sample song to make sure the audio output is working.

Test the alarm song

As I mentioned in the intro, one of the best parts of making your own alarm clock is the option to play any song or sound.

For testing purposes, you can download an audio sample file here, or get these free mindful alarms from Headspace.

To test the playback, we’ll use VLC Media Player since it comes pre-installed with Pi OS, and has a featured-rich audio player.

As an initial audio test, double-click the audio file, and VLC will open up. Make sure the audio plays fine in this way.

vlc playing song
VLC playing a sample audio track

If you don’t hear anything, double-check the output device is set properly.

Next, run the following command to make sure the speaker is also playing the audio properly when executed from the command line:

cvlc /home/pi/Music/song.mp3

I’ll be using this same file path throughout the guide, so make sure to update it point to your file each time you copy code from here.

The cvlc command will run VLC in the background rather then opening up the player window. By the way, if you use vlc as the command, it will open up the player window.

We could schedule the command the way it is now with Cron and have the song play automatically on a schedule. However, the problem with playing the song with a shell command is that it doesn’t give us a way to pause/unpause the song. Additionally, we can’t program the GPIO pins like this.

That’s why we’re going to write a script with Python that can do all of these things, and then use Cron to execute the script.

Play the song with Python

Python doesn’t have a native way to play, pause, and stop audio tracks, but luckily for us, there is a Python VLC library that allows us to operate VLC via Python.

To install the Python VLC library for Python 3, run the following command:

sudo pip3 install python-vlc

With the package installed, open up your favorite IDE and create a new file called alarm-clock.py.

I’m still playing around with the editors that come pre-installed on the Pi and will be using Thonny in this tutorial.

select thonny editor

In the empty file, start by importing the VLC module.

import vlc

Next, add the following lines to create a media player object that will use the alarm song, and tell it to play.

player = vlc.MediaPlayer("/home/pi/Music/song.mp3")
player.play()

If you run the script now, you should hear the song playing through your speaker.

Run script

I wish the code could stay this simple, but there’s one major issue: the song doesn’t loop. For an alarm clock, we need the song to play over and over. To create that behavior, we have to break down the code into a few more pieces.

Loop the song

We need to create a new VLC instance and use the --input-repeat parameter to repeat the song.

Here’s how to do that:

vlc_instance = vlc.Instance("--input-repeat=999")

We create a variable named vlc_instance and set it equal to a new VLC instance provided with the --input-repeat parameter set to 999. This will make the song repeat 999 times.

Previously, it was possible to use -1 to make a song loop forever, but this functionality stopped working in VLC 3.0. In this case, “999” is a magic number which is unfortunate, but given the extremely small scope I think we can let it slide.

Next, we need to create a new media player from the instance, and register the audio file as a media object. Here’s how to do that:

player = vlc_instance.media_player_new()
song = vlc_instance.media_new("/home/pi/Music/song.mp3")

Then we can set the song as the media object for the player to use, and then tell it to play:

player.set_media(song)
player.play()

While it took a few more lines, this code is still fairly succinct and allows us to play a song on repeat with VLC. Here’s what the final code looks like:

import vlc

vlc_instance = vlc.Instance("--input-repeat=999")
player = vlc_instance.media_player_new()
song = vlc_instance.media_new("/home/pi/Music/song.mp3")

player.set_media(song)
player.play()

Hit the Run button to try it now.

Next, let’s test the script out via the command line.

Run the script via command line

When running the script from the IDE, the song will keep playing until we hit Stop or exit the IDE. When playing in the background via Cron, the script will exit after the script executes, and you’ll never even hear the song play.

You can keep the script running by adding the following code to the bottom of the file:

while True: pass()

With that code added, test it out by using the following command to run the Python script:

python /home/pi/Scripts/alarm-clock.py

In this example, I’ve placed the alarm-clock.py file in a new folder named “Scripts,” but you can add it wherever you want. Once you run that command, you should hear the song playing right away.

Make sure you do NOT use sudo at the beginning of this command or the audio will not play.

With our script playing the wakeup song via the terminal, the next step is to get it play on a schedule. After that, we’ll hook up a button via the GPIO pins and update our script so that the button can snooze and stop the song.

Schedule the song to play

The Raspberry Pi has built-in support for Cron which is a Unix utitility for scheduling tasks. It’s perfect for an alarm clock.

Start by executing the following command to open up the cron editor.

crontab -e

The first time you run this command, you’ll be asked to choose an editor. You can enter “1” to select the Nano editor which I’ll be using here.

In the editor, arrow down passed the comments to start your first scheduled command.

cron editor

As you can see in the comments in the cron file, the scheduling follows a straightforward syntax:

Minute Hour DayofMonth Month DayofWeek Command

If you want to run a command at 7am every day, you would write it like this:

0 7 * * * Command

The asterisk, or wildcard, is used to allow all values, so this tells the task to run at 7:00 on every day of the month, every month, every day of the week.

Keep in mind that cron uses a 24-hour clock, so you would use 15 for 3pm.

That said, you’ll probably want your alarm to go off on weekdays only. Each day of the week has a numerical value and a three letter code, as follows:

Sunday:    0 Sun
Monday:    1 Mon
Tuesday:   2 Tue
Wednesday: 3 Wed
Thursday:  4 Thu
Friday:    5 Fri
Saturday:  6 Sat

You can comma-separate the days you want to schedule, like this: Mon,Wed,Fri

Or, if you use the numerical values, you can use a hyphen, like this: 1-5

I only want my alarm to go off on Monday through Friday at 9am, so I’ll write the command like this:

0 9 * * 1-5 python /home/pi/Scripts/alarm-clock.py

To test out your command, try setting a task for a couple of minutes in the future and wait for it to go off. I don’t know about you, but I felt like a wizard the first time it played 🧙‍♂️.

With your repeating song scheduled, the functionality for the alarm clock is nearly complete, but of course, you wouldn’t want to open up the terminal every morning to turn off your alarm.

The final step is to hook up a physical button so you can snooze the alarm and turn it off.

It is a good idea to turn off your Pi now while you create and inspect your circuit.

How to connect a physical “off” button

We’ll start by creating a simple circuit with a tactile button. Then we’ll use the GPIO Zero library to make the button stop the song when it’s pressed. Lastly, we’ll modify the script so that the button can differentiate between presses and holds so it can both pause and stop the song.

As a reminder, following my GPIO pin and breadboard tutorials first will help a lot with this section if you haven’t used them before.

Start by connecting one of the ground pins to the negative rail on the right with a M-F jumper wire.

connect ground

Next, use a 1,000Ω resistor to connect from the negative rail to one of the rows.

Add a resistor

Next up is the button.

When using a tactile button, it’s important to understand exactly how they function. You’ll see that the legs are attached on two of the opposite sides.

Tactile buttons have legs attached on two sides

The legs are both single metal strips that enter from one side and pass through the opposite side. Picturing that, it’s easy to understand why the current will always flow through tactile buttons in this direction.

Currents always run this way

When the button is pressed, it makes a connection between the two metal strips allowing the current to flow in the other direction as well.

When pressed, currents also run this way

With this in mind, here’s how you want to place the button in your breadboard.

Button connected to breadboard

The button won’t fit over the ravine if you turn it the other way, so placing it over top of the ravine is a good way to ensure you’ve got it facing the right direction.

Next, use the M-M jumper wire to connect from row 5 to the positive rail on the left.

Jumper connecting row 5 to positive rail

Lastly, connect from the positive rail to GPIO pin 17 using the second M-F jumper wire.

If you last used GPIO 17 as an output (like to power an LED), make sure to reboot your Pi. Otherwise, clicking the button can short circuit the pin.

Completed circuit

You can see how the button’s upper leg is connected to the positive and the lower leg to the negative. When the button is pressed, the circuit is completed allowing for a measurable difference in voltage change.

There are many ways you could wire this, but I thought this was a simple and easy to understand setup.

Now let’s move on to programming GPIO 17.

How to stop the song with the button

The first thing we’ll do is import the GPIO Zero library. It gives us a variety of helper functions that make interfacing with the pins much easier.

Since we’re only communicating with a button, you can import the Button object from the library like this:

from gpiozero import Button

Next, create a new variable called btn and assign it as a Button object using pin 17, like this:

btn = Button(17)

The Button object provides a variety of helpful methods including one called when_pressed which runs the function assigned every time the button is pressed.

The function we can write to stop the music is extremely simple:

def stopMusic():
	player.stop()

Then we tell the button to use that function when pressed:

btn.when_pressed = stopMusic

Run the script now, and you should hear the music right away, but this time, you can press the button to stop the song.

With our song scheduled and a way to turn it off with the click of a button, the last capability the alarm clock needs is snoozing.

If you’re confused about where the voltage is coming from when connecting an input pin to a ground pin, it’s because GPIO Zero is automatically configuring a pull-up resistor that is inside the Raspberry Pi for pin 17 causing it to have “high” voltage. It was a “floating” pin until we set the pin using btn = Button(17).

How to snooze the song with the button

Adding the snooze feature makes things a bit more complicated.

The most sensible design in my opinion is to press the button to snooze the alarm and hold it to turn it off completely. To add the snooze functionality, we’ll pause the song and then run the sleep() function to keep it paused for a period of time.

It sounds simple enough, but the trouble is that the sleep() function delays code execution, so the script is paused from the moment the button is pressed meaning it won’t track whether or not the button is held for seconds afterwards.

Rather than writing a complex multi-threading solution to continue running part of our script while using sleep(), we’ll lift a solution straight out of the GPIO Zero documentation for handling this situation.

The logic

Here’s how the logic works.

When the button is held, we’ll stop the song. When the button is released, we’ll check if it was held. If it was held, we won’t do anything. If the button was released and it wasn’t held, that means it was pressed, so we’ll snooze the song.

The code

Start by deleting this code from your script:

def stopMusic():
	player.stop()
    
btn.when_pressed = stopMusic

We won’t be using when_pressed anymore.

Next, below the imports, add the following line of code:

Button.was_held = False

This is going to give the Button object a new property called was_held and assign it a default value of False. It’s important to give this property to the Button object before creating the btn variable so that it’s available.

Next, add the following after you define the btn variable:

def held(btn):


def released(btn):


def pressed():

btn.when_held = held
btn.when_released = released

Previously, we used when_pressed to trigger the function that stops the music. Here, we are using when_held and when_released instead. As you can see, they both call their respective functions. The held() and released() functions are also passed the btn variable so they can check the was_held property.

When the button is held, we want to stop the song, so we can update held() as follows:

def held(btn):
  btn.was_held = True
  player.stop()

This stops the song and also sets the was_held property to True which will be used in the released() function.

If you run the script now, you should be able to hold the button for a second to turn off the song.

Moving on, update released() with the following code:

def released(btn):
  if not btn.was_held:
    pressed()
  btn.was_held = False

First, we check if the button was held. If it was not held, we call the pressed() function. Regardless of whether or not it was held, we then reset was_held to False so it can be re-evaluated next time. Otherwise, once the button is held it would always stay true.

The last thing we must do is add the functionality for pressing the button. Start by importing the sleep() function from the time module.

from time import sleep

Then update the pressed() function to snooze the song:

def pressed():
  player.pause()
  sleep(3)
  player.play()

The song is paused, the code is then delayed for 3 seconds, and then the song resumes. You can use player.stop() instead if you want the song to restart from the beginning after snoozing.

Additionally, the 3 second value is just for testing purposes. You can pause the code for much longer once you’re ready to use it IRL.

There are a couple of small additions I’d recommend you add before calling it a day.

A few tweaks

The default hold time is one second. With tired hands, it’s easy to imagine holding the button by accident.

Update the button to require 2 seconds to qualify as a hold, like this:

btn = Button(17, hold_time=2)

One more update worth making is to set the volume every time the script runs. While I didn’t experience this issue firsthand, I found some accounts online claiming they needed to do this to guarantee VLC wouldn’t get muted. It doesn’t hurt to add, so here’s how to do that:

player.audio_set_volume(100)

Here’s how the final code looks with everything put together:

import vlc
from gpiozero import Button
from time import sleep

vlc_instance = vlc.Instance("--input-repeat=999")
player = vlc_instance.media_player_new()
song = vlc_instance.media_new("/home/pi/Music/song.mp3")

player.set_media(song)
player.audio_set_volume(100)
player.play()
 
Button.was_held = False

def held(btn):
    btn.was_held = True
    player.stop()

def released(btn):
    if not btn.was_held:
        pressed()
    btn.was_held = False

def pressed():
    player.pause()
    sleep(3)
    player.play()

btn = Button(17, hold_time=2)

btn.when_held = held
btn.when_released = released

while True: pass

Enjoy your new custom alarm clock

This project turned out to be a pretty long post!

Congrats to you for sticking with it.

As I mentioned in the intro, I may return to this article to update it with more stuff like casing so it looks like an actual alarm clock, but for now I’ll leave that up to your imagination.

With the circuitry and code outlined here, you’ve got everything you need to create functioning alarm clock with the Raspberry Pi.

If you have some more ideas, clever implementations of your own, or any questions about a step in this guide, please post in the comments section below.

Thanks for reading!

My Favorite RPi Products

Get new post notifications

Subscribe to get new projects & tutorials in your inbox

    Unsubscribe at any time in one click.

    Be First to Comment

    Leave a Reply

    Your email address will not be published. Required fields are marked *