Was wird benötigt
- Raspberry Pi
- Hifiberry AMP oder Justboom AMP
- zwei Boxen
- MFRC522 NFC Reader
- TTP223 Schalter
- NFC Karten / Sticker oder sonstiger
- ein Gehäuse damit alles schön aussieht
- vielleicht noch ein paar LED’s
Grundinstallation
- Raspian installieren
- JustBoom aufstecken und konfigurieren
- Boxen an Justboom anschließen
mit etcher kann man das Image leicht auf eine SD Karte flashen
beim ersten Boot hilft es, den Raspberry Pi mit Tastatur und Monitor zu starten. Sobald man SSH Konfiguriert hat und ggf. eine Fixe IP zugeteilt hat braucht der Pi nur mehr Strom und Netzwerk.
SSH aktivieren:
Raspi-config -> Interfacing Options -> ssh enablen
FAQ von Justboom:
FAQ
Vorbereitungen:
1 2 3 4 |
#dtparam=audio=on dtparam=audio=off dtoverlay=justboom-dac dtparam=spi=on |
Test der Lautsprecher:
Lautsprecher mit +/- anklemmen und nach einem Reboot mit dem Programm speakertest überprüfen ob ein Rauschen aus den Boxen kommt
1 |
speakertest |
Falls hier Probleme auftauchen kann man anhand alsamixer überprüfen ob die neue „Soundkarte“ erkannt wurde – bei einer meiner Testinstallationen waren die Outputs auf Mute gestellt (MM)
Installation von RPi-Jukebox-RFID
Da wir für unsere spezielle Installation ein paar Dateien anpassen müssen, empfiehlt es sich eine aktuelle Release, anstatt des ansonsten üblichen git clones, direkt herunter zu laden. Unter https://github.com/MiczFlor/RPi-Jukebox-RFID/releases gibt es eine Übersicht der aktuellen Releases. Zum Zeitpunkt des Blog Beitrages war dies die Version 1.1.7
1 2 3 4 |
wget https://github.com/MiczFlor/RPi-Jukebox-RFID/archive/v1.1.7.tar.gz tar -xzvvf v1.1.7.tar.gz cd RPi-Jukebox-RFID-1.1.7 ./scripts/installscripts/stretch-install-default.sh |
Die Installation ist selbsterklärend, falls man sich bei irgendwelchen Settings nicht sicher ist, ist der Default Wert eigentlich immer richtig.
MPD Daemon anpassen
Die Phoniebox ist im Grunde genommen nur ein Kontrollsystem für den MPD. Wir müssen also dem „Music Player Daemon“ beibringen wie er unseren Sound ausgeben kann. Das Installationsskript hat bereits die meisten Sachen angepasst. Der audio_output funktioniert aber leider mit der Justboom noch nicht ganz. Anbei die zu ändernde Sektion:
1 2 3 4 5 6 7 |
audio_output { type "alsa" name "JustBoom" device "hw:0,0" mixer_type "software" mixer_device "digital" } |
Nach der Änderung müssen wir den MPD anhand von folgendem Command neustarten
1 |
/etc/init.d/mpd restart |
Test – Abspielen einer Musikdatei über Phoniebox
Die Installation ist nun unter /home/pi/RPi-Jukebox-RFID/ zu finden. Man kann über http://raspberrypi.ip/ auf die Oberfläche von Phoniebox zugreifen. Hier kann man gemütlich eine beliebige MP3 Datei hochladen, und diese test weise abspielen. Die Datei wird in meinem Fall unter /home/pi/RPi-Jukebox-RFID/shared/audiofiles/FOLDER abgelegt.
Den MFRC522 RFiD Reader in Betrieb nehmen
Zu aller erst benötigen wir zwei weitere Pakete (pyserial / SPI-Py)
1 2 3 4 5 6 |
sudo pip install pyserial cd ~ git clone https://github.com/lthiery/SPI-Py.git cd SPI-Py sudo python setup.py install |
Außerdem müssen wir folgende Dateien in unserem scripts Ordner ersetzen: Reader.py, RegisterDevice.py und daemon_rfid_reader.py. Der Einfachheit habe ich den Inhalt der Dateien hier nochmals eingefügt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# Forked from Francisco Sahli's https://github.com/fsahli/music-cards/blob/master/Reader.py import os.path import sys import serial import string import RPi.GPIO as GPIO from evdev import InputDevice, categorize, ecodes, list_devices import MFRC522 def get_devices(): devices = [InputDevice(fn) for fn in list_devices()] devices.append(NonUsbDevice('MFRC522')) devices.append(NonUsbDevice('RDM6300')) return devices class NonUsbDevice(object): name = None def __init__(self, name): self.name = name class UsbReader(object): def __init__(self, device): self.keys = "X^1234567890XXXXqwertzuiopXXXXasdfghjklXXXXXyxcvbnmXXXXXXXXXXXXXXXXXXXXXXX" self.dev = device def read_card(self): from select import select stri = '' key = '' while key != 'KEY_ENTER': select([self.dev], [], []) for event in self.dev.read(): if event.type == 1 and event.value == 1: stri += self.keys[event.code] key = ecodes.KEY[event.code] return stri[:-1] class Mfrc522Reader(object): def __init__(self): self.device = MFRC522.MFRC522() def read_card(self): # Scan for cards status, tag_type = self.device.MFRC522_Request(self.device.PICC_REQIDL) # If a card is found if status == self.device.MI_OK: print "Card detected" # Get the UID of the card (status, uid) = self.device.MFRC522_Anticoll() # If we have the UID, continue if status == self.device.MI_OK: return ''.join((str(x) for x in uid)) else: print "No Device ID found." return None @staticmethod def cleanup(): GPIO.cleanup() class Rdm6300Reader: def __init__(self): device = '/dev/ttyS0' baudrate = 9600 ser_timeout = 0.1 self.last_card_id = '' try: self.rfid_serial = serial.Serial(device, baudrate, timeout=ser_timeout) except serial.SerialException as e: print(e) exit(1) def read_card(self): byte_card_id = b'' try: while True: try: read_byte = self.rfid_serial.read() if read_byte == b'\x02': # start byte while read_byte != b'\x03': # end bye read_byte = self.rfid_serial.read() byte_card_id += read_byte card_id = byte_card_id.decode('utf-8') byte_card_id = '' card_id = ''.join(x for x in card_id if x in string.printable) # Only return UUIDs with correct length if len(card_id) == 12 and card_id != self.last_card_id: self.last_card_id = card_id self.rfid_serial.reset_input_buffer() return self.last_card_id else: # wrong UUID length or already send that UUID last time self.rfid_serial.reset_input_buffer() except ValueError as ve: print(ve) except serial.SerialException as se: print(se) def cleanup(self): self.rfid_serial.close() class Reader(object): def __init__(self): path = os.path.dirname(os.path.realpath(__file__)) if not os.path.isfile(path + '/deviceName.txt'): sys.exit('Please run config.py first') else: with open(path + '/deviceName.txt', 'r') as f: device_name = f.read() if device_name == 'MFRC522': self.reader = Mfrc522Reader() elif device_name == 'RDM6300': self.reader = Rdm6300Reader() else: try: device = [device for device in get_devices() if device.name == device_name][0] self.reader = UsbReader(device) except IndexError: sys.exit('Could not find the device %s.\n Make sure it is connected' % device_name) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/usr/bin/env python2 # Forked from Francisco Sahli's https://github.com/fsahli/music-cards/blob/master/config.py import os.path from Reader import get_devices devices = get_devices() print "Choose the reader from list:" for i in range(len(devices)): print i, devices[i].name dev_id = int(raw_input('Device Number: ')) path = os.path.dirname(os.path.realpath(__file__)) with open(path + '/deviceName.txt', 'w') as f: f.write(devices[dev_id].name) f.close() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#!/usr/bin/env python2 import subprocess import os import signal from Reader import Reader reader = Reader() continue_reading = True # get absolute path of this script dir_path = os.path.dirname(os.path.realpath(__file__)) # Capture SIGINT for cleanup when the script is aborted def end_read(signal, frame): global continue_reading print "Ctrl+C captured, ending read." continue_reading = False reader.reader.cleanup() # Welcome message print "Press Ctrl-C to stop." # Hook the SIGINT signal.signal(signal.SIGINT, end_read) while continue_reading: # reading the card id cardid = reader.reader.read_card() if cardid is not None: try: # start the player script and pass on the card id subprocess.call([dir_path + '/rfid_trigger_play.sh --cardid=' + cardid], shell=True) except OSError as e: print "Execution failed:" + str(e) |
python RegisterDevice.py (0 -> MFRC522)
nach wiring – reboot
in MFRC522.py ist die spidev0.0 drin -> hat bei mir gepasst / koennte sein dass man das auf spi0.1.
/home/pi/RPi-Jukebox-RFID/scripts/daemon_rfid_reader.py
root@raspberrypi:/home/pi/RPi-Jukebox-RFID/scripts# ./daemon_rfid_reader.py
Press Ctrl-C to stop.
No Device ID found.
No Device ID found.
No Device ID found.
Card detected
No Device ID found.
^Ctrl+C captured, ending read.
Startscripte installieren
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
sudo cp /home/pi/RPi-Jukebox-RFID/misc/sampleconfigs/phoniebox-rfid-reader.service.stretch-default.sample /etc/systemd/system/phoniebox-rfid-reader.service sudo cp /home/pi/RPi-Jukebox-RFID/misc/sampleconfigs/phoniebox-light.service.stretch-default.sample /etc/systemd/system/phoniebox-light.service sudo cp /home/pi/RPi-Jukebox-RFID/misc/sampleconfigs/phoniebox-startup-sound.service.stretch-default.sample /etc/systemd/system/phoniebox-startup-sound.service sudo cp /home/pi/RPi-Jukebox-RFID/misc/sampleconfigs/phoniebox-gpio-buttons.service.stretch-default.sample /etc/systemd/system/phoniebox-gpio-buttons.service sudo cp /home/pi/RPi-Jukebox-RFID/misc/sampleconfigs/phoniebox-idle-watchdog.service.sample /etc/systemd/system/phoniebox-idle-watchdog.service sudo systemctl enable phoniebox-idle-watchdog sudo systemctl enable phoniebox-rfid-reader sudo systemctl enable phoniebox-light sudo systemctl enable phoniebox-startup-sound sudo systemctl enable phoniebox-gpio-buttons sudo systemctl start phoniebox-idle-watchdog sudo systemctl start phoniebox-rfid-reader sudo systemctl start phoniebox-light sudo systemctl start phoniebox-startup-sound sudo systemctl start phoniebox-gpio-buttons |
Automount in die /etc/fstab schreiben
1 |
//NAS.local/Musik /home/pi/RPi-Jukebox-RFID/shared/audiofolders/ cifs credentials=/home/pi/.smbcredentials 0 0 |
.smbcredentials im home folder ablegen und mit mount -a den nfsmount testen
1 2 |
username=pi password=myreallysecretsecret |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
#!/usr/bin/env python2 import os import time import RPi.GPIO as GPIO from signal import pause from subprocess import check_call dir_path = os.path.dirname(os.path.realpath(__file__)) GPIO.setmode(GPIO.BCM) haltPin = 27 volDPin = 5 volUPin = 16 nextPin = 22 prevPin = 17 shutPin = 26 GPIO.setup(haltPin, GPIO.IN) GPIO.setup(volDPin, GPIO.IN) GPIO.setup(volUPin, GPIO.IN) GPIO.setup(nextPin, GPIO.IN) GPIO.setup(prevPin, GPIO.IN) GPIO.setup(shutPin, GPIO.IN) def shut(): for i in range(30): time.sleep(0.1) if GPIO.input(shutPin) == 0: # button not held down return check_call(dir_path + "/playout_controls.sh -c=shutdown", shell=True) def volU(): check_call(dir_path + "/playout_controls.sh -c=volumeup", shell=True) for i in range(150): time.sleep(0.1) if ((GPIO.input(volUPin) == 1) & (i%5 == 0) & (i<>0)): check_call(dir_path + "/playout_controls.sh -c=volumeup", shell=True) if GPIO.input(volUPin) == 0: return def volD(): check_call(dir_path + "/playout_controls.sh -c=volumedown", shell=True) for i in range(150): time.sleep(0.1) if ((GPIO.input(volDPin) == 1) & (i%5 == 0) & (i<>0)): check_call(dir_path + "/playout_controls.sh -c=volumedown", shell=True) if GPIO.input(volDPin) == 0: return alreadyHaltPressed = False alreadyVolDPressed = False alreadyVolUPressed = False alreadyNextPressed = False alreadyPrevPressed = False alreadyShutPressed = False while True: haltPressed = GPIO.input(haltPin) volDPressed = GPIO.input(volDPin) volUPressed = GPIO.input(volUPin) nextPressed = GPIO.input(nextPin) prevPressed = GPIO.input(prevPin) shutPressed = GPIO.input(shutPin) if haltPressed and not alreadyHaltPressed: check_call(dir_path + "/playout_controls.sh -c=playerpause", shell=True) if volDPressed and not alreadyVolDPressed: volD() if volUPressed and not alreadyVolUPressed: volU() if nextPressed and not alreadyNextPressed: check_call(dir_path + "/playout_controls.sh -c=playernext", shell=True) if prevPressed and not alreadyPrevPressed: check_call(dir_path + "/playout_controls.sh -c=playerprev", shell=True) if shutPressed and not alreadyShutPressed: shut() alreadyHaltPressed = haltPressed alreadyVolDPressed = volDPressed alreadyVolUPressed = volUPressed alreadyNextPressed = nextPressed alreadyPrevPressed = prevPressed alreadyShutPressed = shutPressed time.sleep(0.01) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#!/usr/bin/env python2 import subprocess import os import signal import time from Reader import Reader reader = Reader() continue_reading = True # get absolute path of this script dir_path = os.path.dirname(os.path.realpath(__file__)) # Capture SIGINT for cleanup when the script is aborted def end_read(signal, frame): global continue_reading print "Ctrl+C captured, ending read." continue_reading = False reader.reader.cleanup() # Welcome message print "Press Ctrl-C to stop." # Hook the SIGINT signal.signal(signal.SIGINT, end_read) while continue_reading: # reading the card id cardid = reader.reader.read_card() if cardid is not None: try: # start the player script and pass on the card id subprocess.call([dir_path + '/rfid_trigger_play.sh --cardid=' + cardid], shell=True) except OSError as e: print "Execution failed:" + str(e) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
#!/usr/bin/env python2 import os import time import RPi.GPIO as GPIO from signal import pause from subprocess import check_call dir_path = os.path.dirname(os.path.realpath(__file__)) GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) red = 12 green = 20 blue = 13 lightPin = 6 GPIO.setup(lightPin, GPIO.IN) GPIO.setup(red, GPIO.OUT) GPIO.setup(green, GPIO.OUT) GPIO.setup(blue, GPIO.OUT) Freq = 100 outval = 128 def wheel_color(position): if position < 0: position = 0 if position > 383: position = 383 if position < 128: r = 127 - position % 128 g = position % 128 b = 0 elif position < 256: g = 127 - position % 128 b = position % 128 r = 0 else: b = 127 - position % 128 r = position % 128 g = 0 return r, g, b RED = GPIO.PWM(red, Freq) GREEN = GPIO.PWM(green, Freq) BLUE = GPIO.PWM(blue, Freq) alreadyLightPressed = False lightSwitch = "Off" while True: for pos in range(0,385): lightPressed = GPIO.input(lightPin) if lightPressed and not alreadyLightPressed: if lightSwitch == "Off": lightSwitch = "On" RED.start(100) GREEN.start(100) BLUE.start(100) else: lightSwitch = "Off" RED.start(0) GREEN.start(0) BLUE.start(0) if lightSwitch == "On": r, g, b = wheel_color(pos) percenttestr = (r/255.0)*100.0 percenttestg = (g/255.0)*100.0 percenttestb = (b/255.0)*100.0 RED.ChangeDutyCycle(percenttestr) GREEN.ChangeDutyCycle(percenttestg) BLUE.ChangeDutyCycle(percenttestb) time.sleep(0.1) alreadyLightPressed = lightPressed time.sleep(0.01) |