UPDATE: This file combines the code below into one script.
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:https://www.markwheeler.com # import smbus import time import os import glob import subprocess from datetime import datetime import threading from multiprocessing import Process import psutil #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 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) 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('hostname -I').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 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()) def long_album(): str_album = " " * 20 long_album = str_album + current_album() for i in range (0, len(long_album)): lcd_text = long_album[i:(i+20)] lcd_string(lcd_text,LCD_LINE_2,1) time.sleep(0.4) lcd_string(str_album,LCD_LINE_2,1) continue def radio_song(): sstring = os.popen('mpc -f %title%').readline() astring = os.popen('mpc -f %title%').readline() song = sstring.split('-')[1] artist = astring.split('-')[0] lcd_string(artist.strip(),LCD_LINE_1,2) lcd_string(song.strip(),LCD_LINE_2,2) def long_song(): str_song = " " * 20 long_song = str_song + current_song() for i in range (0, len(long_song)): lcd_text = long_song[i:(i+20)] lcd_string(lcd_text,LCD_LINE_1,1) time.sleep(0.05) lcd_string(str_song,LCD_LINE_1,1) lcd_string(song_elapsed()+"/"+current_time(),LCD_LINE_4,3) def scroll_title(): str_title = " " * 20 str_album = " " * 20 long_title = str_title + current_song() long_album = str_album + current_album() while True: for i in range (0, 32): lcd_text1 = long_title[i:(i+20)] lcd_text2 = long_album[i:(i+20)] lcd_string(lcd_text1,LCD_LINE_3,1) lcd_string(lcd_text2,LCD_LINE_2,1) time.sleep(0.05) lcd_string(str_title,LCD_LINE_3,1) lcd_string(str_album,LCD_LINE_2,1) continue # 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()) 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 if mpc_status() == 0: #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) elif mpc_status() == 1: if (len(current_artist()) == 0): sstring = os.popen('mpc -f %title%').readline() astring = os.popen('mpc -f %title%').readline() song = sstring.split('-')[1] artist = astring.split('-')[0] lcd_string(artist.strip(),LCD_LINE_1,2) lcd_string(song.strip(),LCD_LINE_2,2) lcd_string(song_elapsed()+" / Stream Time",LCD_LINE_4,3) else: 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)