W pierwszej i drugiej części napisałem wszystko co powinno spowodować zadziałanie urządzenia. Muzyka powinna zagrać, klient powinien umieć tym zarządzać. Dla wygody /​bajeru dołożymy sobie do tego skromnego zestawu wyświetlacz LCD, o którym będzie traktować niniejszy elaborat.

Obsługa wyświetlacza LCD i wyłącznika

Pozwoliłem sobie napisać niezgrabny skrypt, który będzie mikro klientem mpd, sterownikiem LCD oraz zarządzaczem guzika od wyłączania z prądu. Czuj się wolny w modyfikacji (i krytyce) tego frywolnego dzieła. Udzielam nań licencji jakoś tak zgodnej z GPL

Najpierw jednak niezbędne dodatkowe pakiety:

apt-get install python python2.7 python-minimal python2.7-minimal mime-support

Do obsługi LCD będzie nam potrzebne jeszcze RPi-​GPIO (wymaga pakietów python wymienionych powyżej)

Ściągamy ten moduł (http://​code​.google​.com/​p​/​r​a​s​p​b​e​r​r​y​-​g​p​i​o​-​p​y​t​h​o​n​/​d​o​w​n​l​o​a​d​s​/list), najlepiej za pomocą wget. Na dziś by to wyglądało tak:

wget http://raspberry-gpio-python.googlecode.com/files/python-rpi.gpio_0.5.3a-1_armhf.deb

Następnie instalujemy go

dpkg -i python-rpi.gpio_0.5.3a-1_armhf.deb

Teraz skrypt, który umieszczam w katalogu /​root

#!/usr/bin/python

from time import sleep
from threading import Timer
import time
import RPi.GPIO as GPIO  
import os
import socket
import sys
import datetime

########################################################################
# LCD service 
class Lcd:  

 	def __init__(self, pin_rs=7, pin_e=8, pins_db=[25, 24, 23, 18]):  # BCM numbers

		self.pin_rs=pin_rs  
		self.pin_e=pin_e  
		self.pins_db=pins_db  
		self.epulse = 0.000001
		self.edelay = 0.000001			# must be > 450 ns = 0.000000450
		self.mychars = 	[0x00, 0x08, 0x0C, 0x0E, 0x0E, 0x0C, 0x08, 0x00,	# 0x00 PLAY
				0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,		# 0x01 PAUSE
				0x00, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x00]		# 0x02 STOP

		self.lines = [0x80, 0xC0]
		self.rows = 8

		GPIO.setmode(GPIO.BCM)  		# BCM numbers
		#GPIO.setmode(GPIO.BOARD)  		# P1 numbers
		GPIO.setup(self.pin_e, GPIO.OUT)  
		GPIO.setup(self.pin_rs, GPIO.OUT)  
		for pin in self.pins_db:  
				GPIO.setup(pin, GPIO.OUT)  

		self.clear()  
		self.myChars()

	def clear(self):  
		# Reset LCD
		self.cmdByte(0x33) 
		self.cmdByte(0x32)
		self.cmdByte(0x28)
		self.cmdByte(0x0C)
		self.cmdByte(0x06)
		self.cmdByte(0x01)

	def myChars(self):
		self.cmdByte(0x40)
		for ch in self.mychars:
			self.cmdChar(ch)
		self.cmdByte(0x80)

	def cmdChar(self,bits):
		self.cmd(bits,True)

	def cmdByte(self,bits):
		self.cmd(bits,False)

	def ePulse(self):
		time.sleep(self.edelay)
		GPIO.output(self.pin_e,True)
		time.sleep(self.epulse)
		GPIO.output(self.pin_e,False)
		time.sleep(self.edelay)

	def cmd(self, bits, char_mode=False):  
		# Send command to LCD
		sleep(0.001)  
		bits=bin(bits)[2:].zfill(8)  
		GPIO.output(self.pin_rs, char_mode)  
		for pin in self.pins_db:  
			GPIO.output(pin, False)  
		for i in range(4):  
			if bits[i] == "1":  
				GPIO.output(self.pins_db[::-1][i], True)  
 		self.ePulse()
		for pin in self.pins_db:  
			GPIO.output(pin, False)  
		for i in range(4,8):  
			if bits[i] == "1":  
				GPIO.output(self.pins_db[::-1][i-4], True)  
 		self.ePulse() 

	def goto(self, line, row = 0):
		self.cmdByte(self.lines[line]+row)

	def write(self, text):  
		for char in text:  
			self.cmdChar(ord(char))  

########################################################################
# Interval from https://gist.github.com/alexbw/1187132
class RepeatingTimer(object):
	"""
	USAGE:
	from time import sleep
	def myFunction(inputArgument):
		print(inputArgument)
	r = RepeatingTimer(0.5, myFunction, "hello")
	r.start(); sleep(2); r.interval = 0.05; sleep(2); r.stop()
	"""

	def __init__(self,interval, function, *args, **kwargs):
		super(RepeatingTimer, self).__init__()
		self.args = args
		self.kwargs = kwargs
		self.function = function
		self.interval = interval

	def start(self):
		self.callback()
	def stop(self):
		self.interval = False
	def callback(self):
		if self.interval:
			self.function(*self.args, **self.kwargs)
			Timer(self.interval, self.callback, ).start()

########################################################################
# MPD Client
class Mpc:
	def __init__(self, host = 'localhost', port = 6600):
		self.recvsize = 2**20
		self.waitsec = 20
		self.host = host
		self.port = port
		self.socket = False
		self.connect()

	def connect(self):
		trycn = 0
		while(trycn < self.waitsec and not self.socket):
			try:
				self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
				self.socket.connect((self.host, self.port))
			except socket.error:
				trycn += 1
				self.socket = False
				sleep(1)
				pass

		return self.socket

	def getStatus(self):
		self.socket.send('status\n')
		status = self.socket.recv(self.recvsize)
		return self.parseMsg(status)

	def parseMsg(self, txt = ''):
		msg = {}
		lines = txt.split('\n')
		for line in lines:
			pair = line.split(': ')
			if(len(pair)==2):
				msg[pair[0]] = pair[1]
		return msg

########################################################################
# main class
class Main:
	def __init__(self):
		self.bttPoweroff = 4
		GPIO.setmode(GPIO.BCM)  		# BCM numbers
		GPIO.setup(self.bttPoweroff, GPIO.IN, pull_up_down=GPIO.PUD_UP) # interrupt for bttPoweroff
		GPIO.add_event_detect(self.bttPoweroff, GPIO.RISING, callback=self.poweroff) # event for this interrupt

		self.lcd = Lcd()
		self.lcd.goto(0)
		self.lcd.write('Waiting ')
		self.lcd.goto(1)
		self.lcd.write('for mpd ')

		self.mpc = Mpc()

		if(self.mpc):
			self.timer = RepeatingTimer(1, self.everySecond)
			self.timer.start()
		else:
			self.lcd.goto(0)
			self.lcd.write('Error   ')
			self.lcd.goto(1)
			self.lcd.write('no mpd  ')
			sys.exit(1)

	# every second
	def everySecond(self):
		msg = self.mpc.getStatus()
		state = ''
		song = '0'
		playlistlength = '0'
		time = '0'

		if 'state' in msg:
			state = msg['state']

		if 'song' in msg:
			song = msg['song']

		if 'playlistlength' in msg:
			playlistlength = msg['playlistlength']

		if 'time' in msg:
			time = self.secToNiceTime(msg['time'])

		first_line = (str(int(song)+1) + '/' + playlistlength).ljust(self.lcd.rows)
		self.lcd.goto(0)
		self.lcd.write(first_line) 

		if state == 'play':
			self.lcd.goto(1)
			self.lcd.cmdChar(0x00)
			self.lcd.write(time.rjust(self.lcd.rows-1))

		elif state == 'pause':
			self.lcd.goto(1)
			self.lcd.cmdChar(0x01)
			self.lcd.write(time.rjust(self.lcd.rows-1))

		elif state == 'stop':
			self.lcd.goto(1)
			self.lcd.cmdChar(0x02)
			self.lcd.write('        ')

	def poweroff(self, channel):
		self.timer.stop()
		self.lcd.goto(0)
		self.lcd.write('Shutdown')
		self.lcd.goto(1)
		self.lcd.write('        ')
		os.system("/sbin/poweroff")
		##sys.exit(1)
		#print "Poweroff"

	def secToNiceTime(self,sec):
		t = str(datetime.timedelta(seconds=int(sec.split(':')[0])))
		if t[:1] == '0':
			return t[-5:]
		else:
			return t

# for /etc/init.d/rplayer script
f = open("/var/run/rplayer.pid", "w")
f.write(str(os.getpid()))
f.close()

GPIO.setwarnings(False) 
m = Main()

Skrypt powinien uruchamiać się przy starcie systemu. Tworzymy zatem w katalogu /etc/init.d/ plik o nazwie rplayer z następującą zawartością:
(Jeśli wcześniej zmieniłeś lokalizację pliku rplayer​.py - tutaj musisz też to zmienić.)

#!/bin/sh

### BEGIN INIT INFO
# Provides:          rplayer
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Should-Start:      
# Should-Stop:       
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Raspberry PI mpd client
# Description:       Start the blah... blah... blah...
### END INIT INFO

. /lib/lsb/init-functions

PATH=/sbin:/bin:/usr/sbin:/usr/bin
NAME=rplayer
DESC="Raspbery PI mpd client"
DAEMON="/root/rplayer.py"
PIDFILE="/var/run/rplayer.pid"

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

mpc_start () {
    log_daemon_msg "Starting $DESC" "$NAME"
    start-stop-daemon --start --quiet --oknodo --exec "$DAEMON" & 
    log_end_msg $?
}

mpc_stop () {
    log_daemon_msg "Stopping $DESC" "$NAME"
    start-stop-daemon --stop --quiet --oknodo --retry 5 --pidfile $PIDFILE
    rm -rf $PIDFILE
    log_end_msg $?
}

case "$1" in
    start)
        mpc_start
        ;;
    stop)
        mpc_stop
        ;;
    status)
    	status_of_proc -p $PIDFILE $DAEMON $NAME
	;;
    restart|force-reload)
        mpc_stop
        mpc_start
        ;;
    force-start)
        mpc_start
        ;;
    force-restart)
        mpc_stop
        mpc_start
        ;;
    force-reload)
	mpc_stop
	mpc_start
	;;
    *)
        echo "Usage: $0 {start|start-create-db|stop|restart|force-reload}"
        exit 2
        ;;
esac

Te zakomentowane linie na początku są ważne.

Nadajemy mu prawa do wykonywania:

chmod +x rplayer

Teraz będąc w katalogu /etc/init.d/ wykonujemy magiczną komendę:

update-rc.d rplayer defaults

Utworzy ona symboliczne dołączenia w katalogach rcX.d ...i pewnie coś jeszcze zrobi.

Teraz wystarczy zrestartować RPi ...lub prościej - uruchomić skrypt ręcznie

/etc/init.d/rplayer start

Pierwsza część opisuje kwestie hardware.
drugiej części mowa jest o instalacji i konfiguracji systemu operacyjnego oraz serwera MPD.

Wszelkie uwagi będą mile widziane.