I gutted an old RCA RC970 speaker into a RPI MPD Jukebox with LCD Screen.

On boot, the LCD screen shows RPI data. If the MPD daemon is actively playing a song, the screen switches over to music data.


I am using a 20×4 Blue LCD display with I2C backpack from eBay.
Wiring Diagram:

Installation:
From Terminal –
sudo raspi-config
Select Advanced Option -> I2C -> Enable I2C ->Finish
The Pi will reboot after you click the Finish Button
After rebooting the Pi, we need to modify the module’s config file. Type the following command in terminal:
sudo nano /etc/modules
Add following two lines in modules file if they do not exist:
i2c-bcm2708
i2c-dev
Then Type Ctrl X and Yes to save the file.
Install smbus and i2c python library
sudo apt-get update
sudo apt-get install -y python-smbus i2c-tools
sudo reboot
After rebooting the system, type the following command in order to check software installation:
lsmod | grep i2c_
You should see i2c_bcm2708 in a list, this means the library has been installed successfully.
If you want to use this for MPD display:
sudo apt-get install mpd mpc
Testing Hardware
Depending on your Raspberry Pi version, please run one of following commands in terminal:
sudo i2cdetect -y 1
or
sudo i2cdetect -y 0
You should see something as follows; the value you see is for I2C_ADDR in the Python code included below.
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: — — — — — — — — — — — — —
10: — — — — — — — — — — — — — — — —
20: — — — — — — — — — — — — — — — —
30: — — — — — — — — — — — — — — — 27
40: — — — — — — — — — — — — — — — —
50: — — — — — — — — — — — — — — — —
60: — — — — — — — — — — — — — — — —
70: — — — — — — — —
Python Requirements:
sudo apt-get install python-pip
sudo pip install python-mpd2
sudo pip3 install python-mpd2
sudo pip install psutil
sudo pip3 install psutil
Start LCD Display at Boot:
sudo nano /etc/rc.local
Add the following line BEFORE the ‘exit 0’ line.
sudo python /home/pi/scripts/lcd_display.py &
You may want to store the following scripts somewhere else, so adjust the path above accordingly.
Copy and save the following as lcd_display.py
#!/usr/bin/env python3
# Project Tutorial Url:http://www.markwheeler.com
#
import smbus
import time
import os
import glob
import subprocess
import psutil
from datetime import datetime
#import mpd
#from socket import error as SocketError
#client = mpd.MPDClient()
# Define some device parameters
I2C_ADDR = 0x3f # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 20 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
LCD_BACKLIGHT = 0x08 # On
#LCD_BACKLIGHT = 0x00 # Off
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
#Open I2C interface
#bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def lcd_init():
# Initialise display
lcd_byte(0x33,LCD_CMD) # 110011 Initialise
lcd_byte(0x32,LCD_CMD) # 110010 Initialise
lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01,LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT
# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
# Toggle enable
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
time.sleep(E_DELAY)
def lcd_string(message,line,style):
# Send string to display
# style=1 Left justified
# style=2 Centered
# style=3 Right justified
if style==1:
message = message.ljust(LCD_WIDTH," ")
elif style==2:
message = message.center(LCD_WIDTH," ")
elif style==3:
message = message.rjust(LCD_WIDTH," ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]),LCD_CHR)
# Is MPD playing a song?
def mpc_status():
playing = (os.popen('mpc status | grep playing')).readline()
if playing=="":
return(0)
elif playing != "":
return(1)
# Stuff to Display
def measure_temp():
temp = os.popen('vcgencmd measure_temp').readline()
return(temp.replace("temp=","").replace("'C\n",""))
def ip_address():
ip = os.popen('host localhost | grep "address" | cut -d" " -f4').readline()
return(ip.strip())
def cpu_load():
CPU_Pct=str(round(float(os.popen('''grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage }' ''').readline()),2))
return(str(CPU_Pct))
def ram_used():
mem_used = (psutil.virtual_memory().used / (1024.0 ** 2))
return(str(round(mem_used,2)))
def main():
# Main program block
# Initialise display
lcd_init()
# Display Method
while True:
# Call MPD Display if Running
# client.connect("localhost", 6600)
# if client.status()['state'] == "play":
# lcd_string("MPD is PLAYING",LCD_LINE_2,1)
# client.disconnect()
# os.system('/home/pi/scripts/mpd_display.py')
# else:
# client.disconnect()
# Call MPD Display if Running - Comment these next two lines if not using MPD
if mpc_status() == 1:
os.system('/home/pi/scripts/mpd_display.py')
# Display Data
lcd_string(datetime.now().strftime('%m/%d/%Y %H:%M'),LCD_LINE_1,2)
lcd_string(ip_address(),LCD_LINE_2,2)
lcd_string("CPU: "+measure_temp()+"c "+cpu_load()+"%",LCD_LINE_3,2)
# lcd_string(" ",LCD_LINE_3,1)
lcd_string("RAM FREE: "+ram_used()+"Mgb",LCD_LINE_4,2)
time.sleep(1)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
lcd_byte(0x01, LCD_CMD)
Copy and save the following as mpd_display.py
#!/usr/bin/env python3
# Project Tutorial Url:http://www.markwheeler.com
#
import smbus
import time
import os
import glob
import subprocess
#import mpd
#from socket import error as SocketError
from datetime import datetime
#client = mpd.MPDClient()
# Define some device parameters
I2C_ADDR = 0x3f # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 20 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
LCD_BACKLIGHT = 0x08 # On
#LCD_BACKLIGHT = 0x00 # Off
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
#Open I2C interface
#bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def lcd_init():
# Initialise display
lcd_byte(0x33,LCD_CMD) # 110011 Initialise
lcd_byte(0x32,LCD_CMD) # 110010 Initialise
lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01,LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT
# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
# Toggle enable
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
time.sleep(E_DELAY)
def lcd_string(message,line,style):
# Send string to display
# style=1 Left justified
# style=2 Centred
# style=3 Right justified
if style==1:
message = message.ljust(LCD_WIDTH)
elif style==2:
message = message.center(LCD_WIDTH)
elif style==3:
message = message.rjust(LCD_WIDTH," ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]),LCD_CHR)
# Is MPD playing a song?
def mpc_status():
playing = (os.popen('mpc status | grep playing')).readline()
if playing=="":
return(0)
else:
return(1)
# Stuff to Display
def current_song():
song = os.popen('mpc -f %title%').readline()
return(song.strip())
def current_artist():
title = os.popen('mpc -f %artist%').readline()
return(title.strip())
def current_time():
stime = os.popen('mpc -f %time%').readline()
return(stime.strip())
def current_album():
album = os.popen('mpc -f %album%').readline()
return(album.strip())
# MPD connection times out
#def song_elapsed():
# elapsed = client.status()['elapsed']
# m, s = divmod(int(float(elapsed)), 60)
# h, m = divmod(m, 60)
# elapsed_min = ("%02d:%02d" % (m, s))
# return(elapsed_min)
def song_elapsed():
elapsed = os.popen('mpc status | awk \'NR==2 { split($3, a, "/"); print a[1]}\'').readline()
return(elapsed.strip())
#This scrolls the song title if it exceeds 20 characters. Not implemented in display here.
def long_song():
str_song = " " * 20
long_song = str_song + current_song()
while True:
for i in range (0, len(long_song)):
lcd_text = long_song[i:(i+20)]
lcd_string(lcd_text,LCD_LINE_3,1)
time.sleep(0.4)
lcd_string(str_song,LCD_LINE_3,1)
continue
def main():
# Main program block
# Initialise display
lcd_init()
# Display Method
while True:
# Call Default Display if Stopped
# client.connect("localhost", 6600)
# if client.status()['state'] != "play":
# lcd_string("MPD is STOPPED",LCD_LINE_2,1)
# client.disconnect()
# os.system('/home/pi/scripts/lcd_display.py')
# else:
# client.disconnect()
# Call Default Display if Stopped
if mpc_status() == 0:
os.system('/home/pi/scripts/lcd_display.py')
# Display Data
# lcd_string(datetime.now().strftime('%m/%d/%Y %H:%M'),LCD_LINE_1,2)
lcd_string(current_artist(),LCD_LINE_1,1)
lcd_string(current_album(),LCD_LINE_2,1)
lcd_string(current_song(),LCD_LINE_3,1)
lcd_string(song_elapsed()+"/"+current_time(),LCD_LINE_4,3)
time.sleep(0.1)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
lcd_byte(0x01, LCD_CMD)
I’ve left some commented code in these files with other things I was experimenting with.