Tag Archives: RPizeBox

RPizeBox + Soundblaster Play!

I hated the fluttery background noises on the standard analogue audio jack on the RPi, so bought a Soubdblaster Play! for £20 from eBay.

http://elinux.org/RPi_VerifiedPeripherals#Class_compliant_USB_sound_cards said:

edit /etc/modprobe.d/alsa-base.conf and comment out the last line; options snd-usb-audio index=-2

I actually commented out all the extra lines that ended -2 and now I have excellent quality audio.  Really pleased.  The RPiBox is complete.  Wires for the GPIO and an improved larger screen have arrived.  I just need to find a container.

Moving RPizeBox to git

500D_1901

Now I have the proof of concept for the RPi, I wanted to improve the code and have long term plans to make it remember tracks we skip, as well as allowing a blacklist!  I wanted to keep some sort of version control, and this is where git comes in.  I have been aware of git for a while but don’t really know much about it.

I now have created my own git hub for RPizeBox at https://github.com/thomaswwp/RPizeBox. I also forked PyLMS (which appears to be abandoned) and will eventually include it in my build as a module, rather than simply importing the code.

I have reduced the code to two scripts, but this looks like it has increased the CPU overhead to about 6%, so I may revert to what I had before.

I have also made a Fritzing diagram of the setup for future reference.

RPizeBox_bb

I also found that the skip forward button was broken on the remote, so just remapped other buttons.

500D_1902

 

LIRC setup on RPi #2

After, much MUCH frustration in failing to get LIRC to recognise my remote on my spare RPi, I set it up fresh on the actual RPizeBox, just to see what happened.  The steps were something like those described on alexba.in but I am copying them here.  Spot the minor change.  Thanks alexba.in!

sudo apt-get install lirc

Add this to /etc/modules file:

lirc_dev
lirc_rpi gpio_in_pin=25

Change /etc/lirc/hardware.conf file to:

########################################################
 # /etc/lirc/hardware.conf
 #
 # Arguments which will be used when launching lircd
 LIRCD_ARGS="--uinput"
 # Don't start lircmd even if there seems to be a good config file
 # START_LIRCMD=false
 # Don't start irexec, even if a good config file seems to exist.
 # START_IREXEC=false
 # Try to load appropriate kernel modules
 LOAD_MODULES=true
 # Run "lircd --driver=help" for a list of supported drivers.
 DRIVER="default"
 # usually /dev/lirc0 is the correct setting for systems using udev
 DEVICE="/dev/lirc0"
 MODULES="lirc_rpi"
 # Default configuration files for your hardware if any
 LIRCD_CONF=""
 LIRCMD_CONF=""
 ########################################################

Restart lircd so it picks up these changes:

sudo /etc/init.d/lirc stop
sudo /etc/init.d/lirc start

It worked immediately.  Here are the remote codes appearing.

pi@hood ~ $ sudo irw
0000000000001826 00 0/10 Sony_RMT-CS33AD
0000000000001826 01 0/10 Sony_RMT-CS33AD
0000000000001826 02 0/10 Sony_RMT-CS33AD
0000000000001826 03 0/10 Sony_RMT-CS33AD
0000000000001826 04 0/10 Sony_RMT-CS33AD
0000000000001826 05 0/10 Sony_RMT-CS33AD
0000000000001826 06 0/10 Sony_RMT-CS33AD
0000000000001826 07 0/10 Sony_RMT-CS33AD
0000000000001826 08 0/10 Sony_RMT-CS33AD
0000000000007026 00 08 Sony_RMT-CS33AD
0000000000007026 01 08 Sony_RMT-CS33AD
0000000000007026 02 08 Sony_RMT-CS33AD

I set up pylirc the easy way this time!

sudo apt-get install python-pip
sudo pip install pylirc2

Easy.

I then downloaded the pylirc_test.py and its conf file as suggested in the Voice of Reason and optimistically ran it.  And nothing happened at all, which was very disappointing indeed.  But I am one step closer I guess.  Maddening that it didn’t work with the other RPi.

I then found this glorious page from 2009 by Will Miro.  It helped me make a config file that worked and finally I got the test page responding.  I think that is enough for now.

RPizeBox Display code

Here is the code for now. It needs pylms downloaded and wiringpi2 to work.  I made some changes to pylms player.py to allow for accented letters in the titles so I just load the code rather than importing it.

#####################################################################
# SqueezeLite LCD Display                                           #
# Thomas W-P - http://thomas.w-p.me.uk                              #
# Needs to be run as sudo                                           #
#                                                                   #
# Known issues:                                                     #
#      Code is a bit crap, but that's life.  It just about works.   #
#                                                                   #
#####################################################################
import wiringpi2 as wp      # to control display
import time, datetime           # for delays and date
import fcntl, socket, struct # to get mac address
import commands           # to get IP address
#import subprocess              # for printing to console
import sys
sys.path.append('/home/pi/PyLMS/')

from pylms.server import Server # to talk to LMS server
from pylms.player import Player # to talk to LMS player


# variables/constants
loggedin = False      # to wait for the server
scrollpos = 0       # for scrolling the title - needs to be remembered...
waitBeforeOffMinutes = 10   # time to wait before switching off in minutes
waitCount = 0               # counter for the suspend mode
elapsed = float(0)          # to hold elapsed time
total = float(0)            # to hold total time
scPort = 9090               # default LMS port for CLI
scUser = ""                 # CLI user
scPassword = ""             # CLI password
whatToShow = 0              # 0 = Artist, 1 = Album, 2 = Position/Length



# to get the mac address
def getHwAddr(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', ifname[:15]))
    return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]

# to scroll the title
def scrollTitle():
    tracktitle = ""       # string to hold track title
    global scrollpos
    try:
        tracktitle = sl.get_track_title()
        if (len(tracktitle) > 16):
            tracktitle += " --- " + tracktitle[:16]
            for x in range(0,7):
                # exit if not in "Play" mode
                if (sl.get_mode() != 'play'):
                    return
                # we're at the start - pause 
                if (scrollpos == 0):
                    # scroll 
                    wp.lcdPosition(lcd, 0, 0)
                    wp.lcdPuts(lcd,tracktitle[0:16])
                    time.sleep(3)
                if (len(tracktitle) > 16+scrollpos):
                    scrollpos += 1
                    wp.lcdPosition(lcd, 0, 0)
                    wp.lcdPuts(lcd,tracktitle[scrollpos:16+scrollpos])
                    time.sleep(0.4)
                elif (len(tracktitle) == 16+scrollpos): #we've got back to the start
                    scrollpos = 0
        else:   #standard title
            for x in range(0,4):
                if (sl.get_mode() != 'play'):
                    return
                wp.lcdPosition(lcd, 0, 0)
                wp.lcdPuts(lcd,(tracktitle + " "*16)[:16])
                time.sleep(1)

    except:
        wp.lcdPosition(lcd, 0, 0)
        #cmd = [ 'echo', tracktitle ]
        #output = subprocess.Popen( cmd, stdout=subprocess.PIPE ).communicate()[0]
        #print output
        wp.lcdPuts(lcd,"(Title unknown)")
        time.sleep(5)  


# get the IP address
import commands
intf = 'eth0'
intf_ip = commands.getoutput("ip address show dev " + intf).split()
intf_ip = intf_ip[intf_ip.index('inet') + 1].split('/')[0]

# set up the display - 4 bit to save pins - apparently slower but marginal
# https://projects.drogon.net/raspberry-pi/wiringpi/lcd-library/
wp.wiringPiSetup();
lcd = wp.lcdInit (2, 16, 4,  11,10 , 0,1,2,3,0,0,0,0)

# connect to the squeezebox
sc = Server(hostname=intf_ip, port=scPort, username=scUser, password=scPassword)

# initialising
wp.lcdClear(lcd)      # clear the lcd
wp.lcdPosition(lcd, 0, 0) # cursor to start of row


# keep trying to connect until there is a response
while loggedin != True:
    try:
        sc.connect()
        loggedin = sc.logged_in
        #wp.lcdPuts(lcd,str(loggedin))
    except:
        wp.lcdClear(lcd)
        wp.lcdPosition(lcd, 0, 0)
        wp.lcdPuts(lcd,"Music server"[:16])
        wp.lcdPosition(lcd, 0, 1)
        wp.lcdPuts(lcd,"   not ready :("[:16])
        time.sleep(3)

# set up the player
sl = sc.get_player(getHwAddr("eth0")) # http://stackoverflow.com/questions/159137/getting-mac-address

# change the display
while True:

    # show something
    if (sl.get_mode() == 'play'):
        waitCount = 0 
        try:
            wp.lcdPosition(lcd, 0, 1)
            # no switch in python!
            if(whatToShow == 0):
                wp.lcdPuts(lcd,(sl.get_track_artist() + " "*16)[:16])
            elif(whatToShow == 1):
                wp.lcdPuts(lcd,(sl.get_track_album() + " "*16)[:16])
            elif(whatToShow == 2):
                wp.lcdPosition(lcd, 0, 1)  
                elapsed = sl.get_time_elapsed()
                total = sl.get_track_duration()
                progress = int(9 * elapsed / total)#
                wp.lcdPuts(lcd,">" + ">"*(progress+1)+"-"*(8-progress) + " " + str(datetime.timedelta(seconds=int(total)))[-5:])            
            whatToShow += 1
            if (whatToShow == 3):
                whatToShow = 0
        except:
            wp.lcdPuts(lcd,"      ~~~~      "[:16])          
        # title scrolling
        scrollTitle()  


    # deal with pause/stop
    if (sl.get_mode() == 'pause'):
        wp.lcdPosition(lcd, 0, 0)
        wp.lcdPuts(lcd,(sl.get_track_artist() + " "*16)[:16])
        wp.lcdPosition(lcd, 0, 1)  
        wp.lcdPuts(lcd,("     PAUSED" + " "*16)[:16])
        time.sleep(1)
        waitCount += 1
        if (waitCount >= (waitBeforeOffMinutes * 60)): 
            # send "OFF" message to player
            sl.set_power_state(False)

    if (sl.get_mode() == 'stop'):
        waitCount = 0
        wp.lcdPosition(lcd, 0, 1)  
        wp.lcdPuts(lcd,"           " + time.strftime("%H:%M", time.gmtime())[:16])
        wp.lcdPosition(lcd, 0, 0)
        wp.lcdPuts(lcd,(datetime.datetime.now().strftime("%A") + " " + datetime.datetime.now().strftime("%d")+ " " + datetime.datetime.now().strftime("%B")[:3] + " "*16)[:16])
        time.sleep(1)