Rafael Cavalcanti

Linux enthusiast and human being.

github email
Smart morning radio with Raspberry Pi, cron and MPD
Aug 13, 2018
6 minutes read

What if your Pi waked you up every morning with your favorite radio station? Would it be cool if it stopped playing when you left home? And what about not bothering you on holidays?

I have a pair of speakers connected to my Pi, and I keep them on 247. This open a lot of possibilities. One is to make my Pi always play a streaming at a fixed time.

Having set up the speakers, configured a player such as MPD, and obtained the streaming URL, it becomes fairly easy to do. Only 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. For this, I wrote a small Bash script. On this post, I will walk you through my fairly simple, but convenient setup.

Requirements

I’ll assume you:

  • Have MPD installed, running and properly configured
  • Have some speakers connected to your Pi, and configured on MPD
  • Have MPC installed
  • Have cron installed

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 was creating a silent track and asking MPD to play it. In the meanwhile, I set the volume. Like this:

set_volume() {
  mpc clear
  mpc add http://localhost/silence.ogg
  mpc play
  sleep 10
  mpc volume $1
  mpc clear
}

Notice that I placed the file on my web server, since MPD won’t play local files outside of the library.

Did you unmute?

This step may sound silly, but for someone as me who mutes the Pi to do some VNC work, it actually can be a lifesaver.

So 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 issue similar to this:

$ amixer -c 0 set Master unmute

Check alsamixer if you need a name other than “Master”. 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 wake up at 6 am!

I solved that in a simple way. I placed a text file with all the holidays, one per line. Then, made the script look for the current day on that file, and to abort if finds it is there.

So we got a function like this:

check_holiday() {
  if grep -q "$(date +%Y-%m-%d)" "$HOLIDAYS_FILE"; then
    printf "Today is a holiday. Not doing anything.\n" >&2
    exit 0
  fi
}

Let’s play!

Now that we checked the day is not a holiday, 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

This will play your preferred stream if available, and fallback to a backup radio when not. As a latest precaution, it will also have a local song to play, for example when your Internet connection is down, or both streams decided to hate you.

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.

My actual script is a bit different on that part, because 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/rc/pi-scripts/radioauto start
00 08 * * 1-5 pi /opt/rc/pi-scripts/radioauto stop

This will run the script from Monday to Friday at 6 and 8 am. First it start argument, than with stop.

If you copy and paste those lines in a user crontab, remember the columns are a bit different. So be sure to remove the user column (the one which says pi).

The result

And we are done. Our Pi will wake up us every day with our favourite radio. It will stop playing at a given time automatically. And we won’t be bothered on holidays.

You can check my full script here.



Back to posts


comments powered by Disqus