Getting started …
How cool would it be take a vintage 1940’s or 1950’s wooden radio and rebuild it as a modern Internet Radio? That’s the premise I had in mind when I started out on my first Raspberry Pi project.
I used the Adafruit Occidentalis Linux distribution and Adafruit python class for the 16×2 LCD display.
I found a great YouTube tutorial by MeisterVision that covered the basics of the MPC/MPD Linux Music Player really well.

Parts
To build this project, I used:
- Raspberry Pi, model B;
- Adafruit Pi Box enclosure;
- Edimax WiFi dongle;
- Adafruit Pi Cobbler;
- full-size breadboard;
- standard LCD 16×2 + extras;
- push-button switches;
- hookup-wire & staples;
- powered speakers.
I like the Edimax WiFi dongle because it works well and requires low power which makes it perfect for use with the Raspberry Pi without a powered USB hub.
YouTube Video
Here’s a 20-minute YouTube video that describes the radio in detail and demonstrates many of its capabilities, including:
- an LCD display;
- push button control;
- a menu system; and
- a loadable playlist.
The Python Source Code
The source code for this project is in one file called radio.py. This is my first ever Python program so please forgive any non-pythonesque usage. ☺
#!/usr/bin/python # radio.py # January 23, 2013 # Written by Sheldon Hartling for Usual Panic. # MIT license, all text above must be included in any redistribution # # # based on code from Kyle Prier (http://wwww.youtube.com/meistervision) # and AdaFruit Industries (https://www.adafruit.com) # Kyle Prier - https://www.dropbox.com/s/w2y8xx7t6gkq8yz/radio.py # AdaFruit - https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git, Adafruit_CharLCD # # Define GPIO output pins for Radio Controls PIN_SW1_PREV = 18 PIN_SW2_NEXT = 4 # The Adafruit_CharLCD class controls the LCD display # using six GPIO output pins: # 25 = RS (register select) # 24 = E (enable/strobe) # 23 = Data bit 4 # 17 = Data bit 5 # 27 = Data bit 6 # 22 = Data bit 7 #dependancies from Adafruit_CharLCD import Adafruit_CharLCD from datetime import datetime from subprocess import * from time import sleep, strftime import RPi.GPIO as GPIO # globals LCD = Adafruit_CharLCD() PLAYLIST_MSG = [] STATION = 1 NUM_STATIONS = 0 def main(): global STATION, NUM_STATIONS, PLAYLIST_MSG # Stop music player output = run_cmd("mpc stop" ) # Setup GPIO GPIO.setmode(GPIO.BCM) # Use BCM GPIO numbers GPIO.setup(PIN_SW1_PREV, GPIO.IN) # Previous Channel button GPIO.setup(PIN_SW2_NEXT, GPIO.IN) # Next Channel button # Setup AdaFruit LCD LCD.begin(16,2) LCD.clear() # ---------------------------- # LOAD PLAYLIST OF STATIONS # ---------------------------- # Startup banner LCD.message('Welcome to\nSheldon Radio!') # Run shell script to add all stations # to the MPC/MPD music player playlist output = run_cmd("/home/pi/projects/radio/radio_playlist.sh") # Load PLAYLIST_MSG list with open ("/home/pi/projects/radio/radio_playlist.sh", "r") as playlist: # Skip leading hash-bang line for line in playlist: if line[0:1] != '#!': break # Remaining comment lines are loaded for line in playlist: if line[0] == "#" : PLAYLIST_MSG.append(line.replace(r'\n','\n')[1:-1] + " ") playlist.close() sleep(1.5) NUM_STATIONS = len(PLAYLIST_MSG) # ---------------------------- # START THE MUSIC! # ---------------------------- # Start music player LCD.clear() LCD.message(PLAYLIST_MSG[STATION - 1] ) mpc_play(STATION) countdown_to_play = 0 # Main loop while True: press = read_switches() # PREV button pressed if(press == 1): STATION -= 1 if(STATION < 1): STATION = NUM_STATIONS LCD.setCursor(0,0) LCD.message(PLAYLIST_MSG[STATION - 1] ) # start play in 300msec unless another key pressed countdown_to_play = 3 # NEXT button pressed if(press == 2): STATION += 1 if(STATION > NUM_STATIONS): STATION = 1 LCD.setCursor(0,0) LCD.message(PLAYLIST_MSG[STATION - 1] ) # start play in 300msec unless another key pressed countdown_to_play = 3 # BOTH buttons pressed together if(press == 3): menu_pressed() # If we haven't had a key press in 300 msec # go ahead and issue the MPC command if(countdown_to_play > 0): countdown_to_play -= 1 if(countdown_to_play == 0): # Play requested station mpc_play(STATION) delay_milliseconds(100) def read_switches(): # Initialize got_prev = False got_next = False # Read switches sw1_prev = GPIO.input(PIN_SW1_PREV) sw2_next = GPIO.input(PIN_SW2_NEXT) # Debounce switches and look for two-button combo while(sw1_prev or sw2_next): if(sw1_prev): got_prev = True if(sw2_next): got_next = True delay_milliseconds(1) sw1_prev = GPIO.input(PIN_SW1_PREV) sw2_next = GPIO.input(PIN_SW2_NEXT) if(got_prev and got_next): return 3 if(got_next): return 2 if(got_prev): return 1 return 0 def delay_milliseconds(milliseconds): seconds = milliseconds / float(1000) # divide milliseconds by 1000 for seconds sleep(seconds) # ---------------------------- # RADIO SETUP MENU # ---------------------------- MENU_LIST = [ '1. Display Time \n & IP Address ', '2. Output Audio \n to HDMI ', '3. Output Audio \n to Headphones', '4. Auto Select \n Audio Output ', '5. System \n Shutdown! ', '6. Exit \n '] def menu_pressed(): global MENU_LIST item = 0 LCD.clear() LCD.message(MENU_LIST[item] ) keep_looping = True while (keep_looping): # Wait for a key press press = read_switches() # PREV button if(press == 1): item -= 1 if(item < 0): item = len(MENU_LIST) - 1 LCD.clear() LCD.message(MENU_LIST[item] ) # NEXT button elif(press == 2): item += 1 if(item >= len(MENU_LIST)): item = 0 LCD.clear() LCD.message(MENU_LIST[item] ) # BOTH buttons together, This is "Select" elif(press == 3): keep_looping = False # Take action if( item == 0): # display time and IP address display_ipaddr() elif(item == 1): # output to HDMI output = run_cmd("amixer -q cset numid=3 2") elif(item == 2): # output to headphone jack output = run_cmd("amixer -q cset numid=3 1") elif(item == 3): # output auto-select output = run_cmd("amixer -q cset numid=3 0") elif(item == 4): #shutdown the system output = run_cmd("mpc clear") output = run_cmd("sudo shutdown now") else: delay_milliseconds(100) # Restore display LCD.clear() LCD.message(PLAYLIST_MSG[STATION - 1] ) def display_ipaddr(): show_wlan0 = "ip addr show wlan0 | cut -d/ -f1 | awk '/inet/ {printf \"w%15.15s\", $2}'" show_eth0 = "ip addr show eth0 | cut -d/ -f1 | awk '/inet/ {printf \"e%15.15s\", $2}'" ipaddr = run_cmd(show_eth0) if ipaddr == "": ipaddr = run_cmd(show_wlan0) i = 0 keep_looping = True while (keep_looping): # Every second, update the time display i += 1 if(i % 10 == 0): LCD.setCursor(0,0) LCD.message(datetime.now().strftime('%b %d %H:%M:%S\n')) LCD.message(ipaddr) #LCD.message('e%15.15s' % ( ipaddr ) ) # Every 3 seconds, update ethernet or wi-fi IP address if(i == 60): ipaddr = run_cmd(show_eth0) i = 0 elif(i == 30): ipaddr = run_cmd(show_wlan0) # Every 100 milliseconds, read the switches press = read_switches() if(press == 3): keep_looping = False delay_milliseconds(99) def run_cmd(cmd): p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT) output = p.communicate()[0] return output def run_cmd_nowait(cmd): pid = Popen(cmd, shell=True, stdout=NONE, stderr=STDOUT).pid def mpc_play(STATION): pid = Popen(["/usr/bin/mpc", "play", '%d' % ( STATION )]).pid if __name__ == '__main__': main()
The Radio Play List
The radio play list / channel line-up is loaded dynamically from a file called radio_playlist.sh. This file is processed twice by the radio.py program: the first time it is executed as a shell script; and the second time it is read as a text file to load the channel display names.
Here’s the sample file I used in my video …
#! /bin/sh mpc clear 1>/dev/null #1 SomaFM, Lush \nfemale vocals mpc add http://mp1.somafm.com:8800 #2 CHFX Halifax \ncountry mpc add mms://ysj00ms01s0.aliant.net/CHFX #3 CJCB Sydney \ncountry mpc add mms://ysj00ms01s0.aliant.net/CJCB #4 CHNS Halifax \nclassic rock mpc add mms://ysj00ms01s0.aliant.net/CHNS #5 CFQM Moncton \nadult Contempora mpc add mms://ysj00ms01s0.aliant.net/CFQM #6 CBD St John \npublic radio mpc add mms://ysj00ms01s0.aliant.net/CBD #7 CJYC St John \nclassic rock mpc add mms://ysj00ms01s0.aliant.net/CJYC #8 CFCY CharTown \ncountry mpc add mms://ysj00ms01s0.aliant.net/CFCY #9 CHLQ ChrlTown \nhot AC mpc add mms://ysj00ms01s0.aliant.net/CHLQ #10 CHTN ChrlTown\nclassic hits mpc add mms://ysj00ms01s0.aliant.net/CHTN #11 CJRW ChrlTown\nclassic rock mpc add mms://ysj00ms01s0.aliant.net/CJRW #12 CBC Halifax \nradio 2 mpc add http://3143.live.streamtheworld.com:80/CBC_R2_HFX_H_SC #13 CFMJ Toronto \ntalk radio mpc add http://208.92.54.5:80/CFMJAMAAC_SC #14 CBC Halifax \nradio 1 mpc add http://3383.live.streamtheworld.com:80/CBC_R1_HFX_H_SC
Next Up …
Radio Pi Plate. A Raspberry Pi Internet Radio that uses Adafruit’s RGB Negative 16×2 LCD+Keypad Kit for Raspberry Pi pi plate. (coming soon)

Here’s something that might interest you as food for thought on this project:
https://www.flickr.com/photos/deusx/8747957195/in/photostream/
That’s a hack I did on top of the Adafruit LCD class, which lets me use only 3 GPIO pins to drive the LCD (not counting power & ground). I’m thinking I might try building an internet radio like this, but add a few more buttons and possibly some more blinking lights & maybe change colors on the RGB backlight
I am new to the raspberry pi and python programming. lcd and buttons all setup and working. installed mpc mpd tested and working with playlist. try the radio player code above keep getting errors.
File “radio.py”, line 292, in
main()
File “radio.py”, line 92, in main
LCD.message(PLAYLIST_MSG[STATION – 1] )
IndexError: list index out of range
can you help thanks.
any help greatly appreciated as I would like to learn
Hi Ben
The radio_playlist.sh file is executed as a Linux command script. Please make sure:
(a) you have execute permissions on your playlist file (a “chmod 775 radio_playlist.sh” should do it);
(b) that it is a properly formatted command script; and
(c) that it has UNIX line terminators and not Windows/DOS line terminators (LF and not CRLF).
Try running radio_playlist.sh from a terminal command line to see if you have it right. You can end up with the wrong line terminators if you SFTP the file from Windows to Linux as a “text” file and not as a “binary” file.
Hope this helps. Good luck with your project,
Sheldon
I notice 2 resistors on the breadboard, are they in use? Could you give more information on those please?
These are 10K ohm pull-down resisters used for the Previous and Next switches. Each resister is connected between ground and one end of a SPST switch. The other side of each switch is tied to 3.3V and also to one of the Raspberry Pi’s GPIO input connections; pin 18 for the previous switch; and pin 4 for next switch.
I tried this and having two distinct problems. The first us that no matter what I cannot get the playlist to load. And the second that even without being connected its acting as if the push buttons are being pressed in a random sequence. Any thoughts?
Hi Bryan,
1. The Playlist.
What permissions do you have on the file? Remember that it is run as a Linux shell command; so you’ll need execute permissions. What happens when you try to run it from a SSH session? A chmod 775 on the radio_playlist.sh file may help.
2. The switches.
How do you have the switches wired? I used 10Kohm pull-down resisters. Each resister is connected between ground and one end of a switch. The other side of each switch is tied to 3.3V and also to one of the Raspberry Pi’s GPIO input connections; pin 18 for the previous switch; and pin 4 for next switch.
Good luck,
Sheldon
I’ll try the permissions settings. That may help. Thank you.
In regards to the switches – I had them wired this exact same way when I got this result. Curiously, I get the same result even when I physically disconnect from 4 and 18. Could it be something in RPi.GPIO that’s sending a false positive to the Pins?
Hello!
I have got everything to work with some modifications.
But I get no sound out of the speakers!
I have tried but I can not think of anything that can help me.
The components I have are:
Raspberry Pi mod: B, 512 Kb
Adafruit Blue & White 16×2 LCD + Keypad.
Computer speakers.
If I write from SSH:
MPC add …………………..
MPC play
Then the sound works but not via the python program.
This is a fantastic program that I really want to get to work!
Please, someone help me!
Hi Dennis
It sounds like the file protection might be wrong on the playlist file. Remember the radio_playlist.sh file is run as a Linux shell command so you’ll need execute permissions. What happens if you run your radio_playlist.sh script from SSH?
I’ve emailed a copy of the files I used.
Good luck with your project!
Sheldon
Pingback: 「Raspberry Pi(ラズベリー・パイ)」について知っておくべきこと | ReadWrite Japan
usualpanic.com参照していただきありがとうございます
Sheldon