Sonos ist ein geiles System, aber … Von Flexibilität haben die da leider noch nichts gehört. Auch die wollen Geld schöffeln und für jeden Zweck ein eigenes Gerät verkaufen. Unser Problem: Wir haben einen Sonos Connect Amp im Wohnzimmer und zusätzlich einen AVReceiver als Verstärker und HDMI-Umschalter für den Beamer. Jeder für sich braucht ein Lautsprecherpaar, d.h. es stehen vier Lautsprecher in der Gegend rum. Wir haben uns unterschiedliche Konfigurationen überlegt, auch mit anderen Sonos Geräten, kamen aber nie auf eine Zufriedenstellende und/oder bezahlbare Lösung. Also durfte ich endlich wieder was basteln 😀
Problem beim Umschalten zwischen zwei Verstärkern ist, dass die Verstärker niemals miteinander verbunden werden dürfen. Bei einem Lautsprecherumschalter ist dies nicht gegeben, da wird nicht darauf geachtet weil es unwichtig ist. Die am Markt verfügbaren Verstärkerumschalter sind alle technisch veraltet (Automation? Schnittstellen?) oder wieder sehr sehr teuer. Wir haben so viel Zeit in die Hausautomation gesteckt, da will ich doch nicht immer von Hand umschalten müssen. Vor allem nicht wenn ich bereits auf dem Sofa liege 😉
Also ging es an einen Plan für einen Umschalter über Relais mit dem ESP8266 (Microcontroller mit WLAN). Ich arbeite bewusst mit vier Relais, um ein zeit verzögertes aus- und einschalten beim Wechsel zwischen den beiden Verstärkern realisieren zu können. Zudem wurde eine Schutzschaltung in Hardware eingebaut die beim Schalten des einen Verstärkers die Schalteingänge für die Relais des zweiten Verstärkers auf Masse zieht, damit diese nicht versehentlich gleichzeitig geschaltet werden können. Sollte es nun passieren, dass alle Relais gleichzeitig geschaltet werden, gibt es keinen Kurzschluss, sondern ein Verstärker gewinnt immer.
Neben den im Schaltplan ersichtlichen Bauteilen kam noch folgendes dazu:
- Gehäuse
- Anschlussklemmen rot & schwarz
- LED für Gehäuseeinbau grün & gelb
- Taster für Gehäuseeinbau mit Sicherungsring
Da die Front- und Rückseite des Gehäuses aus Metall ist und die Anschlussklemmen nicht isoliert sind, habe ich die Rückseite durch eine Epoxy-Platte ersetzt.
Als Software kommt MicroPython für den ESP8266 zum Einsatz. Aktuell gibt es das Binary noch nicht öffentlich sondern nur eine Preview für Unterstützer über Kickstarter.
Fazit: Die Preview ist schon mega geil! Macht viel mehr Laune damit den ESP zu bestücken als mit der ArduinoIDE. Zudem hat man eine direkte Python-Konsole auf dem ESP und kann per Kommandozeile mit dem Microcontroller arbeiten. Das macht das Programmieren und Debuggen um einiges einfacher.
Hier ein erster Entwurf des Python Codes für den Umschalter – ist aber eher ein Proof of Concept – vernünftiger Code muss noch nachträglich gebaut werden 😀
Den jeweils aktuellsten Code gibts auf github: https://github.com/Torsten-/MicroPython_MQTTAmpSwitch
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 |
SSID='WLAN SSID here' PW='WLAN PW here' MQTT_SERVER='192.168.1.23' MQTT_TOPIC=b"ampswitch" MQTT_TOPIC_STATE=b"ampswitch/state" import network sta_if = network.WLAN(network.STA_IF) if not sta_if.isconnected(): print('connecting to network...') sta_if.active(True) sta_if.connect(SSID,PW) while not sta_if.isconnected(): pass print('network config:', sta_if.ifconfig()) ap_if = network.WLAN(network.AP_IF) ap_if.active(False) import machine import time from umqtt.simple import MQTTClient import ubinascii ledr = machine.Pin(4, machine.Pin.OUT) ledl = machine.Pin(2, machine.Pin.OUT) switch = machine.Pin(5, machine.Pin.IN) amp1r = machine.Pin(14, machine.Pin.OUT) amp1l = machine.Pin(13, machine.Pin.OUT) amp2r = machine.Pin(16, machine.Pin.OUT) amp2l = machine.Pin(12, machine.Pin.OUT) act_amp = 1 new_amp = 1 def set_amp(n): global act_amp if n == 2: amp1l.low() amp1r.low() ledl.low() time.sleep_ms(200) amp2l.high() amp2r.high() ledr.high() act_amp = 2 mqtt.publish(MQTT_TOPIC_STATE, b"2") else: amp2l.low() amp2r.low() ledr.low() time.sleep_ms(200) amp1l.high() amp1r.high() ledl.high() act_amp = 1 mqtt.publish(MQTT_TOPIC_STATE, b"1") def switch_pressed(p): global new_amp if act_amp == 1: new_amp = 2 else: new_amp = 1 def mqtt_input(topic, msg): global new_amp if msg == b"2": new_amp = 2 else: new_amp = 1 CLIENT_ID = ubinascii.hexlify(machine.unique_id()) mqtt = MQTTClient(CLIENT_ID, MQTT_SERVER) mqtt.set_callback(mqtt_input) mqtt.connect() mqtt.subscribe(MQTT_TOPIC) print("MQTT connected to %s, subscribed to %s topic" % (MQTT_SERVER, MQTT_TOPIC)) set_amp(act_amp) switch.irq(trigger=machine.Pin.IRQ_FALLING, handler=switch_pressed) while True: mqtt.check_msg() if new_amp != act_amp: set_amp(new_amp) |
Der Code schickt übrigens auch jede Statusänderung über MQTT raus – egal ob manuell über den Taster, oder ob automatisiert über MQTT. So ist FHEM immer auf dem aktuellsten Stand.
In FHEM wird dann ein neues Device angelegt:
1 2 3 4 5 6 7 8 9 10 11 12 |
define MQTTD_Shared_AmpSwitch MQTT_DEVICE attr MQTTD_Shared_AmpSwitch IODev MQTT_Shared attr MQTTD_Shared_AmpSwitch alias Amp Switch attr MQTTD_Shared_AmpSwitch devStateIcon 1:icoSONOSPLAYER_icon-ZP120 2:it_television@orange attr MQTTD_Shared_AmpSwitch event-on-change-reading .* attr MQTTD_Shared_AmpSwitch group 1.Entertainment attr MQTTD_Shared_AmpSwitch publishSet amp ampswitch attr MQTTD_Shared_AmpSwitch publishSet_amp ampswitch attr MQTTD_Shared_AmpSwitch room Wohnzimmer attr MQTTD_Shared_AmpSwitch stateFormat state attr MQTTD_Shared_AmpSwitch subscribeReading_state ampswitch/state attr MQTTD_Shared_AmpSwitch webCmd amp 1:amp 2 |
Zu den Schaltregeln – für den Anfang gibt es folgende:
- Wenn ein Entertainment-Programm gestartet wird (Leinwand runterfahren, Beamer an, ..) wird der Umschalter auf den AVReceiver umgestellt
- Beim Beenden des Entertainment-Programms wird der Umschalter wieder auf Sonos zurück gestellt
- Wenn der Umschalter auf den AVReceiver umgeschaltet wird, wird die Wiedergabe des Sonos gestoppt