Internet Radio Player with Raspberry Pi, PiFace CAD and MPD/MPC

I recently worked with the PiFace Control and Display for my Santa Catcher, in which I used the PiFace CAD as an IR receiver and display without using any of the local controls.
So I decided to create an Internet Radio player which could be controlled using the PiFace CAD’s buttons.

The result is mainly a software project, but I had fun diving a little deeper into the Python programming language.

Project Components

For this project, I used following components:

  • Raspberry Pi Model B running Raspbian
  • PiFace Control and Display
  • Enclosure for Pi and PiFace CAD
  • Wi-Pi
  • Portable speaker
  • 5V 1A micro USB power supply


Required Software

As mentioned earlier, I started off by using Raspbian with wifi and ssh enabled.

These were the modifications on top of Raspbian to get everything I needed up and running:

  • Updated Raspbian to latest version
    • sudo apt-get upgrade
    • sudo apt-get update
  • Enabled SPI support for the PiFace CAD
    • sudo raspi-config
    • Select option 8: “Advanced options”
    • Select option A5: “SPI”
    • Select “Yes”
    • Select “Finish” to exit
  • Installed the mpd (music player daemon) and mpc (music player controller) applications
    • sudo apt-get install mpd mpc

Python Script

From this point on, everything is done via Python.

Using Python, I am able to control the mpc application using the PiFace CAD’s buttons and display the status on its LCD.

Code explanation

You can find the full code a bit further down, but I’ll try to explain some bits of code here.

Custom bitmaps

I wanted to display some icons on the LCD to clarify the meaning of some values being displayed or to visualise the current state.
It is possible to define “custom bitmaps” to be displayed. This tool comes in very handy to create your own. (be sure to select 5×8 when using PiFace CAD)

Following function defines and stores custom bitmaps:

def custom_bitmaps():
    speaker = pifacecad.LCDBitmap([1,3,15,15,15,3,1,0])
    play = pifacecad.LCDBitmap([0,8,12,14,12,8,0,0])
    stop = pifacecad.LCDBitmap([0,31,31,31,31,31,0,0])
    playlist = pifacecad.LCDBitmap([2,3,2,2,14,30,12,0])

    cad.lcd.store_custom_bitmap(0, speaker)
    cad.lcd.store_custom_bitmap(1, play)
    cad.lcd.store_custom_bitmap(2, stop)
    cad.lcd.store_custom_bitmap(3, playlist)

The custom bitmaps can then be displayed on the LCD as follows, using the id of the corresponding bitmap:


MPC status

In order to display correct information on the LCD (volume & playlist position and size), I rely on the information coming from the mpc application itself.

A sample output looks as follows:

pi@piRadio ~ $ mpc status

[playing] #1/2 1187:22/0:00 (0%)
volume:100% repeat: off random: off single: off consume: off

Using Python, it is possible to execute that command, take the output and parse the interesting bits of information.


def display_playlist():
    playlist = subprocess.check_output("mpc status | grep playing", shell=True, stderr=subprocess.STDOUT)
    playlist = playlist[ playlist.find("#")+1:playlist.find("/")+2]
    cad.lcd.set_cursor(4, 1)

This bit of code executes the “mpc status” command and only keeps the part of the output containing the word “playing”.
Then, it parses the output and keeps the part after “#” and up to two character after the “/”. This covers playlists of up to 99 items.

The playlist information is then written to the LCD, with an icon to clarify the meaning of the value.


def display_volume():
    volume = subprocess.check_output("mpc status | grep volume", shell=True, stderr=subprocess.STDOUT)
    volume = volume[7:volume.find("%")+1]

    cad.lcd.set_cursor(12, 1)

Similar to the playlist parsing, this bit of code takes the output of the “mpc status” command containing the word “volume”.
It parses the characters after the word “volume” up to and including the “%” character.

The volume is then written to the LCD.

Event listener

The script needs to know when a button on the PiFace CAD has been pressed and trigger the appropriate action.

I recuperated this bit of code from one of the PiFace examples and extended it to fit my application.

First, a listener is defined which will register which button has been pressed:

listener = pifacecad.SwitchEventListener(chip=cad)

for i in range(8):
        listener.register(i, pifacecad.IODIR_FALLING_EDGE, update_pin_text)


The listener executes the specified function in which it execute different actions depending on the button that was pressed:

def update_pin_text(event):
        global channel_pos
        global status
        if(event.pin_num == 0):
                status = "playing"
                os.system('mpc play')
                event.chip.lcd.set_cursor(0, 1)
                event.chip.lcd.write(" ")

        elif(event.pin_num == 1):
                status = "stopped"
                os.system('mpc stop')
                event.chip.lcd.set_cursor(0, 1)
                event.chip.lcd.write(" ")

        elif(event.pin_num == 2 and status == "playing" and channel_pos > 1):
                os.system('mpc prev')

        elif(event.pin_num == 3 and status == "playing" and channel_pos < len(channelLink)):
                os.system('mpc next')

        elif(event.pin_num == 4):
                global backlight
                if(backlight == 1):
                        backlight = 0
                        backlight = 1

        elif(event.pin_num == 5):

        elif(event.pin_num == 6):
                os.system('mpc volume -5')

        elif(event.pin_num == 7):
                os.system('mpc volume \+5')


Above actions correspond to following button mapping:


Full code

The code still requires to be cleaned up a little, but it should be clear what I’m trying to do.

The code is available on GitHub.


The script needs to be started automatically after the system booted. This is done by adding following entry to /etc/rc.local:

sudo python /home/pi/ &


© Frederick Vandenbosch, 2014-2021. Unauthorised use and/or duplication of this material without express and written permission from this blog’s author and owner is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to Frederick Vandenbosch with appropriate and specific direction to the original content.