Smart morning radio with Raspberry Pi, cron and MPD
What if your Pi waked you up every morning with your favorite radio station? Wouldn’t it be cool if it stopped playing when you leave home? And what about not bothering you on holidays?
I have a pair of speakers connected to my Pi, and I keep them on 24/7. This opens a lot of possibilities. One is to make my Pi stream some radio always at a fixed time.
After configuring a player such as MPD and obtaining the streaming URL, that becomes fairly easy to do. Just a matter of placing a couple of commands on your crontab.
I wanted, however, to make something more robust and take care of some details.
This post walks you through my fairly simple, but convenient setup. If you want to cut through the talk and just take a hint at it, you can check it here.
Requirements
I’ll assume you have:
- Some speakers connected to your Pi, and configured on MPD
- MPC installed, to control MPD
- Cron installed, to schedule our commands
Cron and scripting
As I said, to schedule our Pi to play radio at specific times, we could just drop something as mplayer url_of_the_stream
on the crontab.
But what about the volume? And holidays?
As your command becomes more complex, it makes sense to extract it from the crontab and make it a script.
While you could write it in any language you like, Bash and Python are sensible choices. I pick Bash.
In the following sections, we’ll build that script together. You can check mine here.
First of all, set the volume!
As much as you like a station, you probably don’t want to listen to them on a random volume first thing in the morning. Neither your neighbours.
So let’s set it to a good level.
On ALSA
If your Pi uses ALSA, doing it is as simple as this command, replacing 20 for the desired level:
$ mpc volume 20
On PulseAudio
For PulseAudio, things get a bit trickier. In this case, the volume
command adjusts the volume of the MPD sink-input, which is closed whenever MPD stops the playback. This means that, if you issue the same command before anything is playing, you’ll get an error.
A solution for that is setting always_on = true
for the PulseAudio output in /etc/mpd.conf
. However, doing this made me experience some delays and weird behaviours on MPD. So I did another thing.
My hacky workaround is to create a silent track and ask MPD to play it. In the meanwhile, I can set the volume. Like this:
set_volume() {
mpc clear
mpc add /path/to/silence.ogg
mpc play
sleep 10
mpc volume $1
mpc clear
}
Did you unmute?
This step may sound silly, but for someone as me who mutes the Pi to do some VNC work, it can actually be a lifesaver.
My script makes sure my Pi is not muted and it also assures the general volume to be at 100%.
For PulseAudio:
pactl set-sink-mute sink_name false
pactl set-sink-volume sink_name 100%
Where sink_name
will be something like alsa_output.pci-0000_00_1f.3.analog-stereo
. You can get it issuing:
$ pactl list sinks short
For ALSA, you should run something similar to this:
$ amixer -c 0 set Master unmute
Check alsamixer
and replace 0
and Master
with the values for your setup. We don’t set anything to 100% here, because on ALSA you only have one volume per output (the one we set on the previous step).
Holidays!
On cron, we’ll make sure that our radio alarm only plays on weekdays. But what about holidays? You probably don’t want to be woken up at 6 am!
I solved that in a simple way. In a text file I placed all the holidays, one per line, in the mm-dd
format. The ones that change each year, such as Easter, are written as yyyy-mm-dd
. I made the script look for the current day on that file, and to abort if it is found.
So we got a function like this:
check_holiday() {
if grep -q -e "^\s*$(date +%Y-%m-%d)\s*" -e "^\s*$(date +%m-%d)\s*" "$holidays_file"; then
printf "Today is a holiday. Not doing anything.\n" >&2
exit 0
fi
}
Disable dates
At times, you may want the radio not to play at some workable dates. Maybe you’ll be out of town, you’ll not go to work for some reason, or you’ll wake up much later.
While we could use here the same solution that we did for the holidays (placing the dates in a text file), this didn’t cut it for me. Reasons:
- You would have to SSH to the Pi and mess with a text file every time you wanted to disable a date.
- Do you ever want other people in your household to use this?
For storing mostly stable values, as in the holidays case, a plain text file works well. But for something more dynamic and ad-hoc as this, I wanted other thing.
So I coded a simple web app to handle that. Under the hood, it still writes to a plain text file, very similar to the holidays one, with the script grepping it the same way. It does the management of that file and offers a friendly interface.
Let’s play!
Now that we checked the day is not a holiday nor a undesired date and properly set the volume, it’s time to play our radio!
For this, I’d also recommend to have a backup station, in case the streaming URL of your favorite radio gets broken. You could also add a song from your library, in case there are any network problems. This way, you make sure something will always play.
One possible way:
mpc clear
mpc add https://example.com/preferred_stream
mpc add https://example.com/backup_stream
mpc add "A song.ogg"
mpc random off
mpc play
You can get creative here. For example, you could add many radios, maybe using a playlist, and turn random on. So each day a different station would wake you up.
On my script, instead of passing some URLs through MPC, I call the PiFi Radio (a MPD web client to listen to radio that I wrote) API with the radio names. This is more convenient to me, since I can store all the streaming URLs in a single place.
What about stopping?
The same way I wanted my Pi to play radio automatically every morning, it would be nice that would stop playing it without human intervention.
While we could get fancy here and try to detect when we leave home, I decided to just schedule a reasonable time for the playback to stop.
At the given time, cron calls the necessary steps to do it, which are simply:
mpc stop
set_volume 50
Where set_volume
is the function we’ve written before.
Let’s schedule it
Now that our script is done, we need to make it run at the desired time. For that, we’ll use cron. Alternatively, you could use systemd timers. I’ll do it old school.
You can add the script to your personal crontab, running:
$ crontab -e
I dropped it under /etc/cron.d
:
# /etc/cron.d/radioauto
# Play radio automagically in week days
00 06 * * 1-5 pi /opt/scripts/radioauto start
00 08 * * 1-5 pi /opt/scripts/radioauto stop
This will run the script from Monday to Friday at 6 and 8 am. First with the start
argument, than with stop
.
If you copy and paste those lines to a user crontab, the columns are a bit different. Be sure to remove the user column (the one which says pi
).
The result
And we are done. Our Pi will wake us up every day with our favourite radio. It will stop playing at a given time automatically. And we won’t be bothered on holidays and whenever we don’t want it.