Adafruit LCD Pi Plate Rocks!
The RGB 16×2 LCD+Keypad Pi Plate from Adafruit Industries makes a great addition to an Internet radio project. This little circuit board makes it easy to add an LCD display and numeric keypad to a Raspberry Pi.
One of the neat things about this board is that it uses only two pins on the R-Pi GPIO header to control: the 16×2 Character LCD; up to 3 backlight pins; and 5 keypad buttons. It uses an MCP23017-E/SP I2C port expander chip to make this happen.
The best part is you don’t really lose those two pins either, since you can still add I2C based sensors, RTCs, etc and have them share the I2C bus.
In this post, we update our original Raspberry Pi Internet Radio project using this cool Pi Plate. Our new radio shares many of the features of the original radio and adds: compact size; a color-changing LCD display; and more buttons for an improved user interface.
The Software
Once again, we’re using the Adafruit Occidentalis Linux distribution for the R-Pi. Three python classes from Adafruit handle all of the heavy-lifting for the LCD display, I2C bus, and MCP23017 port expander. We did have to make a few small changes to the Adafruit python classes to allow us to read all the buttons at once. You’ll find the details below.
Programming this beauty turned out to be a little trickier than the previous radio. The Pi Plate uses a serial interface to the R-Pi that’s quite a bit slower than a directly connected LCD. Polling for button changes in the same loop that handles the LCD made the buttons feel somewhat unresponsive. The solution was to move the LCD display to a separate worker thread and to use a Python queue to pass update messages. You’ll see the details in the source code below.
Parts
To build this project, I used:
- Raspberry Pi, model B;
- Adafruit Pi Box enclosure;
- Edimax WiFi dongle;
- Adafruit RGB Negative 16×2 LCD+Keypad Kit for Raspberry Pi
- 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 14-minute YouTube video that describes the radio in detail and demonstrates many of its features, including:
- the multi-color LCD display;
- key pad controls;
- volume control;
- menu system; and
- loadable playlist.
The Python Source Code
The source code for this project is in one file called radio.py, version 2.1.
#!/usr/bin/python # radio.py, version 2.1 (RGB LCD Pi Plate version) # February 17, 2013 # Written by Sheldon Hartling for Usual Panic # BSD 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_CharLCDPlate # #dependancies from Adafruit_I2C import Adafruit_I2C from Adafruit_MCP230xx import Adafruit_MCP230XX from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate from datetime import datetime from subprocess import * from time import sleep, strftime from Queue import Queue from threading import Thread import smbus # initialize the LCD plate # use busnum = 0 for raspi version 1 (256MB) # and busnum = 1 for raspi version 2 (512MB) LCD = Adafruit_CharLCDPlate(busnum = 1) # Define a queue to communicate with worker thread LCD_QUEUE = Queue() # Globals PLAYLIST_MSG = [] STATION = 1 NUM_STATIONS = 0 # Buttons NONE = 0x00 SELECT = 0x01 RIGHT = 0x02 DOWN = 0x04 UP = 0x08 LEFT = 0x10 UP_AND_DOWN = 0x0C LEFT_AND_RIGHT = 0x12 # ---------------------------- # WORKER THREAD # ---------------------------- # Define a function to run in the worker thread def update_lcd(q): while True: msg = q.get() # if we're falling behind, skip some LCD updates while not q.empty(): q.task_done() msg = q.get() LCD.setCursor(0,0) LCD.message(msg) q.task_done() return # ---------------------------- # MAIN LOOP # ---------------------------- def main(): global STATION, NUM_STATIONS, PLAYLIST_MSG # Stop music player output = run_cmd("mpc stop" ) # Setup AdaFruit LCD Plate LCD.begin(16,2) LCD.clear() LCD.backlight(LCD.VIOLET) # Create the worker thread and make it a daemon worker = Thread(target=update_lcd, args=(LCD_QUEUE,)) worker.setDaemon(True) worker.start() # Display startup banner LCD_QUEUE.put('Welcome to\nUsualPanic Radio', True) # Load our station playlist load_playlist() sleep(2) LCD.clear() # ---------------------------- # START THE MUSIC! # ---------------------------- # Start music player LCD_QUEUE.put(PLAYLIST_MSG[STATION - 1], True) run_cmd("mpc volume +100") mpc_play(STATION) countdown_to_play = 0 # Main loop while True: press = read_buttons() # LEFT button pressed if(press == LEFT): STATION -= 1 if(STATION < 1): STATION = NUM_STATIONS LCD_QUEUE.put(PLAYLIST_MSG[STATION - 1], True) # start play in 300msec unless another key pressed countdown_to_play = 3 # RIGHT button pressed if(press == RIGHT): STATION += 1 if(STATION > NUM_STATIONS): STATION = 1 LCD_QUEUE.put(PLAYLIST_MSG[STATION - 1], True) # start play in 300msec unless another key pressed countdown_to_play = 3 # UP button pressed if(press == UP): output = run_cmd("mpc volume +2") # DOWN button pressed if(press == DOWN): output = run_cmd("mpc volume -2") # SELECT button pressed if(press == SELECT): 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(99) update_lcd.join() # ---------------------------- # READ SWITCHES # ---------------------------- def read_buttons(): buttons = LCD.readButtons() # Debounce push buttons if(buttons != 0): while(LCD.readButtons() != 0): delay_milliseconds(1) return buttons def delay_milliseconds(milliseconds): seconds = milliseconds / float(1000) # divide milliseconds by 1000 for seconds sleep(seconds) # ---------------------------- # LOAD PLAYLIST OF STATIONS # ---------------------------- def load_playlist(): global STATION, NUM_STATIONS, PLAYLIST_MSG # Run shell script to add all stations # to the MPC/MPD music player playlist output = run_cmd("mpc clear") output = run_cmd("/home/pi/projects/radio/radio_playlist.sh") # Load PLAYLIST_MSG list PLAYLIST_MSG = [] 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() NUM_STATIONS = len(PLAYLIST_MSG) # ---------------------------- # RADIO SETUP MENU # ---------------------------- def menu_pressed(): global STATION 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. Reload \n Playlist File', '6. System \n Shutdown! ', '7. Exit \n '] item = 0 LCD.clear() LCD.backlight(LCD.YELLOW) LCD_QUEUE.put(MENU_LIST[item], True) keep_looping = True while (keep_looping): # Wait for a key press press = read_buttons() # UP button if(press == UP): item -= 1 if(item < 0): item = len(MENU_LIST) - 1 LCD_QUEUE.put(MENU_LIST[item], True) # DOWN button elif(press == DOWN): item += 1 if(item >= len(MENU_LIST)): item = 0 LCD_QUEUE.put(MENU_LIST[item], True) # SELECT button = exit elif(press == SELECT): keep_looping = False # Take action if( item == 0): # 1. display time and IP address display_ipaddr() elif(item == 1): # 2. audio output to HDMI output = run_cmd("amixer -q cset numid=3 2") elif(item == 2): # 3. audio output to headphone jack output = run_cmd("amixer -q cset numid=3 1") elif(item == 3): # 4. audio output auto-select output = run_cmd("amixer -q cset numid=3 0") elif(item == 4): # 5. reload our station playlist LCD_QUEUE.put("Reloading\nPlaylist File...", True) load_playlist() sleep(2) STATION = 1 LCD_QUEUE.put(PLAYLIST_MSG[STATION - 1], True) mpc_play(STATION) elif(item == 5): # 6. shutdown the system LCD_QUEUE.put('Shutting down\nLinux now! ... ', True) LCD_QUEUE.join() output = run_cmd("mpc clear") output = run_cmd("sudo shutdown now") LCD.clear() LCD.backlight(LCD.OFF) exit(0) else: delay_milliseconds(99) # Restore display LCD.backlight(LCD.VIOLET) LCD_QUEUE.put(PLAYLIST_MSG[STATION - 1], True) # ---------------------------- # DISPLAY TIME AND IP ADDRESS # ---------------------------- 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) LCD.backlight(LCD.VIOLET) i = 29 muting = False keep_looping = True while (keep_looping): # Every 1/2 second, update the time display i += 1 #if(i % 10 == 0): if(i % 5 == 0): LCD_QUEUE.put(datetime.now().strftime('%b %d %H:%M:%S\n')+ ipaddr, True) # 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_buttons() # Take action on switch press # UP button pressed if(press == UP): output = run_cmd("mpc volume +2") # DOWN button pressed if(press == DOWN): output = run_cmd("mpc volume -2") # SELECT button = exit if(press == SELECT): keep_looping = False # LEFT or RIGHT toggles mute elif(press == LEFT or press == RIGHT ): if muting: #amixer command not working, can't use next line #output = run_cmd("amixer -q cset numid=2 1") mpc_play(STATION) # work around a problem. Play always starts at full volume delay_milliseconds(400) output = run_cmd("mpc volume +2") output = run_cmd("mpc volume -2") else: #amixer command not working, can't use next line #output = run_cmd("amixer -q cset numid=2 0") output = run_cmd("mpc stop" ) muting = not muting 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()
Modifying the Adafruit Python Classes
We made a few small changes to the Adafruit Python classes to allow us to read all the buttons at once. To implement these changes, you’ll need to add the following code.
Add this new method to the Adafruit_CharLCDPlate.py class; and
def readButtons(self): return self.mcp.input_all()
Add this new method to the Adafruit_MCP230xx.py class.
def input_all(self): """ return all 5 switches, as a bitmap """ assert self.num_gpios >= 16, "16bits required" return 0x1f ^ ( self.i2c.readU8(MCP23017_GPIOA) & 0x1F )
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.
Don’t forget to change the Linux file permissions on this file to allow execute access.
> chmod 775 radio_playlist.sh
Here’s the sample file I used in my video …
#! /bin/sh #1 WOLF Seattle \ncountry mpc add http://7279.live.streamtheworld.com:80/KKWFFMAAC_SC #2 CHFX Halifax \ncountry mpc add mms://ysj00ms01s0.aliant.net/CHFX #3 CJCB Sydney \ncountry mpc add mms://ysj00ms01s0.aliant.net/CJCB #4 CFCY CharTown \ncountry mpc add mms://ysj00ms01s0.aliant.net/CFCY #5 SomaFM, Lush \nfemale vocals mpc add http://mp1.somafm.com:8800 #6 CHNS Halifax \nclassic rock mpc add mms://ysj00ms01s0.aliant.net/CHNS #7 CFQM Moncton \nadult contempory mpc add mms://ysj00ms01s0.aliant.net/CFQM #8 CBD St John \npublic radio mpc add mms://ysj00ms01s0.aliant.net/CBD #9 CJYC St John \nclassic rock mpc add mms://ysj00ms01s0.aliant.net/CJYC #10 CHLQ ChrlTown \nhot AC mpc add mms://ysj00ms01s0.aliant.net/CHLQ #11 CHTN ChrlTown\nclassic hits mpc add mms://ysj00ms01s0.aliant.net/CHTN #12 CJRW ChrlTown\nclassic rock mpc add mms://ysj00ms01s0.aliant.net/CJRW #13 CBC Halifax \nradio 2 mpc add http://3143.live.streamtheworld.com:80/CBC_R2_HFX_H_SC #14 BBC London UK\nradio 1 mpc add "mms://wmlive-nonacl.bbc.net.uk/wms/bbc_ami/radio1/radio1_bb_live_int_ep1_sl0?BBC-UID=349e068f3a2633271418974ca119245ef80d149440d04184c40fc9b78246568b&SSO2-UID=" #15 CBC Halifax \nradio 1 mpc add http://3383.live.streamtheworld.com:80/CBC_R1_HFX_H_SC
This is perfect.
I had been struggling with my own program to do exactly this with no python or programming skills – managed to get mine working but no were as functional or nice as yours. (i did use Mplayer not MPC, as I could not get bbc live radio to work with MPC)
But I am having one problem with your script.
LCD.readButtons – I get an error, that doesn’t exist at all in my Adafruit_CharLCDPlate .py typed to change it to LCD.buttonPressed but doesnt seem that simple.
Are you using an old GIT version of CharLCDPlate or is there something else i am missing?
Hope you can help – your program would get me a home run with the wife!
Cheers
Hi “Tangoman”
Great catch! My apologies, I wrote this code months ago and forgot that I had to modify the Adafruit classes. I’ve added the details to the post. Good luck with your project and the “home run”!
Could you please send me the updates to the adafruit class files.
The radio iscurrently playing on the first channel but the buttons are not working. The LCD test does indicate they are functional.
I saw someone else whose similar problem was solved with the 3 new files.
Thanks, Gary
Hi Sheldon,
Thanks for a great project.
I have tried to duplicate your Pi Plate radio.I have been able to get
to the point where the radio is functioning with the first station loaded
and displayed on the LCD. My remaining problem relates to the push buttons; I can’t get them to work. Do you have a working radio.py and
the associated Adafruit files? If you can send me a set of working files
for the Pi Plate radio I would be grateful. I am new to python and trying
to learn.
Regards,
Lionel
All working perfectly – it’s great!
I am just looking around now to see what case i can put it all into – but this saved me heaps of time on the programming side of things.
All credit and kudos to usualpanic.
Hi ,
I am having problems getting my push buttons to work. Could I get
a copy of you script? I have see other posts relating to this issue by
still unable to solve the problem.
Thanks
Hi Lionel
I emailed a copy of the files you requested.
Good luck with your project!
Sheldon
Two interesting addon projects would be to add a FM transmitter and FM tuner that use I2C:
FM Transmitter: https://www.sparkfun.com/products/8482
FM Tuner: https://www.sparkfun.com/products/11083
The Halifax stations caught my eye because I work in halifax, Nova Scotia. Most of the posts are from the US. Cool.
A great little radio project using the raspberry pi and Adafruit’s nice RGB Character lcd plate!
A big thanks to Sheldon for his help in obtaining the original class files for this project.
Works great! Nice Canadian Halifax Radio Stations to listen too!
Regards Barry
Hello,
I’m so sorry this nice application for my raspi v2 with the rgb-lcd-plate is not running here.
This are the error messages:
Traceback (most recent call last):
File “/home/pi/radio/radio.py”, line 356, in
main()
File “/home/pi/radio/radio.py”, line 109, in main
press = read_buttons()
File “/home/pi/radio/radio.py”, line 159, in read_buttons
buttons = LCD.readButtons()
File “/home/pi/radio/Adafruit_CharLCDPlate.py”, line 82, in readButtons
return self.mcp.input_all()
AttributeError: Adafruit_CharLCDPlate instance has no attribute ‘mcp’
Changes to the latest Adafruit Python classes are made
Music is playing and station info is displayed on lcd but the buttons are not functioning.
Hoping if there is any help possible
Olaf
Hi can you send me the Adafruit classes ?
regards
Done.
Hi,
I like your project, but ‘m a bit stuck with the library files, would you mind sending them to me?
Thanks in advance.
Files are on the way. Good luck with your project!
Dear Sheldon,
Can you please send me the library files?
Many thanks
Luca
Done!
Good luck with your project,
Sheldon
The versions of the Adafruit classes available via Git (as of July 2) don’t work with the current version of radio.py. (The buttons won’t respond) Replacing the new Adafruit files with the three that Sheldon has used instantly resolves the issue. Ask Sheldon to send you the zip of his versions after you’ve used LCDtest.py to confirm that all buttons on your plate are working correctly. Otherwise, this is a great project. Now I have to buy another Pi to play with, this one is now my Internet Radio. Thanks, Sheldon
Thanks for your help Sheldon. Your files correct installed made the succes.
Regards
Olaf
Greetings,
I built the adafruit plate /lcd and load os v2 and used Bob Rathbone pi radio software – it works perfect.
However, I like your menu layouts better.
I followed your tutorial but am have some problems.
I suspect, it is because i did not put the changes in the correct location.
Exactly where do I put the changes for:
Adafruit_CharLCDPlate.py class
and
Adafruit_MCP230xx.py
Thanks for the great article, looking forward to getting it running
Joe
Thanks for the work on this. I’ve been looking for a project of interest to dabble in python on the RPi.
I’m getting the following error when I try to run. I’ve reloaded everything and applied the mods as described, but I’m still getting the same error. I’m wondering if something is out-of-date.
Thanks,
erf
> sudo python radio.py
Traceback (most recent call last):
File “radio.py”, line 377, in
main()
File “radio.py”, line 115, in main
press = read_buttons()
File “radio.py”, line 165, in read_buttons
buttons = LCD.readButtons()
File “/home/pi/radio2/Adafruit_CharLCDPlate.py”, line 76, in readButtons
return self.mcp.input_all()
AttributeError: Adafruit_CharLCDPlate instance has no attribute ‘mcp’
http://mp1.somafm.com:8800
[playing] #1/4 0:00/0:00 (0%)
volume: 0% repeat: off random: off single: off consume: off
The LCD plate version is working nicely now. To eliminate pops when changing streams, install and configure PulseAudio following the directions in the link below. No changes to Sheldon’s instructions are required, but the pops are gone after the change.
http://dbader.org/blog/crackle-free-audio-on-the-raspberry-pi-with-mpd-and-pulseaudio
Thanks Kit for the “PulseAudio” work-around. I haven’t personally experienced the crackling and popping noises when changing streams. I’m using Occidentalis v0.2.
For those of you having problems with the latest versions of the Adafruit classes, you can work around them by replacing “LCD.readButtons()” with “LCD.buttons()” in lines 165 and 169 of radio.py
Adafruit has rewritten the CharLCDPlate and I2C classes and done a kick-ass job of speeding things up. My modifications to these classes are no longer required!
I’ll be updating this blog entry in the next few days with a new version of radio.py designed to work with the updated Adafruit classes.
Sheldon
Thanks for the info on what needs to be changed, I’m looking forward to the updated blog entry. Have you added any more features? This was my first project with the Pi. I learned how to solder and now learning python due to this project. Thanks for making it possible.
Thanks very much for your detailed overview on how you got this running. I think I am close to success but I am getting the following error when kicking off with ‘sudo python radio.py’. Any suggestions?
Traceback (most recent call last):
File “radio.py”, line 377, in
main()
File “radio.py”, line 110, in main
mpc_play(STATION)
File “radio.py”, line 372, in mpc_play
pid = Popen([“/usr/bin/mpc”, “play”, ‘%d’ % ( STATION )]).pid
File “/usr/lib/python2.7/subprocess.py”, line 679, in __init__
errread, errwrite)
File “/usr/lib/python2.7/subprocess.py”, line 1259, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Sorry if I’m missing an obvious issue but I am new to python so trying to figure this out.
You’ll need the Music Player Daemon (MPD) installed on your R-pi. To install it …
1. Update raspian/occidentalis to the latest packages
$ sudo apt-get update
2. Then install the mpd / mpc packages
$ sudo apt-get install mpc mpd
This will install the Music Player Daemon (mpd) and it’s client mpc.
Good luck with your project!
Addition of mpc/mpd solved it. Thanks Sheldon!
Hi sorry for what is probably a very simple question, but I’m very new to linux/python etc.
How do I get the radio.py script to run on startup?
I googled around and some people were suggesting putting things in the rc.local file but so far I haven’t been able to get it to work.
Thanks in advance
Hi Dave
I use a startup script in the /etc/init.d directory that I registered using the update-rc.d command. I’ll send you more detail and a copy of the script in an email.
Good luck with your project!
Sheldon
Great tutorial! I have only one problem from getting it to work and that is this:
Traceback (most recent call last):
File “./radio.py”, line 218, in
main()
File “./radio.py”, line 115, in main
press = read_buttons()
File “./radio.py”, line 157, in read_buttons
buttons = LCD.Buttons()
AttributeError: Adafruit_CharLCDPlate instance has no attribute ‘Buttons’
Thanks
Please try LCD.buttons() instead of LCD.Buttons().
Thanks and good luck with your project,
Sheldon
Hi!
Great script! Please tell me, how you starting up this script with system for embedded use, w/o monitor etc.
Thank you for help!
Hi ld
I created an initialization script called “radio” and placed it in the /etc/init.d directory; and then I registered it to be run at start-up and shutdown using using update-rc.d.
Hi everyone
I’m pretty sure i have installed every thing as i should of done. I have run LCDtest.py and Adafruit_CharLCDPlate.py and the screen and buttons all seem to be working all ok. But i get this error message when attempting to run radio.py.
“Traceback (most recent call last):
File “radio.py”, line 31, in
LCD = Adafruit_CharLCDPlate(busnum = 1)
File “/home/pi/Projects/Radio/Adafruit_CharLCDPlate.py”, line 94, in __init__
self.i2c.address, self.MCP23017_IOCON_BANK1, 0)
IOError: [Errno 5] Input/output error”
Anybody got any ideas I’m very new to all this lol
Thanks in advance.
Not to worry i have slept on it and figured it out lol
Cheers for the great script
Hi Sheldon,
Can I also have the script to launch the radio.py on boot?
I tried creating a boot file in init.d but that seems to wipe the radio_playlist.sh…
Thanks,
Sander
Hi Sander
I emailed you a copy of the “radio” script I use in /etc/init.d to run the program automatically on start-up. When I get a chance, I’ll update this post to add a section on starting the program automatically.
Sheldon
hi, Sheldon
I have these errors, I have sound and I change up /down volume but I don’t have a display and left /right give me these error can you help.
$ sudo python radio.py
mms://ysj00ms01s0.aliant.net/CHFX
[playing] #1/15 0:00/0:00 (0%)
volume:100% repeat: off random: off single: off consume: off
Traceback (most recent call last):
File “radio.py”, line 377, in
main()
File “radio.py”, line 122, in main
LCD_QUEUE.put(PLAYLIST_MSG[STATION – 1], True)
IndexError: list index out of range
regard´s
Manuel
Hi Manuel
I suspect a possible problem with your radio_playlist.sh file. I emailed a ZIP archive with all of the files I used. Please try the radio_playlist.sh file from this ZIP as a replacement for yours to see if it helps. Also, remember the radio_playlist.sh file is run as a Linux shell command so you’ll need to set execute permissions.
Sheldon
hi ,Sheldon
it´s work very god ,
and yes the problem was in the file radio_playlist.sh ,i changed by your file and now everything works 100%
can I also have the script to launch the radio.py on boot ! ,I already tried all ways and I can not do boot .
thanks for your great project .
best regard´s
Manuel
Hi Sheldon
Great work I’ve got my radio working a treat using your code.
I was just wondering if there was any way of adding some code in so that the station info (i.e. what song is playing) can be scrolling on the second line of the LCD screen. I do not have a clue where to start or if its even possible.
Cheers
Joel
Hello Sheldon,
Sorry, another nooby here, I also cannot get the radio working, I have made the changes that you have posted to the Adafruit_*.pi files but still no luck.
Here are the error reports:
Traceback (most recent call last):
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
Traceback (most recent call last):
File “LCDtest.py”, line 4, in
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate
File “/home/pi/projects/radio/Adafruit_CharLCDPlate.py”, line 11, in
from Adafruit_I2C import Adafruit_I2C
ImportError: No module named Adafruit_I2C
This is my first R-Pi project and don’t know if it’s something I am doing wrong.
Can you help?
Thanks
Best regards
Tony
Great Project. Newbie at this (still learning at 61!).Have got LCD display and buttons all working OK. However no music output and following error message when selecting a station:- “song number greater than playlist length”
Any help you can give me would be much appreciated.
Best Regards
John
Hello Sheldon,
Thanks for the files, everything ‘appears’ to be working but I have the same problem as John Matthews, No Sound!
Any ideas?
Best regards
Tony
Hi Tony
If you’re seeing the “song number greater than playlist length” error check to make sure you have execute permissions on your playlist file. A “chmod 775 radio_playlist.sh” should do it.
Best regards,
Sheldon
Hi!
Like this project, but get this result.
Traceback (most recent call last):
File “radio.py”, line 17, in
from Adafruit_I2C import Adafruit_I2C
ImportError: No module named Adafruit_I2C
I have Occidentalis as OS, I’ve cloned the library files needed from Adafruit.
When looking in the map Adafruit-Raspberry-Pi-Python-Code, everything supposted to be there is there…
What have I done wrong, please help me!?
//Hans
Hi Hans
Please make sure your Adafruit_CharLCDPlate.py, Adafruit_I2C.py and Adafruit_MCP230xx.py files are in the same directory as your radio.py file.
Good luck,
Sheldon
I have the same problem with “song number greater than playlist” and I changed permissions to 775. I even tried 777 and I get the same error. Thanks for the help.
Mark
Hi Mark
Try running “sudo radio_playlist.sh” as a Linux terminal command to see if the shell script will run okay by itself. I sent you an email with a zip archive containing the files I used for comparison to your playlist.
Good luck,
Sheldon
I found that I had to change the absolute reference to the location of radio_playlist.sh on lines 133 and 136 of radio.py from
“/home/pi/projects/radio/radio_playlist.sh” to its location on my system to make the “song number greater than playlist length” error go away.
Thanks! Great project!
(Now if only I could be sure that I really soldered the pi plate together properly… display is a little flaky — I am afraid to push any buttons for fear of disturbing it….)
Hi sheldon
Great job! The script is working like a charm.
Could you please send me the startup script to run it automaticly?
And an other question.
Is it possible to use the second line of the display to show the titel information?
And if the answer is yes how do i make it working?
kind regards
Andy
Thanks, Andy
I emailed a copy of my start-up script to you.
A second line display of title information is on my list for a version 2.
Best regards,
Sheldon
Hi Sheldon,
Great script! I’m new to python but this has inspired me to delve in & get learning!
I’ve added a slight mod in that I’ve got Airpi (http://trouch.com/2012/08/03/airpi-airplay-audio-with-raspberry/) running on my pi as well.
I’ve added a new function:
—————————-
# CHECK FOR AIRPLAY
# —————————-
def check_airplay():
netstat = subprocess.Popen(“sudo /bin/netstat -t”.split(), stdout=subprocess.PIPE).stdout
grep = subprocess.Popen([“/bin/grep”, “rfe”], stdin=netstat, stdout=subprocess.PIPE).stdout
grepout = grep.read().split(“\n”)
vals = map(string.strip, grepout[0].split())
if ‘raspberrypi.local:rfe’ in vals:
# Start Airplay mode
LCD.clear()
LCD.backlight(LCD.GREEN)
LCD_QUEUE.put(‘Airplay Mode \n Airpi ‘, True)
LCD_QUEUE.join()
output = run_cmd(“mpc pause -q”)
else:
output = run_cmd(“mpc play -q”)
That actively checks for airplay connections and pauses mpc if one is detected… the else needs some work with intelligence around if mpc is actually already playing…..
I’ve added this at the start of the main loop straight after read_buttons… and I’ve got unresponsive buttons, similiar to what you had before adafruit re-worked their code.
Trying to optimise this but enjoying the challenge.
Thanks.
Love this I have been using a RPI as a internet radio using ssh or ampache to listen to radio for a while this is a great improvement in that I do not need another device to control it. Only thing I would change and my do some research on doing is getting the stream data to post up on an update from mpd through an mpc command or “watch -n 1 mpc” which I use in ssh to see whats playing on the streams that update for each song. I do not know python but it looks like its approachable with the very basic programming knowledge that I have.
which gives you this for SOG:
South of Gilman St.: Dead Kennedys – I Fought The Law
[playing] #4/14 33:12/0:00 (0%)
volume: 92% repeat: on random: off single: off consume: off
Nice work love it Thank You for sharing this!
Nick
Have got it scrolling through the menus, but am having the same problem of “song number greater than playlist length” error and no audio. Have tried to chmod the radio_playlist.sh file without any joy.
So close, but yet so far. : )
Thanks Sheldon
Cheers for the email and files along with the tips.
I think I was able to get it going by cleaning up the radio_playlist.sh. I think I must have picked up
and added some invisibles. I ran the script through a text cleaner as your script would run and mine wouldn’t.
Anyway after scrubbing my playlist to Unix format all is beautiful.
You are real gent.
Thanks again.
This gives you “mpc current” stream data where avalable with a quick double click of the select button, on menu item 1. with mute and volume
<
# —————————-
def menu_pressed():
global STATION
MENU_LIST = [
'1. Stream Data \n mpc current ',
'2. Output Audio \n to HDMI ',
'3. Output Audio \n to Headphones',
'4. Auto Select \n Audio Output ',
'5. Reload \n Playlist File',
'6. Display Time \n & IP Address ',
'7. System \n Shutdown! ',
'8. Exit \n ']
item = 0
LCD.clear()
LCD.backlight(LCD.YELLOW)
LCD_QUEUE.put(MENU_LIST[item], True)
keep_looping = True
while (keep_looping):
# Wait for a key press
press = read_buttons()
# UP button
if(press == UP):
item -= 1
if(item = len(MENU_LIST)):
item = 0
LCD_QUEUE.put(MENU_LIST[item], True)
# SELECT button = exit
elif(press == SELECT):
keep_looping = False
# Take action
if( item == 0):
# 1. mpc_data
mpc_current()
elif(item == 1):
# 2. audio output to HDMI
output = run_cmd(“amixer -q cset numid=3 2″)
elif(item == 2):
# 3. audio output to headphone jack
output = run_cmd(“amixer -q cset numid=3 1″)
elif(item == 3):
# 4. audio output auto-select
output = run_cmd(“amixer -q cset numid=3 0″)
elif(item == 4):
# 5. reload our station playlist
LCD_QUEUE.put(“Reloading\nPlaylist File…”, True)
load_playlist()
sleep(2)
STATION = 1
LCD_QUEUE.put(PLAYLIST_MSG[STATION – 1], True)
mpc_play(STATION)
elif(item == 5):
# 6. display time and IP address
display_ipaddr()
elif(item == 6):
# 7. shutdown the system
LCD_QUEUE.put(‘Shutting down\nLinux now! … ‘, True)
LCD_QUEUE.join()
output = run_cmd(“mpc clear”)
output = run_cmd(“sudo shutdown now”)
LCD.clear()
LCD.backlight(LCD.OFF)
exit(0)
else:
delay_milliseconds(99)
# Restore display
LCD.backlight(LCD.RED)
LCD_QUEUE.put(PLAYLIST_MSG[STATION – 1], True)
# —————————-
# ———————————–
# mpc data
# ———————————–
# read data from comand “mpc current”
# must add “import subprocess”
# ———————————–
def mpc_station():
mpc_data = subprocess.check_output([‘mpc’, ‘current’])
station = mpc_data[:mpc_data.rfind(“:”)]
print “station – ” + station
return station;
def mpc_song():
mpc_data = subprocess.check_output([‘mpc’, ‘current’])
mpc_data2 = mpc_data.rfind(“-“)
mpc_data3 = mpc_data.rfind(“\n”)
song = mpc_data[mpc_data2:mpc_data3]
print “song – ” + song
return song;
def mpc_artist():
mpc_data = subprocess.check_output([‘mpc’, ‘current’])
mpc_data1 = mpc_data.rfind(“:”) + 2
mpc_data2 = mpc_data.rfind(“-“)
artist = mpc_data[mpc_data1:mpc_data2]
print “artist – ” + artist
return artist;
# ———————————–
# ———————————–
# Display mpc current
# ———————————–
def mpc_current():
LCD.backlight(LCD.RED)
i = 29
muting = False
keep_looping = True
while (keep_looping):
i += 1
# # Every 3 seconds, update music data
if(i == 60):
LCD.clear()
LCD_QUEUE.put(mpc_station() + “\n” + mpc_artist())
i = 0
elif(i == 30):
song = mpc_song()
LCD.clear()
LCD_QUEUE.put(song[2:18] + “\n” + song[18:34])
# Every 100 milliseconds, read the switches
press = read_buttons()
# Take action on switch press
# UP button pressed
if(press == UP):
output = run_cmd(“mpc volume +2″)
# DOWN button pressed
if(press == DOWN):
output = run_cmd(“mpc volume -2″)
# SELECT button = exit
if(press == SELECT):
keep_looping = False
# LEFT or RIGHT toggles mute
elif(press == LEFT or press == RIGHT ):
if muting:
#amixer command not working, can’t use next line
#output = run_cmd(“amixer -q cset numid=2 1″)
mpc_play(STATION)
# work around a problem. Play always starts at full volume
delay_milliseconds(400)
output = run_cmd(“mpc volume +2″)
output = run_cmd(“mpc volume -2″)
else:
#amixer command not working, can’t use next line
#output = run_cmd(“amixer -q cset numid=2 0″)
output = run_cmd(“mpc stop” )
muting = not muting
delay_milliseconds(99)
# —————————-
>
Hi Nick,
thank you very much for your work. Would it be possibly that you paste your code on pastebin or so? Line intents
Additionally big thx to you Sheldon for sharing your code!
simon
Hello,
Would it be possible to have this code with good indentation python.
I suck at programming and I’m not really able to properly reformat the code.
In advance thank you.
Best regards
Jacky
Hi Jacky,
Files are on the way …
debug print not commented out in mpc data section it will output to console.
print “station – ” + station
print “song – ” + song
print “artist – ” + artist
got as far as this error:
AttributeError: Adafruit_CharLCDPlate instance has no attribute ‘mcp’
believe for reading comments need differant versions of files from GitHub
could you please email the file required
thanks for your work ans assistants
Jim
Hi Jim,
already read this comment by Sheldon:
For those of you having problems with the latest versions of the Adafruit classes, you can work around them by replacing “LCD.readButtons()” with “LCD.buttons()” in lines 165 and 169 of radio.py
Adafruit has rewritten the CharLCDPlate and I2C classes and done a kick-ass job of speeding things up. My modifications to these classes are no longer required!
Check that you are using the latest libraries from Adafruit…
cheers,
Simon
Sheldon,
Thanks the change to LCD.buttons was the solution.
I love the program
Gar
Great Gary!
Glad you found the comment on the change to LCD.buttons!
I have some plans for an improved version 2.0 but work commitments are keeping me away from the fun stuff at the moment.
All the best,
Sheldon
Sheldon,
Could I also request a copy of the startup script?
Thanks again, Gary
Email is on the way.
Hello,
how to create a menu item to change the color lcd?
Menu – LCD color change (up and down button – change colors, select – save color)
You write code?
Thank you.
Hey Sheldon,
Unfortunately it seems that the new Adafruit Python Classes are not working for me…
Could you please upload the classes you are using?
Keep on the great work!
Hey there, thanks for your great work!
Unfortunately it seems, that the new python classes from Adafruit aren’t working for me. Radio is starting and playing, but the buttons don’t work and the LCD is only showing the first radio station.
Could you please upload the python classes you are using?
Thanks in advance!
Nevermind! I found the fix in a comment of yours:
“by replacing “LCD.readButtons()” with “LCD.buttons()”
that was the fix! Thanks!
Sheldon, I’m having the same issues as some others with the ‘song number greater than playlist length’. Tried creating a new file, changing permissions and still not working. The rest of the radio.py and the LCD all work, and the titles under # in the playlist all work on the display and can be scrolled through. Any help or tips are appreciated, it’s a great project and I have it ‘almost’ working.
Hi all
First thing is to say thanks for all the comments, as it has solved sevral of my faults getting the wifi radio up and running..
Just to give an update on my headaches getting it working,
I started the radio project with the Pi Plate at the begining of december, and tried so many things to get it working, I could run the test program fine, but not the radio… nothing… just errors..
A big thanks to you lot and sevral errors later including the buttons error, it now works as far as the buttons and the display works fine.
But I get no sound…. (i have tried mpc add, and play, this works fine)
Now for the strange bit…
If i remove the hashbang ( #! /bin/sh ) at the begining of the playlist, it plays the first 3 tracks on the play list in any order, but not any more, unless I duplicate an entry at the end, and this one plays as well..??? (I didn’t think it would read the list correctly with out the hashbang …?? desperation….) I did set the file permissions correctly.
If I keep the hashbang I get the error “song number greater than playlist length.” (and no music)
Any ideas ……
Another thing I did wrong, was to de-crackle the audio by installing pulse audio, this worked ok but made it slugish, (this could have been due to the so many things I installed trying to get it to work)
I then read an update to reanable alsa and disable pulse audio and update the files and op system. (big mistake)
This took ages and then locked up…. on a reboot it had killed the boot elf.. a quick copy over from a backup and it was working.. sort of.
with lotts of errors.
So A wipe and reinstall, a quick reconfig and i’m back up and running in just over an hour, (pew)
I still have the same problems outlined earlyer.. (help)..
Any ideas, as this is driving me mad…
Cheers….
An update, I’ve had a play with the play list,
If I try to run it as a script as sugested earlyer I get the error “sudo: radio_playlist.sh : command not found”, (ls shows the file)
This is my play list, (partly modified from thr original)
#! /bin/sh
#1 Absolute 80’s \n 80’s Music
mpc add http://stream.timlradio.co.uk/ABSOLUTE80SIRMP3?ats=1
#2 Absolute 70’s \n 70’s Music
mpc add http://stream.timlradio.co.uk/ABSOLUTE70SIRMP3?ats=1
#3 Absolute 90’s \n 90’s Music
mpc add http://stream.timlradio.co.uk/ABSOLUTE90SIRMP3?ats=1
#4 Gem 106 \n Varied Music
mpc add http://stream2.radiomonitor.com:80/Gem-128
#5 Heart 100.7 \n Varied Music
mpc add http://ice-sov.musicradio.com:80/HeartPeterboroughMP3
#6 SomaFM, Lush \n female vocals
mpc add http://mp1.somafm.com:8800
#7 SOMA FM lush \n chillout
mpc add http://sfstream1.somafm.co.:8800
#8 KIIS-FM \n 102.7 Kiss FM
mpc add http://kiis-fm.akacast.akamaistream.net/7/572/1977…
Hi all
just to update readers,
Thanks to sheldon for his help I have got it up and running,
It turned out I had compiled the file in dos so had the wrong file extention type,
Once I had used the correct format it and worked fine..
Cheers and thanks to all…
Sheldon,
Many thanks for the code, all works great…………….Kinda.
Is it possible to get a copy of your startup script please?
At the moment if I start through putty everything works fine, all buttons work, but if I close my putty session the radio keeps playing but the buttons no longer work. Have I missed something?
Aidan
Hi Aidan
The thing you’re missing is an & at the end of your command line in putty. This will run the command as a background task that keeps running even after your putty session is closed.
I emailed a copy of the “radio” startup script I wrote and added to /etc/init.d to automatically start the radio program on startup.
Good luck with your project!
Sheldon
To start at boot this worked for me:
sudo crontab -e
Add at the bottom of the file or the location of your radio.py:
@reboot python /home/pi/projects/radio/radio.py &
Many compliments, it work perfectly. Please add to main page the “by replacing “LCD.readButtons()” with “LCD.buttons()”” mod.
I’ve some suggestions for V2:
-Add display of the song title on LCD (very important and useful for me!)
-Add change color option
-Add Sleep Timer, before shutdown the raspberry, for example 10,20,30,60,90 minutes
Thanks in advance
kind regards
Giorgio
Thanks for the great work, this a very nice script. I first started with a project from Bob Rathbone, but the pi-plate wasn’t responsive.
This code works great!
On an other blog i als found code for MPD with a Adafruit-pi-plate, and this has a scrolling text with song/artis information (@Giorgio)
http://didtheypush.blogspot.nl/2013/10/raspyfi-and-adafruit-16×2-char-lcd-plate.html
Is it possible to get a copy of your startup script?
THX
Harold
Thanks, Harold.
I’ve emailed you a copy of my startup script.
Here is a working example of MPC scrolling text not mine but could be good to look at in implementing it for those interested. If I have time to play I will be looking at it.
Doh! Scroll Song Info Link: http://didtheypush.blogspot.com/2013/10/raspyfi-and-adafruit-16×2-char-lcd-plate.html
Great post. I think the usage of threads/queues to delink the display from the reading of the buttons was a great enhancement over similar projects (I was using Adafruit’s Pandora radio – but am now sold on this).
The issues I faced were
1) The Adafruit_CharLCDPlate changes didn’t work. Then I read the posts below the main article and was able to fix it. Could I request that a note to that be put in the main article
2) The default raspbian install did not seem to have mpd/mpc which I fixed by an apt-get install. The article assumes an Occidentalis distrib.
The next thing for me is to box it up and use a single 5 way button like http://www.adafruit.com/products/504
Thanks, Rajaramani.
I haven’t had much time to spend on this – but I do have some big plans for a V2.0.
I’m building a vintage radio project around a 1940 Addison wooden tube radio using a combination of a RPi and an Arduino. The Arduino will drive an OLED display and include a rotary encoder for channel selection along with a micro-servo to move the old radio dial (just for fun). I’ve worked out the interrupt-driven encoder code and have some of the hardware built on a prototype board. … Figuring out where to cut the wooden case to add the OLED display will be next.
Sheldon
Hi Sheldon
Thanks for sharing your efforts with us. I have done everything except playing with class files and i’m still getting a
station on the lcd and buttons not working. Could you please send me the class files so I can give that a try.
Thanks for your time and consideration.
Bill
Hi Bill
I’ve emailed a copy of the files I used. Good luck with your project!
Sheldon
I’d love to see your observations on V2.0 once you finish. I’ll just be making minor mods to your code to make the following changes
(a) Have some config (or ini) file which keeps track of the volume / station # across a device reboot. Otherwise it always seems to come up at full volume on station 1.
(b) Add some optional extras like occasionally scrolling the current time on the screen, give a temp display etc.
Hi all,
Has anyone had a problem with the play list being jumbled / ignoring / or playing wrong station being displayed.
But ONLY when you reach channel 20 and plus stations.
All other work fine.
And another one,,,, slow password prompt when connecting using ssh, once connected its quick as before.
Any ideas…
Apart from these slight bugs I find the radio fantastic… I’ve even built a second one…
I recommend persevering on any problems as its well worth it…..
An update to my problems,
The play list not displaying or reading correctly was due to a typo (a , instead of a .) by me very early on in the listing, but didn’t show up till I had more than 20 entries… strange… But sorted..
Still having a 30 to 40 second delay from user name to pass word prompt when logging on to via http://ftp..
Many thanks as always to sheldon for all his help,
This project is now my main radio i tend to listen to, and I will be building a second..
Best use of a raspberry pi to date…
Hi Sheldon!
Great stuff if i get it up and running!
After a a while “try and fault” i´m at the end of my python knowing.
I cant resolve this error:
Traceback (most recent call last):
File “radio.py”, line 377, in
main()
File “radio.py”, line 115, in main
press = read_buttons()
File “radio.py”, line 165, in read_buttons
buttons = LCD.readbuttons()
AttributeError: Adafruit_CharLCDPlate instance has no attribute ‘readbuttons’
song number greater than playlist length.
volume: 0% repeat: off random: off single: off consume: off
And, if you can solve my problen, could you send me your startup schript?
With greetings from lower Austria and many thanks!
Karl
For those of you having problems with the latest versions of the Adafruit classes, you can work around them by replacing “LCD.readButtons()” with “LCD.buttons()” in lines 165 and 169 of radio.py
Adafruit has rewritten the CharLCDPlate and I2C classes and done a kick-ass job of speeding things up. My modifications to these classes are no longer required!
Karl, I’ve emailed a copy of my files to you.
Good luck with your project!
Sheldon
Hi I just found your page and bought the pi 512 and the LCD screen, i managed to make it display the left right up down slect etc..
However i could not download your file and install it… it says could not find file radio.py what i am doing wrong.
Please can you help me i am a newbie in linux and pi.
Thank you for your help.
Ray
Hi Ray
I tried to email a copy of my files to you, but your email bounced. Please contact me directly through the contact form and I’ll send you the files you need.
Good luck with your project!
Sheldon
I love this project, and I was very pleased to see it respond for the first time. I did, however, run into an error like one of your previous commenters. I have pasted the message I get below:
Traceback (most recent call last):
File “radio.py”, line 377, in
main()
File “radio.py”, line 115, in main
press = read_buttons()
File “radio.py”, line 165, in read_buttons
buttons = LCD.readButtons()
AttributeError: Adafruit_CharLCDPlate instance has no attribute ‘readButtons’
What do I need to do to fix this?
Thank you,
Mike
For those of you having problems with the latest versions of the Adafruit classes, you can work around them by replacing “LCD.readButtons()” with “LCD.buttons()” in lines 165 and 169 of radio.py
Adafruit has rewritten the CharLCDPlate and I2C classes and done a kick-ass job of speeding things up. My modifications to these classes are no longer required!
Mike, good luck with your project!
Sheldon
Very cool Sheldon, i do furniture restoration for a living and we get some interesting radios come through at times. I have played with my setup a little and added IrRemote and sleep timer function through the remote. I have not looked at keeping your playlist in line with MPC at all though. Remote just passes commands to MPC but in all reality it could pass the commands to the PiRadio to make a neater package. I am also using cron for my morning wake-up.
FYI: thanks for your work on this it is used daily and fully enjoyed.
Nick
Amazing job man, your scripts have traveled to France where I’ve successfully made it work almost out from the box, thanks to all the replyz !!
I’ve witnessed a weird thing though, the display keep some letters @ the end of the upper line …. is there a way to refresh the display ?
Thanks again for your great share !
John
Hi John
In your radio_playlist.sh file, pad out the first line with spaces to 16 characters. For example:
#1 CBC Halifax \nradio 2
and not
#1 CBC Halifax\nradio 2
Sheldon
Howdy,
Also, I’ve witnessed something else, the shutdown now command does not shut down the system actually it fails to do so … but with “init 0″ it works. ;o)
Hi Sheldon
Many thanks for all your help with the internet radio.
It has become one of my main audio units I listen to to pass the time.
I have been looking at your forum posts and came across this, http://didtheypush.blogspot.nl/2013/10/raspyfi-and-adafruit-16×2-char-lcd-plate.html
It utilises a scrolling text display from the station, which looks and is very useful as quite a few stations don’t ID or state what’s playing, as I have now got over 40 to go at.
What I would like to know is do you think it would be possible to just import just the scrolling info line to the second display line of your program , as I like your program layout and ease of use and don’t want to change that.
Ideas ???
Cheers
Dave…
Hi Dave,
Thanks for the link! I’ll have a look. Scrolling text display of current content on line 2 is one of the things I have planned for version 2.0.
Sheldon
Much appreciated,,,, I will look forward to the updated program,
It will put the cherry on the top of an already brilliant use of a raspberry pi.
Cheers
Dave…
Hi Sheldon
Wonder if you or anyone knows of a way to set the wifi user name and password (or have more than one set) without using a pc,
As I would like to take my wifi radio to and from my works, and just need to be able to plug in and go.
Cheers
Dave…
Hi Sheldon,
I really like what you done here but I need your help with how to set this up. I have no experience with python but a little with linux and the command line. I have set up the Adafruit and it works OK but I don’t want to be tide to the pandora web site. What I need to know is just where do I put the python scripts (what folder) to make it work? Sorry if you have covered this already. I just found your site and haven’t gone read all the comments yet.
Glenn
Hi Glenn
I have all of the files in a directory called: /home/pi/projects/radio
Good luck,
Sheldon
Hi Sheldon
Just something I noticed, and may be of help.
I finally got around to getting a HDMI to VGA adapter, and watching the radio working live , not via ftp.
Upon booting I noticed afsck warning, telling me it hadn’t been shut down properly,
I also noticed after shutting the radio down I could still type and command directly.
So to be on the safe side I added the -H switch to line 278 …….. output = run_cmd(“sudo shutdown now -h”)
This seems to shut down better and also flash the green led 10 times,
Which I found to be a nice indicator it was shut down and safe to pull the power.
As I have found the little radio to be so useful I wouldn’t want to corrupt the sd card. (better safe than sorry)
Cheers
Dave…
Hi Sheldon,
Just like some other fans of your project I would like to have the LCD showing some extra info.
I was searching around and at the raspberry forum i found some info about python-mpd2. I have installed the library and it works great, any easy way to get the info.
http://www.raspberrypi.org/forums/viewtopic.php?f=38&t=48359
By the way, your project is mentioned in the first post!
Cheers
Harold
Hi Sheldon
So close but still no cigar! I get the welcome message on my home brewed LCD Plate but I still keep getting this message:
L:CD_QUEUE .put(PLAYLIST_MSG(STATION – 1) TRUE)
Line 108.
I read it was part of the playlist but after trying everything I copied yours and renamed & chmod’d it so the file turned from grey to green and in the right directory. But that is as far as thing go.
Sure would appreciate some help.
Thank you very much. I can do pretty good with a soldering iron but python… not so much
Thanks for all the work it took to get it all on the net.
Claude
Hi Claude
I suspect you may have SFTP’ed the radio_playlist.sh file from Windows to Linux as a “text” file and not a “binary” file. The radio_playlist.sh file must have 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 it runs without errors.
Hope this helps. Good luck with your project,
Sheldon
Hi.
Nice guide. I had to try it.
Everything went fine untill I hit ENTER after typing ‘sudo python radio.py’.
I am no Python guru so what do I do?
The message I got is as follows:
Traceback (most recent call last):
File “radio.py”, line 377, in
main()
File “radio.py”, line 115, in main
press = read_buttons()
File “radio.py”, line 165, in read_buttons
buttons = LCD.readButtons()
AttributeError: Adafruit_CharLCDPlate instance has no attribute ‘readButtons’
http://7279.live.streamtheworld.com:80/KKWFFMAAC_SC
[playing] #1/15 0:00/0:00 (0%)
volume:100% repeat: off random: off single: off consume: off
It looks to me that the problem is in radio_playlist.sh….
Hi Ben
This has been answered a number of times in the comments. Try searching the comments for “readButtons” …
“For those of you having problems with the latest versions of the Adafruit classes, you can work around them by replacing “LCD.readButtons()” with “LCD.buttons()” in lines 165 and 169 of radio.py Adafruit has rewritten the CharLCDPlate and I2C classes and done a kick-ass job of speeding things up. My modifications to these classes are no longer required!”
Good luck with your project, Ben!
Sheldon
Hi All
Has anyone tried to scroll the second line with the station info,
As I have followed several links and all I seem to do no matter what I try is kill the radio program,
I have also been trying to mod the pi plate files so I can use a rotary encoder as the channel selector to no avail.
(as I have now got over 60 channels and two Pi radios)
Electronics and soldering I can do in my sleep, but python is twisting my melons….
Can anyone throw me a line and point me in the right direction..
Cheers,
And a big thanks to Sheldon for the best use of a Pi yet.
Hi, love your work. I have one of these set up on my work bench. Good stuff.
I have a feature request for version 2. it would be great to have ‘long press’ buttons. I’m working on it at the moment with no success. Below is what I am aiming for.
* Select Button *
If playing = Stop
If Stopped = Play
Long Press = Menu
* Left Button *
Short Press = Previous Track
Long Press = Show IP address for 5 Seconds
* Right Button *
Short Press = Next Track
Long Press = Reload Playlist
* Up Button *
Short Press = Volume Up
Long Press =
* Down Button *
Short Press = Volume Down
Long Press = Shutdown
Hi, I’ve had a crack at modifying you work. I don’t use the volume control, as I hook up to a stereo, so I’ve swapped them for a play and stop button. You can get rid of the references to Adafruit_I2C and Adafruit_MCP230xx. You don’t use them.
Also, I don’t think you licence notice is valid. Without the copyright notice and the actual text of the BSD licence it’s not valid. But I think that is a good thing. Even an open source licence imposes restrictions, and for something like this, that is a learning tool, I think it’s better to let people do whatever they want with it, much like the work that you reference at the top of your script. The community is strong enough that the information will get shared, and a licence just scares people off.
Anyway, here is my version of your code.
#!/usr/bin/python
# radio.py, version 2.1 (RGB LCD Pi Plate version)
# February 17, 2013
# Written by Sheldon Hartling for Usual Panic
# BSD 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_CharLCDPlate
#
#dependancies
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate
from datetime import datetime
from subprocess import *
from time import sleep, strftime
from Queue import Queue
from threading import Thread
import smbus
# initialize the LCD plate No argument needed for autodetect
# use busnum = 0 for raspi version 1 (256MB)
# and busnum = 1 for raspi version 2 (512MB)
LCD = Adafruit_CharLCDPlate()
# Define a queue to communicate with worker thread
LCD_QUEUE = Queue()
# Globals
PLAYLIST_MSG = []
STATION = 1
NUM_STATIONS = 0
# Buttons
NONE = 0x00
SELECT = 0x01
RIGHT = 0x02
DOWN = 0x04
UP = 0x08
LEFT = 0x10
UP_AND_DOWN = 0x0C
LEFT_AND_RIGHT = 0x12
# —————————-
# WORKER THREAD
# —————————-
# Define a function to run in the worker thread
def update_lcd(q):
while True:
msg = q.get()
# if we’re falling behind, skip some LCD updates
while not q.empty():
q.task_done()
msg = q.get()
LCD.setCursor(0,0)
LCD.message(msg)
q.task_done()
return
# —————————-
# MAIN LOOP
# —————————-
def main():
global STATION, NUM_STATIONS, PLAYLIST_MSG
# Stop music player
output = run_cmd(“mpc stop” )
LCD.backlight(LCD.RED) #Set the backlight to red, as we will used red for stop
# Setup AdaFruit LCD Plate
LCD.begin(16,2)
LCD.clear()
# Create the worker thread and make it a daemon
worker = Thread(target=update_lcd, args=(LCD_QUEUE,))
worker.setDaemon(True)
worker.start()
# Display startup banner, and flash the display a few colors
LCD_QUEUE.put(‘ Raspberry Pi \n Internet Radio ‘, True)
LCD.backlight(LCD.RED)
sleep(0.5)
LCD.backlight(LCD.VIOLET)
sleep(0.5)
LCD.backlight(LCD.BLUE)
sleep(0.5)
LCD.backlight(LCD.TEAL)
sleep(0.5)
LCD.backlight(LCD.GREEN)
sleep(0.5)
# Load our station playlist
load_playlist()
LCD.clear()
# —————————-
# START THE MUSIC!
# —————————-
# Start music player
LCD_QUEUE.put(PLAYLIST_MSG[STATION – 1], True)
run_cmd(“mpc volume +100″) # sets the volume to maximum. This is good if you want to output to a line in, but might be a bit loud if you are going to use headphones.
mpc_play(STATION)
countdown_to_play = 0
# Main loop
while True:
press = read_buttons()
# LEFT button pressed
if(press == LEFT):
STATION -= 1
if(STATION NUM_STATIONS):
STATION = 1
LCD_QUEUE.put(PLAYLIST_MSG[STATION – 1], True)
# start play in 300msec unless another key pressed
countdown_to_play = 3
# UP button pressed
if(press == UP):
mpc_play(STATION) #start playing the music again
# DOWN button pressed
if(press == DOWN):
output = run_cmd(“mpc stop”) #stop the music
LCD.backlight(LCD.RED) # and make the display red
# SELECT button pressed
if(press == SELECT):
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(99)
update_lcd.join()
# —————————-
# READ SWITCHES
# —————————-
def read_buttons():
buttons = LCD.buttons()
# Debounce push buttons
if(buttons != 0):
while(LCD.buttons() != 0):
delay_milliseconds(1)
return buttons
def delay_milliseconds(milliseconds):
seconds = milliseconds / float(1000) # divide milliseconds by 1000 for seconds
sleep(seconds)
# —————————-
# LOAD PLAYLIST OF STATIONS
# —————————-
def load_playlist():
global STATION, NUM_STATIONS, PLAYLIST_MSG
# Run shell script to add all stations
# to the MPC/MPD music player playlist
output = run_cmd(“mpc clear”)
output = run_cmd(“/home/pi/projects/radio/radio_playlist.sh”)
# Load PLAYLIST_MSG list
PLAYLIST_MSG = []
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()
NUM_STATIONS = len(PLAYLIST_MSG)
# —————————-
# RADIO SETUP MENU
# —————————-
def menu_pressed():
global STATION
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. Reload \n Playlist File’,
‘6. System \n Shutdown! ‘,
‘7. Exit \n ‘]
item = 0
LCD.clear()
LCD.backlight(LCD.BLUE) #set the backlight to blue for the menu
LCD_QUEUE.put(MENU_LIST[item], True)
keep_looping = True
while (keep_looping):
# Wait for a key press
press = read_buttons()
# UP button
if(press == UP):
item -= 1
if(item = len(MENU_LIST)):
item = 0
LCD_QUEUE.put(MENU_LIST[item], True)
# SELECT button = exit
elif(press == SELECT):
keep_looping = False
# Take action
if( item == 0):
# 1. display time and IP address
display_ipaddr()
elif(item == 1):
# 2. audio output to HDMI
output = run_cmd(“amixer -q cset numid=3 2″)
elif(item == 2):
# 3. audio output to headphone jack
output = run_cmd(“amixer -q cset numid=3 1″)
elif(item == 3):
# 4. audio output auto-select
output = run_cmd(“amixer -q cset numid=3 0″)
elif(item == 4):
# 5. reload our station playlist
LCD_QUEUE.put(“Reloading\nPlaylist File…”, True)
load_playlist()
sleep(2)
STATION = 1
LCD_QUEUE.put(PLAYLIST_MSG[STATION – 1], True)
mpc_play(STATION)
elif(item == 5):
# 6. shutdown the system
LCD_QUEUE.put(‘Shutting down\nLinux now! … ‘, True)
LCD_QUEUE.join()
output = run_cmd(“mpc clear”)
output = run_cmd(“sudo shutdown now”)
LCD.clear()
LCD.backlight(LCD.OFF)
exit(0)
else:
delay_milliseconds(99)
# Need to add some code that lets us remember if MPC was playing or not, and choose the colour accordingly until then, just make it white
LCD.backlight(LCD.WHITE)
LCD_QUEUE.put(PLAYLIST_MSG[STATION – 1], True)
# —————————-
# DISPLAY TIME AND IP ADDRESS
# —————————-
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)
LCD.backlight(LCD.BLUE)
i = 29
muting = False
keep_looping = True
while (keep_looping):
# Every 1/2 second, update the time display
i += 1
#if(i % 10 == 0):
if(i % 5 == 0):
LCD_QUEUE.put(datetime.now().strftime(‘%b %d %H:%M:%S\n’)+ ipaddr, True)
# 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_buttons()
# Take action on switch press
# UP button pressed
if(press == UP):
keep_looping = False
#output = run_cmd(“mpc volume +2″)
# DOWN button pressed
if(press == DOWN):
keep_looping = False
#output = run_cmd(“mpc volume -2″)
# SELECT button = exit
if(press == SELECT):
keep_looping = False
# DOWN button pressed
if(press == LEFT):
keep_looping = False
#output = run_cmd(“mpc volume -2″)
# SELECT button = exit
if(press == RIGHT):
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 mpc_play(STATION):
pid = Popen([“/usr/bin/mpc”, “play”, ‘%d’ % ( STATION )]).pid
LCD.backlight(LCD.GREEN) # if we are playing music, make the screen green
if __name__ == ‘__main__':
main()
# End
Hi sheldon
I made the change line 165 and 168 (not 169), so the program now displays correctly.
But I have a problem with audio, no sound on the “headphone” output even if I validate this output in the “Menu”.
Buttons “up” and “down” does not display the volume. The buttons work properly because they act in the “Menu”.
If I test the command “mpc play” outside of your script, the sound works correctly.
Thank you for your advice.
Best regards
Jacky
Hi Sheldon,
I think my problem is no sound because my “radio_playlist.sh” file does not have proper permissions “775”
For the “volume” I realized that when you press the “up” button and “down” there is no display on the display.
I would like to test the code “song info, artist” who is on this link:
http://didtheypush.blogspot.nl/2013/10/raspyfi-and-adafruit-16 × 2-char-lcd-plate.html
Could you send me your startup script? If possible.
Your work is excellent, and I hope you find the time to change your script to display scrooling current title and artist name.
Again thank you and congratulations.
Best regards.
Jacky
The “radio_playlist.sh” file is executed by the program as a shell script. It must be a properly formatted shell script (with LF UNIX line terminators and not CRLF Windows line terminators) and you must have execute permissions. A “chmod 755″ usually does the trick.
I emailed you the Startup script.
Good luck with your project,
Sheldon
sorry for my bad language.
if you are the problem:
song number greater than playlist length
Just add two line, line 203:
else:
run_cmd(line)
after:
# Remaining comment lines are loaded
for line in playlist:
if line[0] == “#” :
There is no song in your list of song of mpc.
a++
thank’s Sheldon, very good job
Thanks, Polonium73
The “song number greater than playlist length” error is most often caused by problems with the “radio_playlist.sh” file. This file is executed by the program as a shell script and it must have proper Linux/UNIX line terminators and execute permissions. A “chmod 755″ usually does the trick.
Hi Sheldon,
would you be so kind and send me start-up skript please? I tried solve it, but without success. Radio scipt working great.
Thank you.
Andrej
Hi Andrej
I’ve emailed a copy of my start-up script.
Good luck!
Shelodn
Hi Sheldon, May I trouble you for your startup script? Thank you!
Hi Nick
I’ve emailed a copy of my startup script.
Good luck with your project,
Sheldon