I created a program in Python for Raspberry Pi model B rev 1.0 with 2x16 LCD and 6 buttons, with the following features:
- Displaying artist in first line and title in second line; when playing radio: first line is radio name, second line is in ARTIST - TITLE format
- It scrolls long texts (artist or title name) and it scrolls both lines independently; when it reaches the end, it scrolls backwards and then again forward and so on
- On volume change, it shows Volume: XY % in first line and volume level with squares in second line for few seconds and then returns on song/radio name
- play, pause, previous, next, stop, volume up and volume down keys
- it shows PAUSED or STOPPED on display in these states
- it can automatically turn off LCD backlight when you pause/stop the playback, after specified timeout time passed
Here's the video of it in action: https://www.youtube.com/watch?v=G2FPAcL_NZc
And another one with IR remote: https://www.youtube.com/watch?v=AxEGq0txyPw
UNFINISHED
This is still a work in progress so you can expect bugs and problems. Any bug report, criticism, idea or fix/solution is welcome
Problems so far:
- For some reason, starting it as a service is failing so I haven't managed to get it starting at boot, so for now, you have to turn it on manually (from SSH) everytime you reboot your Pi
TODO:
- fast forward/backward on long press
- 4x20 LCD with additional info like current time, remaining time/total time, bitrate etc.
- Nokia 3310 LCD!?
WARNING
There are plenty of things that could go wrong. Believe me, I managed to broke completely RuneAudio a few times And I'm currently having some problems with MPD which could be as a result from this. Arch Linux and MPD are obviously very sensitive and everything you install additionally can break something. Also, this tutorial seems a bit complicated. Unfortunatelly, the code I wrote requires lot of libraries which can be hard to install on Arch Linux. I'm a total Linux newbie, especially for Arch, so I'm not able to create some kind of installation for this.
So, before proceeding, you should do a backup of your RuneAudio, if you don't want to lose something. If you have a fresh installation of RuneAudio, then there's nothing you can lose so you can just proceed. If anything goes wrong, you can install it from scratch. But if you have a lot of settings, playlists, web radios or some other custom programs, DO A BACKUP before proceeding with this! You can use Win32 Disk Imager on Windows for this.
I'M NOT RESPONSIBLE IF SOMETHING GOES WRONG AND YOU BREAK YOUR SYSTEM OR LOSE SOMETHING!!
TUTORIAL
0) SSH into the Pi
Well, this is obvious But if you're doing it for the first time, you should consider learning what SSH is and how to do it. If on Windows, you can use Putty.
Username: root
Password: rune
1) Installing Python 2
The program is written for Python 2 so we have to install Python 2. Before doing this, we have to update directories. Otherwise, it won't find Python2 package or it will give some errors (like 404 Not Found).
To update only packages, execute the following command in terminal:
- Code: Select all
pacman –Syy
DO NOT use pacman -Syu for updating the whole system. It broke my Rune Audio completely and it couldn't boot anymore.
Now, we can proceed with installing Python. Execute the following command in terminal:
- Code: Select all
pacman –S python2
After it's done, if everything went alright, we can proceed with installation of Python PIP which will help us to install packages for Python (for GPIO and LCD). Execute the following command in terminal:
- Code: Select all
pacman –S python2-pip
Now, if you want to test that your Python2 is working, type "python2" in terminal and when you get ">>", type "print "Hello World" and press Enter. You should see "Hello World". Press CTRL+D to exit from Python2.
3) Installing GCC compiler
The next step is to install GCC compiler which is needed for installing GPIO and RPLCD. Execute the following command in terminal:
- Code: Select all
pacman –S gcc
4) Installing RPi.GPIO compiler
Now we need to install Python library for GPIO. It can be installed using PIP but for some reason, it wasn't working for me so I installed it manually. Here's how you do it: first, navigate to a folder where you want to download it, for example in root:
- Code: Select all
cd /root
Then download the RPi.GPIO package by executing the following command in terminal:
- Code: Select all
wget http://raspberry-gpio-python.googlecode.com/files/RPi.GPIO-0.5.2a.tar.gz
NOTE: If you get 404 Not Found error, the link is probably out-of-date so try to find this version on Google, or you can download the newest version.
Then we have to extract it, with:
- Code: Select all
tar -xvf RPi.GPIO-0.5.2a.tar.gz
And install it, with:
- Code: Select all
cd RPi.GPIO-0.5.2a
- Code: Select all
python2 setup.py install
5) Installing Adafruit LCD library
We have to download this library from github and then install it. So first, navigate to the directory where you want to download it (for example "cd /root" and execute the following command:
- Code: Select all
wget https://github.com/adafruit/Adafruit_Python_CharLCD/archive/master.zip
NOTE: If you get 404 Not Found error, the link is probably out-of-date so try to find this version on Google, or you can download the newest version.
Once we got the archive (it's name is master.zip), we will need UNZIP to extract this ZIP archive. Execute the following command
- Code: Select all
pacman -S unzip
After installing UNZIP, execute the following command:
- Code: Select all
unzip master.zip
Now we have to enter the folder we got from unziping, execute the following command:
- Code: Select all
cd Adafruit_Python_CharLCD-master
And run the installation by executing the following command:
- Code: Select all
python2 setup.py install
Now, if everything went OK, we have our LCD library! And now comes the tricky part: Adafruit has included functions for I2C displays as well, but here we are missing a module called "smbus" so you will probably get the following error:
No module smbus
If that's the case: if you need I2C and you know what you're doing, you can fix this (get that module). I removed a few lines from Adafruit library which uses I2C, so I will give instructions here how to do it. You will need something to modify files: you can use "nano" editor integrated in bash, but it's not very practical. You use it by executing "nano path_to_file". If you're on Windows, you can use a program like WinSCP. You connect with your Pi and get a file manager. If you're using SAMBA, even better!
First file is:
/usr/lib/python2.7/site-packages/Adafruit_CharLCD-1.0.0-py2.7.egg/Adafruit_CharLCD/Adafruit_CharLCD.py
WARNING: notice those red parts. They depends on version of Python you have installed and version of Adafruit library. It can be different on your side, but you will surely find them. NOTE: I have Python3 and Python2 folders, since we're using Python 2, look for "python2.x" folder.
In that file, find this line (at the beggining):
- Code: Select all
import Adafruit_GPIO.I2C as I2C
And comment it, by adding # at the beggining of that line, like this:
- Code: Select all
# import Adafruit_GPIO.I2C as I2C
Next, at the end of the file, find the last class, it looks like this:
- Code: Select all
class Adafruit_CharLCDPlate(Adafruit_RGBCharLCD):
"""Class to represent and interact with an Adafruit Raspberry Pi character
LCD plate."""
def __init__(self, address=0x20, busnum=I2C.get_default_bus(), cols=16, lines=2):
"""Initialize the character LCD plate. Can optionally specify a separate
I2C address or bus number, but the defaults should suffice for most needs.
Can also optionally specify the number of columns and lines on the LCD
(default is 16x2).
"""
# Configure MCP23017 device.
self._mcp = MCP.MCP23017(address=address, busnum=busnum)
# Set LCD R/W pin to low for writing only.
self._mcp.setup(LCD_PLATE_RW, GPIO.OUT)
self._mcp.output(LCD_PLATE_RW, GPIO.LOW)
# Set buttons as inputs with pull-ups enabled.
for button in (SELECT, RIGHT, DOWN, UP, LEFT):
self._mcp.setup(button, GPIO.IN)
self._mcp.pullup(button, True)
# Initialize LCD (with no PWM support).
super(Adafruit_CharLCDPlate, self).__init__(LCD_PLATE_RS, LCD_PLATE_EN,
LCD_PLATE_D4, LCD_PLATE_D5, LCD_PLATE_D6, LCD_PLATE_D7, cols, lines,
LCD_PLATE_RED, LCD_PLATE_GREEN, LCD_PLATE_BLUE, enable_pwm=False,
gpio=self._mcp)
def is_pressed(self, button):
"""Return True if the provided button is pressed, False otherwise."""
if button not in set((SELECT, RIGHT, DOWN, UP, LEFT)):
raise ValueError('Unknown button, must be SELECT, RIGHT, DOWN, UP, or LEFT.')
return self._mcp.input(button) == GPIO.LOW
Comment it, but this time by adding ''' (three single quotes) at the beggining AND at the end, so it should look like this:
- Code: Select all
'''class Adafruit_CharLCDPlate(Adafruit_RGBCharLCD):
"""Class to represent and interact with an Adafruit Raspberry Pi character
LCD plate."""
def __init__(self, address=0x20, busnum=I2C.get_default_bus(), cols=16, lines=2):
"""Initialize the character LCD plate. Can optionally specify a separate
I2C address or bus number, but the defaults should suffice for most needs.
Can also optionally specify the number of columns and lines on the LCD
(default is 16x2).
"""
# Configure MCP23017 device.
self._mcp = MCP.MCP23017(address=address, busnum=busnum)
# Set LCD R/W pin to low for writing only.
self._mcp.setup(LCD_PLATE_RW, GPIO.OUT)
self._mcp.output(LCD_PLATE_RW, GPIO.LOW)
# Set buttons as inputs with pull-ups enabled.
for button in (SELECT, RIGHT, DOWN, UP, LEFT):
self._mcp.setup(button, GPIO.IN)
self._mcp.pullup(button, True)
# Initialize LCD (with no PWM support).
super(Adafruit_CharLCDPlate, self).__init__(LCD_PLATE_RS, LCD_PLATE_EN,
LCD_PLATE_D4, LCD_PLATE_D5, LCD_PLATE_D6, LCD_PLATE_D7, cols, lines,
LCD_PLATE_RED, LCD_PLATE_GREEN, LCD_PLATE_BLUE, enable_pwm=False,
gpio=self._mcp)
def is_pressed(self, button):
"""Return True if the provided button is pressed, False otherwise."""
if button not in set((SELECT, RIGHT, DOWN, UP, LEFT)):
raise ValueError('Unknown button, must be SELECT, RIGHT, DOWN, UP, or LEFT.')
return self._mcp.input(button) == GPIO.LOW'''
(You can copy this code and replace it).
Next file is:
/usr/lib/python2.7/site-packages/Adafruit_GPIO-0.9.3-py2.7.egg/Adafruit_GPIO/MCP230xx.py
Again, pay attention to red parts!
In that file, find this line (at the beggining):
- Code: Select all
import Adafruit_GPIO.I2C as I2C
And again, comment it (with #).
If everything went OK, you're ready to write some programs in Python2 which will use LCD and GPIO. You can test that your GPIO is working by executing "python2" and then writting "import RPi.GPIO" and pressing enter. If you don't get any error, it's working.
Now it would be good to reboot your system.
HARDWARE
For this program, you will need:
- 2x16 LCD display, it will be connected in 4-bit mode
- 6 push buttons
Optionaly (for dynamic LCD backlight):
- a NPN transistor (I use BD139)
- a resistor (I use 10k resistor with BD 139)
You can connect it following my schematic and then use default settings (without touching anything in the code) or you can connect it by your own, but in that case, you will have to specify all the pins in the code. The code is well commented, so there should be no problems with that.
You can find my schematic in attachment. Yes I know, it's bad (done in Paint ) but I currently don't have time to do a better one. You can also find in my code on which pins something is connected. I'm using GPIO.BCM numbering so you can find this pinout on Google. Next to each pin in code I also wrote his board number (as Px).
If you're using different pins, just change that in code. Buttons are pulled up and thus they have to be connected to ground, not 3.3V.
WARNING: after wiring this, only 2 pins will be left free (on Raspberry Pi model B 26 pin GPIO)! If you use dynamic LCD backlight, only 1 will left free!! If you want to use IR receiver for IR remote, you can because it needs only one pin. I'm using it on the pin 7 (GPIO4 by BCM numbering).
THE CODE
So, the code is written in Python. I tried to comment as much as possible, but the code is currently pretty a mess! You can change it to fit your needs if you want. I will further develop this code and try to fix all the bugs and mistakes and I will let you know here once I do something.
The code is here:
TAR Archive: http://buzzthisnow.com/RA_LCD_Buttons.tar (TAR archive)
RAR Archive: http://buzzthisnow.com/RA_LCD_Buttons.rar (RAR archive)
If you want to get it straight to your Pi, navigate to the folder where you want to store it (ex. "cd /root") and use this command to download it:
- Code: Select all
wget http://buzzthisnow.com/RA_LCD_Buttons.tar
And then use this command to extract it:
- Code: Select all
tar -xvf RA_LCD_Buttons.tar
Now you can delete the archive if you want, to free up some space, by executing:
- Code: Select all
rm RA_LCD_Buttons.tar
It will create a folder named RA_LCD_Buttons, execute this command to enter it:
- Code: Select all
cd RA_LCD_Buttons
Now you can start it with:
- Code: Select all
python2 RA_LCD_Buttons.py
And stop it by pressing CTRL+Z.
And it should work. But starting it like this will make it dependable on your SSH connection. As soon as you close Putty or other SSH client, it will stop working. To start it independent on your terminal (SSH Connection), use this:
- Code: Select all
nohup python2 RA_LCD_Buttons.py >/dev/null 2>&1 &
Now you can close your SSH and it will continue to work. To stop it, you will have to use:
- Code: Select all
ps -x
To see all running processes. Find it on the list as "python2 RA_LCD_Buttons.py" and see it's PID (number in first collumn) and use:
- Code: Select all
kill [PID]
Replace [PID] with the PID of your process.
Or you can just reboot your Pi
CHANGING PREFERENCES
If you want to change some preferences, like LCD or button pins, scroll speed (period) etc., open the code (RA_LCD_Buttons.py) and at the beggining of file, you will find all these options. They are well commented, with instructions how to use them.
CHANGELOG
05.07.2015
- Fixed problems with buttons; MPD was closing connection after 60 seconds of inactivity -> fixed with pinging MPD every 50 seconds
- Added dynamic backlight control: don't know if it will be useful for somebody, but I had problems due to display lightning up my room so I wasn't able to sleep now the backlight will go off when you stop or pause playback, after specified time, you can enable/disable this and specify the time between pause/stop and going off
29.5.2015
- Executing changed to "nohup python2 RA_LCD_Buttons_v2.py >/dev/null 2>&1 &" because old one was storing all the output to file, which would quickly become very large
- RPLCD library replaced with Adafruit library, for better performance
- Button pooling replaced with interrupts, for better performance and less resource usage
- Executing terminal commands (for buttons and for getting stats) replaced with MPD library for Python, for better performance and cleaner code
- Now you can change scroll speed, whether to scroll webradio station name or not, button bounce time, volume screen duration, scrolling start time etc.
- Pin numbering changed from GPIO.BOARD to GPIO.BCM
PROBLEMS, BUGS
If there are any problems or bugs in the code, let me know.