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

IMG_3150.JPG

 

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 5x8 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:

 

cad.lcd.write_custom_bitmap(0)












 

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

mms://streaming.q-music.be/QBE_HI
[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.

 

Playlist:

 

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)
    cad.lcd.write_custom_bitmap(3)
    cad.lcd.write(playlist)












 

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.

 

Volume:

 

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)
    cad.lcd.write(volume)












 

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)

listener.activate()











 

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_custom_bitmap(1)
                event.chip.lcd.write(" ")
                display_channel()
                display_playlist()

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

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

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

        elif(event.pin_num == 4):
                global backlight
                if(backlight == 1):
                        event.chip.lcd.backlight_off()
                        backlight = 0
                else:
                        event.chip.lcd.backlight_on()
                        backlight = 1

        elif(event.pin_num == 5):
                sleep(1)

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

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

        else:
                sleep(1)











 

Above actions correspond to following button mapping:

IMG_3152.JPG

 

Full code

 

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

 

 

Autostart

 

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/radio.py &






 

Demo

 

IMG_3148.JPG