Die folgende Anleitung beschreibt den Umbau eines alten Küchenradios in einen vollwertigen /wiki/spaces/LOXBERRY/pages/1191313649 für das Logitech Media Center. Verwendet werden die Lautsprecher des alten Radios sowie die Bedienelemente. Für einen guten WAF (Woman Acceptance Faktor) kann der Client über 6 Taster und einen Drehimpulsgeber vor Ort ohne App, Handy, etc. bedient werden. Über den Drehimpulsgeber wird die Lautstärke geregelt, die 6 Taster dienen zur Belegung mit Radiosender-Favoriten und zum Ausschalten. Je nach Ausstattung eures Radios kann man selbstverständlich mehr oder weniger Tasten verwenden oder auch nachträglich Taster und/oder Drehimpulsgeber hinzufügen. Die Belegung der Taster erfolgt rein softwareseitig und kann natürlich dem eigenen Bedarf angepasst werden.
Das Ganze ist in einem Nachmittag erledigt. Mehr als rudimentäre Lötkenntnisse sind nicht notwendig.
Hardware
...
Diskussion und Fragen zum Artikel bitte im Loxforum: https://www.loxforum.com/forum/projektforen/musicserver4lox/hardware/290286-umbau-eines-alten-k%C3%BCchenradios-in-einen-squeezelite-client-wlan
Hardware
Raspberry Pi ZeroW oder alternativ Raspberry Pi A3+: ca. 20 EUR
Der ZeroW oder der A3+ haben genügend Leistungsreserve für einen Squeezelite Client und verbrauchen am wenigsten Strom. Darauf solltet ihr achten, da der Pi im Dauerbetrieb läuft. Ich habe den ZeroW verwendet, da er von der Leistung her vollkommen ausreicht, sehr günstig ist und aus der Pi-Familie am wenigsten Strom verbraucht. Vergesst nicht auch eine SD-Karte (mindestens 16 GB) und ein Netzteil dazu zu bestellen. Ein Gehäuse braucht ihr nicht.
...
Ihr müsst unbedingt darauf achten, dass ihr die GPIOs bzw. PINs nicht verwendet, die der HifiBerry selbst belegt. Weitere Informationen findet ihr hier: https://www.hifiberry.com/docs/hardware/gpio-usage-of-hifiberry-boards/ Beim HiFiBerry MiniAMP sind das: GPIO 16, 18-21 und 26 (PINs 36, 12, 35, 38, 40 und 37). Die Belegung des Headers findet ihr in der Raspberry Dokumentation: https://www.raspberrypi.org/documentation/usage/gpio/
Zunächst steckt man den Stacking Header auf den RaspPi und biegt sich die PINs, die man als GPIO verwenden möchte, nach außen. Daran kann man dann die Jumperkabel seitlich anschließen. So kann man die Taster und den Drehimpulsgeber anschließen und gleichzeitig später den HiFiBerry MiniAMP ebenfalls auf den Header stecken.
Ich benutze die folgenden GPIOs:
- GPIO 17 (PIN 11): Drehimpulsgeber
- GPIO 27 (PIN 13): Drehimpulsgeber
- GPIO 23 (PIN 16): Button 1
- GPIO 24 (PIN 18): Button 2
- GPIO 25 (PIN 22): Button 3
- GPIO 8 (PIN 24): Button 4
- GPIO 7 (PIN 26): Button 5
- GPIO 6 (PIN 31): Button 6
- PIN 20: Ground
- PIN 17: +3.3V
Installation
...
Codeblock | ||||||
---|---|---|---|---|---|---|
| ||||||
#!/usr/bin/env python2 import RPi.GPIO as GPIO from encoder import Encoder import time import os # # Einstellungen # # GPIO-Bezeichnungien (BCM) im Skript verwenden GPIO.setmode(GPIO.BCM) # LMS Einstellungen # Player, deder rmitmit den Tasten gesteuert werden soll player = "02:a7:37:bc:bd:1d" # Host Deines Logitech Media Server (oder IP-Adresse) server = "192.168.3.213" # Port asmam LMS für CLI KOmmandosKommandos port = "9000" # GPIO-Pins Drehimpulsgeber - gemeinsamer PIN auf +3.3V in_a = 17 in_b = 27 # GPIO-Pins Pushbutton - wahlweise gegen GND oder +3.3V in_c = 23 in_d = 24 in_e = 25 in_f = 8 in_g = 7 in_h = 6 # LMS Kommandos Drehimpulsgeber # Links: Vol -5% cmd_a = "curl -s -H \"Content-Type: application/json\" -X POST -d '{\"id\":1,\"method\":\"slim.request\",\"params\":[\"" + player + "\", [\"mixer\",\"volume\",\"+5\"]]}' http://" + server + ":" + port + "/jsonrpc.js" # Rechts: Vol +5% cmd_b = "curl -s -H \"Content-Type: application/json\" -X POST -d '{\"id\":1,\"method\":\"slim.request\",\"params\":[\"" + player + "\", [\"mixer\",\"volume\",\"-5\"]]}' http://" + server + ":" + port + "/jsonrpc.js" # LMS Kommandos Pushbuttons # Play Favorit 1 (Liste startet mit 0) cmd_c = "curl -s -H \"Content-Type: application/json\" -X POST -d '{\"id\":1,\"method\":\"slim.request\",\"params\":[\"" + player + "\", [\"favorites\",\"playlist\",\"play\",\"item_id:0\"]]}' http://" + server + ":" + port + "/jsonrpc.js" # Play Favorit 2 cmd_d = "curl -s -H \"Content-Type: application/json\" -X POST -d '{\"id\":1,\"method\":\"slim.request\",\"params\":[\"" + player + "\", [\"favorites\",\"playlist\",\"play\",\"item_id:21\"]]}' http://" + server + ":" + port + "/jsonrpc.js" # Play Favorit 3 cmd_e = "curl -s -H \"Content-Type: application/json\" -X POST -d '{\"id\":1,\"method\":\"slim.request\",\"params\":[\"" + player + "\", [\"favorites\",\"playlist\",\"play\",\"item_id:12\"]]}' http://" + server + ":" + port + "/jsonrpc.js" # Play Favorit 4 cmd_f = "curl -s -H \"Content-Type: application/json\" -X POST -d '{\"id\":1,\"method\":\"slim.request\",\"params\":[\"" + player + "\", [\"favorites\",\"playlist\",\"play\",\"item_id:93\"]]}' http://" + server + ":" + port + "/jsonrpc.js" # Play Favorit 5 cmd_g = "curl -s -H \"Content-Type: application/json\" -X POST -d '{\"id\":1,\"method\":\"slim.request\",\"params\":[\"" + player + "\", [\"favorites\",\"playlist\",\"play\",\"item_id:84\"]]}' http://" + server + ":" + port + "/jsonrpc.js" # Stop cmd_h = "curl -s -H \"Content-Type: application/json\" -X POST -d '{\"id\":1,\"method\":\"slim.request\",\"params\":[\"" + player + "\", [\"mode\",\"stop\"]]}' http://" + server + ":" + port + "/jsonrpc.js" # Pullup-/Pulldown-Widerstand einschalten # Bei Verschaltung gegen GND: GPIO.PUD_UP # Bei Verschaltung gegen +3.3V: GPIO.PUD_DOWN pullupdown_in_c = GPIO.PUD_UP pullupdown_in_d = GPIO.PUD_UP pullupdown_in_e = GPIO.PUD_UP pullupdown_in_f = GPIO.PUD_UP pullupdown_in_g = GPIO.PUD_UP pullupdown_in_h = GPIO.PUD_UP # Bounce-Zeit in ms bouncetime = 250 # # Einstellungen Ende # # GPIO Settings GPIO.setup(in_c, GPIO.IN, pull_up_down = pullupdown_in_c) GPIO.setup(in_d, GPIO.IN, pull_up_down = pullupdown_in_d) GPIO.setup(in_e, GPIO.IN, pull_up_down = pullupdown_in_e) GPIO.setup(in_f, GPIO.IN, pull_up_down = pullupdown_in_f) GPIO.setup(in_g, GPIO.IN, pull_up_down = pullupdown_in_g) GPIO.setup(in_h, GPIO.IN, pull_up_down = pullupdown_in_h) if pullupdown_in_c == GPIO.PUD_UP: edge_in_c = GPIO.FALLING else: edge_in_c = GPIO.RISING if pullupdown_in_d == GPIO.PUD_UP: edge_in_d = GPIO.FALLING else: edge_in_d = GPIO.RISING if pullupdown_in_e == GPIO.PUD_UP: edge_in_e = GPIO.FALLING else: edge_in_e = GPIO.RISING if pullupdown_in_f == GPIO.PUD_UP: edge_in_f = GPIO.FALLING else: edge_in_f = GPIO.RISING if pullupdown_in_g == GPIO.PUD_UP: edge_in_g = GPIO.FALLING else: edge_in_g = GPIO.RISING if pullupdown_in_h == GPIO.PUD_UP: edge_in_h = GPIO.FALLING else: edge_in_h = GPIO.RISING # Drehimpulsgeber oldvalue = 0 def DIG1(value): global oldvalue if value > oldvalue: print str(value) + " -> Richtung ist rechts. Sende: " os.system(cmd_a) print "" if value < oldvalue: print str(value) + " -> Richtung ist links. Sende: " os.system(cmd_b) print "" oldvalue = value # Button 1 def Button1(channel): print "Button 1 aktiviert. Sende:" os.system(cmd_c) print "" # Button 2 def Button2(channel): print "Button 2 aktiviert. Sende:" os.system(cmd_d) print "" # Button 3 def Button3(channel): print "Button 3 aktiviert. Sende:" os.system(cmd_e) print "" # Button 4 def Button4(channel): print "Button 4 aktiviert. Sende:" os.system(cmd_f) print "" # Button 5 def Button5(channel): print "Button 5 aktiviert. Sende:" os.system(cmd_g) print "" # Button 6 def Button6(channel): print "Button 6 aktiviert. Sende:" os.system(cmd_h) print "" # Interrupts e1 = Encoder(in_a, in_b, callback = DIG1) GPIO.add_event_detect(in_c, edge_in_c, callback = Button1, bouncetime = bouncetime) GPIO.add_event_detect(in_d, edge_in_d, callback = Button2, bouncetime = bouncetime) GPIO.add_event_detect(in_e, edge_in_e, callback = Button3, bouncetime = bouncetime) GPIO.add_event_detect(in_f, edge_in_f, callback = Button4, bouncetime = bouncetime) GPIO.add_event_detect(in_g, edge_in_g, callback = Button5, bouncetime = bouncetime) GPIO.add_event_detect(in_h, edge_in_h, callback = Button6, bouncetime = bouncetime) # Schleife try: while True: time.sleep(1) except: GPIO.cleanup() print "\nBye" |
...
Codeblock | ||||||
---|---|---|---|---|---|---|
| ||||||
#!/bin/bash
pgrep -f radiotasten.py >/dev/null 2>&1
if [[ $? -eq 1 ]]
then
echo "Skript wird neu gestartet"
./radiotasten.py &
else
echo "Skript läuft noch"
fi |
...
Codeblock | ||||
---|---|---|---|---|
| ||||
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""
#
# m h dom mon dow user command
*/5 * * * * loxberry cd /opt/loxberry/bin/plugins/radiotasten && ./watchdog.sh >/dev/null 2>&1 |
Hinweis:
Ich habe festgestellt, dass die Bedienung des Radios über die Ein- und Ausgänge nach einiger Zeit (mehrere Tage) nicht mehr funktioniert, obwohl das Radiotasten-Skript noch läuft. Ich vermute ein Problem mit den GPIOs und den Interrupts. Nach einem Neustart des Skripts funktioniert wieder alles einwandfrei. Daher starte ich mittlerweile das Skript einfach jede Nacht einmal neu. Dazu fügt man dem obigen Crontab-File einfach eine weitere Zeile an (hier wird das Skript um 03:01 jedne Tag neu gestartet):
Codeblock | ||||
---|---|---|---|---|
| ||||
01 03 * * * loxberry cd /opt/loxberry/bin/plugins/legacy/radiotasten && pkill -f radiotasten.py && ./watchdog.sh >/dev/null 2>&1 |
...