SONOS
SONOS | |
---|---|
Zweck / Funktion | |
Anbindung des Sonos-Systems via UPnP | |
Allgemein | |
Typ | Gerätemodul |
Details | |
Dokumentation | EN / DE |
Support (Forum) | Multimedia |
Modulname | 00_SONOS.pm |
Ersteller | Reinerlein |
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref! |
SONOSPLAYER | |
---|---|
Zweck / Funktion | |
Steuerung eines Sonos Zoneplayer | |
Allgemein | |
Typ | Gerätemodul |
Details | |
Dokumentation | EN / DE |
Support (Forum) | Multimedia |
Modulname | 21_SONOSPLAYER.pm |
Ersteller | Reinerlein |
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref! |
Sonos ist ein Multiroom-Musiksystem der kalifornischen Firma Sonos. Es bietet die Möglichkeit der verteilten Musikabspielung und Steuerung, sowie der Verknüpfung von mehreren Playern, um diese dasselbe abspielen zu lassen. Hierfür gibt es verschiedene Abspiel-Komponenten, die in einem eigenen Netzwerk miteinander kommunizieren und für verschiedene Anwendungsfälle konzipiert wurden.
Diese Beschreibung soll den Einstieg in die Steuerung der heimischen Zoneplayer erleichtern. Es werden die Verwendung und Einrichtung der dazugehörenden FHEM-Module SONOS und SONOSPLAYER beschrieben, und einige Beispiele für eine mehr oder weniger sinnvolle Nutzung von Events und Steuerungsmöglichkeiten gegeben.
Sollte etwas fehlen oder unklar sein, dann einfach eine kurze Nachricht an den Autor.
Obwohl die Module in FHEM mitgeliefert werden, sind trotzdem die Vorbedingungen bzgl. der Perl-Installation unter Softwarevoraussetzungen einzuhalten, da das Modul sonst nicht lauffähig ist.
Kurzüberblick
Hier soll nur ein kurzer Überblick über die mittlerweile doch recht umfangreichen Möglichkeiten geboten werden:
- Automatisches Erkennen aller ZonePlayer im lokalen Netzwerk. Dabei werden alle Player einer Paarung zusammengehörig benannt und gruppiert
- Automatische Aktualisierung aller aktuellen (und wenn verfügbar: der nächsten) Titelinformationen innerhalb von FHEM
- Dabei wird für jede veränderte Information ein Event erzeugt, man kann also dediziert darauf reagieren
- Bei normalen Abspiellisten werden auch die Informationen zum nächsten Titel ermittelt und angezeigt
- Es können auch verschiedene Zusammenfassungen der bestehenden Informationen zusammengestellt werden
- Anzeige des aktuellen (oder auch nächsten) Covers als Weblink oder readingsGroup
- Steuern der ZonePlayer: Play, Pause, Nächster Titel, Vorheriger Titel, Lautstärke Lauter/Leiser (auch als vordefinierte Rampe), Stummschalten
- Alle Player auf einen Befehl hin stoppen, pausieren oder stummschalten lassen
- Einstellen und Abfragen der Abspielparameter Repeat, RepeatOne, Shuffle, CrossfadeMode, Loudness, Bass und Treble
- Festlegen einer minimalen und maximalen Lautstärke für jeden ZonePlayer (getrennt zwischen Normalbetrieb und Kopfhörernutzung)
- Laden, Speichern und Löschen von Playlisten (Laden und Speichern: auch M3U-Dateien aus dem Filesystem)
- Abspielen eines Sonos-Favoriten (z.B. Playlist, Spotify-Playlist, Titel, Radiosender, usw.)
- Abspielen beliebiger Titel (auch von Freigaben, die nicht von Sonos indiziert wurden)
- Abspielen beliebiger Radiostationen über deren HTTP-Link
- Hinzufügen beliebiger Titel und Radiostationen zur aktuellen Abspielliste
- Temporäres Abspielen von Dateien, mit nachfolgender Wiederherstellung des vorherigen Titels inkl. genauer Position im vorherigen Titel und der Lautstärke
- Füllen der aktuellen Abspielliste mit nach diversen Kriterien zusammengesuchten Titeln aus der Sonos Bibliothek
- Erzeugen und temporäres Abspielen von Sprachdurchsagen auf Basis von eingegebenen Texten und vorhandenen MP3-Dateien
- Wird standardmäßig über die Google-Übersetzungsmaschine realisiert
- Kann auch über eine eigenständige, lokale Installation eines Text2Speech-Tools realisiert werden
- Auslesen und Setzen/Starten der verfügbaren gespeicherten Playlisten, Radiofavoriten und Sonos-Favoriten
- Erzeugung und Bearbeitung von Alarmen, sowie Event bei Veränderung der Alarme duch andere Controller
- Setzen des Sleeptimer inkl. FHEM-Event bei Veränderung durch andere Controller und Ablauf des Timers
- Setzen und Auslesen der Gruppierungskonfiguration, sowie einzelnes Hinzufügen und Entfernen von Gruppenmitgliedern
- Bildung und Trennung von Stereopaaren
- Erzeugen von Events nach festgelegten Tastensequenzen (am Player)
- Umbenennen der Zonen und festlegen der Zonenicons
- Standardanzeige eines Player als ReadingsGroup mit automatischem Titel- und Coverwechsel sowie einer RemoteControl zum Steuern
- Anzeigemöglichkeit einer Vollbilddarstellung ähnlich dem Original-Controller
- Definitionsmöglichkeit von automatischen Bookmarks, die beim Aufrufen derselben Playliste oder Titel die gespeicherte Position anspringen.
Kurze Anmerkungen zur Sonos-Landschaftsgestaltung
Es ist im allgemeinen besser, die Sonos-Landschaft mit allen Paarungen vor dem Einrichten des Moduls zu erzeugen. Dieses Modul benennt die FHEM-Playerdevices nach den Zonennamen und der jeweiligen Funktion des Players innerhalb der Paarung.
Das bedeutet aber auch, dass in diesem Augenblick möglichst keine Player gruppiert sein sollten (mehrere Zonen spielen dasselbe ab), da diese sonst komische Namen erhalten könnten (es geht hier ausschliesslich um die FHEM-interne Device-Benennung, natürlich bleiben die Zoneplayer selbst wie sie sind).
Insbesondere gilt das für temporäre Stereopaare. Diese nicht ständigen Paare sollten erst getrennt werden, bis das Modul alle Player erkannt und angelegt hat.
Damit man nun eine einigermaßen passende Bezeichnung in FHEM erhält, sollte also die Gestaltung der Sonos-Player abgeschlossen sein. Natürlich funktioniert das System nach einer FHEM-Einrichtung und anschließender Sonos-Umbenennung immer noch, da intern alles mittels der eindeutigen Bezeichner gehandhabt wird, allerdings wird es u.U. etwas unübersichtlich bzgl. der FHEM-Device-Namen. Diese passen dann nicht mehr zu den Zonennamen (die entsprechenden Readings werden aber natürlich korrekt besetzt), was man aber natürlich auch nachträglich wieder anpassen kann.
Hinweis: Man kann das Attribut disable am Sonos-Device setzen, um den Subprozess zu beenden. Damit kann man seine Zonenlandschaft später erweitern, ohne FHEM komplett abschalten zu müssen. Nachdem die Einrichtung des neuen Zoneplayers abgeschlossen ist, löscht man das Attribut disable einfach wieder - der Subprozess startet und beginnt mit der Erkennung der neuen Komponenten.
Einbindung von Sonos in FHEM
Die Einbindung erfolgt über die beiden Module SONOS und SONOSPLAYER. Dabei ist Hauptsächlich das Modul SONOS einzurichten. Alle Zoneplayer werden automatisch erkannt, und dann entsprechend angelegt:
define <Devicename> SONOS [<Hostname:Port> [Prüfintervall [WaitTime [DelayTime]]]]
Beispiele für die Einbindung
Einfachste Einbindung mit Standardwerten:
define Sonos SONOS
Einbindung mit Kontrolle über den verwendeten Port und das IsAlive Prüfintervall:
define Sonos SONOS localhost:4711 45
Der Name dieses Devices ist automatisch das Namensprefix beim Anlegen der SonosPlayer. In diesem Fall werden alle erkannten Zoneplayer mit dem Prefix "Sonos_
" anfangen. Natürlich kann man das nach dem Anlegen einfach umbenennen.
Als Prüfintervall wurde hier 45s angegeben. Wenn kein Intervall angegeben wird, dann werden 30s verwendet.
define Sonos SONOS localhost:4711 30 1
Hier wurde eine verkürzte Wartezeit für den Subprozess von einer Sekunde angegeben. Bei schnellen Systemen wird dadurch der gesamte Startmechanismus schneller verarbeitet.
Wenn nichts angegeben wird, dann wird 8s verwendet, was einen guten Wert für einen Raspberry Pi darstellt.
define Sonos SONOS localhost:4711 30 1 5
Hier wurde noch eine zusätzliche Verzögerung von 5s eingebaut, da manche Systeme bei einem FHEM-Restart oder ähnlichem die belegten Ports nicht schnell genug wieder freigeben.
Hier kann diese Verzögerung helfen, da erst nach Ablauf dieser Zeitspanne ein Verbindungsversuch zum SubProzess unternommen wird (und auch erst dann der Versuch einen eigenen Prozess zu Starten unternommen wird).
Wenn nichts angegeben wird, dann wird keine Verzögerung durchgeführt.
Namensvergabe der automatischen Erkennung
Der automatische Erkennungsmechanismus vergibt Devicenamen auf Basis der Zonennamen und der Funktion eines Players innerhalb eines Stereopaares oder einer Surroundkonstellation. Dabei wird immer ein Player (der Master dieser Konstellationen) nur den Namen der Zone erhalten (ohne Anhängekürzel) und die anderen werden mit Kürzel versehen. Dadurch ist der Master der Zone automatisch dasjenige Playerdevice, welches gesteuert werden muss. Alle anderen Player leiten Steueranfragen automatisch an den Master weiter. Besteht eine Zone nur aus einem Player, so gibt es natürlich auch nur diesen einen als Master.
Als Anhängekürzel wird immer der Inhalt des Readings fieldType verwendet.
Bei der Funktion gibt es später dann zwei Fälle zu unterscheiden:
- Stereopaare werden von Sonos intern als Gruppe behandelt. Das bedeutet, dass der zweite Player (der nicht-Master) immer PLAYING als Status anzeigt, und nur der Master den korrekten Wert. Stereopaare haben, wie normale Gruppen oder Einzelplayer auch, eine Verzögerung von 70ms zu einem Eingangssignal.
- Surroundsysteme werden als Satelliten angebunden, und werden vom Modul nur mit intialized angegeben, da Sonos für diese nie eine Statusmeldung sendet. Diese Playersysteme haben eine verkürzte Verzögerung von 30ms zu einem Eingangssignal.
Dabei ist ein Eingangsignal so etwas wie ein Line-In- oder SPDIF-Eingang.
Beispiel für eine Zonenlandschaft
Folgende Landschaft mit Status könnte es geben:
Sonos_Schlafzimmer (STOPPED => [Keine Musikdatei]) Sonos_Schlafzimmer_RF (PLAYING => 'Keine Titelinformation bei Gruppenwiedergabe') Sonos_Kinderzimmer (PAUSED_PLAYBACK => 'Titelinformation') Sonos_Gaestezimmer (STOPPED => [Keine Musikdatei]) Sonos_Wohnzimmer (STOPPED => [Keine Musikdatei]) Sonos_Wohnzimmer_LR (initialized) Sonos_Wohnzimmer_RR (initialized) Sonos_Wohnzimmer_SW (initialized)
Dabei wäre Schlafzimmer ein Stereopaar, Kinder- und Gästezimmer jeweils ein einzelner Player und Wohnzimmer z.B. eine Playbar mit zwei Rear-Lautsprechern und Subwoofer. In keiner Zone läuft eine aktive Wiedergabe. Hier kann man schön die einzelnen Zustände und die erzeugten Namen erkennen.
Zusammenfassung der Spracheinrichtung
Um die Sprachausgabe des Moduls nutzen zu können, müssen einige Grundvoraussetzungen geschaffen werden. Hier soll nur eine kurze Übersicht geschaffen werden, was alles getan werden muss. Die einzelnen Themen selbst sind in diesem Wiki-Artikel bereits beschrieben.
- Es muss einen Speicherplatz für Dateien geben, wo das Sonos-Modul (also FHEM) schreibend zugreifen kann, und das Sonos-System selbst lesend zugreifen kann. Das Sonos-System versucht immer ohne Passwort zuzugreifen, FHEM mit seinem Benutzerkontext
- Dafür kann man sich z.B. auf dem lokalen Debian-System (sofern FHEM darauf läuft) eine Samba-Freigabe einrichten. Das ist unter "Einrichtung von Samba für Sprachausgabemöglichkeit" beschrieben.
- Man kann sich auch auf einem bestehenden NAS-System einen Ordner extra für diesen Zweck anlegen und entsprechend freigeben
- Bei Problemen bitte die Datei-/Ordnerrechte genauestens prüfen, notfalls mit einem Windows-/Macrechner einen direkten Zugriffstest durchführen. Hier sind die häufigsten Fehlerquellen zu suchen.
- Es müssen mindestens die Attribute targetSpeakDir und targetSpeakURL am FHEM-Sonos-Device gesetzt werden. Diese Attribute werden bei den "Sonos Sprachattributen" beschrieben.
- Empfehlenswert ist auch das Setzen eines der Attribute targetSpeakFileTimestamp oder targetSpeakFileHashCache am FHEM-Sonos-Device. Damit werden Indizierungsprobleme des Sonos-Systems umgangen. Es ist nicht sinnvoll beide Attribute gleichzeitig zu setzen. Auch diese Attribute werden bei den "Sonos Sprachattributen" beschrieben.
- Wenn man die Möglichkeit der in den Text eingebetteten MP3-Dateien nutzen möchte, ist es empfehlenswert, das Attribut targetSpeakMP3FileDir für den Standardpfad der Jingles zu setzen. Damit werden die einzugebenden Texte deutlich übersichtlicher.
- Bei Bedarf kann man sich ein lokales Programm installieren und dem Modul angeben, welches die Sprachausgabedatei erzeugt.
Das sollte man nicht als Anfänger tun!- Unter Beispiel für einen Offline-Sprachsynthetisierer ist das am Beispiel von espeak beschrieben.
- Das Programm kann man dem Modul mit den Attributen Speak1, Speak2, Speak3 und Speak4 einstellen. Also bis zu vier verschiedene. Diese Attribute werden ebenfalls bei den "Sonos Sprachattributen" beschrieben.
- Mit einem Shell-Skript kann man den Cacheordner für die Sprachausgabe bereinigen lassen. Unter Beispiel für ein Shell-Skript zum Aufräumen eines Speak-Verzeichnisses gibt es den Code.
Schnelleinrichtung einer Sprachausgabe
Siehe auch: "Einrichtung von Samba für Sprachausgabemöglichkeit", "Sonos Sprachattributen", "Beispiel für eine Sprachdurchsage auf Basis eines Notify"
FHEM Befehl zum Aktualisieren ausführen:
update
FHEM neustarten:
shutdown restart
Software nachinstallieren mit User root (per SSH):
sudo apt-get update && sudo apt-get -y install libwww-perl libsoap-lite-perl libxml-parser-lite-perl
Samba Installieren (per SSH):
sudo apt-get update && sudo apt-get -y install samba samba-common-bin
Ordner Anlegen (per SSH):
sudo mkdir -p /opt/fhem/SonosSpeak
Ordner Rechte geben (per SSH):
sudo chmod 777 /opt/fhem/SonosSpeak
SMB Konfigurationsdatei öffnen (per SSH):
sudo nano /etc/samba/smb.conf
Folgenden Eintrag ergänzen:
[global] security = user map to guest = bad user
Folgenden Eintrag am Ende hinzufügen:
[SonosSpeak] comment = Audio-Files for SonosPlayer to Speak read only = false path = /opt/fhem/SonosSpeak guest ok = yes
Sonos spricht nur Samba V1, daher kann es bei neueren Debian/Samba-Installationen zu Zugriffsproblemen kommen (Sonos Fehler 900). Um Abhilfe zu schaffen, muss der Samba-Server SambaV1 aktiviert haben.
Im Global direkt unter workgroup= WORKGROUP:
server min protocol = NT1
Neustart Samba (per SSH):
sudo /etc/init.d/samba restart
Sonos in FHEM anlegen:
define Sonos SONOS
Hinweis: Es wird ein Raum Sonos angelegt in welchem automatisch die Sonos-Zoneplayer angelegt werden.
Via FHEM Befehl weitere Einstellungen am Sonos-Device vornehmen: Pfad in dem FHEM die mp3-Datei ablegt:
attr Sonos targetSpeakDir /opt/fhem/SonosSpeak
Pfad aus Sicht des Sonos-Zoneplayers angeben:
attr Sonos targetSpeakURL \\<ip-Adresse-oder-der-Name-des-raspberry>\SonosSpeak
Zeitstempel an Dateinamen anhängen, damit Sonos keine alten Dateien aus dem Cache nutzt:
attr Sonos targetSpeakFileTimestamp 1
Pfad für eingebettete MP3-Dateien angeben:
attr Sonos targetSpeakMP3FileDir /opt/fhem/SonosSpeak
Mit FHEM-Befehl die neue Konfiguration speichern:
save
FHEM neustarten:
shutdown restart
Sprachausgabe Testen:
set <NameDesAngelegtenLautsprechersImSonosRaum> Speak 30 de Der auszugebene Text.
Zusammenfassung der Bookmarkeinrichtung
Da die Möglichkeiten mit den Bookmarks sehr vielfältig sind, soll in dieser kleinen Zusammenfassung ein Überblick gegeben werden.
Grundsätzlich muss zwischen den beiden Grundbereichen für Bookmarks unterschieden werden. Diese können unabhängig voneinander verwendet werden:
- Bookmarks für die aktuelle Abspielliste/Playlisten
- Bookmarks für Titel
Bei den Listen wird über die aktuelle Abspielliste (also alle Titel die gerade so abgespielt werden sollen) ein Hashwert gebildet, und mit diesem der aktuelle Titel (genauer: die Tracknummer) zusammen mit einem Zeitstempel gespeichert.
Bei den Titeln wird für jeden Titel die genaue Position im Titel zusammen mit einem Zeitstempel gespeichert, wenn der Titel gewechselt wird.
Beide Bereiche behandeln also getrennte Situationen und können jeder für sich, aber auch gemeinsam, sinnvoll eingesetzt werden.
Die Konfiguration der Bookmarks wird erst bei einem Neustart des SubProzesses (also durch einen FHEM-Neustart (vorher Speichern nicht vergessen) oder dem Setzen/Zurücksetzen des Attributs disable am Sonos-Device) berücksichtigt.
Mit den Befehlen DisableBookmark und EnableBookmark können Bookmark-Gruppen (temporär) deaktiviert bzw. wieder aktiviert werden.
Achtung: Diese Änderung gilt nur bis zum nächsten FHEM Neustart, da dieser Zustand nicht in die Definition (also das Attribut) zurückgeschrieben wird.
Die im Arbeitsspeicher gehaltenen Bookmarks werden beim Starten des SubProzesses aus den vorhandenen Dateien geladen, und beim Beenden entsprechend dort gespeichert. Man kann mit dem Befehl SaveBookmarks (oder entsprechend LoadBookmarks) diesen Vorgang selber anstossen. Bei einem globalen Save-Aufruf (also dem FHEM-Befehl 'save') werden die Bookmark-Daten ebenfalls gesichert.
Die komplette Verarbeitung der Bookmarks erfolgt im SubProzess (zunächst mal ohne FHEM-Interaktion) und damit sehr nah an den Ereignissen des Players. Im Normalfall hört man z.B. beim Sprung innerhalb eines Titel (nach einem Wechsel des Titels) gerade mal ein kurzes Zucken des Titels, bevor dieser schon vorgespult wird. Beim Anspringen eines Titels in der aktuellen Abspielliste (wegen der Hash-Berechnung, je nach Länge der aktuellen Abspielliste) etwas länger, aber bei mir deutlich unter einer Sekunde. FHEM ist nur insoweit involviert, da die Sprungaktionen abschließend als LastActionResult-Aktualisierungen gemeldet werden.
Attribute für Bookmarks am Sonos-Device
bookmarkSaveDir
: Verzeichnis, wo die Bookmarkdateien abgelegt und geladen werden sollenbookmarkPlaylistDefinition
: Definition für Playlist-BookmarksbookmarkTitleDefinition
: Definition für Titel-Bookmarks
Readings für Bookmarks am Sonosplayer-Device
QueueHash
: Der Hash-Wert für die aktuelle Abspielliste. Damit kann man in eigenen Events bei Bedarf Dinge selber entsprechend verarbeiten.
Bookmarks für die aktuelle Abspielliste/Playlisten
Attributname am Sonos-Device:
bookmarkPlaylistDefinition
Definition:
<Groupname>:<PlayerDeviceRegEx>:<MinListLength>:<MaxListLength>:<MaxAge> [...]
Bedeutung:
Groupname
: Ein beliebiger Name, der auch als Dateiname verwendet werden kann und keinerlei Sonder-/Leerzeichen enthältPlayerDeviceRegEx
: Ein regulärer Ausdruck, der für das Matching der zu berücksichtigten Player verwendet wird. Das Matching erfolgt auf dem FHEM-Devicenamen. Wenn nicht angegeben, dann wird '.*' verwendet.MinListLength
: Eine Zahl die angibt, wieviel Titel eine aktuelle Abspielliste mindestens haben muss, um berücksichtigt zu werden. Wenn nicht angegeben, dann wird '0' verwendet.MaxListLength
: Eine Zahl die angibt, wieviel Titel eine aktuelle Abspielliste maximal haben darf, um berücksichtigt zu werden. Wenn nicht angegeben, dann wird '99999' verwendet.MaxAge
: Das maximale Alter für die Verwendung eines gespeicherten Bookmarks in Sekunden. Hier kann ein beliebiger Perl-Ausdruck (natürlich ohne Doppelpunkte) verwendet werden, der zu einer Zahl evaluierbar sein muss. Wenn nicht angegeben, dann wird '28*24*60*60' (also vier Wochen) verwendet.
Nach hinten hin dürfen die Doppelpunkte von leergelassenen Werten ebenfalls weggelassen werden.
Es können beliebig viele Gruppen mit diversen (auch überlappenden) Bereichen gebildet werden. Diese verschiedenen Gruppen werden mit Leerzeichen getrennt, sodass innerhalb einer Bookmarkdefinition selbst keinerlei Leerzeichen vorkommen dürfen.
Die Dateinamen für das Speichern und Laden werden wie folgt gebildet: <bookmarkSaveDir>/BookmarkPlaylist_<BookmarkGroupName>.save
Beispiele
Eltern:Sonos_(Schlaf|Wohn|Ess)zimmer
Hiermit wird eine Gruppe mit dem Namen Eltern definiert, die alle Listen, die auf den drei Playern Schlafzimmer, Wohnzimmer und Esszimmer verwendet werden, beachtet.Kind1:Sonos_Kind1:0:5
Hiermit wird eine Gruppe Kind1 definiert, die alle Listen, die mindestens 0 und maximal 5 Titel haben, berücksichtigt.All
Alle Listen aller Player werden berücksichtigt.
Bookmarks für Titel
Attributname am Sonos-Device:
bookmarkTitleDefinition
Definition:
<Groupname>:<PlayerdeviceRegEx>:<TrackURIRegEx>:<MinTitleLength>:<RemainingLength>:<MaxAge>:<ReadOnly> [...]
Bedeutung:
Groupname
: Ein beliebiger Name, der auch als Dateiname verwendet werden kann und keinerlei Sonder-/Leerzeichen enthältPlayerDeviceRegEx
: Ein regulärer Ausdruck, der für das Matching der zu berücksichtigten Player verwendet wird. Das Matching erfolgt auf dem FHEM-Devicenamen. Wenn nicht angegeben, dann wird '.*' verwendet.TrackURIRegEx
: Ein regulärer Ausdruck, der für das Matching der zu berücksichtigten Titel verwendet wird. Wenn nicht angegeben, dann wird .*' verwendet.MinTitleLength
: Die minimale Lieddauer in Sekunden, die der Titel lang sein muss, um berücksichtigt zu werden. Wenn nicht angegeben, dann wird '60' verwendet.RemainingLength
: Die minimale Restspielzeit in Sekunden, die ein Titel noch haben muss, um berücksichtigt zu werden. Wenn nicht angegeben, dann wird '10' verwendet.MaxAge
: Das maximale Alter für die Verwendung eines gespeicherten Bookmarks in Sekunden. Hier kann ein beliebiger Perl-Ausdruck (natürlich ohne Doppelpunkte) verwendet werden, der zu einer Zahl evaluierbar sein muss. Wenn nicht angegeben, dann wird '28*24*60*60' (also vier Wochen) verwendet.ReadOnly
: Wenn hier etwas angegeben wird, was von Perl als true erkannt wird, dann wird diese Gruppe beim Aufruf von SaveBookmarks (also auch beim Beenden von FHEM) nicht berücksichtigt. Wenn nicht angegeben, dann wird '0' verwendet (die Gruppe wird also gespeichert).
Nach hinten hin dürfen die Doppelpunkte von leergelassenen Werten ebenfalls weggelassen werden.
Es können beliebig viele Gruppen mit diversen (auch überlappenden) Bereichen gebildet werden. Diese verschiedenen Gruppen werden mit Leerzeichen getrennt, sodass innerhalb einer Bookmarkdefinition selbst keinerlei Leerzeichen vorkommen dürfen.
Die Dateinamen für das Speichern und Laden werden wie folgt gebildet: <bookmarkSaveDir>/Bookmark_<BookmarkGroupName>.save
Beispiele
Eltern:Sonos_(Schlaf|Wohn|Ess)zimmer
Hiermit wird eine Gruppe mit dem Namen Eltern definiert, die alle Titel, die auf den drei Playern Schlafzimmer, Wohnzimmer und Esszimmer laufen, beachtet.Kind1:Sonos_Kind1:.*?\/Hörspiele\/.*:240:30
Hiermit wird eine Gruppe Kind1 definiert, die alle Titel, die im Pfad den Teil /Hörspiele/ enthalten, mindestens 240 Sekunden (also vier Minuten) lang und mehr als 30 Sekunden vom Ende entfernt sind, berücksichtigt.All
Alle Titel aller Player werden berücksichtigt.
Hinweise
- Beim Speichern/Laden kann der Einfachheit halber nur der Gruppenname mitgegeben werden. Gibt es sowohl im Bereich Playlist als auch im Bereich Titel eine Gruppe mit diesem Namen, dann werden beide gespeichert/geladen. Wenn man das verhindern möchte, dann müssen die Gruppennamen global eindeutig sein.
Hardware-/Betriebssystemvoraussetzungen
Diese Liste sollte im Laufe der Zeit fortgeführt werden. Es soll die Hardware-/Softwarevoraussetzungen festhalten, um Probleme im Vorfeld erkennen zu können.
Funktionierende Kombinationen:
- Windows, ActivePerl 32Bit (zusätzliche Pakete sollten dort mit Hilfe des mitgelieferten, grafischen Paketmanagers installiert werden)
- Raspberry Pi, Default-Perl
- Mac Mini, Perl 5.18 mit -useThreads kompiliert
Problematische Kombinationen:
- FritzBox: Anscheinend ist Perl dort ohne Thread-Möglichkeit kompiliert. Diese sind aber essentiell notwendig für dieses Modul.
- Windows, ActivePerl 64Bit (das Paket SOAP::Lite gibt es momentan nicht für 64Bit)
Anpassungen bei Nutzung von IPTables als Firewall
Benutzt man bereits IPTables, so müssen folgende Regeln hinzugefügt werden. z.B. unter /etc/defauts/iptables
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Sonos Kommunikation -A INPUT -m pkttype --pkt-type multicast -j ACCEPT -A INPUT -s 224.0.0.0/8 -j ACCEPT # alles im lokalen LAN -A INPUT -s 192.168.0.0/16 -j ACCEPT
Softwarevoraussetzungen
Für die Verwendung sind Perlmodule notwendig, die unter Umständen noch nachinstalliert werden müssen:
- LWP::Simple
- LWP::UserAgent
- SOAP::Lite
- HTTP::Request
- (XML::Parser::Lite)
Ist im Normalfall im Standardpaket von Perl enthalten. Kann aber u.U. fehlen (scheint unter Ubuntu und verschiedenen Debian-Systemen so zu sein), und muss dann manuell nachinstalliert werden.
Die Installation dieser Module geht in der Regel per CPAN. Das bedeutet das zum Beispiel mit
sudo cpan LWP::Simple
das Modul "LWP::Simple
" installiert wird. Wenn man bereits als Benutzer root arbeitet, dann ist das sudo
natürlich nicht nötig.
Sollte es bei der Installation mittels CPAN zu Problemen kommen, dann folgt hier eine Beschreibung der manuellen Installation.
Hinweis für Debian-Systeme
Bei Debian-basierten Systemen (also auch Raspbian für den Raspberry Pi oder Ubuntu usw.) kann auch mittels
sudo apt-get install <paketname>
installiert werden. Manchmal ist es etwas schwieriger, die Paketnamen zu ermitteln, aber Google ist da sehr hilfreich.
Hier mal die Liste für die oben genannten Pakete:
- LWP::Simple-Paketname (inkl. LWP::UserAgent und HTTP::Request):
libwww-perl
- SOAP::Lite-Paketname:
libsoap-lite-perl
- XML::Parser::Lite-Paketname:
libxml-parser-lite-perl
oder falls nicht verfügbarlibxml-parser-perl
Hinweis für Windows-Systeme mit ActivePerl
Bei Windows Systemen mit ActivePerl kann man die Installation über den ActivePerl Packagemanager durchführen:
- Installation von Package LWP (inkl. LWP::UserAgent und HTTP::Request)
- Installation von Package SOAP::Lite
- SOAP::Lite-Besonderheit für Versionen nach 5.18:
- Eine neue Paketquelle aus den Vorschlägen oder manuell hinzufügen: Bribes de Perl (http://www.bribes.org/perl/ppm)
- Installation von Package: SOAP::Lite
- SOAP::Lite-Besonderheit für Versionen nach 5.18:
Hinweis: Windows ActivePerl 64Bit kann momentan nicht verwendet werden, da es das Paket SOAP::Lite aktuell nicht gibt.
Manuelle Installation LWP::Simple
Wenn sich dieses Paket nicht einfach per CPAN-Anweisung installieren läßt, dann hilft folgende Anleitung weiter. Beim Abbruch der Installation mittels CPAN erscheint mittendrin ein Fehler, das die Datei nicht entpackt werden könne (couldn't untar). Da scheint es einen Fehler im Installationsskript zu geben.
Man kann das aber auch Manuell installieren:
- Am Einfachsten ist ein Wechsel in den Kontext des Benutzers root: "
sudo su -
" - Erstellen eines Ordners, z.B. "
mkdir lwpsimple
" - Wechsel in diesen Ordner "
cd lwpsimple
" - Herunterladen der Datei von libwww-perl-6.04 oder direkter Link: libwww-perl-6.04.tar.gz: z.B. "
wget http://search.cpan.org/CPAN/authors/id/G/GA/GAAS/libwww-perl-6.04.tar.gz
" - Entpacken der Datei: "
tar -xzvf libwww-perl-6.04.tar.gz
" - Wechsel in das neu entstandene Verzeichnis: "
cd libwww-perl-6.04
" - Nun kann es nach dem Standardvorgehen weitergehen:
- "
perl Makefile.PL
" - "
make
" - "
make install
"
- "
Manuelle Installation SOAP::Lite
Wenn sich dieses Paket nicht einfach per CPAN-Anweisung installieren läßt, dann hilft folgende Anleitung weiter. Beim Abbruch der Installation mittels CPAN erscheint mittendrin ein Fehler, das die Datei nicht entpackt werden könne (couldn't untar). Da scheint es einen Fehler im Installationsskript zu geben.
Man kann das aber auch Manuell installieren:
- Am Einfachsten ist ein Wechsel in den Kontext des Benutzers root: "
sudo su -
" - Erstellen eines Ordners, z.B. "
mkdir soaplite
" - Wechsel in diesen Ordner "
cd soaplite
" - Herunterladen der Datei von CPAN-SOAP-Lite-0.715 oder direkter Link: SOAP-Lite-0.715.tar.gz: z.B. "
wget http://mirror.informatik.uni-mannheim.de/pub/mirrors/CPAN/authors/id/M/MK/MKUTTER/SOAP-Lite-0.715.tar.gz
" - Entpacken der Datei: "
tar -xzvf SOAP-Lite-0.715.tar.gz
" - Wechsel in das neu entstandene Verzeichnis: "
cd SOAP-Lite-0.715
" - Nun kann es nach der Anleitung weitergehen:
- "
perl Makefile.PL
" - Dann kommt eine Nachfrage, was zusammengebaut werden soll. An dieser Stelle ist es jetzt wie eine normale CPAN Installation. Einfach mit <Enter> weitermachen lassen.
- "
make
" - "
make install
"
- "
Einrichtung von Samba für Sprachausgabemöglichkeit
Wenn die Sprachausgabe verwendet werden soll, muss ein lokaler Samba-Daemon (Server für Windowsfreigaben) laufen oder eine für FHEM beschreibbare (Windows-)Freigabe woanders existieren, da Sonos nur auf eine solche lesend zugreifen kann.
Diese Beschreibung soll anhand des Raspberry-Pi (und anderer Debian-Systeme) zeigen, wie man einen solchen lokalen Samba-Server schnell für diesen Zweck einrichten kann:
- Lokales Verzeichnis für die Ablage der Tondateien erzeugen. z.B.:
sudo mkdir /mnt/SonosSpeak sudo chmod 777 /mnt/SonosSpeak/
- Installation der notwendigen Pakete für Samba:
sudo apt-get install samba samba-common-bin
- Starten des Editors zum Anpassen der Konfigurationsdatei:
sudo nano /etc/samba/smb.conf
- Ist die Datei Original von der Raspbian Installation, muss außer dem Eintrag für das Share nichts geändert werden! Folgende Zeilen am Ende der smb.conf hinzufügen (Pfade müssen natürlich u.U. angepasst werden):
[SonosSpeak] comment = Audio-Files for SonosPlayer to Speak read only = false path = /mnt/SonosSpeak guest ok = yes
- Falls der Zugriff nicht funktioniert, ist eventuell die smb.conf nicht im Originalzustand:
- Sicherstellen, dass in der Global-Sektion der Parameter Security nicht definiert wurde oder auf security = user steht und der Eintrag map to guest = bad user noch vorhanden ist.
[global] security = user map to guest = bad user
- Samba-Server neustarten:
sudo systemctl restart smbd
Ältere Systeme
sudo /etc/init.d/samba restart
Damit wird eine Freigabe mit dem Namen SonosSpeak erzeugt, die von allen ohne Anmeldung gelesen und beschrieben werden kann.
Interner Aufbau
Um die Kommunikation mit dem UPnP-Netzwerk parallel zum normalen Betrieb von FHEM zu ermöglichen, werden Threads eingesetzt. Dadurch sind manche Hardwareplattformen leider überfordert und können u.U. nicht mit diesem Modul verwendet werden.
Das läßt sich aus technologischen Gründen auch nicht umgehen.
Dabei wird der SubThread verwendet um die Callback-Aufrufe, die erfolgen, wenn z.B. eine Statusänderung eines Players erfolgt, zu verarbeiten. Die Aktualisierung der Daten selbst wird dann über eine interne Queue "nach oben" zum Hauptthread übertragen, und dann mittels einer bestehenden TCP-Verbindung zur Verarbeitung in FHEM übertragen.
Dadurch wird gewährleistet, dass die Daten immer im Hauptthread (also dem "eigentlichen" FHEM-Thread) verfügbar sind.
Da dieser SubThread auch die Kommandoübergabe an den Player übernimmt, gibt es auch eine Kommando-Queue in die andere Richtung, die dann mittels eines Thread-Signals im SubThread-Kontext ausgeführt wird.
Dieser Aufbau sorgt natürlich dafür, dass man auf die üblichen Nebenläufigskeitsprobleme achten muss (in der Hauptsache sind das Dead-Locks, da man oftmals über drei Ecken aufeinander wartet, ohne das direkt zu sehen). Deswegen wird in allen Log-Ausgaben des Moduls ein Kürzel vorangestellt: "SONOS_
", wobei der Unterstrich durch die Nummer des aktiven, loggenden, Threads ersetzt wird. Damit kann man sehr leicht feststellen, auf welcher "Ebene" diese Ausgabe erfolgt ist, und ob das alles so seine Richtigkeit hat.
Der Rest sind nur viele Zeilen, die XML-Strukturen (mittels regulärer Ausdrücke) parsen oder erzeugen, und die entsprechenden Informationen setzen oder abfragen.
Installation des Moduls selbst
Hier wird die Installation des eigentlichen Moduls beschrieben, sowie ein Changelog ausgegeben, damit man nachvollziehen kann, was am Modul so passiert ist. Dieser Changelog steht auch in der Datei 00_SONOS.pm.
Installation mittels FHEM-Updatemechanismus
Dieses Modul wird seit Dezember 2014 zusammen mit FHEM ausgeliefert. Es sind keine weiteren Schritte zur Installation des Moduls selbst notwendig.
Fehlersuche
Da das Modul noch in der Entwicklung steht, und natürlich sowieso immer wieder Probleme auftauchen können, hier ein paar Hinweise zur Fehlersuche: Das Modul besteht zunächst aus zwei Ebenen:
- Eine Ebene, die innerhalb von FHEM selbst läuft
- Eine Ebene, die als eigenständiger Prozess läuft (entweder durch FHEM selbst oder manuell angestartet)
Die Logausgaben der ersten Ebene landen direkt im FHEM-Log, die der zweiten Ebene können dort nicht reingeschrieben werden, und landen dementsprechend auf der Konsole (genauer: auf STDOUT).
Wenn man also die Log-Ausgaben dieses Sub-Prozesses sehen möchte, muss man im Startskript den STDOUT entsprechend umlenken, oder einen manuellen Start ausführen:
sudo perl fhem.pl fhem.cfg
Dazu muss man natürlich vorher in das entsprechende Verzeichnis wechseln.
Die Menge der Logausgaben werden, wie in FHEM üblich, über das Attribut Verbose am Sonos-Device gesteuert (Bis auf wenige Zeilen beim Start des Sub-Prozesses, die nur mit dem globalen Verbose-Attribut gesteuert werden können, da noch keine Verbindung besteht).
Hinweis!:
In neueren Versionen von FHEM wird die Konsolenlogausgabe in das normale FHEMlog umgeleitet, sodass man das nicht mehr umständlich selber umlenken und suchen muss.
Im Normalfall sollte Anhand der Ausgabe erkennbar sein, was das jeweilige Problem ist. Bei Unklarheiten am Besten im Forum suchen/posten.
Hinweise / Häufige Fehler / FAQ
Hier soll mal eine Liste mit häufigen Fehlern, Problemen und Hinweisen entstehen.
- In neueren Versionen von FHEM werden die Konsolen-Logausgaben in das FHEMlog umgeleitet. Dadurch wird die Logdatei in der Standardeinstellung von (3) ziemlich voll. Wenn man das verhindern möchte, dann muss man das Attribut verbose am Sonos-Device auf einen Wert kleiner 3 setzen (z.B. 0).
- Das Modul wird im Normalfall stets an die aktuelle Sonos-Firmwareversion angepasst. Es empfiehlt sich also im Normalfall bei komischem Verhalten des Moduls, welches auf eine solche Inkompatibilität hindeutet, auf die neueste Sonos-Firmware upzudaten.
Ein Beispiel ist hierfür die Verarbeitung der Alarme. Dort wurde bei einem Sonos-Update die Logik verändert, sodass das Modul nun eine Inkompatibilität mit der Vorgängerfirmwareversion hat. - Allgemein läuft das Modul besser, wenn es im Benutzerkontext root läuft. Für diverse Funktionalitäten ist das sogar notwendig (z.B. Pingtype auf icmp konfiguriert).
- Um FHEM als root laufen lassen zu können, kann es notwendig sein, den Benutzer fhem in der Datei /etc/passwd auszumarkieren oder mittels deleteuser zu löschen. FHEM schaltet in den Benutzerkontext fhem um, wenn es diesen Benutzer beim Start findet.
- Wenn man das Problem hat, dass Befehle an den falschen Player gesendet werden, sollte man das Reading ZoneGroupID prüfen. Bei ungruppierten Playern sollte es die eigene UDN enthalten, bei gruppierten Playern die UDN des Gruppenmaster.
Sollte das mal nicht der Fall sein, so kann es sein, dass im Sonos-System eine Falschinformation vorliegt. Da es jetzt nicht so einfach ist, die bei Sonos dazu zu bewegen, diesen Fehler zu beseitigen, gibt es u.U. eine Workaround-Möglichkeit mit dem Modul.
Wenn wir z.B. zwei Player haben: Sonos_Bad und Sonos_Kueche, und dort die Steuerung nicht korrekt funktioniert, dann einmal die folgenden Schritte versuchen (bei mehr oder anderen Playern natürlich analog dazu).
Dadurch werden die Gruppen gebildet, und nochmal explizit aufgelöst.set Sonos Groups [Sonos_Bad, Sonos_Kueche]
set Sonos Groups [Sonos_Kueche, Sonos_Bad]
set Sonos Groups [Sonos_Bad], [Sonos_Kueche]
- Es ist wichtig, dass erst das Sonos-Device definiert wird, und dann erst die entsprechenden Sonosplayer-Devices dazu. Sonst kann es u.U. zu einer Verdoppelung des SubProzesses kommen.
- Manchmal bleiben 'Reste' beim Beenden von FHEM. Dann kann es sinnvoll sein, erst alle Perl-Prozesse zu beenden. Diese kann man mit
sudo ps -aux | grep perl
finden, und dann einzeln mittelssudo kill ID
beenden (die ID steht in der ersten Spalte des Ergebnisses des vorherigen Befehls).
Einträge, die mittlerweile behoben wurden:
- Fehler-Ausgaben beim FHEM-Start: Einige Readings dürfen bei einem Neustart von FHEM nicht bereits vorbelegt sein, da der entsprechende Zoneplayer mittlerweile andere Informationen haben könnte, bzw. einige Events sonst nicht erzeugt werden. Aus diesem Grund werden diese beim Start auch nicht geladen.
Folgende Meldung erscheint z.B.:Reading Sonos_Wohnzimmer->AlarmListVersion must not be used out of statefile.
Diese Meldungen kann man getrost ignorieren, da sie nicht auf einen Fehler hindeuten, sondern nur klarstellen, dass diese Readings eben nicht aus dem Statefile verwendet werden dürfen (was durch Ausgabe dieser Meldung auch nicht passiert).- Das konnte mittlerweile durch ein Setzen eines "Lademarkers" verhindert werden. Dadurch wird das Laden des Readings nicht mehr unterbunden, sondern auf einen sicher ungültigen Wert gesetzt. Damit funktionieren die folgenden Readings-Update Aufrufe wieder.
Changelog
Datum | Version | Änderungen |
---|---|---|
SVN-History | ||
14.07.2020 |
| |
30.06.2020 |
| |
25.04.2018 |
| |
15.04.2018 |
| |
24.03.2018 |
| |
10.03.2018 |
| |
26.02.2018 |
| |
07.01.2018 |
| |
23.12.2017 |
| |
28.09.2017 |
| |
14.07.2017 |
| |
09.07.2017 |
| |
05.07.2017 |
| |
05.07.2017 |
| |
21.06.2017 |
| |
20.06.2017 |
| |
14.05.2017 |
| |
09.04.2017 |
| |
04.04.2017 |
| |
19.03.2017 |
| |
13.03.2017 |
| |
12.03.2017 |
| |
19.03.2016 |
| |
06.02.2016 |
| |
31.01.2016 |
| |
31.12.2015 |
| |
24.12.2015 |
| |
15.12.2015 |
| |
08.12.2015 |
| |
07.12.2015 |
| |
02.08.2015 |
| |
12.07.2015 |
| |
14.06.2015 |
| |
02.05.2015 |
| |
14.04.2015 |
| |
07.04.2015 |
| |
03.04.2015 |
| |
28.03.2015 |
| |
28.02.2015 |
| |
19.02.2015 |
| |
14.02.2015 |
| |
06.02.2015 |
| |
01.02.2015 |
| |
31.01.2015 |
| |
30.01.2015 |
| |
27.01.2015 |
| |
26.01.2015 |
| |
24.01.2015 |
| |
19.01.2015 |
| |
16.01.2015 |
| |
15.01.2015 |
| |
08.01.2015 |
| |
05.01.2015 |
| |
04.01.2015 |
| |
03.01.2015 |
| |
02.01.2015 |
| |
01.01.2015 |
| |
31.12.2014 |
| |
28.12.2014 |
| |
26.12.2014 |
| |
Versionen von fhem.lmsoft.de | ||
17.12.2014 | 2.6 |
|
07.03.2014 | 2.5 |
|
31.12.2013 | 2.4 |
|
02.12.2013 | 2.3 |
|
12.10.2013 | 2.2 |
|
23.09.2013 | 2.1 |
|
15.09.2013 | 2.0 |
|
27.05.2013 | 1.13 |
|
23.05.2013 | 1.12 |
|
10.03.2013 | 1.11 |
|
22.02.2013 | 1.10 |
|
16.02.2013 | 1.9 |
|
13.02.2013 | 1.8 |
|
04.02.2013 | 1.7 |
|
30.01.2013 | 1.6 |
|
29.01.2013 | 1.5 |
|
28.01.2013 | 1.4 |
|
26.01.2013 | 1.3 |
|
24.01.2013 | 1.2 |
|
18.01.2013 | 1.1 |
|
16.01.2013 | 1.0 |
|
Modul SONOS
Dieses Modul erledigt die eigentliche Kommunikationsarbeit zu den ZonePlayern mittles UPnP. Es startet (und läßt ihn dauerhaft laufen) einen Discovery Prozess, der alle ZonePlayer auffordert, sich zu melden, und reagiert auf entsprechende Signalisierungen. Es instantiiert einen Listener und meldet diesen bei allen ZonePlayern für Abspielaktualisierungen an.
Wenn ein Aufruf des Discovery-Prozesses erfolgt, wird geprüft, ob der Player bereits definiert wurde. Wenn nicht, wird eine Definition erzeugt, wenn ja, dann wird die Komponente mit den neu erhaltenen Informationen aktualisiert.
Wenn ein Aufruf der Abspielaktualisierung erfolgt, so wird die entsprechene Zoneplayer-Komponente in FHEM mit den neu erhaltenen Informationen aktualisiert, und entsprechende FHEM-Events generiert.
Wenn das Feature mit minVolume
oder maxVolume
verwendet wird, wird ein weiterer Listener beim entsprechenden Zoneplayer angemeldet. Mittels diesem werden Lautstärkenänderungen am Zoneplayer gemeldet umd können entsprechend umgehend korrigiert werden.
Als Nebeneffekt wird für jede Lautstärkenänderung auch ein Event in FHEM erzeugt (als Folge einer Aktualisierung des Readings Volume
).
Readings von SONOS
AllPlayer
: Enthält alle Player.AllPlayerCount
: Enthält die Anzahl der Player in "AllPlayer".AllPlayerNotBonded
: Enhtält alle Masterplayer, die nicht gebunden sind (also keine Stereo- oder Satellitenteilnehmer sind).AllPlayerNotBondedCount
: Enhtält die Anzahl der Player in "AllPlayerNotBonded".LastProcessAnswer
: Enthält den letzten Zeitpunkt einer Datenübertragung vom SubProzess zum FHEM-Modul.LastProcessRestart
: Enthält (falls vorhanden) den Zeitpunkt des letzten Neustarts des SubProzesses.LastProcessRestartCount
: Enthält (falls vorhanden) die Anzahl der durchgeführten Neustarts des SubProzesses.LineInPlayer
: Enthält die gültigen LineIn-Eingänge aller Player, die für die Wiedergabe ausgewählt werden können als visualisiertes Perl-Array.LineInPlayerList
: Enthält die gültigen LineIn-Eingänge aller Player, die für die Wiedergabe ausgewählt werden können als "|"-separierte Liste von Devicenamen, wenn das Attribut "" am Sonos-Device angegeben ist.LineInPlayerListAlias
: Enthält die gültigen LineIn-Eingänge aller Player, die für die Wiedergabe ausgewählt werden können als "|"-separierte Liste von Raumnamen, wenn das Attribut "" am Sonos-Device angegeben ist.MasterPlayer
: Hier werden alle Masterplayer in einer per eval zu einem Array umwandelbaren Liste angegeben. z.B.: ['Sonos_Kueche','Sonos_Flur']MasterPlayerCount
: Hier wird die Anzahl der erkannten Masterplayer angegeben. z.B.: 2MasterPlayerNotPlaying
: Hier werden alle Masterplayer in einer per eval zu einem Array umwandelbaren Liste angegeben, die gerade keine laufende Wiedergabe haben. z.B.: ['Sonos_Kueche']MasterPlayerNotPlayingCount
: Hier wird die Anzahl der nicht abspielenden Masterplayer angegeben. z.B.: 1MasterPlayerPlaying
: Hier werden alle Masterplayer in einer per eval zu einem Array umwandelbaren Liste angegeben, die gerade eine laufende Wiedergabe haben. z.B.: ['Sonos_Flur']MasterPlayerPlayingCount
: Hier wird die Anzahl der abspielenden Masterplayer angegeben. z.B.: 1QueueHash
: Der Hash-Wert für die aktuelle Abspielliste. Dieser wird bei jeder Änderung der aktuellen Abspielliste aktualisiert.ShareIndexInProgress
: Gibt an, ob gerade eine Aktualisierung des Indexes der Freigaben erfolgt.UserId_Napster
: Speichert die UserId für den Napster-Zugriff. Diese Information ist notwendig, wenn eine M3U-Datei mit Napster-Titeln importiert werden soll, und wird automatisch ermittelt, sobald man mit dem Original-Controller einen einzelnen Titel aus Napster in die aktuelle Abspielliste überträgt.UserId_Spotify
: Speichert die UserId für den Spotify-Zugriff. Diese Information ist notwendig, wenn eine M3U-Datei mit Spotify-Titeln importiert werden soll, und wird automatisch ermittelt, sobald man mit dem Original-Controller einen einzelnen Titel aus Spotify in die aktuelle Abspielliste überträgt.ZoneGroupState
: Die Konfigurationsinformationen zu der aktuellen Gruppenlandschaft der Zoneplayer. Der Befehlget SONOS Groups
vereinfacht den Zugriff hierauf, indem es eine einfach les- und verarbeitbare Liste erzeugt.
Attribute von SONOS
Hinweis
Die Attribute werden (bis auf verbose
und disable
) erst bei einem Neustart von FHEM verwendet, da diese dem SubProzess initial zur Verfügung gestellt werden müssen.
- Grundsätzliches
allowedWebAccess
: Definiert einen regulären Ausdruck für die erlaubten Adressen für Nachladedaten wie Musikdienste, Cover o.ä. Wenn nicht angegeben, dann wird alles zugelassen.
Hinweis: Dabei erfolgt die Prüfung ausschließlich auf den Namen der Adresse, so wie vom System angegeben. Es erfolgt keine vorherige Übersetzung in IP-Adressen o.ä.
Beispiel: Mit der Angabe von ^http:\/\/192\.168\.0\.\d+.*$ wird der Zugriff auf das lokale Netz (z.B. beim Laden von Daten vom Sonosplayer selbst) beschränkt.
Alles Sperren geht über eine unmögliche Adresse wie ^xyzcoverLoadTimeout(0..10,15,20,25,30)
: Definiert den Timeout der für die Abfrage des Covers beim Sonosplayer verwendet wird. Wenn nicht angegeben, dann wird 5 verwendet.deviceRoomView(Both,DeviceLineOnly)
: Gibt an, was in der Raumansicht zum Sonosplayer-Device angezeigt werden soll.Both
bedeutet "normale" Devicezeile zzgl. Cover-/Titelanzeige und u.U. Steuerbereich,DeviceLineOnly
bedeutet nur die Anzeige der "normalen" Devicezeile.disable(0,1)
: Hiermit kann das Modul abgeschaltet werden. Wirkt sofort. Bei 1 wird der SubProzess beendet, und somit keine weitere Verarbeitung durchgeführt. Bei 0 wird der Prozess wieder gestartet.
Damit kann das Modul temporär abgeschaltet werden, um bei der Neueinrichtung von Sonos-Komponenten keine halben Zustände mitzubekommen.
Des Weiteren kann man damit Attribut-Änderungen an den SubProzess weiterreichen, da ja ein neuer Prozess gestartet wird, dem natürlich zu Beginn wieder alle verfügbaren/notwendigen Attribute zur Verfügung gestellt werden.getFavouritesListAtNewVersion(0,1)
: Mit diesem Attribut kann das Modul aufgefordert werden, die Favoriten (bei definiertem AttributgetListsDirectlyToReadings
) bei Aktualisierung automatisch herunterzuladen.getPlaylistsListAtNewVersion(0,1)
: Mit diesem Attribut kann das Modul aufgefordert werden, die Playlisten (bei definiertem AttributgetListsDirectlyToReadings
) bei Aktualisierung automatisch herunterzuladen.getQueueListAtNewVersion <value>
: Mit diesem Attribut kann das Modul aufgefordert werden, die aktuelle Abspielliste (bei definiertem AttributgetListsDirectlyToReadings
) bei Aktualisierung automatisch herunterzuladen.getRadiosListAtNewVersion <value>
: Mit diesem Attribut kann das Modul aufgefordert werden, die Radioliste (bei definiertem AttributgetListsDirectlyToReadings
) bei Aktualisierung automatisch herunterzuladen.getListsDirectlyToReadings(0,1)
: Mit diesem Attribut kann das Modul aufgefordert werden, die Listen für Favoriten, Playlists, Radios und Queue direkt in die entsprechenden Readings zu schreiben. Dafür sind dann keine Userreadings mehr notwendig.getLocalCoverArt(0,1)
: Mit diesem Attribut kann das Modul aufgefordert werden, die Cover lokal herunterzuladen (bisheriges Standardverhalten).ignoredIPs
: Mit diesem Attribut können IP-Adressen angegeben werden, die vom UPnP-System ignoriert werden sollen. Z.B.: 192.168.0.11,192.168.0.37. Es sind auch reguläre Ausdrücke pro Element zulässig. Diese dürfen nur keine Kommata oder Doppelpunkte enthalten. Z.B: /192.168.0.(1|2|3)/,/192.168.1.\d*/. Alle Meldungen und Benachrichtigungen von den angegebenen IP-Adressen werden ignoriert.
Hinweis: Dieses Attribut kann hilfreich sein, wenn sich falsche UPnP-Devices melden, obwohl nur Sonos-Devices angefragt waren. Manchmal passiert das mit irgendwelchen NAS oder sonstigen Serverdevices.
Folgende Meldungen (z.B.) sind ein Indiz für falsche Devices:Loading device description failed with error: 500 Can't connect to 192.168.2.29:2869 (timeout) at ./FHEM/00_SONOS.pm line xx thread 1
, wenn die angegebene IP-Adresse gar kein Sonos-Devices ist.pingType(none,tcp,udp,icmp,syn)
: Definiert die Art, wie der Alive-Check eines Zoneplayers erfolgen soll. Die Verfahren funktionieren unterschiedlich gut. Am Ressourcensparsamsten ist icmp, benötigt aber "root
"-Rechte. An zweiter Stelle ist syn zu empfehlen. Die anderen Verfahren melden manchmal fehlerhafte not alives. Einfach probieren. Mittels none kann dieser Mechanismus auch deaktiviert werden.reusePort(0,1)
: Eines von (0,1). Gibt an, ob die Portwiederwendung für SSDP aktiviert werden soll, oder nicht. Kann Restart-Probleme lösen. Wenn man diese Probleme nicht hat, sollte man das Attribut nicht setzen.SubProcessLogfileName <Pfad>
: Hiermit kann für den SubProzess eine eigene Logdatei angegeben werden. Unter Windows z.B. überschreiben sich die beiden Logausgaben (von Fhem und SubProzess) sonst gegenseitig. Wenn "-" angegeben wird, wird wie bisher auf STDOUT (und damit im Fhem-Log) geloggt. Der Hauptanwendungsfall ist die mehr oder weniger kurzfristige Fehlersuche. Es werden keinerlei Variablenwerte ersetzt, und der Wert direkt als Dateiname verwendet.usedonlyIPs <IP-Adresse>[,IP-Adresse]
: Mit diesem Attribut können IP-Adressen angegeben werden, die ausschließlich vom UPnP-System berücksichtigt werden sollen. Z.B.: "192.168.0.11,192.168.0.37". Es sind auch reguläre Ausdrücke pro Element zulässig. Diese dürfen nur keine Kommata oder Doppelpunkte enthalten. Z.B: /192.168.0.(1|2|3)/,/192.168.1.\d*/.
- Bookmark-Einstellungen
Hinweis: Die Konfiguration der Bookmarks wird erst bei einem Neustart des SubProzesses (also durch einen FHEM-Neustart (vorher Speichern nicht vergessen) oder dem Setzen/Zurücksetzen des Attributs disable am Sonos-Device) berücksichtigt.bookmarkSaveDir <path>
: Das Verzeichnis, in dem die Dateien für die gespeicherten Bookmarks abgelegt werden sollen. Wenn nicht festgelegt, dann wird "." verwendet.bookmarkTitleDefinition <Groupname>:<PlayerdeviceRegEx>:<TrackURIRegEx>:<MinTitleLength>:<RemainingLength>:<MaxAge>:<ReadOnly> [...]
: Die Definition für die Verwendung von Bookmarks für Titel.bookmarkPlaylistDefinition <Groupname>:<PlayerdeviceRegEx>:<MinListLength>:<MaxListLength>:<MaxAge> [...]
: Die Definition für die Verwendung von Bookmarks für aktuelle Abspiellisten/Playlisten.
- Proxy-Einstellungen
generateProxyAlbumArtURLs(0,1)
: Wenn aktiviert, werden alle Cover-Links als Proxy-Aufrufe an FHEM generiert. Dieser Proxy-Server wird vom Sonos-Modul bereitgestellt. In der Grundeinstellung erfolgt kein Caching der Cover, sondern nur eine Durchreichung der Cover von den Sonosplayern (Damit ist der Zugriff durch einen externen Proxyserver auf FHEM möglich).proxyCacheDir
: Hiermit wird das Verzeichnis festgelegt, in dem die Cover zwischengespeichert werden. Wenn nicht festgelegt, so wird /tmp verwendet.proxyCacheTime
: Mit einer Angabe ungleich 0 wird der Caching-Mechanismus des Sonos-Modul-Proxy-Servers aktiviert. Dabei werden Cover, die im Cache älter sind als diese Zeitangabe in Sekunden, neu vom Sonosplayer geladen, alle anderen direkt ausgeliefert, ohne den Player zu fragen.webname <String>
: Hiermit kann der zu verwendende Webname für die Cover-Link-Erzeugung angegeben werden. Da vom Modul Links zu Cover u.ä. erzeugt werden, ohne dass es einen FhemWeb-Aufruf dazu gibt, kann das Modul diesen Pfad nicht selber herausfinden. Wenn das Attribut nicht angegeben wird, dann wird 'fhem' angenommen.
- Sprachoptionen
targetSpeakDir
: Das Verzeichnis, in dem dieses Modul die Sprachdateien vonSpeak
(siehe Set-Befehle an den SONOSPLAYER) ablegen soll (also die Adresse für den Schreibzugriff). Es wird empfohlen, dass dieses Verzeichnis nicht von Sonos indiziert ist.
z.B. Pfade unter *Nix:/home/www/Sonos
oder unter Windows:C:\InetPub\Sonos
targetSpeakMP3FileConverter
: Hiermit kann ein MP3-Konverter angegeben werden, der am Ende der Verkettung der Speak-Ansage das resultierende MP3-File nochmal sauber durchkodiert. Damit können Restzeitanzeigeprobleme behoben werden. Dadurch vegrößert sich allerdings u.U. die Ansageverzögerung.
z.B./usr/bin/avconv -i %infile% %outfile%
- Hinweis: Der Platzhalter %infile% wird durch den Quelldateinamen ersetzt werden.
- Hinweis: Der Platzhalter %outfile% wird durch den Zieldateinamen ersetzt werden.
- Hinweis: Das Programm avconv kann unter Debian z.B. mittels
sudo apt-get install ffmpeg
installiert werden.
targetSpeakMP3FileDir
: Das Verzeichnis, welches als Standard für MP3-Fileangaben in Speak-Texten verwendet werden soll. Wird dieses Attribut definiert, können die Angaben bei Speak ohne Verzeichnis erfolgen.
z.B. Pfade unter *Nix:/home/www/Sonos
oder unter Windows:C:\InetPub\Sonos
targetSpeakURL
: Die URL, unter der von außen (also aus Sicht des Zoneplayers) auf die abgelegte Sprachdatei zugegriffen werden kann (also die Adresse für den Lesezugriff).
z.B.\\192.168.178.45\Sonos
- Achtung!: Dabei muss darauf geachtet werden, dass als letztes Zeichen vor dem Zeilenumbruch kein Backslash steht (ist hier für den Pfad auch nicht notwendig). Dieser würde von FHEM als Maskierer für den folgenden Zeilenumbruch interpretiert werden, und die nächste Zeile wäre auch noch Bestandteil dieses Attributs (und damit des Pfades).
targetSpeakFileTimestamp(0,1)
: Definiert, ob in dem Namen der Sprachausgabedatei ein Zeitstempel enthalten sein soll. Das sorgt dafür, dass alle Dateien beibehalten werden (da nicht mit demselben Namen überschrieben wird).
Manchmal kann das auch Caching-Probleme beseitigen. In meinen Tests hat die Anzeige der in der Sprachdatei enthaltenen MP3-Tags nur mit dieser aktivierten Option sauber funktioniert, da der ZonePlayer bei mir die Tags gecached hält.
Anderseits muss man sich dabei Gedanken über eine Aufräumstrategie machen, da die alten Dateien immer vorhanden bleiben.targetSpeakFileHashCache(0,1)
: Definiert, ob in dem Namen der Sprachausgabedatei ein Hash-Wert enthalten sein soll. Das sorgt dafür, dass die Dateien bei gleichem Text wiederverwendet werden und nicht neu generiert werden.- Für diese Funktionalität wird das Perl-Modul Digest::SHA1 für die Berechnung des Hash-Werts benötigt. Am einfachsten kann es bei Bedarf per CPAN installiert werden:
sudo cpan install Digest::SHA1
.
- Für diese Funktionalität wird das Perl-Modul Digest::SHA1 für die Berechnung des Hash-Werts benötigt. Am einfachsten kann es bei Bedarf per CPAN installiert werden:
Speak1
: Hiermit kann ein Systemaufruf definiert werden, der zu Erzeugung einer Sprachausgabe verwendet werden kann. Sobald dieses Attribut definiert wurde, ist ein entsprechender Setter am Sonosplayer verfügbar.
Das Format ist:
<Ausgabedateiendung>:<Befehlszeile>- Es dürfen folgende Platzhalter verwendet werden:
%language%: Wird durch die eingegebene Sprache ersetzt
%filename%: Wird durch den kompletten Dateinamen (inkl. Dateiendung) ersetzt.
%text%: Wird durch den zu übersetzenden Text ersetzt.
%textescaped%: Wird durch den URL-Enkodierten zu übersetzenden Text ersetzt.
Zusätzliche Ersetzungen:
%textutf8%: Wird durch den zu übersetzenden Text im UTF8-Format ersetzt.
%textutf8escaped%: Wird durch den URL-Enkodierten zu übersetzenden Text im UTF8-Format ersetzt.
- Es dürfen folgende Platzhalter verwendet werden:
Speak2
: Siehe Speak1Speak3
: Siehe Speak1Speak4
: Siehe Speak1SpeakCover
: Hiermit kann ein JPG- oder PNG-Bild als Cover für die Google-Sprachdurchsagen definiert werden.Speak1Cover
: Analog zu SpeakCover für Speak1.Speak2Cover
: Analog zu SpeakCover für Speak2.Speak3Cover
: Analog zu SpeakCover für Speak3.Speak4Cover
: Analog zu SpeakCover für Speak4.SpeakGoogleURL <GoogleURL>
: Die zu verwendende Google-URL. Wenn dieser Parameter nicht angegeben wird, dann wird ein Standard verwendet. Hier müssen Platzhalter für die Ersetzung durch das Modul eingetragen werden: %1$s -> Sprache, %2$s -> Text- Die Standard-URL lautet momentan:
http://translate.google.com/translate_tts?tl=%1$s&client=tw-ob&q=%2$s
- Die Standard-URL lautet momentan:
Get-Befehle an SONOS
- Gruppenbefehle
Groups
: Liefert die aktuelle Gruppierungskonfiguration der Sonos-Systemlandschaft zurück. Das Format ist eine Komma-getrennte Liste von Listen mit Devicenamen, also z.B.[Sonos_Kueche], [Sonos_Wohnzimmer, Sonos_Schlafzimmer]
. In diesem Beispiel sind also zwei Gruppen definiert, von denen die erste aus einem Player und die zweite aus Zwei Playern besteht. Dabei ist die Reihenfolge innerhalb der Unterlisten wichtig, da der erste Eintrag der sogenannte Gruppenkoordinator ist (in diesem Fall alsoSonos_Wohnzimmer
), von dem die aktuelle Abspielliste und der aktuelle Titel auf die anderen Gruppenmitglieder übernommen wird.
Set-Befehle an SONOS
- Grundsätzliches
RefreshShareIndex
: Startet eine Aktualisierung des Indexes der FreigabenRescanNetwork
: Startet die Erkennung der im Netzwerk vorhandenen Player erneut.
- Steuerbefehle
Mute <State>
: Setzt den Mute-Zustand bei allen Playern. Der Wert kann on oder off sein.PauseAll
: Pausiert die Wiedergabe in allen Zonen.Pause
: Synonym für PauseAll.StopAll
: Stoppt die Wiedergabe in allen Zonen.Stop
: Synonym für StopAll.
- Bookmark-Befehle
DisableBookmark <Groupname>
: Deaktiviert die angegebene Gruppe.EnableBookmark <Groupname>
: Aktiviert die angegebene Gruppe.LoadBookmarks [Groupname]
: Lädt die angegebene Gruppe (oder alle Gruppen, wenn nicht angegeben) aus den entsprechenden Dateien.SaveBookmarks [Groupname]
: Speichert die angegebene Gruppe (oder alle Gruppen, wenn nicht angegeben) in die entsprechenden Dateien.
- Gruppenbefehle
Groups <Gruppendefinition>
: Setzt die aktuelle Gruppierungskonfiguration der Sonos-Systemlandschaft. Das Format ist jenes, welches auch von dem Get-Befehl Groups geliefert wird.
Hinweis: Hier kann als Gruppendefinition das Wort Reset verwendet werden, um alle Player aus ihren Gruppen zu entfernen.
Modul SONOSPLAYER
Dieses Modul dient im großen und ganzen als Platzhalter für FHEM, damit der Anwender FHEM-Konform informiert werden, bzw. steuern kann.
Hier werden die Informationen, die vom SONOS-Modul erkannt werden, abgelegt, und die Aktualisierungs-Events erzeugt.
Readings von SONOSPLAYER
Folgende Informationen werden im SONOSPLAYER als Reading abgelegt:
- Systemzustand
AlarmList
: Enthält die textuelle Repräsentation des Hashs mit den aktuell für diesen Player gültigen Alarminformationen. Diese Information wird automatisch aktualisiert, wenn das Attribut getAlarms auf 1 gesetzt wurde, ansonsten steht sie nicht zur Verfügung (und es kann kein Alarm angelegt, verändert und gelöscht werden). Das Format des Hashs entspricht dem, das zum Setzen oder Anpassen eines Alarms notwendig ist.
Folgene Schlüssel sind dort zulässig/notwendig:- Enabled(0,1): Gibt an, ob der Alarm aktiviert ist.
- Volume(0..100): Die Lautstärke, mit der der Alarm wiedergegeben werden soll.
- StartTime(Timstamp): Die Uhrzeit, zu der der Alarm starten soll.
- Duration(Timstamp): Die Dauer, die der Alarm laufen soll.
- Repeat(0,1): Gibt an, ob die Wiedergabe wiederholt werden soll.
- Shuffle(0,1): Gibt an, ob die Wiedergabe zufällig erfolgen soll.
- RoomUUID: Die ID der Zone, in der der Alarm wiedergegeben werden soll. Dieser Wert muss nie mit angegeben werden, da er automatisch befüllt wird (Diese Information ist durch das verwendete FHEM-Zoneplayer-Device klar).
- ProgramURI: Die abzuspielende URI.
- ProgramMetaData: Die Metadaten zu der abzuspielenden URI.
- Recurrence_Once(0,1): Gibt an, dass der Alarm nur einmal laufen soll. Wenn hier eine 1 angegeben wurde, dann werden die anderen Recurrence-Angaben ignoriert.
- Recurrence_Monday(0,1): Gibt an, dass der Alarm jeden Montag laufen soll. Kann mit den anderen Tagesangaben kombiniert werden.
- Recurrence_Tuesday(0,1): Gibt an, dass der Alarm jeden Dienstag laufen soll. Kann mit den anderen Tagesangaben kombiniert werden.
- Recurrence_Wednesday(0,1): Gibt an, dass der Alarm jeden Mittwoch laufen soll. Kann mit den anderen Tagesangaben kombiniert werden.
- Recurrence_Thursday(0,1): Gibt an, dass der Alarm jeden Donnerstag laufen soll. Kann mit den anderen Tagesangaben kombiniert werden.
- Recurrence_Friday(0,1): Gibt an, dass der Alarm jeden Freitag laufen soll. Kann mit den anderen Tagesangaben kombiniert werden.
- Recurrence_Saturday(0,1): Gibt an, dass der Alarm jeden Samstag laufen soll. Kann mit den anderen Tagesangaben kombiniert werden.
- Recurrence_Sunday(0,1): Gibt an, dass der Alarm jeden Sonntag laufen soll. Kann mit den anderen Tagesangaben kombiniert werden.
- IncludeLinkedZones(0,1): Gibt an, ob die aktuell verlinkten Zonen diesen Alarm ebenfall abspielen sollen.
- Beispiel-Hash: { Enabled => 1, Volume => 12, StartTime => '16:00:00', Duration => '00:15:00', Repeat => 0, Shuffle => 0, ProgramURI => 'x-rincon-buzzer:0', ProgramMetaData => ' ', Recurrence_Once => 0, Recurrence_Monday => 1, Recurrence_Tuesday => 1, Recurrence_Wednesday => 1, Recurrence_Thursday => 1, Recurrence_Friday => 1, Recurrence_Saturday => 0, Recurrence_Sunday => 0, IncludeLinkedZones => 0 }
AlarmListIDs
: Enthält die Hash-Schlüssel der Alarme als kommaseparierte Liste. Dieses Reading gibt es Hauptsächlich zur Vereinfachung des Zugriffs auf das Reading AlarmList. Damit hat man direkt die Anzahl und Primärschlüssel im Zugriff.AlarmListVersion
: Dieses Reading enthält die Information über die aktuelle Version der gespeicherten Alarm-Informationen. Diese Information wird Hauptsächlich intern benötigt, um beurteilen zu können, ob die Alarminformationen neu geladen werden müssen.AudioDelay
: Gibt das AudioDelay des Players an. Der Wert kann zwischen 0 und 5 liegen.AudioDelayLeftRear
: Gibt den AudioDelayLeftRear des Players an. Der Wert kann zwischen 0 und 2 liegen. Wobei die Werte folgende Bedeutung haben: 0: >3m, 1: >0.6m und <3m, 2: <0.6mAudioDelayRightRear
: Gibt den AudioDelayRightRear des Players an. Der Wert kann zwischen 0 und 2 liegen. Wobei die Werte folgende Bedeutung haben: 0: >3m, 1: >0.6m und <3m, 2: <0.6mButtonState
: Gibt den Zustand des Buttons an.ButtonLockState
: Gibt den Sperr-Zustand des Buttons an.DailyIndexRefreshTime
: Enthält die aktuell gültige DailyIndexRefreshTime, zu der der Medienindex neu aufgebaut werden soll.
Diese Information wird automatisch aktualisiert, wenn sie bei einem Player verändert wird, wenn das Attribut getAlarms des Player auf 1 gesetzt wurde.DialogLevel
: Gibt den Zustand der Sprachverbesserung an der Playbar an.FavouritesVersion
: Dieses Reading enthält die Information über die aktuelle Version der gespeicherten Favoriten. Eine Änderung dieses Readings wird durch eine Anpassung der Favoriten (z.B. durch einen Controller) ausgelöst.fieldType
: In einer Paarung wird jedem Player vom Sonos-System ein eindeutiger FieldType zugewiesen. Dieser wird von diesem Modul für die Eindeutigkeit des Device-Namen verwendet. Bei einer Stereopaarung z.B. hat ein Player den Type 'LF' (für Left-Front), 'RF' (für Right-Front) oder SW (für Subwoofer); bei Surround-Konfigurationen aber auch RR (für Right-Rear) oder LR (für Left-Rear).HeadphoneConnected
: Enthält, wenn eines der beiden AttributeminVolume
odermaxVolume
(oder auchminVolumeHeadphone
undmaxVolumeHeadphone
) gesetzt wurde, den Zustand, ob ein Kopfhörer verwendet wird, oder nicht.
Wenn zusätzlich noch das AttributgenerateVolumeEvent
gesetzt ist, erzeugt jede Änderung dieses Zustands auch ein FHEM-Event. Standardmäßig ist dies aus Zeitgründen deaktiviert, da FHEM-Events an jeden(!) notify innerhalb FHEM gemeldet werden. Dies kann u.U. zu Verzögerungen bei dem ZonePlayer führen.LastActionResult
: Enthält den Namen und das Ergebnis der letzten Aktion auf dem Player. Da die Aktionen asyncron übertragen werden, kann nur hier kontrolliert werden, ob das gewünschte Ergebnis erreicht wurde.LineInConnected
: Gibt an, ob der Line-In-Eingang angeschlossen ist, oder nicht. Wird bei Änderung am Player automatisch aktualisiert, und erzeugt damit auch ein Event.location
: URL zum Informationsdokument des ZonePlayersNightMode
: Gibt den Zustand des Nachtsounds an der Playbar an.Orientation
: Gibt die Lage des Players an.playerType
: Typbezeichnung des ZonePlayer. z.B. "ZP90"PlaylistsVersion
: Dieses Reading enthält die Information über die aktuelle Version der gespeicherten Playlists. Eine Änderung dieses Readings wird durch eine Anpassung der Playlists (z.B. durch einen Controller) ausgelöst.presence
: Erreichbarkeit des Players. Kann "appeared" oder "disappeared" seinRadiosVersion
: Dieses Reading enthält die Information über die aktuelle Version der gespeicherten Radiofavoriten. Eine Änderung dieses Readings wird durch eine Anpassung der Radios (z.B. durch einen Controller) ausgelöst.roomName
: Originalname des ZonePlayers. Kann Leer- oder Sonderzeichen enthaltenroomNameAlias
: Originalname des ZonePlayers mit einem angehangenen Funktionsnamen, wie er für das Attribut "alias" verwendet werden würde (z.B. "Wohnzimmer - Rechts"). Wird zur Laufzeit aktualisiert. Kann Leer- oder Sonderzeichen enthaltensaveRoomName
: Sicherer Name des Zoneplayer. Sonderzeichen wurden in Unterstriche umgewandelt. Das Device wird beim Anlegen mit diesem Namen angelegtserialNum
: Seriennummer des ZonePlayers. Entspricht weitestgehend der MAC-Adresse. z.B. "00-0E-58-28-D0-F4:2"softwareRevision
: Version der installierten Software. z.B. "8.4"softwareRevisionAvailable
: Version der verfügbaren Software. z.B. "8.5"softwareRevisionInternal
: Interne Version der installierten Software. z.B. "41.3-50131"softwareRevisionInternalAvailable
: Interne Version der verfügbaren Software. z.B. "42.2-51240"SubEnable
: Gibt den Zustand des Sub-Zustands für diesen Player an.SubGain
: Gibt den SubGain für diesen Player an. Der Wert kann zwischen -15 und 15 liegen.SubPolarity
Gibt den SubPolarity für diesen Player an. Der Wert kann zwischen 0 und 2 liegen.SurroundEnable
: Gibt an, ob für diesen Player die Surround-Wiedergabe aktiviert wurde, oder nicht.SurroundLevel
: Gibt den Surroundlevel für diesen Player an. Der Wert kann zwischen -15 und 15 sein.TruePlay
: Gibt an, ob für diesen Player die TruePlay-Wiedergabe aktiviert ist, oder nicht.WifiEnabled
: Gibt an, ob für diesen Player Wifi aktiviert ist, oder nicht.WirelessMode
: Gibt den Wirelessmode des Players an.
- Gruppierungsinformationen
AvailablePlayerList
: Wird gesetzt, wenn das Attribut "getListsDirectlyToReadings" am Sonos-Device gesetzt wurde. Es enthält die anderen und noch verfügbaren und nicht gebundenen Player-Devicenamen. Das ist die Grundlage für eine Player-zur-Abspielgruppe-hinzufügen-Funktion als Listendarstellung.AvailablePlayerListAlias
: Wird gesetzt, wenn das Attribut "getListsDirectlyToReadings" am Sonos-Device gesetzt wurde. Es enthält die anderen und noch verfügbaren und nicht gebundenen Player-Raumnamen. Das ist die Grundlage für eine Player-zur-Abspielgruppe-hinzufügen-Funktion als Listendarstellung.IsBonded
: Gibt an, ob der Player in einer Bindung zum Masterplayer steht (anstatt ein einfaches Gruppenmitglied zu sein). Gebundene Player sind z.B. der rechte Player im Stereoverbund, sowie die Satellitenplayer in einem 5.1er Surroundsystem (also Subwoofer, hintere Lautsprecher und vordere Lautsprecher).IsMaster
: Gibt an, ob dieser Player aktuell ein Masterplayer einer Gruppe ist. Dabei kann die Gruppe auch nur einen Teilnehmer haben (wieder dieser Player).
Damit kann ermittelt werden, welche Player korrekte Abspielinformationen darstellen können.IsZoneBridge
: Gibt an, ob dieser Player eine Bridge ist.MasterPlayer
: Gibt den FHEM-Devicenamen des Masterplayers zu diesem Player an. Wenn dieser Player alleine eine Gruppe darstellt, dann steht in diesem Reading der FHEM-Devicenamen dieses Players.SlavePlayer
: Gibt eine per eval umwandelbare Liste von FHEM-Devicenamen der zu diesem Masterplayer gehörenden Slaveplayer an. Diese Liste kann auch leer sein, wenn dieser Player kein Masterplayer ist, oder die Gruppe nur aus einem Mitglied besteht.SlavePlayerNotBonded
: Enthält alle SlavePlayer, die nicht gebunden sind als visualisiertes Perl-Array.SlavePlayerNotBondedList
: Enthält alle SlavePlayer, die nicht gebunden sind als "|"-separierte Liste der Devicenamen.SlavePlayerNotBondedListAlias
: Enthält alle SlavePlayer, die nicht gebunden sind als "|"-separierte Liste der Raumnnamen.ZoneGroupID
: Die ID des Gruppenkoordinators plus eine laufende Nummer. Sollte die Gruppe nur aus einem Mitglied bestehen, so ist es die eigene ID (=UDN).ZoneGroupName
: Der Name der aktuellen GruppeZoneGroupNameDetails
: Enthält die Slavezonen als textuelle Auflistung mittels '+'. Ist leer, wenn es keine Slaveplayer gibt. Enthält den Namen des Gruppenmasters, wenn es einen solchen gibt.ZonePlayerUUIDsInGroup
: Eine Liste der in der aktuellen Gruppe befindlichen Zoneplayer.
- Abspielzustand
AlarmRunning
: Dieses Reading enthält 1, wenn gerade ein Alarm abgespielt wird, sonst 0AlarmRunningID
: Dieses Reading enthält die ID des verursachenden Alarms, wenn gerade ein Alarm abgespielt wird, sonst ist es leer.Balance
: Enthält im Normalfall die am Player eingestellte Balance zum Zeitpunkt der Erkennung. Wenn eines der beiden AttributeminVolume
odermaxVolume
gesetzt wurde, wird diese Balance bei jeder Änderung am Player mit aktualisiert.
Wenn zusätzlich noch das AttributgenerateVolumeEvent
gesetzt ist, erzeugt jede Änderung der Balance auch ein FHEM-Event. Standardmäßig ist dies aus Zeitgründen deaktiviert, da FHEM-Events an jeden(!) notify innerhalb FHEM gemeldet werden. Dies kann u.U. zu Verzögerungen bei dem ZonePlayer führen.Bass
: Enthält im Normalfall den am Player eingestellten Basslevel zum Zeitpunkt der Erkennung. Wenn eines der beiden AttributeminVolume
odermaxVolume
gesetzt wurde, wird dieser Basslevel bei jeder Änderung am Player mit aktualisiert.
Wenn zusätzlich noch das AttributgenerateVolumeEvent
gesetzt ist, erzeugt jede Änderung des Basslevels auch ein FHEM-Event. Standardmäßig ist dies aus Zeitgründen deaktiviert, da FHEM-Events an jeden(!) notify innerhalb FHEM gemeldet werden. Dies kann u.U. zu Verzögerungen bei dem ZonePlayer führen.CrossfadeMode
: Enthält den aktuellen Zustand von CrossfadeMode. Wird durch Event des Players aktualisiert (zusammen mit der Titelinformation).GroupMute
: Enthält den GroupMute-Zustand. Wird automatisch aktualisiert.GroupVolume
: Enthält den GroupVolume-Zustand. Wird automatisch aktualisiert.GroupVolumeD
: Verringert die aktuelle Gruppenlautstärke um volumeStep-Einheiten.GroupVolumeU
: Erhöht die aktuelle Gruppenlautstärke um volumeStep-Einheiten.Loudness
: Enthält, wenn eines der beiden AttributeminVolume
odermaxVolume
gesetzt wurde, den aktuellen Zustand des Loudness.
Wenn zusätzlich noch das AttributgenerateVolumeEvent
gesetzt ist, erzeugt jede Änderung des Loudness-Zustands auch ein FHEM-Event. Standardmäßig ist dies aus Zeitgründen deaktiviert, da FHEM-Events an jeden(!) notify innerhalb FHEM gemeldet werden. Dies kann u.U. zu Verzögerungen bei dem ZonePlayer führen.Mute
: Enthält, wenn eines der beiden AttributeminVolume
odermaxVolume
gesetzt wurde, den aktuellen Zustand des Mute.
Wenn zusätzlich noch das AttributgenerateVolumeEvent
gesetzt ist, erzeugt jede Änderung des Mute-Zustands auch ein FHEM-Event. Standardmäßig ist dies aus Zeitgründen deaktiviert, da FHEM-Events an jeden(!) notify innerhalb FHEM gemeldet werden. Dies kann u.U. zu Verzögerungen bei dem ZonePlayer führen.numberOfTracks
: Anzahl der momentan in der Abspielliste befindlichen TitelOutputFixed
: Enthält, wenn eines der beiden AttributeminVolume
odermaxVolume
gesetzt wurde, den aktuellen Zustand des OutputFixed.
Wenn zusätzlich noch das AttributgenerateVolumeEvent
gesetzt ist, erzeugt jede Änderung des OutputFixed-Zustands auch ein FHEM-Event. Standardmäßig ist dies aus Zeitgründen deaktiviert, da FHEM-Events an jeden(!) notify innerhalb FHEM gemeldet werden. Dies kann u.U. zu Verzögerungen bei dem ZonePlayer führen.QueueDuration
: Enthält die Abspieldauer der aktuellen Abspielliste als Zeitangabe. Achtung!: Nicht jeder Titel wird mit Abspiellänge von Sonos geliefert, sodass dieser Wert auch ungenau sein kann.QueueDurationSec
: Enthält die Abspieldauer der aktuellen Abspielliste in Sekunden. Achtung!: Nicht jeder Titel wird mit Abspiellänge von Sonos geliefert, sodass dieser Wert auch ungenau sein kann.QueueHash
: Enthält den Hashwert der aktuellen Abspielliste. Dieser wird für die Bookmarkfunktionalität verwendetRepeat
: Enthält den aktuellen Zustand von Repeat. Wird durch Event des Players aktualisiert (zusammen mit der Titelinformation).RepeatOne
: Enthält den aktuellen Zustand von RepeatOne. Wird durch Event des Players aktualisiert (zusammen mit der Titelinformation).Shuffle
: Enthält den aktuellen Zustand von Shuffle. Wird durch Event des Players aktualisiert (zusammen mit der Titelinformation).SleepTimer
: Enthält die Restzeit des Sleeptimers. Diese Information wird vom Player beim Setzen und Ablaufen gemeldet, und erzeugt somit ein Event zu Beginn und Ende des Timers. Während der Timer läuft, wird hier nichts aktualisiert. Man muss also, falls benötigt, selber die verbleibende Restzeit mittels des Readings-Timestamps und diesem Wert ermitteln.
Diese Information wird automatisch aktualisiert, wenn sie bei einem Player verändert wird.
Beim Ablaufen des Timers wird vom Player eine Aktualisierung auf den Wert off gesendet. Darauf kann in einem Notify-Event geprüft werden.SleepTimerVersion
: Dieses Reading enthält die Information über die aktuelle Version der gespeicherten SleepTimer-Informationen. Diese Information wird Hauptsächlich intern benötigt, um beurteilen zu können, ob das Reading SleepTimer neu geladen werden muss.transportState
: Aktueller Abspielstatus. Kann "ERROR", "STOPPED", "PLAYING" oder "PAUSED_PLAYBACK" sein. Wobei ERROR heißt, dass es keine Verbindung zum Player gibt.
'Hinweis: Bei Gruppen hat nur der Gruppenmaster den korrekten Abspielzustand. Alle Slaveplayer enthalten immer den Zustand "PLAYING", da sie ja gerade den Masterplayer "abspielen", und keine Information dazu haben, ob und was abgespielt wird.Treble
: Enthält im Normalfall den am Player eingestellten Treblelevel zum Zeitpunkt der Erkennung. Wenn eines der beiden AttributeminVolume
odermaxVolume
gesetzt wurde, wird dieser Treblelevel bei jeder Änderung am Player mit aktualisiert.
Wenn zusätzlich noch das AttributgenerateVolumeEvent
gesetzt ist, erzeugt jede Änderung des Treblelevels auch ein FHEM-Event. Standardmäßig ist dies aus Zeitgründen deaktiviert, da FHEM-Events an jeden(!) notify innerhalb FHEM gemeldet werden. Dies kann u.U. zu Verzögerungen bei dem ZonePlayer führen.Volume
: Enthält im Normalfall die am Player eingestellte Laustärke zum Zeitpunkt der Erkennung. Wenn eines der beiden AttributeminVolume
odermaxVolume
gesetzt wurde, wird diese Lautstärke bei jeder Änderung am Player mit aktualisiert.
Wenn zusätzlich noch das AttributgenerateVolumeEvent
gesetzt ist, erzeugt jede Änderung der Lautstärke auch ein FHEM-Event. Standardmäßig ist dies aus Zeitgründen deaktiviert, da FHEM-Events an jeden(!) notify innerhalb FHEM gemeldet werden. Dies kann u.U. zu Verzögerungen bei dem ZonePlayer führen.
- Infos zum aktuellen Titel
currentTitle
: Titelbezeichnung des aktuellen TitelscurrentArtist
: Interpret des aktuellen TitelscurrentAlbum
: Albumname des aktuellen TitelcurrentAlbumArtist
: Interpret des Albums. Kann z.B. auch "(compilations)" sein.currentEnqueuedTransportHandle
: Handle, welches zur Weitergabe der aktuellen Quelle des aktuellen Titels verwendet werden kann.currentEnqueuedTransportURI
: Enthält den Identifier der Quelle des aktuellen Titels. Z.B. die ID der Spotify-PlaylistecurrentFavouriteName
: Enthält den Namen des Quellfavoriten, der den aktuellen Titel zur Liste hinzugefügt hat. Dazu müssen die Favoriten mittels "get FavouritesWithCover" ermittelt worden sein, und die Liste im Reading "Favourites" zur Verfügung stehen.currentPlaylistName
: Enthält den Namen der Quellplaylist, die den aktuellen Titel zur Liste hinzugefügt hat. Dazu müssen die Playlisten mittels "get PlaylistsWithCover" ermittelt worden sein, und die Liste im Reading "Playlists" zur Verfügung stehen.currentRadioName
: Enthält den Namen des Quellradios, der den aktuellen Titel zur Liste hinzugefügt hat. Dazu müssen die Radios mittels "get RadiosWithCover" ermittelt worden sein, und die Liste im Reading "Radios" zur Verfügung stehen.currentOriginalTrackNumber
: Nummer des aktuellen Titels bezogen auf das AlbumcurrentSource
: Enthält die aktuelle Quelle zum aktuellen Titel. Bei Spotify z.B. die gewählte Playliste oder das Album, oder die gewählte Sonos-Playliste.currentTrack
: Nummer des aktuellen Titels in der AbspiellistecurrentTrackHandle
: Handle des aktuellen Titels, welches zur Weitergabe geeignet ist.currentTrackURI
: Dateipfad des aktuellen Titels in der Abspielliste. Gültige Formate siehe PlayURI.currentTrackDuration
: Länge des aktuellen Titels im Format H:MM:SScurrentTrackDurationSec
: Länge des aktuellen Titels in Sekunden.currentTrackPosition
: Position innerhalb des aktuellen Titels im Format H:MM:SS. Wird zum Zeitpunkt einer Änderung des Abspielstatus (Play, Pause, Stop, Nächster Titel, usw.) aktualisiert.currentTrackPositionSimulated
: Simulierte und laufend aktualisierte Abspielposition des Titels im Format H:MM:SS.currentTrackPositionSimulatedSec
: Simulierte und laufend aktualisierte Abspielposition des Titels in Sekunden.currentTrackPositionSimulatedPercent
: Simulierte und laufend aktualisierte Abspielposition des Titels in Prozent.currentTrackProvider
: 'Quelle' der aktuellen Wiedergabe. Enthält z.B. Spotify oder BibliothekcurrentTrackProviderIconQuadraticURL
: Enthält eine URL zu einem quadratischen TrackProvider-Icon.currentTrackProviderIconRoundURL
: Enthält eine URL zu einem runden TrackProvider-Icon.currentSender
: Senderbezeichnung, wenn es ein Radiostream istcurrentSenderCurrent
: Zusatzinformationen zur Radiosendung, meist der Programmtitel wie 'Pop&Weck'currentSenderInfo
: Zusatzinformationen zur Radiosendung, meist der Titel des aktuellen LiedescurrentAlbumArtURI
: Relativer Verzeichnis-Pfad im lokalen FHEM (physisch). Beginnt momentan mit "www"currentAlbumArtURL
: Kompletter Pfad für den eigenen Download der Coverdatei des aktuellen Titels oder für die Angabe in einer HTML-IMG-Source.
- Infos zum nächsten Titel
nextTitle
: Titelbezeichnung des nächsten TitelsnextArtist
: Interpret des nächsten TitelsnextAlbum
: Albumname des nächsten TitelnextAlbumArtist
: Interpret des Albums des nächsten Titels. Kann z.B. auch "(compilations)" sein.nextOriginalTrackNumber
: Nummer des nächsten Titels bezogen auf das AlbumnextAlbumArtURI
: Relativer Verzeichnis-Pfad im lokalen FHEM (physisch). Beginnt momentan mit "www"nextAlbumArtURL
: Kompletter Pfad für den eigenen Download der Coverdatei des nächsten Titels oder für die Angabe in einer HTML-IMG-Source.nextTrackHandle
: Handle des nächsten Titels, welches zur Weitergabe geeignet ist.nextTrackURI
: Dateipfad des nächsten Titels in der Abspielliste. Gültige Formate siehe PlayURI.nextTrackDuration
: Länge des nächsten Titels im Format H:MM:SSnextTrackDurationSec
: Länge des nächsten Titels in Sekunden.nextTrackProvider
: 'Quelle' der nächsten Wiedergabe. Enthält z.B. Spotify oder BibliotheknextTrackProviderIconQuadraticURL
: Enthält eine URL zu einem quadratischen TrackProvider-Icon.nextTrackProviderIconRoundURL
: Enthält eine URL zu einem runden TrackProvider-Icon.
- Generierte Informationen
infoSummarize1
: Frei zusammenstellbare Informationszeile. Zum Format siehe [InfoSummarize]infoSummarize2
: Frei zusammenstellbare Informationszeile. Zum Format siehe [InfoSummarize]infoSummarize3
: Frei zusammenstellbare Informationszeile. Zum Format siehe [InfoSummarize]infoSummarize4
: Frei zusammenstellbare Informationszeile. Zum Format siehe [InfoSummarize]currentStreamAudio
: Boolean. 1 wenn gerade ein Radiostream läuft, sonst 0. Momentan faktisch Negation zu <currentNormalAudio>currentNormalAudio
: Boolean. 1 wenn gerade ein normaler Titel läuft, sonst 0. Momentan faktisch Negation zu <currentStreamAudio>
Attribute von SONOSPLAYER
Hinweis
Die Attribute werden meistens erst bei einem Neustart von FHEM verwendet, da diese dem SubProzess initial zur Verfügung gestellt werden müssen.
- Grundsätzliches
disable(0,1)
: Deaktiviert die Verarbeitung von Events dieses DevicesgenerateSomethingChangedEvent(0,1)
: Bestimmt, ob ein Event mit dem Namen 'SomethingChanged' generiert werden soll, wenn überhaupt ein Event generiert wurde. Das ist nützlich, wenn man auf eine beliebige Änderung des Player reagieren möchte.generateVolumeEvent(0,1)
: Aktiviert die Generierung eines Events bei Lautstärkeänderungen, wenn mindestens eines der AttributeminVolume
,maxVolume
,minVolumeHeadphone
odermaxVolumeHeadphone
definiert ist. Standardmäßig ist dies deaktiviert (=0), um die Zeitverzögerung so gering wie möglich zu halten.generateVolumeSlider(0,1)
: Aktiviert einen Slider für die Lautstärkeneinstellung auf der Detailansicht. Standardmäßig ist dieser aktiviert (=1).getAlarms(0,1)
: Meldet sich bei Playern für die Aktualisierung von Alarm-Informationen an. Diese werden bei Änderung direkt aktualisiert, und erzeugen dementsprechend ein FHEM-Event. Gleichzeitig wird hiermit die DailyIndexRefreshTime mit aktualisiert.suppressControlButtons(0,1)
: Gibt an, ob die Steuerbuttons unter der Cover-/Titelanzeige angezeigt werden sollen (=1) oder nicht (=0).VolumeStep
: Definiert die Schrittweite für den Aufruf vonVolumeU
undVolumeD
.
- Informationen generieren
generateInfoSummarize1
: Generiert das Reading 'InfoSummarize1' mit dem angegebenen Format.generateInfoSummarize2
: Generiert das Reading 'InfoSummarize2' mit dem angegebenen Format.generateInfoSummarize3
: Generiert das Reading 'InfoSummarize3' mit dem angegebenen Format.generateInfoSummarize4
: Generiert das Reading 'InfoSummarize4' mit dem angegebenen Format.getTitleInfoFromMaster(0,1)
: Bringt das Device dazu, seine aktuellen Abspielinformationen vom aktuellen Gruppenmaster zu holen, wenn es einen solchen gibt.simulateCurrentTrackPosition(0,1)
: Bringt das Device dazu, seine aktuelle Abspielposition simuliert weiterlaufen zu lassen. Dazu werden die ReadingscurrentTrackPositionSimulated
undcurrentTrackPositionSimulatedSec
gesetzt. Gleichzeitig wird auch das ReadingcurrentTrackPositionSimulatedPercent
(zwischen 0.0 und 100.0) gesetzt.simulateCurrentTrackPositionPercentFormat <Format>
: Definiert das Format für die sprintf-Prozentausgabe im ReadingcurrentTrackPositionSimulatedPercent
.stateVariable(TransportState,NumberOfTracks,Track,TrackDuration,Title,Artist,Album,
OriginalTrackNumber,AlbumArtist,Sender,SenderCurrent,SenderInfo,StreamAudio,NormalAudio,
: Legt fest, welcher Variablenwert in den State geschrieben werden soll.
AlbumArtURI,nextTrackDuration,nextTrackURI,nextAlbumArtURI,nextTitle,nextArtist,
nextAlbum,nextAlbumArtist,nextOriginalTrackNumber,Volume,Mute,Shuffle,Repeat,RepeatOne,CrossfadeMode,
Balance,HeadphoneConnected,SleepTimer,Presence,RoomName,RoomNameAlias,SaveRoomName,PlayerType,Location,
SoftwareRevision,SerialNum,InfoSummarize1,InfoSummarize2,InfoSummarize3,InfoSummarize4)
- Steueroptionen
maxVolume(0..100)
: Legt die obere Grenze für die einstellbare Lautstärke dieses ZonePlayers fest. Diese kann auch mit keinem Controller überschritten werden, da diese überwacht wird.- Wenn eine untere oder obere Grenze festgelegt wurde, so wird das Reading Volume am entsprechenden SonosPlayer bei jeder Änderung am Player aktualisiert.
Möchte man also immer die aktuelle Lautstärke kennen, aber keine Enschränkung machen, dann sollte der Wert vonminVolume
auf0
odermaxVolume
auf100
gesetzt werden. Desweiteren werden gleichzeitig auch Änderungen an der Balance aktualisiert, da diese mit übertragen werden. - Achtung!: Wenn eine untere oder obere Grenze festgelegt wird, werden für Lautstärkenänderungen auch Events erzeugt. Es ist unbedingt darauf zu achten, dass etwaige Notify-Definitionen zügig bearbeitet werden, da sonst das Sonos-System träge werden könnte.
- Hinweis: Dieses Attribut kann auch im laufenden Betrieb angepasst werden. Die Einhaltung der Grenzen wird umgehend sichergestellt.
Bedingung ist nur, dass zum Startzeitpunkt des SubProzesses eine Grenze festgelegt sein musste, damit die entsprechenden Listener angemeldet werden.
- Wenn eine untere oder obere Grenze festgelegt wurde, so wird das Reading Volume am entsprechenden SonosPlayer bei jeder Änderung am Player aktualisiert.
minVolume(0..100)
: Legt die untere Grenze für die einstellbare Lautstärke dieses ZonePlayers fest. Diese kann auch mit keinem Controller unterschritten werden, da diese überwacht wird.- Wenn eine untere oder obere Grenze festgelegt wurde, so wird das Reading Volume am entsprechenden SonosPlayer bei jeder Änderung am Player aktualisiert.
Möchte man also immer die aktuelle Lautstärke kennen, aber keine Enschränkung machen, dann sollte der Wert vonminVolume
auf0
odermaxVolume
auf100
gesetzt werden. Desweiteren werden gleichzeitig auch Änderungen an der Balance aktualisiert, da diese mit übertragen werden. - Achtung!: Wenn eine untere oder obere Grenze festgelegt wird, werden für Lautstärkenänderungen auch Events erzeugt. Es ist unbedingt darauf zu achten, dass etwaige Notify-Definitionen zügig bearbeitet werden, da sonst das Sonos-System träge werden könnte.
- Hinweis: Dieses Attribut kann auch im laufenden Betrieb angepasst werden. Die Einhaltung der Grenzen wird umgehend sichergestellt.
Bedingung ist nur, dass zum Startzeitpunkt des SubProzesses eine Grenze festgelegt sein musste, damit die entsprechenden Listener angemeldet werden.
- Wenn eine untere oder obere Grenze festgelegt wurde, so wird das Reading Volume am entsprechenden SonosPlayer bei jeder Änderung am Player aktualisiert.
maxVolumeHeadphone(0..100)
: Legt die obere Grenze für die einstellbare Lautstärke dieses ZonePlayers im Kopfhörerbetrieb fest.- Hinweis!: Es gelten die gleichen Bedingungen und Hinweise wie bei
maxVolume
.
- Hinweis!: Es gelten die gleichen Bedingungen und Hinweise wie bei
minVolumeHeadphone(0..100)
: Legt die untere Grenze für die einstellbare Lautstärke dieses ZonePlayers im Kopfhörerbetrieb fest.- Hinweis!: Es gelten die gleichen Bedingungen und Hinweise wie bei
minVolume
.
- Hinweis!: Es gelten die gleichen Bedingungen und Hinweise wie bei
buttonEvents <Time:Pattern>[ <Time:Pattern> ...]
: Definiert, dass bei einer bestimten Tastenfolge am Player ein Event erzeugt werden soll. Die Definition der Events erfolgt als Tupel: Der erste Teil vor dem Doppelpunkt ist die Zeit in Sekunden, die berücksichtigt werden soll, der zweite Teil hinter dem Doppelpunkt definiert die Abfolge der Buttons, die für dieses Event notwendig sind.- Folgende Button-Kürzel sind zulässig:
- M: Der Mute-Button (Achtung: Der Mute-Button am SonosPlayer ist seit Firmware 4.2 ein Play/Pause/Next-Button, der kein Mute-Event mehr erzeugt, meine Beschwerde an Sonos, dass es nicht benutzerfreundlich ist, einen Mute-Symbolisierten Button mit Play/Pause zu belegen, wurde im großen und ganzen ignoriert)
- H: Die Headphone-Buchse
- U: Up-Button (Lautstärke Hoch)
- D: Down-Button (Lautstärke Runter)
- Das Event, das geworfen wird, heißt
ButtonEvent
, der Wert ist die definierte Tastenfolge
Z.B.:2:MM
Hier wird definiert, dass ein Event erzeugt werden soll, wenn innerhalb von 2 Sekunden zweimal die Mute-Taste gedrückt wurde. Das damit erzeugte Event hat dann den NamenButtonEvent
, und den WertMM
.
- Folgende Button-Kürzel sind zulässig:
saveSleeptimerInAction(0,1)
: Wenn gesetzt, wird ein etwaig gesetztes Attribut "stopSleeptimerInAction" ignoriert.stopSleeptimerInAction(0,1)
: Wenn gesetzt, wird bei einem Wechsel des transportState auf "PAUSED_PLAYBACK" oder "STOPPED" ein etwaig definierter SleepTimer deaktiviert.
Get-Befehle an den SONOSPLAYER
Hinweis!: Es wurden ein paar Get-Möglichkeiten entfernt. Diese Befehle (wie z.B. Volume) können mittlerweile direkt geliefert werden, und müssen nicht angefordert werden. Übrig geblieben sind nur noch solche Anweisungen, die Informationen beschaffen, die nicht automatisch geliefert werden (können).
- Grundsätzliches
Alarm <ID>
: Ausnahmefall. Diese Get-Anweisung liefert direkt ein Hash zurück, in welchem die Informationen des Alarms mit der gegebenen ID enthalten sind. Es ist die Kurzform füreval(ReadingsVal(<Devicename>, 'Alarmlist', ()))->{<ID>};
, damit sich nicht jeder ausdenken muss, wie er jetzt am einfachsten an die Alarm-Informationen rankommen kann.EthernetPortStatus <PortNumber>
: Liefert den Ethernet-Portstatus des gegebenen Ports ('0' oder '1'). Kann 'Active' oder 'Inactive' liefern.PossibleRoomIcons
: Liefert eine Liste aller möglichen RoomIcon-Bezeichnungen zurück.SupportLinks
: Ausnahmefall. Diese Get-Anweisung liefert eine Liste mit passenden Links zu den Supportseiten des Player.WifiPortStatus
: Liefert den Wifi-Portstatus. Kann 'Active' oder 'Inactive' liefern.
- Listen
Favourites
: Liefert eine Liste mit den Namen aller gespeicherten Sonos-Favoriten. Das Format der Liste ist eine Komma-Separierte Liste, bei der die Namen in doppelten Anführungsstrichen stehen. z.B. "Liste 1","Eintrag 2","Test"FavouritesWithCovers
: Liefert die Stringrepräsentation eines Hash mit den Namen und Covern aller gespeicherten Sonos-Favoriten. Z.B.: {'FV:2/22' => {'Cover' => 'urlzumcover', 'Title' => '1. Favorit'}}. Dieser String kann einfach mit eval in eine Perl-Datenstruktur umgewandelt werden.Playlists
: Liefert eine Liste aller gespeicherten Playlists. Diese Anfrage liefert bei allen Zoneplayern die gleiche Liste zurück. Das Format ist eine Komma-Separierte Liste, bei der die Einträge in doppelten Anführungszeichen stehen z.B. "Liste 1","Liste 2","Test"PlaylistsWithCovers
: Liefert die Stringrepräsentation eines Hash mit den Namen und Covern aller gespeicherten Sonos-Playlisten. Z.B.: {'SQ:14' => {'Cover' => 'urlzumcover', 'Title' => '1. Playlist'}}. Dieser String kann einfach mit eval in eine Perl-Datenstruktur umgewandelt werden.Queue
: Liefert eine Liste mit den Namen aller Titel in der aktuellen Abspielliste. Das Format der Liste ist eine Komma-Separierte Liste, bei der die Namen in doppelten Anführungsstrichen stehen. z.B. "1. Liste 1 [0:02:14]","2. Eintrag 2 [k.A.]","3. Test [0:14:00]"QueueWithCovers
: Liefert die Stringrepräsentation eines Hash mit den Namen und Covern aller Titel der aktuellen Abspielliste. Z.B.: {'Q:0/22' => {'Cover' => 'urlzumcover', 'Title' => '1. Titel'}}. Dieser String kann einfach mit eval in eine Perl-Datenstruktur umgewandelt werden.Radios
: Liefert eine Liste aller gespeicherten Radiosender (Favoriten). Diese Anfrage liefert bei allen Zoneplayern die gleiche Liste zurück. Das Format ist eine Komma-Separierte Liste, bei der die Einträge in doppelten Anführungszeichen stehen z.B. "Sender 1","Sender 2","Test"RadiosWithCovers
: Liefert die Stringrepräsentation eines Hash mit den Namen und Covern aller gespeicherten Sonos-Radiofavoriten. Z.B.: {'R:0/0/2' => {'Cover' => 'urlzumcover', 'Title' => '1. Radiosender'}}. Dieser String kann einfach mit eval in eine Perl-Datenstruktur umgewandelt werden.SearchlistCategories
: Liefert eine Liste mit allen verfügbaren Kategorien, die beim Set-Befehl LoadSearchlist verwendet werden können. Diese Liste kann dynamisch durch Sonos erweitert werden.
- Informationen zum aktuellen Titel
CurrentTrackPosition
: Liefert die aktuelle Zeitposition im Lied
Set-Befehle an den SONOSPLAYER
Hinweis!: Alle Set-Befehle liefern kein direktes Ergebnis zurück. Sollte ein Ergebnis generiert werden (meistens eine Statusmeldung, bzw. was genau getan wurde), so landet dies nach der Ausführung in dem Reading LastActionResult
.
- Grundsätzliche Einstellungen
Alarm <Create|Update|Delete|Enable|Disable> <ID[,ID]|All> <Datenhash>
: Diese Anweisung wird für die Bearbeitung der Alarme verwendet:- Create: Erzeugt einen neuen Alarm-Eintrag mit den übergebenen Hash-Daten. Der Rückgabewert ist die ID des neuen Alarms.
- Update: Aktualisiert die Alarme mit den übergebenen IDs und den angegebenen Hash-Daten.
- Delete: Löscht die Alarm-Einträge mit den übergebenen IDs.
- Enable: Aktiviert die Alarm-Einträge mit den übergebenen IDs.
- Disable: Deaktiviert die Alarm-Einträge mit den übergebenen IDs.
- Hinweis: Bei Angabe des Worts All als ID werden alle, diesem Player zugeordneten, Alarme verarbeitet.
- Datenhash: Das Format ist ein Perl-Hash und wird mittels der eval-Funktion interpretiert. Eine Beschreibung befindet sich bei der Dokumentation des Readings AlarmList oder den folgenden Beispielen.
- Beispiele:
set Sonos_Wohnzimmer Alarm Create 0 { Enabled => 1, Volume => 35, StartTime => '00:00:00', Duration => '00:15:00', Repeat => 0, Shuffle => 0, ProgramURI => 'x-rincon-buzzer:0', ProgramMetaData => ' ', Recurrence_Once => 0, Recurrence_Monday => 1, Recurrence_Tuesday => 1, Recurrence_Wednesday => 1, Recurrence_Thursday => 1, Recurrence_Friday => 1, Recurrence_Saturday => 0, Recurrence_Sunday => 0, IncludeLinkedZones => 0 }
: Erzeugt einen neuen Alarm mit den angegebenen Informationen. Die neue ID wird als Ergebnis zurückgegeben.set Sonos_Wohnzimmer Alarm Update 17 { Shuffle => 1 }
: Aktualisiert den Alarm mit der ID 17, und passt dort Shuffle auf Aktiv an.set Sonos_Wohnzimmer Alarm Delete 17
: Löscht den Alarm mit der ID 17.
AudioDelay <Level>
: Setzt das AudioDelay der Playbar auf den angegebenen Wert. Der Wert kann zwischen 0 und 5 liegen.AudioDelayLeftRear <Level>
: Setzt den AudioDelayLeftRear des Players auf den angegebenen Wert. Der Wert kann zwischen 0 und 2 liegen. Wobei die Werte folgende Bedeutung haben: 0: >3m, 1: >0.6m und <3m, 2: <0.6mAudioDelayRightRear <Level>
: Setzt den AudioDelayRightRear des Players auf den angegebenen Wert. Der Wert kann zwischen 0 und 2 liegen. Wobei die Werte folgende Bedeutung haben: 0: >3m, 1: >0.6m und <3m, 2: <0.6mButtonLockState(0,1)
: Setzt den aktuellen Button-Sperr-Zustand.DailyIndexRefreshTime <Timestring>
: Legt die aktuell gültige DailyIndexRefreshTime fest, zu der der Medienindex neu aufgebaut werden soll. Der Wert muss ein kompletter Zeitstempel sein (HH:MM:SS).DialogLevel <Level>
: Legt den Zustand der Sprachverbesserung an der Playbar fest.ExportSonosBibliothek <Filename>
: Exportiert eine Datei mit der textuellen Darstellung eines Struktur- und Titelhashs, das die komplette Navigationsstruktur aus der Sonos-Bibliothek abbildet. Dieser Prozess braucht viel CPU-Zeit und Arbeitsspeicher zum Ermitteln und wegspeichern der Daten.- Hinweis: Richtwerte bei ca. 22.000 Titeln auf einem Windows-Server mit Intel Core i5 mit 2.8GHz: Laufzeit: ca. 28Min, Arbeitsspeicher: ca. 1GB, Resultierende Datei: ca. 90MB
Name
: Legt den Namen der Zone fest.NightMode <State>
: Legt den Zustand des Nachtsounds an der Playbar fest.OutputFixed <State>
: Setzt den OutputFixed-Zustand (die Lautstärkepegelsteuerung des Ausgangs des Players) auf den angegebenen Wert. Der Wert kann on oder off sein. Liefert als Ergebnis den neuen Zustand.Reboot
: Führt für den Zoneplayer einen Neustart durch.ResetAttributesToDefault <DeleteAllOtherAttributes>
: Setzt die Attribute eines Players auf die Voreinstellung zurück, wie sie beim Anlegen des Players gesetzt waren. Wenn der Parameter "DeleteAllOtherAttributes" mit "1" oder "on" angegeben wurde, werden vor dem Setzen alle Attribute gelöscht.RoomIcon
: Legt das Icon für die Zone fest.SnoozeAlarm <Timestring|Seconds>
: Unterbricht eine laufende Alarmwiedergabe für den übergebenen Zeitraum.SubEnable <State>
: Legt den Zustand des Sub-Zustands fest.SubGain <Level>
: Setzt den SubGain auf den angegebenen Wert. Der Wert kann zwischen -15 und 15 liegen.SubPolarity <Level>
Setzt den SubPolarity auf den angegebenen Wert. Der Wert kann zwischen 0 und 2 liegen.SurroundEnable <State>
: Legt den Zustand des Surround-Zustands fest. Liefert den aktuell gültigen Surround-Zustand.SurroundLevel <Level>
: Setzt den Surroundlevel auf den angegebenen Wert. Der Wert kann zwischen -15 und 15 sein.TruePlay <State>
: Setzt den TruePlay-Zustand.Wifi <State>
: Setzt den WiFi-Zustand des Players. Kann 'off', 'persist-off' oder 'on' sein.
- Abspiel-Steuerbefehle
CurrentTrackPosition <TimePosition>
: Setzt die aktuelle Zeitposition im Lied. Man kann hier auch relative Angaben machen wie '+0:00:10' oder nur '+10'. Zusätzlich kann man auch Prozentwerte angeben wie z.B. '+10%'. Natürlich können diese Angaben auch negativ sein.Pause
: Pausiert die WiedergabePrevious
: Springt zum Anfang des vorhergehenden Liedes. Das ist ein anderes Verhalten als mit einem Controller. Der Controller springt zunächst an den Anfang des aktuellen Liedes, und erst beim erneuten Drücken an den Anfang des vorhergehenden Liedes.Play
: Startet die WiedergabePlayT
: Startet die Wiedergabe, wenn gerade nichts abgespielt wird und pausiert sonst.PlayURI <SongURI> [Volume]
: Spielt die angegebene MP3-Datei mit der optional verwendbaren Lautstärke ab. Die Datei muss vom SonosPlayer aus direkt erreichbar (und natürlich auch lesbar) sein, braucht aber nicht indiziert worden zu sein.
Folgende Formate werden momentan akzeptiert:- Sonos-Devicenamen: z.B.
Sonos_Wohnzimmer
. Der Devicename muss natürlich bereits definiert worden sein. Es wird der Audio(oder AV)-Eingang des gewählten Zoneplayer-Device als Wiedergabestrom gewählt.- Bei normalen Audio-Eingängen (LineIn) kann man einen beliebigen Player für die Wiedergabe verwenden. Es muss nicht der lokale Player für die Wiedergabe verwendet werden.
- Besonderheit bei Sonos Playbar-Komponenten:
Wenn als Quelle eine Playbar ausgewählt wird, so wird erst die Playbar selbst auf den SPDIF-Eingang umgestellt, und anschließend eine Gruppe mit dem gewünschten Player gebildet.
Wenn diese Anweisung an die Playbar selbst gegeben wird, dann wird nur der SPDIF-Eingang als Quelle aktiviert.
- UNC-Pfade: z.B.
\\Server\Freigabe\Dateiname.mp3
. Erkennungsmerkmal ist der Doppelte Backslash am Anfang. Darstellung aller üblichen Informationen inkl. Cover u.ä. - Web-Streams: z.B.
http://www.energyradio.de/hot
. Erkennungsmerkmal ist die Angabe vonhttp://
am Anfang. Es werden keine Cover aber Streaminformationen dargestellt. - Sonstige URI-Typen: z.B.
x-sonos-spotify:spotify:track:0jkLC0noG4A4i9lob2gSc3?sid=9&flags=0
. Darstellung aller üblichen Informationen. Die verfügbaren Formate können durch Sonos erweitert/verändert werden.
Hinweis: Das Format der URI, das hier angegeben werden kann, ist stets identisch zum Reading currentTrackURI, das bedeutet, dass die URI, die man dort sieht, hier direkt wieder angegeben werden kann.
Es gibt lediglich die oben benannte Vereinfachung für MP3-Dateien und Radio-URLs (aber auch dafür könnte man das offizielle Format angeben).
- Sonos-Devicenamen: z.B.
PlayURITemp <SongURI> [Volume]
: Spielt die angegebene MP3-Datei mit der optional verwendbaren Lautstärke als temporäre Datei ab. Nachdem die Datei abgespielt wurde, werden die vorhergehenden Abspielparameter (Lautstärke, Titel, Position usw.) wiederhergestellt. Im Normalfall geht es also direkt dort weiter, wo die Unterbrechung stattgefunden hat. Die Datei muss vom SonosPlayer aus direkt erreichbar (und natürlich auch lesbar) sein, braucht aber nicht indiziert worden zu sein. Für eine ordnungsgemäße Wiederherstellung ist es notwendig, dass dies eine Datei und kein Stream ist, da die Abspiellänge vorher bekannt sein muss.- Für Streams (genauer: Für Dateien, deren Abspiellänge nicht ermittelt werden kann) ist dieser Aufruf identisch zu
PlayURI
, es wird im Anschluß nichts wiederhergestellt. - Zulässige Formate stehen unter
PlayURI
. - Achtung!: Wenn bereits eine temporäre Ausgabe erfolgt, so wird die Aufforderung mit einer entsprechenden Meldung verworfen. Es kann nur eine geben :-)
- Für Streams (genauer: Für Dateien, deren Abspiellänge nicht ermittelt werden kann) ist dieser Aufruf identisch zu
Next
: Springt zum Anfang des nächsten LiedesSpeak <Volume> <Language> <Text>
: Wandelt den angegebenen Text mittels Google in gesprochenen Text um und spielt diesen mittelsPlayURITemp
ab. An dieser Stelle ist zu berücksichtigen, dass der Text-Parameter auch Leerzeichen enthalten darf (und damit nach FHEM-Regeln eigentlich mehrere Parameter sind). Deswegen steht die Lautstärke vorne als nicht optionaler Parameter.- Hinweis: Im Text können MP3-File-Verweise eingebettet werden. Diese müssen vorne und hinten mit einem | und einem Leerzeichen abgetrennt werden. Außerdem darf der Dateiname selbst kein Leerzeichen enthalten.
Beispieltexte:- |/path/to/Gong.mp3| Achtung! Achtung! Die Waschmaschine ist fertig.
- Die Datei kann auch |/path/to/Tada.mp3| mittendrin stehen.
- |/path/to/Gong.mp3| Es können auch |/path/to/Tada.mp3| mehrere Dateien eingebettet werden.
- Hinweis: Es kann ein Standardpfad für diese Jingle-Dateien angegeben werden, dann braucht man im Text nur den Dateinamen anzugeben. Das Attribut am Sonos-Device dafür lautet targetSpeakMP3FileDir. z.B.: /path/to. Des Weiteren kann die Endung .mp3 auch weggelassen werden.
Damit können die Texte z.B. so gekürzt werden:- |Gong| Achtung! Achtung! Die Waschmaschine ist fertig.
- Die Datei kann auch |Tada| mittendrin stehen.
- |Gong| Es können auch |Tada| mehrere Dateien eingebettet werden.
- Hinweis: Eine Website mit einigen Jingles und kurzen Tönen zur kostenfreien, privaten, Verwendung ist z.B. soundbible.com. Dort gibt es auch Gebell und ähnliches :-)
- Achtung!: Die Verkettung der diversen MP3-Dateien erfolgt durch einfaches hintereinanderschreiben. Bei verschiedenen Formaten (Mono oder Stereo, 16kHz oder 22kHz, usw.) funktioniert zwar die Wiedergabe auf dem Sonos-System fehlerfrei, allerdings werden die Zeitinformationen nicht korrekt dargestellt. Um das zu korrigieren, kann man noch nachträglich einen lokal installierten Konverter (z.B. avconv) drüberlaufen lassen. Diesen kann man mit dem Sonos-Device-Attribut targetSpeakMP3FileConverter einstellen (z.B. mit /usr/bin/avconv -i %infile% %outfile%). Dabei ist zu beachten, dass dieser Zeit benötigt und somit die Verzögerung der Durchsage vergrößert.
- Achtung!: Für die korrekte Funktionsweise müssen die Attribute
targetSpeakDir
undtargetSpeakURL
am Sonos-Device konfiguriert sein (siehe Attribute von SONOS). - Mögliche Sprachparamter können bei Google herausgefunden werden. Diese sind z.B. de, en, es, fr, it...
- Achtung!: Die Textlänge ist durch Google begrenzt. Wenn die Größe überschritten wird, wird die Tonerzeugung in mehrere Aufrufe unterteilt. Davon merkt man im Prinzip wenig, ausser dass die Wiedergabeverzögerung höher ist, und die Sprachmelodie an der Trennstelle etwas "holprig" wirkt.
- Achtung!: Wenn bereits eine temporäre Ausgabe erfolgt, so wird die Aufforderung mit einer entsprechenden Meldung verworfen. Es kann nur eine geben :-)
- Hinweis: Im Text können MP3-File-Verweise eingebettet werden. Diese müssen vorne und hinten mit einem | und einem Leerzeichen abgetrennt werden. Außerdem darf der Dateiname selbst kein Leerzeichen enthalten.
StartFavourite <FavouriteName> [NoStart]
: Startet den angegebenen Favoriten. Der Name bezeichnet einen Eintrag in der Sonos-Favoritenliste. Der Parameter sollte/kann URL-Encoded (z.B. mittels uri_escape() oder manuell) werden um auch Spezialzeichen zu ermöglichen.
Siehe auch die Hinweise unter LoadFavourite.- Wenn das Wort 'NoStart' als zweiter Parameter angegeben wurde, dann wird der Favorit geladen und fertig vorbereitet, aber nicht explizit gestartet (entspricht dann einem LoadFavourite).
StartPlaylist <Playlistname> [ListeVorherLeeren]
: Lädt die benannte Playlist und startet sofort die Wiedergabe.
Zu den Parametern und Bemerkungen bitte unter LoadPlaylist nachsehen.StartRadio <Radiostationname>
: Lädt den benannten Radiosender, genauer gesagt, den benannten Radiofavoriten und startet sofort die Wiedergabe. Dabei wird die bestehende Abspielliste beibehalten, aber deaktiviert. Der Parameter kann/muss URL-Encoded (z.B. mittels uri_escape() oder manuell) sein, um auch Leer- und Sonderzeichen angeben zu können.StartSearchlist <Kategoriename> <KategorieElement> [[TitelfilterRegEx]/[AlbumfilterRegEx]/[ArtistfilterRegEx] [maxElem]]
: Ruft den Befehl LoadSearchlist auf und startet anschließend die Wiedergabe. Zu den genauen Beschreibungen der Funktion und Parameter bitte den Set-Befehl LoadSearchlist nachschlagen.Stop
: Stoppt die WiedergabeTrack <TrackNumber>
: Stellt das Lied an der Position TrackNumber in der Abspielliste als aktuelles Lied ein. Dabei kann als Tracknummer der WertRandom
angegeben werden. Dann wird eine zufällige Tracknummer ausgewählt (diese Ermittlung erfolgt nach Setzen der aktuellen Abspielliste, und erfolgt somit korrekt auf die gesamte zur Verfügung stehende Liste).
- Einstellungen zum Abspielen
Balance
: Setzt die Balance auf den angegebenen Wert. Der Wert kann zwischen -100 (voll links) und 100 (voll rechts) liegen. Gibt die wirklich eingestellte Balance als Ergebnis zurück.Bass
: Setzt den Bass-Level auf den angegebenen Wert. Der Wert kann zwischen -10 und 10 liegen.CrossfadeMode
: Legt den Zustand des Crossfade-Mode fest. Liefert den aktuell gültigen Crossfade-Mode.LEDState
: Legt den Zustand der LED fest. Liefert den aktuell gültigen Zustand zurück.Loudness
: Aktiviert oder deaktiviert das Loudness (Bassanhebung bei geringen Lautstärken). Kann 0 oder 1 sein.Mute <State>
: Setzt den Mute-Zustand auf den angegebenen Wert. Der Wert kann on oder off sein. Liefert als Ergebnis den neuen Zustand.MuteT
: Schaltet den Mute-Zustand um. Liefert als Ergebnis den neuen Zustand.Repeat
: Legt den Zustand des Repeat-Zustands fest. Liefert den aktuell gültigen Repeat-Zustand.RepeatOne
: Legt den Zustand des RepeatOne-Zustands fest. Liefert den aktuell gültigen RepeatOne-Zustand.RepeatOneT
: Schaltet den Zustand des RepeatOne-Zustands um. Liefert den aktuell gültigen RepeatOne-Zustand.RepeatT
: Schaltet den Zustand des Repeat-Zustands um. Liefert den aktuell gültigen Repeat-Zustand.Shuffle
: Legt den Zustand des Shuffle-Zustands fest. Liefert den aktuell gültigen Shuffle-Zustand.ShuffleT
: Schaltet den Zustand des Shuffle-Zustands um. Liefert den aktuell gültigen Shuffle-Zustand.SleepTimer <Timestring|Seconds>
: Legt den aktuellen SleepTimer fest. Der Wert muss ein kompletter Zeitstempel sein (HH:MM:SS) (oder eine Zahl in Sekunden). Zum Deaktivieren darf der Zeitstempel nur Nullen enthalten oder das Wort 'off'.Treble
: Setzt den Höhen-Level auf den angegebenen Wert. Der Wert kann zwischen -10 und 10 liegen.Volume <VolumeLevel> [RampType]
: Setzt die Lautstärke auf den angegebenen Wert. Der kann eine relative Angabe mittels + oder - sein. Dann wird um die entsprechende Höhe erhöht oder verringert. Wird eine relative Lautstärke angegeben, so kann diese mit einem folgenden Prozentzeichen als anteilige Änderung ausgeführt werden (z.B. +20%). Liefert als Ergebnis die neue Lautstärke.
Als optionaler Parameter ist ein Ramptype zulässig. Mögliche Werte sind 1 (SLEEP_TIMER_RAMP_TYPE), 2 (AUTOPLAY_RAMP_TYPE) und 3 (ALARM_RAMP_TYPE). Die Werte entsprechen verschiedenen Mustern bei der Geschwindigkeit nach oben oder unten.VolumeD
: Verringert die Lautstärke um [VolumeStep]-Einheiten (Standardmäßig 7).VolumeRestore
: Stellt die mittels VolumeSave gespeicherte Lautstärke wieder her.VolumeSave <VolumeLevel>
: Setzt die Lautstärke auf den angegebenen Wert. Der kann eine relative Angabe mittels + oder - sein. Dann wird um die entsprechende Höhe erhöht oder verringert. Liefert als Ergebnis die neue Lautstärke. Zusätzlich wird die alte Lautstärke in einem Reading abgelegt, um sie wiederherstellen zu können.VolumeU
: Erhöht die Lautstärke um [VolumeStep]-Einheiten (Standardmäßig 7).
- Steuerung der aktuellen Abspielliste
AddURIToQueue <SongURI>
: Fügt die angegebene Datei in die aktuelle Abspielliste an die Stelle hinter dem aktuellen Titel hinzu. Ändert nichts am aktuell abgespielten Titel.
Zulässige Formate stehen unterPlayURI
.- Achtung!: Es kann auch ein Radio-Stream hinzugefügt werden. Dieser wird auch normal abgespielt, wenn er dran ist. Dabei ist zu beachten, dass dieser Titel nie enden wird, und die Titel- und Interpretinformationen nicht dargestellt werden. Auch nicht die sonst üblichen Streaminformationen. Diese werden nur angezeigt, wenn der Stream mittels
PlayURI
direkt (ohne Verwendung der Queue) abgespielt wird.
- Achtung!: Es kann auch ein Radio-Stream hinzugefügt werden. Dieser wird auch normal abgespielt, wenn er dran ist. Dabei ist zu beachten, dass dieser Titel nie enden wird, und die Titel- und Interpretinformationen nicht dargestellt werden. Auch nicht die sonst üblichen Streaminformationen. Diese werden nur angezeigt, wenn der Stream mittels
CurrentPlaylist
: Setzt den Abspielmodus auf die aktuelle Abspielliste, startet aber keine Wiedergabe (z.B. nach dem Hören eines Radiostreams, wo die aktuelle Abspielliste zwar noch existiert, aber gerade "nicht verwendet" wird)DeleteFromQueue <index_of_elems>
: Löscht die angegebenen Elemente aus der aktuellen Abspielliste. Die Angabe erfolgt über die Indizies der Titel. Es können die bei Perl-Array-üblichen Formate verwendet werden: "1..12,17,20..22". Die Indizies beziehen sich auf die aktuell angezeigte Reihenfolge (diese unterscheidet sich zwischen der normalen Abspielweise und dem Shufflemodus).DeletePlaylist
: Löscht die bezeichnete Playliste. Zum möglichen Format des Playlistenamen unter LoadPlaylist nachsehen.EmptyPlaylist
: Löscht die aktuelle AbspiellisteLoadFavourite <FavouriteName>
: Lädt den angegebenen Favoriten. Der Name bezeichnet einen Eintrag in der Sonos-Favoritenliste. Der Parameter sollte/kann URL-Encoded (z.B. mittels uri_escape() oder manuell) werden um auch Spezialzeichen zu ermöglichen.- Hinweis: Man kann anstatt des Namens auch einen regulären Ausdruck verwenden. Es dürfen keine Leerzeichen vorkommen. Der erste Treffer wird verwendet.
Beispiele:- /meine.hits/ - Trifft Case-Sensitive auf z.B. meine hits zu. Auch meineXhits oder meine-hits wird gefunden.
- /(?i)meine.hits/ - Trifft Case-Insensitive auf z.B. Meine Hits zu. Auch Meine-Hits wird gefunden.
- Folgende Unterscheidungen werden auf Basis des Typs des Sonos-Favoriten gemacht:
- Bei einem Playlist-Typ (z.B. Sonos-Playlist, Spotify-Playlist, usw.) wird die aktuelle Abspielliste geleert, mit dem neuen Inhalt befüllt und die Wiedergabe gestartet
- Bei einem Einzel-Eintrag (Direkter Titel, Radiosender, Spotify-Titel, usw) wird die aktuelle Abspielliste nicht angetastet, sondern der aktuelle Abspieleintrag entsprechend angepasst und gestartet
- Hinweis: Man kann anstatt des Namens auch einen regulären Ausdruck verwenden. Es dürfen keine Leerzeichen vorkommen. Der erste Treffer wird verwendet.
LoadPlaylist <Playlistname|FHEM-Devicename> [ListeVorherLeeren]
: Lädt die benannte Playliste in die aktuelle Abspielliste. Der Parameter kann/muss URL-Encoded (z.B. mittels uri_escape() oder manuell) sein, um auch Leer- und Sonderzeichen angeben zu können. Wenn der Parameter ListeVorherLeeren mit 1 angegeben wurde, wird die aktuelle Abspielliste vor dem Import geleert. Standardmäßig wird hier eine 1 angenommen.- Hinweis: Man kann anstatt des Namens auch einen FHEM-Sonosplayer-Devicenamen angeben. Dann wird dessen aktuelle Abspielliste zum Player übertragen/kopiert.
- Hinweis: Man kann anstatt des Namens auch einen regulären Ausdruck verwenden. Es dürfen keine Leerzeichen vorkommen. Der erste Treffer wird verwendet.
Beispiele:- /meine.hits/ - Trifft Case-Sensitive auf z.B. meine hits zu. Auch meineXhits oder meine-hits wird gefunden.
- /(?i)meine.hits/ - Trifft Case-Insensitive auf z.B. Meine Hits zu. Auch Meine-Hits wird gefunden.
- Hinweis: Es kann auch ein Dateiname angegeben werden, um eine übliche M3U-Datei aus dem Filesystem zu laden. Dieser muss mit "file:" eingeleitet werden. Beispiel: "file:c:/Test.m3u".
Innerhalb der Datei selbst werden bislang folgende Sonderformate unterstützt:- Spotify: Titel aus Spotify werden mit dem Kürzel x-sonos-spotify: begonnen.
- Napster/Rhapsody: Titel aus Napster/Rhapsody werden mit dem Kürzel npsdy: begonnen.
- Hinweise: Die Benutzernamen für diese Importe, die zum Zeitpunkt des Import bekannt sein müssen, müssen zuvor dem System bekannt gemacht werden. Ansonsten erscheint eine entsprechende Fehlermeldung.
So kann der Benutzername für eines der Systeme bekannt gemacht werden:- Aktuelle Abspielliste eines Players leeren
- Einen beliebigen Titel aus dem gewünschten Anbieter in die aktuelle Abspielliste einfügen. Dabei ist zu beachten, dass man das direkt aus der Auswahl des Anbietes heraus macht (also nicht über eine Playliste, Favoriten o.ä. Direktzugriffe)
- Nun gibt es ein neues Reading am zentralen Sonos-Device, welches den Benutzernamen enthält. Um diesen Dauerhaft bereitzustellen, muss der Zustand mittels save gespeichert werden.
LoadRadio <Radiostationname>
: Lädt den benannten Radiosender, genauer gesagt, den benannten Radiofavoriten. Dabei wird die bestehende Abspielliste beibehalten, aber deaktiviert. Der Parameter kann/muss URL-Encoded sein, um auch Leer- und Sonderzeichen angeben zu können.- Hinweis: Man kann anstatt des Namens auch einen regulären Ausdruck verwenden. Es dürfen keine Leerzeichen vorkommen. Der erste Treffer wird verwendet.
Beispiele:- /NRJ.90s/ - Trifft Case-Sensitive auf z.B. NRJ 90s zu. Auch NRJx90s oder NRJ-90s wird gefunden.
- /(?i)nrj.90s/ - Trifft Case-Insensitive auf z.B. NRJ 90s zu. Auch NRJ-90s wird gefunden.
- Hinweis: Man kann anstatt des Namens auch einen regulären Ausdruck verwenden. Es dürfen keine Leerzeichen vorkommen. Der erste Treffer wird verwendet.
LoadSearchlist <Kategoriename> <KategorieElement> [[TitelfilterRegEx]/[AlbumFilterRegEx]/[ArtistfilterRegEx] [[*]maxElem[+|-]]]
: Hiermit kann die aktuelle Abspielliste mit Suchergebnissen aus der Sonos-Bibliothek gefüllt werden.
Dazu kann man sich im Controller anschauen, wie die Suchstruktur aufgebaut ist:- Kategoriename: kann "Albums", "Artists", "Composers", "Contributing Artists", "Genres", "Playlists" oder "Tracks" sein. Leerzeichen müssen wie immer URI-Encoded sein (also %20). Diese Liste kann mit dem Get-Befehl SearchlistCategories ermittelt werden, da Sonos auch neue hinzufügen könnte.
Man kann hier einen regulären Ausdruck mit / eingeschlossen angeben, z.B. /Contr.*/. - KategorieElement: enthält einen zur Suchkategorie passenden Wert als gesamten Match. Kann/muss URI-Encoded (z.B. mittels uri_escape() oder manuell) sein.
Man kann hier auch einen regulären Ausdruck mit / eingeschlossen angeben, z.B. /(?i)udo.jürgens/. - Filter: Man kann reguläre Ausdrücke als Titel-, Album- oder Artistfilter angeben, der als ein Parameter mit / getrennt angegeben werden muss.
Dieser Filter filtert die durch die beiden vorangehenden Werten vorgegebene Liste getrennt nach Titel, Album oder Artist, z.B. (?i)haus (enthält dann alles, was auf Haus im Titel ohne Berücksichtigung der Groß-/Kleinschreibung passt) oder (?i)haus//(?i)udo (enhält dann alles, was auf den Titel Haus und den Interpret Udo ohne Berücksichtigung der Groß-/Kleinschreibung passt) sowie z.B. /(?i)Best.of/ (enthält dann alle Best-of-Alben beliebiger Interpreten).- Beispiele für den Filter-Parameter:
//Udo
: Filtert nach dem Interpretenbestandteil Udo, der Titel ist beliebig. Alternative Schreibweise:.*/.*/Udo
Sahne
: Filtert nach dem Titelbestandteil Sahne, das Album und der Interpret sind beliebig. Alternative Schreibweisen:Sahne/.*/.*
oderSahne//
.Sahne//Udo
: Filtert nach dem Titelbestandteil Sahne und dem Interpretenbestandteil Udo(?i)sahne//(?i)udo
: Filtert nach dem Titelbestandteil sahne und dem Interpretenbestandteil udo ohne die Groß-/Kleinschreibung zu berücksichtigen./(?i)best.of/
: Filtert nach dem Albumtitel Best-of. Alternative Schreibweisen:.*/(?i)best.of
oder.*/(?i)best.of/.*
- Beispiele für den Filter-Parameter:
- maxElem: Hiermit kann eine Begrenzung der einzutragenden Element angegeben werden. Des Weiteren kann hier durch ein vorangestelltes * eine Durchmischung der Ausgangsmenge erreicht werden, und durch ein nachgestelltes - das Leeren der aktuellen Abspielliste erreicht werden. Durch ein nachgestelltes + wird ein Anhängen der gefundenen Titel an das Ende der aktuellen Abspielliste erreicht (sonst wird hinter dem aktuellen Titel eingefügt).
Eine Angabe von 0 übernimmt alle verfügbaren Titel.
Diese Mengenbegrenzung erfolgt erst nach Anwendung der Filter auf die Ausgangsmenge (die Durchmischung ebenfalls). z.B. *20- (es werden nur 20 Titel ausgesucht, die Ausgangsmenge wird zuvor zufällig gemischt, und die aktuelle Abspielliste vor dem Einfügen geleert), *10 (es werden 10 zufällige Titel zu der Abspielliste an der aktuellen Stelle hinzugefügt) oder 10 (es werden die ersten 10 Titel zu der Abspielliste an der aktuellen Stelle hinzugefügt). - Hinweis: Wenn die Kategorie Tracks verwendet wird, wird der zweite Parameter (KategorieElement) nicht verwendet. Dieser muss als Platzhalter trotzdem vorhanden sein, und kann z.B. mit einem Punkt . angegeben werden.
- Achtung: Wenn die Kategorie Tracks verwendet wird, werden *alle* Titel, die in der Sonos-Bibliothek enthalten sind, durchsucht. Das kann bei einer Bibliothek mit 20.000 Titeln locker mal 4 Minuten dauern. Dabei wird die Zeit hauptsächlich vom Sonosplayer verbraucht; Es ist also für die Laufzeit nicht relevant, ob das Modul z.B. auf einem Raspberry Pi oder einer leistungsfähigeren Hardware läuft.
Bitte beachten, das während dieser Zeit keine Sonos-Nachrichten verarbeitet werden, und keine Befehle an die Player gesendet werden können. FHEM wird währenddessen nicht blockiert. - Beispiele
Bitte beachten, dass sich die Möglichkeiten nach der zugrundeliegenden Bibliothek richten.set Sonos_Wohnzimmer LoadSearchlist Genres Synthpop .*/(?i)pet *20-
: Hier wird das Genre Synthpop als Ausgangsliste verwendet und nach Interpreten mit pet gefiltert. Von dieser Menge werden 20 zufällige Einträge in die Abspielliste übernommen, die vorher geleert wurde.set Sonos_Wohnzimmer LoadSearchlist /(?i)contr.*/ /(?i)pet.*?shop.*?boys/ / *10-
: Hier werden die Teilnehmenden Interpreten nach den Pet Shop Boys durchsucht, und anschließend aus dieser Liste 10 beliebige Titel in die vorher geleerte Abspielliste übertragen. Es erfolgt keine zusätzliche Filterung.set Sonos_Wohnzimmer LoadSearchlist Tracks . / *50-
: Hier werden 50 beliebige Titel aus der gesamten Bibliothek in die Abspielliste übertragen. Bitte Hinweis zur Laufzeit beachten.set Sonos_Wohnzimmer LoadSearchlist Tracks . /(?i)best.of/ *50-
: Hier werden 50 zufällige Titel von Best-of-Alben aus der gesamten Bibliothek in die Abspielliste übertragen. Bitte Hinweis zur Laufzeit beachten.
- Kategoriename: kann "Albums", "Artists", "Composers", "Contributing Artists", "Genres", "Playlists" oder "Tracks" sein. Leerzeichen müssen wie immer URI-Encoded sein (also %20). Diese Liste kann mit dem Get-Befehl SearchlistCategories ermittelt werden, da Sonos auch neue hinzufügen könnte.
SavePlaylist <Playlistname>
: Speichert die aktuelle Abspielliste unter dem angegebenen Namen als Playliste ab. Dabei wird eine etwaig bestehende Liste gleichen Namens überschrieben. Der Parameter kann/muss URL-Encoded (z.B. mittels uri_escape() oder manuell) sein, um auch Leer- und Sonderzeichen angeben zu können.- Hinweis: Es kann auch ein Dateiname angegeben werden, um eine übliche M3U-Datei im Filesystem zu erzeugen. Dieser muss mit "file:" eingeleitet werden. Beispiel: "file:c:/Test.m3u".
Nähere Informationen zum möglichen Inhalt der Datei siehe unter LoadPlayList.
- Hinweis: Es kann auch ein Dateiname angegeben werden, um eine übliche M3U-Datei im Filesystem zu erzeugen. Dieser muss mit "file:" eingeleitet werden. Beispiel: "file:c:/Test.m3u".
- Gruppenbefehle
AddMember <Devicename>
: Fügt dem Device das übergebene Device als Gruppenmitglied hinzu. Die Wiedergabe des aktuellen Devices bleibt erhalten, und wird auf das angegebene Device mit übertragen.CreateStereoPair <rightPlayerDevicename>
: Fügt dem Device das übergebene Device als rechtes Stereopaar-Element hinzu. Die Wiedergabe des aktuellen Devices bleibt erhalten (als linker Lautsprecher), und wird auf das angegebene Device mit übertragen (als rechter Lautsprecher).GroupMute <State>
: Setzt den Mute-Zustand für die komplette Gruppe in einem Schritt. Der Wert kann on oder off sein.GroupVolume <VolumeLevel>
: Setzt die Gruppenlautstärke. Das dafür verwendete Lautstärkenverhältnis muss zuvor einmal mittels der Anweisung SnapshotGroupVolume festgelegt worden sein.- Hinweis: Wenn man GroupVolume aufruft, ohne vorher SnapshotGroupVolume aufgerufen zu haben, wird nur die Lautstärke des Players verändert wird, für den man den Aufruf durchführt.
MakeStandaloneGroup
: Macht diesen Player zu seiner eigenen Gruppe.RemoveMember <Devicename>
: Entfernt dem Device das übergebene Device, sodass die beiden keine Gruppe mehr bilden. Die Wiedergabe des aktuellen Devices läuft normal weiter. Das abgetrennte Device stoppt seine Wiedergabe, und hat keine aktuelle Abspielliste mehr (seit Sonos Version 4.2 hat der Player wieder die Playliste von vorher aktiv).SeparateStereoPair
: Trennt das Stereopaar wieder auf.SnapshotGroupVolume
: Legt das Lautstärkeverhältnis der aktuellen Player der Gruppe für folgende GroupVolume-Aufrufe fest. Dieses festgelegte Verhältnis wird bis zum nächsten Aufruf von SnapshotGroupVolume beibehalten.- Hinweis: Das einzelne Verstellen von Zoneplayer-Laustärken mittels Volume wird nicht im bereits gespeicherten Lautstärkenverhältnis aktualisiert/widergespiegelt. Hat man also nachträglich die Lautstärke eines einzelnen Players geändert (auch über den Controller), so muss SnapshotGroupVolume erneut aufgerufen werden, damit das Verhältnis bei einer weiteren Gruppenlautstärkenänderung wieder erhalten bleibt (ansonsten wird das alte Verhältnis vor der Lautstärkeänderung wiederhergestellt).
- Hinweis: Dieser Aufruf muss vor einem eventuellen Aufruf von GroupVolume erfolgen, da sonst nur die Lautstärke des Players verändert wird, für den man den Aufruf durchführt.
- Beispiel für eine Gruppe mit stark verschiedenen Lautstärken:
- Aufruf von SnapshotGroupVolume => Aktuelles Lautstärkeverhältnis wird gespeichert
- Aufruf von GroupVolume 2 => Gruppe wird sehr leise gestellt, dabei sieht das relative Lautstärkeverhältnis fast gleich aus, da sich die Abstände immer weiter annähern
- Aufruf von GroupVolume 35 => Gruppe wird laut gestellt, dabei kommt wieder das vorhergehende Lautstärkeverhältnis zum tragen
Nützliche Hilfs-Prozeduren aus den Modulen
Das Modul liefert eine Menge kleiner Hilfs-Prozeduren mit, die teilweise auch für die eigene Verwendung interessant sein können.
- Grundsätzliches
SONOS_getAllSonosplayerDevices()
: Liefert ein Array mit allen Sonosplayerdevices, die in FHEM definiert sind.
Beispiel:my @allPlayer = SONOS_getAllSonosplayerDevices();
Liefert alle Sonosplayer.
SONOSPLAYER_DeleteIfExists($name)
: Löscht das Device mit dem übergebenen Namen, wenn es existiert.
Beispiel:SONOSPLAYER_DeleteIfExists('Sonos_Wohnzimmer');
Löscht das Device mit dem Namen Sonos_Wohnzimmer, sofern es existiert. Es wird also keine Fehlermeldung erzeugt, wenn das Device nicht existiert.
SONOS_GetTimeSeconds($timeStr)
: Liefert die Anzahl der Sekunden, die vom übergebenen Zeitstring beschrieben werden. Der Zeitstring muss vom Format "H:M:S" sein. Die Zahlen könne auch mehrere Stellen umfassen.
Beispiel:my $sec = SONOS_GetTimeSeconds('0:04:12')
Liefert die Anzahl der Sekunden des String '0:04:12', in diesem Fall also 252.
SONOS_LoadExportedSonosBibliothek($fileName, $deviceName, $internalName)
: Lädt die angegebene Datei in das übergebene Device in das übergebene Internal. Vorher wird der Dateiinhalt per eval() in eine interne Datenstruktur umgewandelt. Damit kann eine zuvor mit ExportSonosBibliothek erzeugte Datei als Hash in ein beliebiges FHEM-Device eingelesen werden.
Beispiel:SONOS_LoadExportedSonosBibliothek('c:/data.txt', 'MyDummyDevice', 'Bibliothek');
Lädt die Datei c:/data.txt zunächst in einen Hash ein, und weist diesen Hash dann dem Device MyDummyDevice (kann ein beliebiges FHEM-Device sein) dem Internal Bibliothek zu.
SONOS_Max($param1, $param2)
: Liefert den größeren der beiden übergebenen Parameter zurück.
Beispiel:my $min = SONOS_Min(15, 23);
Das Ergebnis ist 23, da es der größere der beiden Werte ist.
SONOS_Min($param1, $param2)
: Liefert den kleineren der beiden übergebenen Parameter zurück.
Beispiel:my $min = SONOS_Min(15, 23);
Das Ergebnis ist 15, da es der kleinere der beiden Werte ist.
SONOS_isInList($search, @list)
: Liefert 1, wenn $search in @list enthalten ist, sonst 0.
Beispiel:my $exists = SONOS_isInList('Eins', qw(Eins Zwei Drei));
Das Ergebnis ist true (bzw. 1), da der String Eins in der Liste enthalten ist.
SONOS_posInList($search, @list)
: Liefert die Position des gefundenen Strings $search in der Liste @list, wenn $search in @list enthalten ist, sonst -1. Zählt 0-basiert.
Beispiele:my $pos = SONOS_posInList('Eins', qw(Eins Zwei Drei));
Das Ergebnis ist 0, da der String Eins in der Liste an der ersten Stelle enthalten ist.my $pos = SONOS_posInList('Eins', qw(Zwei Eins Drei));
Das Ergebnis ist 1, da der String Eins in der Liste an der zweiten Stelle enthalten ist.my $pos = SONOS_posInList('Vier', qw(Eins Zwei Drei));
Das Ergebnis ist -1, da der String Vier in der Liste nicht enthalten ist.
SONOS_Stringify($elem)
: Liefert eine Stringrepräsentation der übergebenen Datenstruktur. Diese Struktur darf nicht rekursiv sein, da sonst eine Endlosschleife auftritt.
Beispiel:my @list = qw(Eins Zwei Drei); my $string = SONOS_Stringify(\@list);
Liefert eine Stringrepräsentation des Arrayparameters. In diesem Fall also['Eins', 'Zwei', 'Drei']
- Gruppenfunktionen
SONOSPLAYER_GetMasterPlayerName($name)
: Liefert den Namen des Masterplayerdevices zu einem übergebenen Sonosplayer-Devicenamen. Sollte der Player nicht Bestandteil einer Gruppe sein, dann wird der Name des übergebenen Players zurückgegeben.
Beispiel:my $groupMasterName = SONOSPLAYER_GetMasterPlayerName('Sonos_Wohnzimmer');
Liefert den Masterplayernamen der Gruppe, in der sich der Wohnzimmerplayer gerade befindet.
SONOSPLAYER_GetSlavePlayerNames($name)
: Liefert die Teilnehmer einer Gruppe. Der Master wird nicht mit zurückgegeben. Man kann den Namen eines beliebigen Teilnehmers angeben.
Beispiel:my @member = SONOSPLAYER_GetSlavePlayerNames('Sonos_Wohnzimmer');
Liefert alle Teilnehmer der Gruppe in der sich der Player Sonos_Wohnzimmer gerade befindet. Der Master der Gruppe wird nicht mitgeliefert.
SONOSPLAYER_GetRealTargetPlayerHash($hash)
: Liefert den Hash des Masterplayerdevices zu einem übergebenen Sonosplayer-Devicehash. Sollte der Player nicht Bestandteil einer Gruppe sein, dann wird der Hash des übergebenen Players zurückgegeben.
Beispiel:my $groupMasterHash = SONOSPLAYER_GetRealTargetPlayerHash($defs{'Sonos_Wohnzimmer'});
Liefert den Masterplayerhash der Gruppe, in der sich der Wohnzimmerplayer gerade befindet.
Die Funktionalität "ExportSonosBibliothek"
Die Funktionalität ExportSonosBibliothek ermöglicht einen kompletten Export der Struktur und Titelinformationen wie sie in dem Bereich Bibliothek des Sonos-Controllers dargestellt wird. Dabei wird ein großer Perl-Hash erzeugt, der sowohl die Struktur als auch die eigentlichen Titel enthält. Im Bereich Struktur werden auf unterster (Titel-)Ebene die IDs der zugehörigen Titel als Verweis abgelegt, sodass man diese nicht mehrfach im Hash vorliegen hat. Im Bereich Titel werden alle irgendwo referenzierten Titel mit ihren IDs und allen von Sonos übermittelten Informationen abgelegt.
Das Ermitteln dauert einige Zeit. Als Beispiel: Mein WindowsServer mit Intel Core i5 mit 2.8GHz benötigt für meine ca. 22.000 Titel 28 Minuten und 1GB RAM zum Ermitteln. Die resultierende Datendatei ist ca. 90MB groß.
Das Grundkonzept
Es gibt einen Setter ExportSonosBibliothek am Sonosplayer-Device, der eine Datei mit dem übergebenen Dateinamen erzeugt. In dieser Datei wird der komplette Datenhash als textuelle, und damit per eval()
einlesbare, Darstellung gespeichert.
Die Cover der Titel werden als Aufruf auf den verwendeten Player erzeugt, und es wird berücksichtigt, ob man die Proxy-Einstellung aktiviert hat.
Um diese Datei wieder einzulesen, kann die mitgelieferte Prozedur SONOS_LoadExportedSonosBibliothek($fileName, $deviceName, $internalName)
verwendet werden. Diese legt den geladenen Datenhash in einem Internal mit übergebenem Namen im benannten FHEM-Device ab. Das muss kein Sonosplayer-Device sein, sondern kann auch ein Dummy bzw. ein beliebiges FHEM-Device sein.
Von hier aus kann man mit anderen Methodiken auf diese Daten zugreifen. Durch die Dateiablage kann die Datei auch über einen Neustart hinweg verwendet werden, da die Ermittlung ja etwas Zeit in Anspruch nimmt.
Hinweis: Mit Vorsicht ist z.B. der Bereich unter Tracks zu sehen, da dort alle(!) Titel auftauchen werden. Das kann eine Auswahlmöglichkeit auf einer (Web-)Oberfläche schnell mal sprengen.
Das Datenformat
Grundsätzlich gibt es zwei Bereiche im Hash: Einen für die Struktur und einen für die Titel. Die Struktur ist dann mit einem dynamischen Unterbaum ausgestattet, um die nächsten Ebenen zu repräsentieren. Welche Ebenen dort vohanden sind, und wie tief die Verschachtelung geht, kann sich u.U. in Zukunft ändern, wenn Sonos dort Anpassungen vornimmt. Die Titel sind als eine Liste ohne weitere Verschachtelung abgelegt.
Hier der Hash mit einigen Dummy-Beispieldaten, um den Inhalt zu verdeutlichen:
my $hash = {'Structure' => { 'A:PLAYLISTS' => { 'ID' => 'A:PLAYLISTS', 'Type' => 'Container', 'Title' => 'Playlists', 'Children' => {} }, 'A:GENRE' => { 'ID' => 'A:GENRE', 'Type' => 'Container', 'Title' => 'Genres', 'Children' => {} }, 'A:ALBUM' => { 'ID' => 'A:ALBUM', 'Type' => 'Container', 'Title' => 'Albums', 'Children' => { 'A:ALBUM/Chaos' => { 'ID' => 'A:ALBUM/Chaos', 'Type' => 'Container', 'Title' => 'Chaos', 'Artist' => 'Herbert Grönemeyer', 'Cover' => '/Pfad/zum/Cover/auch/mit/proxy/pfad', 'Children' => { 'TitleID1' => { 'ID' => 'TitleID1', 'Type' => 'Track' }, 'TitleID2' => { 'ID' => 'TitleID2', 'Type' => 'Track' }, } }, 'A:ALBUM/Testalbum' => { 'ID' => 'A:ALBUM/Testalbum', 'Type' => 'Container', 'Title' => 'Testalbum', 'Artist' => 'Hansi Fischer', 'Cover' => '/Pfad/zum/Cover/auch/mit/proxy/pfad', 'Children' => { 'TitleID1' => { 'ID' => 'TitleID3', 'Type' => 'Track' }, 'TitleID2' => { 'ID' => 'TitleID4', 'Type' => 'Track' }, } } } }, 'A:TRACKS' => { 'ID' => 'A:TRACKS', 'Type' => 'Container', 'Title' => 'Tracks', 'Children' => {} }, 'A:COMPOSER' => { 'ID' => 'A:COMPOSER', 'Type' => 'Container', 'Title' => 'Composers', 'Children' => {} }, 'A:ARTIST' => { 'ID' => 'A:ARTIST', 'Type' => 'Container', 'Title' => 'Contributing Artists', 'Children' => {} }, 'A:ALBUMARTIST' => { 'ID' => 'A:ALBUMARTIST', 'Type' => 'Container', 'Title' => 'Artists', 'Children' => {} } }, 'Titles' => { 'TitleID1' => { 'ID' => 'TitleID1', 'TrackURI' => '/Pfad/zur/Datei.mp3', 'Title' => 'Titel des Musikstücks', 'Artist' => 'Interpret des Musikstücks', 'Album' => 'Titel des Albums', 'AlbumArtist' => 'Interpret des Albums', 'Cover' => '/Pfad/zum/Cover/auch/mit/proxy/pfad', 'OriginalTrackNumber' => 5 }, 'TitleIDn' => { 'ID' => 'TitleIDn', 'TrackURI' => '/Pfad/zur/Datei.mp3', 'Title' => 'Titel des Musikstücks', 'Artist' => 'Interpret des Musikstücks', 'Album' => 'Titel des Albums', 'AlbumArtist' => 'Interpret des Albums', 'Cover' => '/Pfad/zum/Cover/auch/mit/proxy/pfad', 'OriginalTrackNumber' => 5 } } }
Wie kann es angezeigt werden?
(Das soll noch erweitert werden...)
Was wird alles automatisch erzeugt?
Hier soll kurz beschrieben werden, welche Elemente der automatische Erkennungsprozess anlegt, und welche Funktion diese haben.
Automatische Zoneplayererkennung
Erkannte Zoneplayer werden als SONOSPLAYER-Device angelegt:
define Sonos_Wohnzimmer SONOSPLAYER RINCON_000E5828D0F401400_MR
Der Name des Device wird aus dem Namen des SONOS-Device und dem Namen der Zone gebildet. Dabei werden Leer- und Sonderzeichen in "_
" umgewandelt.
Beim Anlegen werden automatisch einige Attribute mit angelegt, am Beispiel eines Wohnzimmer-Players:
attr Sonos_Wohnzimmer generateInfoSummarize1 <NormalAudio><Artist prefix="(" suffix=")"/> <Title prefix=" '" suffix="'" ifempty="[Keine Musikdatei]"/> <Album prefix=" vom Album '" suffix="'"/></NormalAudio> <StreamAudio><Sender suffix=":"/><SenderCurrent prefix=" '" suffix="' -"/> <SenderInfo prefix=" "/></StreamAudio> attr Sonos_Wohnzimmer generateInfoSummarize2 <TransportState/><InfoSummarize1 prefix=" => "/> attr Sonos_Wohnzimmer generateInfoSummarize3 <Volume prefix="Lautstärke: "/> <Mute instead=" ~ Kein Ton" ifempty=" ~ Ton An" emptyval="0"/> ~ Balance: <Balance ifempty="Mitte" emptyval="0"/> <HeadphoneConnected instead=" ~ Kopfhörer aktiv" ifempty=" ~ Kein Kopfhörer" emptyval="0"/> attr Sonos_Wohnzimmer icon icoSONOSPLAYER_icon-ZP90.png attr Sonos_Wohnzimmer room Sonos attr Sonos_Wohnzimmer stateVariable presence attr Sonos_Wohnzimmer group Wohnzimmer
Dadurch ist dieses Device direkt in der FHEM-Oberfläche steuerbar. Auch hier gilt, dass man das natürlich anpassen kann. Das sollen nur vereinfachende Vorgaben sein.
Das Attribut "room
" wird wieder aus dem Namen des SONOS-Device gebildet.
Das Attribut "group
" wird aus dem Namen der Zone gebildet
Zusätzliche Readingsgroups, die zunächst nichts anzeigen
Es werden zusätzliche readingsGroups angelegt, die zunächst keine Inhalte anzeigen. Diese lesen das der Readingsgroup entsprechende Reading Favourites, Radios oder Playlists aus. Um diese Readings zu füllen gibt es bereits ein angelegtes userReadings, welches auf die Get-Aufrufe von FavouritesWithCovers, RadiosWithCovers oder PlaylistsWithCovers reagiert und die entsprechenden Readings füllt.
Unter Beispiel für eine ReadingsGroup für die Darstellung von Listen (Favoriten, Playlisten und Radios) gibt es Beispiele für ein at-Statement, mit dem diese Readings automatisch gefüllt werden können. Damit werden diese auch in FHEM aktualisiert, wenn man diese am Sonos-Controller verändert.
Definition der InfoSummarize
infoSummarizeX := <NormalAudio>:sumElem:</NormalAudio> <StreamAudio>:sumElem:</StreamAudio>| :sumElem: sumElem := <:variable:[ prefix=":text:"][ suffix=":text:"][ instead=":text:"] [ ifempty=":text:"][ emptyval=":text:"]/> variable := TransportState|NumberOfTracks|Track|TrackDuration|Title|Artist|Album| OriginalTrackNumber|AlbumArtist|Sender|SenderCurrent|SenderInfo|StreamAudio|NormalAudio| AlbumArtURI|nextTrackDuration|nextTrackURI|nextAlbumArtURI|nextTitle|nextArtist| nextAlbum|nextAlbumArtist|nextOriginalTrackNumber|Volume|Mute|Shuffle|Repeat|RepeatOne| CrossfadeMode|Balance|HeadphoneConnected|SleepTimer|Presence|RoomName|RoomNameAlias| SaveRoomName|PlayerType|Location|SoftwareRevision|SerialNum|InfoSummarize1|InfoSummarize2| InfoSummarize3|InfoSummarize4 text := [Beliebiger Text ohne doppelte Anführungszeichen]
Die Unterscheidung zwischen <NormalAudio>
und <StreamAudio>
liegt bei der anliegenden Musikquelle. Gestreamte Audioquellen habe nur einen kleineren Set an Informationen vorliegen, während bei einer "normalen" Musikquelle z.B. eine Unterscheidung zwischen Artist und Title gemacht wird, und im Gegenzug z.B. kein Sendername existiert.
Man kann diese Unterscheidung auch weglassen, und direkt die Variablenausgaben hinschreiben. Dann gilt der Code für beide Musikquellenarten gleichermaßen (u.U. sind dann einige Felder nicht sinnvoll bzw. gar nicht gefüllt).
Die Tag-Erweiterungen prefix
und suffix
werden jeweils vor bzw. hinter den Feldwert in die Ausgabe gesetzt, wenn es einen Feldwert zum Ausgeben gibt.
Die Erweiterung instead
wird anstatt des Feldwerts ausgegeben, wenn normalerweise der Feldwert ausgegeben werden würde (abhängig davon, ob der Feldwert als empty angesehen wird, oder nicht).
Die Erweiterung ifempty
wird eingesetzt, wenn es gerade keinen Feldinhalt gibt. In diesem Fall werden natürlich auch keine Pre- und Suffixe sowie Instead-Angaben ausgegeben.
Die Erweiterung emptyval
legt fest, was neben einem undefinierten Feldwert noch als leer gelten soll. Dies ist interessant, wenn man z.B. den Zahlwert 0 als leer festlegen möchte.
Beim Definieren dieser Erweiterungen ist zu beachten, dass keine doppelten Anführungszeichen angegeben werden. Diese zerstören die weitere, interne Verarbeitung durch FHEM (Irgendwas ist immer :-)
Desweiteren können Verweise auf andere InfoSummarize
-Felder nur in aufsteigender Reihenfolge erfolgen. Es sind also keine Vorwärtsreferenzen oder Rekursionen möglich.
Fehlende Kommandos
Sollte eine Steuerungsmöglichkeit oder Information fehlen, oder anderes gewünscht sein, dann einfach eine Nachricht ins Forum. Meistens läßt sich da was machen :-)
Ideenpipeline
Folgende Ideen sind bereits in der gedanklichen Pipeline. Aber alles Schritt für Schritt und der Reihe nach:
- Momentan Leer
Erledigte Ideen:
- Zwischendurchsage: Eine Datei abspielen, und danach wieder an der alten Stelle mit der alten Lautstärke weiterspielen (In Version 1.5 hinzugekommen)
- Beliebige MP3s in die Queue legen oder abspielen: Entgegen dem Controllergefühl kann man sehr wohl völlig frei abspielbare Dateien in der Queue haben. Es kann nur sein, das man kein Cover oder ähnliches angezeigt bekommt (noch zu testen). (In Version 1.5 hinzugekommen, Cover funktionieren wie immer)
- Beliebige Radiostationen abspielen: Hier gilt das gleich wie für die MP3s. (In Version 1.5 hinzugekommen, Cover und Streaminformationen funktionieren beim Direktabspielen, aus der Queue heraus wird nur der Stream abgespielt)
- Lautstärkegrenzen festlegen: Damit soll festgelegt werden können, in welchen Grenzen die Lautstärke überhaupt verändert werden kann. Das soll in der entsprechenden Zone natürlich auch für die normalen Sonos-Controller gelten. Dabei werden explizit keine Readings im FHEM aktualisiert, da eine Lautstärkeänderung sonst von der Verarbeitungsgeschwindigkeit von FHEM (inkl. seiner Notifies) abhängig wäre. (In Version 1.8 hinzugekommen)
- Zonentopologie verwenden/anpassen: Es soll eine Speichermöglichkeit für die aktuelle Topologie geschaffen werden, und auch eine neue Topologie gesetzt werden können. Ich stelle mir da eine Art von "Szenen" vor die man nach Bedarf setzen und dann natürlich auch steuern kann. Diese Szenen sollen den Gruppierungszustand aller verfügbaren ZonePlayer repräsentieren (können), also wer mit wem in einer Gruppe ist, und wer der jeweilige Koordinator ist (nur dieser kann die Steuerung entgegennehmen, und für die gesamte Gruppe ausführen). (In Version 2.0 hinzugekommen)
- Button-Events: Es soll eine Möglichkeit zum direkten Reagieren auf Tastenevents am Player existieren. Man soll verschiedene Tastensequenzen festlegen können, die dann FHEM-Events erzeugen, auf die man reagieren kann. (In Version 2.0 hinzugekommen)
- relatives Spulen: während einer Wiedergabe soll mit "currentTrackPosition x" mit x festgelegt werden, umwieviel sekunden vorgespult werden soll. Analog dazu das zurückspulen (In Version vom 12.3.2017 hinzugekommen)
Beispiele
Hier können mit der Zeit ein paar Beispiele eingestellt werden, um die Möglichkeiten zu verdeutlichen.
Hinweis: Die Codebeispiele wurden umgebaut, damit diese für eine Bearbeitung über die FHEMWeb-Oberfläche passend sind. Wenn man die Beispiele direkt in einer Konfigurationsdatei verwenden möchte, so müssen die ; maskiert werden (also verdoppelt).
Beispiel zum Loggen aller Aktionen auf allen Playern
define FileLog_Sonos_Actions FileLog /path/to/log/Sonos_Actions-%Y-%m.log \ Sonos_.*:.*LastActionResult.*
Hiermit wird jede Aktion, die, durch FHEM verursacht, an die Player gesendet wurde, mitgeschrieben. Sehr praktisch für Fehlersuche, bzw. die Kontrolle darüber, was eigentlich von FHEM aus so auf den Playern gesteuert wird.
Beispiel zum automatischen Abspielen einer Liste nach dem Einschalten eines Players
define Sonos_Wohnzimmer_Appeared_Notify notify Sonos_Wohnzimmer:presence:.appeared { \ fhem "set Sonos_Wohnzimmer LoadPlaylist R.%20Spielliste" ; \ fhem "set Sonos_Wohnzimmer Volume 15" ; \ fhem "set Sonos_Wohnzimmer Track random" ; \ fhem "set Sonos_Wohnzimmer Play" \ }
Hier wird auf das Event presence: appeared reagiert und eine Playlist geladen (hier mit Leerzeichen im Namen, darum mittels "%20
" HTML-kodiert, was wiederum bei FHEM-Featurelevel < 5.7 wegen FHEM-Notify auf "%%20
" kodiert werden müsste). Anschließend wird die Lautstärke gesetzt, ein Titel ausgewählt (zufällig) und das Abspielen gestartet.
Da dies aber auch bei einem Neustart von FHEM getriggert wird, kann man noch eine zusätzliche Prüfung einbauen:
define Sonos_Wohnzimmer_Appeared_Notify notify Sonos_Wohnzimmer:presence:.appeared { \ if (ReadingsVal('Sonos_Wohnzimmer', 'numberOfTracks', -1) == 0) {\ fhem "set Sonos_Wohnzimmer LoadPlaylist R.%20Spielliste" ; \ fhem "set Sonos_Wohnzimmer Volume 15" ; \ fhem "set Sonos_Wohnzimmer Track random" ; \ fhem "set Sonos_Wohnzimmer Play" \ }\ }
Alternativ kann man auch das Reading currentTrackURI prüfen, je nachdem, was mit dem Player passieren soll.
Beispiel für eine Verstärkerschaltung auf Basis des Player-Zustands
define Sonos_Wohnzimmer_GoPlaying_Notify notify Sonos_Wohnzimmer:transportState.*PLAYING { \ fhem "delete wohnzimmer_Sonos_Ton_Off_Timer" ; \ if (Value('wohnzimmer_Sonos_Ton') ne 'on') { \ fhem "set wohnzimmer_Sonos_Ton on" \ } \ } define Sonos_Wohnzimmer_GoNotPlaying_Notify notify \ Sonos_Wohnzimmer:transportState.*(STOPPED|PAUSED_PLAYBACK) { \ fhem "delete wohnzimmer_Sonos_Ton_Off_Timer" ; \ fhem "define wohnzimmer_Sonos_Ton_Off_Timer at +00:05:00 \ set wohnzimmer_Sonos_Ton off" \ }
Hier wird beim Wechsel des transportState
auf "PLAYING
" der Verstärker angeschaltet, und beim Wechsel auf "STOPPED
" oder "PAUSED_PLAYBACK
" ein Timer zum Ausschalten des Verstärkers in 5 Minuten definiert.
Der Timer ist notwendig, da beim Wechsel zwischen einem "normalen" Titel und einem Radiostream ein kurzer Zwischenwechsel auf "STOPPED
" erfolgt, und ich nicht den Verstärker innerhalb von ein paar Sekunden aus- und wieder einschalten will.
Das Ganze geht mittlerweile viel kürzer mit dem Modul DOIF:
define Sonos_Wohnzimmer_PlayingCheck DOIF ([Sonos_Wohnzimmer:transportState] eq "PLAYING") \ (set wohnzimmer_Sonos_Ton on) DOELSE (set wohnzimmer_Sonos_Ton off) attr Sonos_Wohnzimmer_PlayingCheck wait 0:300
Beispiel für das Loggen des gerade abgespielten Titels
define FileLog_Sonos_Wohnzimmer FileLog /etc/fhem/log/Sonos_Wohnzimmer-%Y-%m.log \ Sonos_Wohnzimmer:infoSummarize2:.{2,} attr FileLog_Sonos_Wohnzimmer room Sonos
Hier wird bei jedem Wechsel des Titels oder des Abspielzustands ein Eintrag ins Log geschrieben. Damit kann man, auch bei einem Radiosender, verfolgen, welche Titel zu welcher Zeit so über den Player gelaufen sind :-)
Beispiel für eine Stummschaltung bei einem Anruf
define fritzBox_anrufstartring_notify notify fritzBox:.*ring set Sonos_Wohnzimmer VolumeSave 15 define fritzBox_anrufstartcall_notify notify fritzBox:.*call set Sonos_Wohnzimmer VolumeSave +0 define fritzBox_anrufende_notify notify fritzBox:.*disconnect set Sonos_Wohnzimmer VolumeRestore
Der Trigger auf 'call' existiert nur, damit ausgehende Telefonate beim Beenden nicht die Lautstärke verändern. Das passiert, weil das Disconnected-Event auch nach ausgehenden Anrufen kommt.
Das Beispiel kann man natürlich noch beliebig erweitern, vielleicht etwas mit Anrufererkennung usw.
Beispiel für eine Anrufsignalisierung per MP3 bei einem Anruf
define fritzBox_anrufstartringsong_notify notify fritzBox:.*ring set Sonos_Wohnzimmer \ PlayURITemp \\Server\Audio\RingRingRing.mp3 30
Hier wird bei Anruf die angegebene MP3-Datei temporär mit der Lautstärke 30 eingeblendet. Wenn die Datei abgespielt wurde, wird der vorherige Zustand im Player wiederhergestellt, und es geht weiter, wo unterbrochen wurde.
Beispiel für beide Varianten beim Telefonanruf gleichzeitig
define fritzBox_anrufstartring_notify notify fritzBox:.*ring set Sonos_Wohnzimmer VolumeSave 15 \ ;; set Sonos_Wohnzimmer PlayURITemp \\Server\Audio\RingRingRing.mp3 30 define fritzBox_anrufstartcall_notify notify fritzBox:.*call set Sonos_Wohnzimmer VolumeSave +0 define fritzBox_anrufende_notify notify fritzBox:.*disconnect set Sonos_Wohnzimmer VolumeRestore
Dieses Beispiel soll nur die Kombinationsmöglichkeiten verdeutlichen, und hat mehr spielerischen Character.
Beispiel für eine Sprachdurchsage auf Basis eines Notify
define wohnzimmer_Tastenfeld_1_Notify notify wohnzimmer_Tastenfeld_1 set Sonos_Wohnzimmer Speak \ 45 de Hier dann die Textnachricht, wie sie auf dem Player ausgegeben werden soll. define wohnzimmer_Tastenfeld_2_Notify notify wohnzimmer_Tastenfeld_2 set Sonos_Wohnzimmer Speak \ +10 de Hier dann die Textnachricht, wie sie auf dem Player ausgegeben werden soll. define wohnzimmer_Tastenfeld_3_Notify notify wohnzimmer_Tastenfeld_3 set Sonos_Wohnzimmer Speak \ +0 en Hello, this is a short message. define wohnzimmer_Tastenfeld_4_doif DOIF ([EnO_switch:?B0] and [?06:00-09:05]) \ ({my $temp = "Außentemperatur: " . ReadingsVal("MeinWetter","temperature","unbekannt") . \ " °C. Höchsttemperatur: " . ReadingsVal("MeinWetter","fc1_high_c","unbekannt") . " °.";; \ fhem "set Sonos_Bad Speak 30 de $temp"})
1: Hier wird auf Basis eines Notify (hier ein FS20-Taster) eine Textnachricht auf Deutsch mit der Lautstärke 45 auf dem SonosPlayer ausgegeben.
2: Hier wird eine deutsche Textnachricht mit 10 Einheiten lauter als aktuell eingestellt ausgegeben.
3: Hier wird eine englische Textnachricht mit der gleichen Lautstärke wie aktuell eingestellt ausgegeben.
4: Hier wird, wenn der EnOcean-Taster rechts oben ("B0") zwischen 6:00 und 9:05 Uhr gedrückt wird, die aktuelle Außentemperatur und die Tageshöchsttemperatur (vom weather-Modul) in Lautstärke 30 ausgegeben (nicht mit notify, sondern mit DOIF realisiert).
Beispiel für das Reagieren auf Tastenevents
Hier ein Beispiel, wie man die Tasten an einem Play5 (und natürlich auch an jedem anderen Player) zu einer einfachen, autarken Steuerung programmieren kann.
Grundlagen, die ich zur allgemeinen Vereinfachung in meiner 99_myUtils.pm
habe:
# Wird benötigt, da ein reDefine nur einen Befehl aufrufen kann sub pauseMuteOff($) { my ($devName) = @_; if (defined($main::defs{$devName})) { fhem("set $devName Pause"); fhem("set $devName Mute Off"); } } # Löscht ein Define, wenn es existiert. Damit kann man dynamische AT-Defines löschen, # ohne zu wissen, ob sie überhaupt existieren sub deleteDefineIfExists($) { my ($devName) = @_; if (defined($main::defs{$devName})) { fhem("delete $devName"); } } # Definiert ein define neu; Heisst, es wird, wenn es bereits existiert, gelöscht und neu angelegt sub reDefine($$) { my ($devName, $define) = @_; deleteDefineIfExists($devName); fhem('define '.$devName.' '.$define); }
Attribut am Sonosplayer-Device:
attr Sonos_Schlafzimmer buttonEvents 1:MM
Notify-Defines, die die Steuerung übernehmen:
define Sonos_Schlafzimmer_WantPlaying_Notify notify Sonos_Schlafzimmer:ButtonEvent:.MM \ set Sonos_Schlafzimmer Play define Sonos_Schlafzimmer_WantStopPlaying notify Sonos_Schlafzimmer:Mute.*1 \ { reDefine('Schlafzimmer_Sonos_Stop_Timer', 'at +00:00:30 \ { pauseMuteOff("Sonos_Schlafzimmer") }') } define Sonos_Schlafzimmer_WantStopPlayingOff notify Sonos_Schlafzimmer:Mute.*0 \ { deleteDefineIfExists('Schlafzimmer_Sonos_Stop_Timer') }
Hier wird mittels des Attributs buttonEvents
ein Event bei zweimaligen Drücken von M
ute innerhalb von 1 Sekunde definiert.
Anschließend wird auf dieses Event reagiert, indem der Player mit der Wiedergabe beginnen soll.
Desweiteren wird auf das Ändern von Mute reagiert, indem beim Aktivieren von Mute (also einmal drücken) ein Timer gestartet wird, der nach 30 Sekunden die Wiedergabe anhält, und den Mute-Zustand wieder zurücksetzt. Das letzte notify existiert nur, damit man das Beenden der Wiedergabe innerhalb der 30 Sekunden noch verhindern kann.
Hier ist zu beachten, dass diese Events natürlich nicht unterscheiden können, ob das ganze am Player selbst oder über einen Controller geschaltet wurde. Von beiden Stellen aus kann diese Funktionalität verursacht werden.
Beispiel für einen Offline-Sprachsynthetisierer
Man kann mit den Attributen Speak1, Speak2, Speak3 und Speak4 am zentralen Sonos-Device Kommandozeilen definieren, die einen Text in eine Sounddatei umwandeln. Hier soll dies am Beispiel von espeak verdeutlicht werden.
wav:/usr/bin/espeak -v %language% -w %filename% "%text%"
Zuerst muss das Ausgabedateiformat definiert werden, damit die internen Funktionen entsprechend reagieren können. Anschließend wird die Befehlszeile mit den entsprechenden Platzhaltern angegeben. Hier muss beachtet werden, dass der Platzhalter %language% mit dem zweiten Parameter der FHEM-Befehlseingabe gefüllt wird. In diesem Beispiel muss man dort also german angeben (anstatt de bei Google), um eine deutsche Ausgabe zu erhalten.
Dieses Beispiel hat den kleinen Nachteil, dass die Ausgabe in einer WAV-Datei erfolgt, die keinerlei Tag-Informationen tragen kann. Um das zu ändern, kann man einen Konverter nachschalten:
mp3:/usr/bin/espeak -v %language% --stdout "%text%" | /usr/bin/avconv -i - %filename%
Damit wird die Ausgabe von espeak direkt in das MP3-Format umgewandelt, und intern mit den entsprechenden Tags versehen. Hier ist allerdings der Nachteil, dass es etwas länger dauert (auf meinem Raspberry Pi ca. 1-3 Sekunden).
Die in diesem Beispiel verwendeten Pakete können unter Debian mittels der Anweisungen
sudo apt-get install espeak sudo apt-get install ffmpeg
installiert werden.
Beispiel zu InfoSummarize
Standard, wie er angelegt wird:
InfoSummarize1 = <NormalAudio><Artist prefix="(" suffix=")"/>\ <Title prefix=" '" suffix="'" ifempty="[Keine Musikdatei]"/>\ <Album prefix=" vom Album '" suffix="'"/></NormalAudio> \ <StreamAudio><Sender suffix=":"/>\ <SenderCurrent prefix=" '" suffix="' -"/>\ <SenderInfo prefix=" "/></StreamAudio> InfoSummarize2 = <TransportState/><InfoSummarize1 prefix=" => "/> InfoSummarize3 = <Volume prefix="Lautstärke: "/>\ <Mute instead=" ~ Kein Ton" ifempty=" ~ Ton An" emptyval="0"/>\ ~ Balance: <Balance ifempty="Mitte" emptyval="0"/>\ <HeadphoneConnected instead=" ~ Kopfhörer aktiv" ifempty=" ~ Kein Kopfhörer" \ emptyval="0"/>
Dabei ist zu beachten, dass man auf andere InfoSummarize-Felder verweisen darf, solange man diese nur in aufsteigender Reihenfolge verwendet. Rekursionen oder Vorwärtrsreferenzen werden nicht unterstützt.
Hier noch ein Beispiel, um die Informationen des nächsten Titels zusammenzufassen:
InfoSummarize4 = <NormalAudio>Nächster Titel: <nextArtist prefix="(" suffix=")"/>\ <nextTitle prefix=" '" suffix="'" ifempty="[Keine Musikdatei]"/>\ <nextAlbum prefix=" vom Album '" suffix="'"/></NormalAudio>\ <StreamAudio>Kein nächster Titel ermittelbar</StreamAudio>
Beispiel für eine Cover-Anzeige des nächsten Titels
Mit diesem Beispiel wird gezeigt, wie man sich einen Weblink für die Anzeige des Covers des nächsten Titels erzeugen kann:
define NextAlbumArt_Wohnzimmer weblink image fhem/icons/SONOSPLAYER/Sonos_Wohnzimmer_NextAlbumArt attr NextAlbumArt_Wohnzimmer group Wohnzimmer attr NextAlbumArt_Wohnzimmer htmlattr width="200" attr NextAlbumArt_Wohnzimmer room Sonos
Beispiel für das Übertragen eines Titels an einen anderen Player
Mein Sohn hat öfter den Wunsch, einen gerade im Wohnzimmer laufenden Titel auch in seine eigene Abspielliste zu bekommen. Der Weg am Sonos-Controller über eine gespeicherte Playliste ist dabei sehr umständlich. Ich habe ein 8-fach Sensorfeld an der Wohnzimmerwand, wo ich ein Feld dafür programmiert habe, das Reading currentTrackURI mittels der Set-Anweisung AddURIToQueue in die aktuelle Abspielliste meines Sohnes zu packen. Das ist natürlich nichts besonderes, aber vielleicht für den einen oder anderen auch eine nette Idee:
define wohnzimmer_Sensorfeld_Notify notify wohnzimmer_Sensorfeld { \ fhem "set Sonos_Sohnemann AddURIToQueue ".\ ReadingsVal("Sonos_Wohnzimmer", "currentTrackURI", "") \ }
Beispiel für eine eigene ReadingsGroup zur Darstellung der Cover- und Titelinformationen
Wenn man das Standarddesign der generierten readingsGroup überarbeiten möchte, muss man sich einfach eine eigene Prozedur in der 99_myUtils.pm anlegen, die dann in der readingsGroup verwendet werden kann.
Da die Original-Vorlage wegen des Vollbildmodus sehr umfangreich ist, gibt es hier nur eine abgespeckte Version, die nur die Anzeige selbst übernimmt. Wer gerne den Vollbildmodus anpassen möchte, kann sich die entsprechende Prozedur SONOS_getCoverTitleRG einfach aus dem Modulcode kopieren (umbenennen nicht vergessen).
Hier die Vorlage der drei Prozeduren:
sub getCoverTitleRG($;$$) { my ($device, $width, $space) = @_; $width = 500 if (!defined($width)); return '<div style="float: left;">'.getCoverRG($device).\ '</div><div style="margin-left: 150px; min-width: '.$width.\ 'px;>'.getTitleRG($device, $space).'</div>'; } sub getCoverRG($;$) { my ($device) = @_; return '<img style="margin-right: 5px; border: 1px solid lightgray; \ height: 175px" src="'.ReadingsVal($device, 'currentAlbumArtURL', '').'" />'; } sub SONOS_getTitleRG($;$) { my ($device, $space) = @_; $space = 20 if (!defined($space)); my $infoString = ''; my $transportState = ReadingsVal($device, 'transportState', ''); $transportState = 'Spiele' if ($transportState eq 'PLAYING'); $transportState = 'Pausiere' if ($transportState eq 'PAUSED_PLAYBACK'); $transportState = 'Stop bei' if ($transportState eq 'STOPPED'); # Läuft Radio oder ein "normaler" Titel if (ReadingsVal($device, 'currentNormalAudio', 1) == 1) { $infoString = sprintf('<div style="margin-left: -150px;">%s Titel %s \ von %s<br />Titel: <b>%s</b><br />Interpret: <b>%s</b><br />Album: \ <b>%s</b><div style="height: %dpx;"></div>'.encode('UTF-8', \ 'Nächste Wiedergabe:').'</div><div style="float: left; margin-left: \ 0px;"><img style="margin: 0px; padding: 0px; margin-right: 5px; \ border: 1px solid lightgray;" height="55" border="0" src="%s" />\ </div><div style="margin-left: 0px;">Titel: %s<br />Artist: %s<br />\ Album: %s</div>', $transportState, ReadingsVal($device, 'currentTrack', ''), ReadingsVal($device, 'numberOfTracks', ''), ReadingsVal($device, 'currentTitle', ''), ReadingsVal($device, 'currentArtist', ''), ReadingsVal($device, 'currentAlbum', ''), $space, ReadingsVal($device, 'nextAlbumArtURL', ''), ReadingsVal($device, 'nextTitle', ''), ReadingsVal($device, 'nextArtist', ''), ReadingsVal($device, 'nextAlbum', '')); } else { $infoString = sprintf('<div style="margin-left: -150px;">%s Radiostream\ <br />Sender: <b>%s</b><br />Info: <b>%s</b><br />'.encode('UTF-8', \ 'Läuft:').' <b>%s</b></div>', $transportState, ReadingsVal($device, 'currentSender', ''), ReadingsVal($device, 'currentSenderInfo', ''), ReadingsVal($device, 'currentSenderCurrent', '')); } return $infoString; }
Diese kann man als Kopiervorlage für eigene Ideen verwenden. Die Backslashs vor den Zeilenumbrüchen sind hauptsächlich der Optik halber hier. Generell empfehle ich die so getrennten Befehle in eine Zeile zu schreiben...
Hier noch eine beispielhafte readingsGroup dazu:
define Sonos_WohnzimmerRG readingsGroup Sonos_Wohnzimmer:\ <{getCoverTitleRG($DEVICE)}@infoSummarize1>
Beispiel für eine ReadingsGroup für die Darstellung von Listen (Favoriten, Playlisten und Radios)
Es gibt eine mitgelieferte Prozedur, die für diese Darstellung verwendet werden kann. Diese stellt die Listen einfach als zweispaltige Tabelle dar (links das Cover, rechts der Titel als ausführbarer Link). Für die Datenlieferung (z.B. die Favoriten in einem Reading) muss man sich noch ein entsprechendes userReading schaffen. Beim Generieren der Devices vom Autocreate-Mechanismus werden diese Elemente und Attribute bereits mit erzeugt. Es muss lediglich ein Automatismus zum Aktualisieren des entsprechenden Readings geschaffen werden, oder dieses einmal manuell ausgeführt werden.
Hier die Vorlage für das userReadings:
attr Sonos_Wohnzimmer userReadings Favourites:LastActionResult.*?\ GetFavouritesWithCovers.* { if (ReadingsVal($name, \ "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } }, Radios:\ LastActionResult.*?GetRadiosWithCovers.* { if (ReadingsVal($name, \ "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } }, Playlists:\ LastActionResult.*?GetPlaylistsWithCovers.* { if (ReadingsVal($name, \ "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } }
Damit wird jeweils ein Reading für Favoriten, Playlisten und Radios angelegt, sobald im Reading LastActionResult dieses Ergebnis asynchron geliefert wurde.
Die Lieferung selbst kann man mit einem at-Statement zu bestimmten Zeitpunkten erzeugen/aktualisieren lassen:
define refreshFavouritesWohnzimmer at *06:00 get Sonos_Wohnzimmer FavouritesWithCovers
Das ganze muss natürlich für jede gewünschte Liste an jedem Player aktualisiert werden. Man kann also auch sowas schreiben:
define refreshFavouritesSonos at *06:00 get Sonos_.*.Favourites FavouritesWithCovers define refreshPlaylistsSonos at *06:01 get Sonos_.*.Playlists PlaylistsWithCovers define refreshRadiosSonos at *06:02 get Sonos_.*.Radios RadiosWithCovers
Möchte man eine andere Darstellung, so muss man sich eine eigene Prozedur in eine 99_myUtils.pm packen. Hier eine Kopiervorlage:
sub getListRG($$;$) { my ($device, $reading, $ul) = @_; $ul = 0 if (!defined($ul)); my $resultString = ''; # Manchmal ist es etwas komplizierter mit den Zeichensätzen... my %elems = %{eval(decode('CP1252', ReadingsVal($device, $reading, '{}')))}; for my $key (keys %elems) { my $command; if ($reading eq 'Favourites') { $command = 'cmd.'.$device.uri_escape('=set '.$device.' \ StartFavourite '.uri_escape($elems{$key}->{Title})); } elsif ($reading eq 'Playlists') { $command = 'cmd.'.$device.uri_escape('=set '.$device.' \ StartPlaylist '.uri_escape($elems{$key}->{Title})); } elsif ($reading eq 'Radios') { $command = 'cmd.'.$device.uri_escape('=set '.$device.' \ StartRadio '.uri_escape($elems{$key}->{Title})); } $command = "FW_cmd('/fhem?XHR=1&$command')"; if ($ul) { $resultString .= '<li style="list-style-type: none; display: inline;">\ <a onclick="'.$command.'"><img style="border: solid 1px lightgray; \ margin: 3px;" width="70" src="'.$elems{$key}->{Cover}.'" /></a></li>'; } else { $resultString .= '<tr><td><img width="70" src="'.$elems{$key}->{Cover}.\ '" /></td><td><a onclick="'.$command.'">'.$elems{$key}->{Title}."</a>\ </td></tr>\n"; } } if ($ul) { return '<ul style="margin-left: 0px; padding-left: 0px; list-style-type: none; \ display: inline;">'.$resultString.'</ul>'; } else { return '<table>'.$resultString.'</table>'; } }
Diese Prozedur hat einen optionalen Parameter ($ul). Mit diesem kann man angeben, ob eine Tabelle mit vertikaler Darstellung ($ul=0) oder eine Unordered-List mit horizontaler Darstellung ($ul=1) erzeugt wird. Die Variante mit den ListItems ist auch für eine Darstellung in einem Dashboard geeignet. Da bei der horizontalen Darstellung kein Platz für Namen ist, eignet sich diese Darstellung nur für Listen, deren Icon für jeden Eintrag unterschiedlich ist (Playlisten kann man hier also nicht mehr unterscheiden :-).
Die eigentliche readingsGroup verwendet dann diese Prozedur:
define Sonos_WohnzimmerFavouriteListRG readingsGroup Sonos_Wohnzimmer:\ <{getListRG($DEVICE,"Favourites")}@Favourites>
oder für die Variante mit den List-Elementen:
define Sonos_WohnzimmerFavouriteListRG readingsGroup Sonos_Wohnzimmer:\ <{getListRG($DEVICE,"Favourites",1)}@Favourites>
Damit kann man sich dynamische Listen auf Basis der Informationen im Sonosplayer für die Darstellung erzeugen lassen.
Die Backslashs vor den Zeilenumbrüchen sind hauptsächlich der Optik halber hier. Generell empfehle ich die so getrennten Befehle in eine Zeile zu schreiben...
Beispiel für die Anzeige der Gruppenkonstellation in einer ReadingsGroup
Mit der folgende Prozedur (in die 99_myUtils.pm schreiben) und der readingsGroup läßt sich auf einfache Weise die Gruppenkonstellation stets aktuell darstellen.
Die Prozedur, die die Zerlegung des Strings und in diesem Fall die Aufbereitung als UL (Unordered-List) übernimmt:
sub getGroupsRG() { my $groups = CommandGet(undef, SONOS_getSonosPlayerByName(undef)->{NAME}.\ ' Groups'); my $result = ''; my $i = 0; while ($groups =~ m/\[(.*?)\]/ig) { my @member = split(/, /, $1); @member = map { my $elem = $_; $elem = FW_makeImage('icoSONOSPLAYER_icon-'.\ ReadingsVal($elem, 'playerType', '').'.png', '', '').ReadingsVal($elem,\ 'roomNameAlias', $elem); $elem; } @member; $result .= '<li>'.++$i.'. Gruppe:<ul style="list-style-type: none; \ padding-left: 0px;"><li>'.join('</li><li>', @member).'</li></ul></li>'; } return '<ul>'.$result.'</ul>'; }
Und hier die entsprechende ReadingsGroup dazu:
define SonosRG readingsGroup Sonos:<{getGroupsRG()}@ZoneGroupState>
Damit wird eine einfache Darstellung der Gruppenkonstellation durchgeführt, die man sich natürlich selber nach Belieben anpassen kann/soll.
Die Backslashs vor den Zeilenumbrüchen sind hauptsächlich der Optik halber hier. Generell empfehle ich die so getrennten Befehle in eine Zeile zu schreiben...
Beispiel für eine ReadingsGroup, die die Informationen des Masters anzeigt
Wenn Player in einer Gruppe sind, werden keine Titelinformationen des eigentlichten Streams angezeigt. Man kann sich jetzt zu jedem Player eine readingsGroup bauen, die die Informationen des Gruppenmasters anzeigen.
define Sonos_WohnzimmerRG2 readingsGroup Sonos_Wohnzimmer:infoSummarize2@{\ SONOSPLAYER_GetMasterPlayerName($DEVICE)} attr Sonos_WohnzimmerRG2 valueFormat {" "} attr Sonos_WohnzimmerRG2 valuePrefix {SONOS_getCoverTitleRG(\ SONOSPLAYER_GetMasterPlayerName($DEVICE))} attr Sonos_WohnzimmerRG2 noheading 1 attr Sonos_WohnzimmerRG2 nonames 1 attr Sonos_WohnzimmerRG2 notime 1
Hinweis: Diese ReadingsGroup wird automatisch per longpoll aktualisiert. Lediglich bei einer Umgruppierung muss bislang die Seite neu geladen werden. Es kann aber gut sein, dass man das in Zukunft auch per longpoll hinbekommen kann.
Beispiel für ein Shell-Skript zum Aufräumen eines Speak-Verzeichnisses
Mit der freundlichen Freigabe von Loredo und CQuadrat hier ein kleines Shell-Skript, mit dem länger nicht abgespielte Dateien gelöscht werden können. Bei allen Varianten muss berücksichtigt werden, dass der ausführende Benutzer die Dateien auch löschen darf. Bitte die Dateirechte prüfen.
Variante mit Ausgabe der gelöschten Dateien
#!/bin/bash FILES=`ls /mnt/SonosSpeak/RINCON*.mp3*` CURRENTTIME=`date +"%s"` PASTDAYS=75 THESHOLDATIME=`expr $CURRENTTIME - $PASTDAYS \* 24 \* 60 \* 60` echo -e "Cleaning up all files older than $PASTDAYS days ...\n\n" for f in $FILES do FILEATIME=`stat -c "%X" $f` if [[ "$FILEATIME" < "$THESHOLDATIME" ]]; then echo "cleaned up $f: last access on `stat -c "%x" $f`" rm $f fi done
Unter Umständen gibt es eine aktuellere Version unter cleanupSonosSpeak.sh auf GitHub.
Variante für die crontab
0 4 * * * find /mnt/SonosSpeak -name "RINCON*" ! -atime -75 -delete
Hier wird jeden Tag um 4:00 Uhr der Ordner mit den Sprachausgabedateien bereinigt.
Betrieb des Sonos an einer Funksteckdose (regelmäßiges Ausschalten) - Verbindungsprobleme
Wenn das Sonossystem per Funksteckdose regelmäßig vom Netz genommen wird, bereitet der Neustart und das anschließende Verbinden mit FHEM oft Probleme. Das Sonosmodul bleibt auf dem Status "disappeared" stehen und das Playerdevice ebenfalls. Ergo ist eine Bedienung per FHEM oder die Sprachausgabe nicht mehr möglich.
Um diesem Problem Abhilfe zu schaffen reicht ein kleines notify oder DOIF, welches den Player beim Abschalten das Attribut disable = 1 verschafft und beim Wiedereinschalten dieses Attribut löscht.
define RebootSonosDOIF DOIF ([FunksteckerSonos:state] eq "on" )(deleteattr MeinSonosDevice disable) (save) DOELSEIF ([FunksteckerSonos:state] eq "off" )(attr MeinSonosDevice disable 1)(save)
Das Setzen von "disable" sorgt dafür, dass der Sonosthread beendet wird und beim Einschalten ein neuer Prozess erstellt wird. Diese automatische Änderung an der Konfiguration des Device benötigt ein save config im Nachgang der DOIF- oder notify-Aktion. Daher wird der jeweilige attr-Befehl mit einem (save) abgeschlossen.
Wichtig hierbei (wie auch in der Überschrift erwähnt) funktioniert das nur, wenn die einzelnen Sonosplayer an einer schaltbaren Steckdose betrieben werden.
Das DOIF triggert nur bei Änderung des "state" der jeweilige Funksteckdose.
Beispiele für FTUI-Integrationen
Hier können diverse Beispiele für eine FTUI (FHEM Tablet User Interface) Integration aufgeführt werden. Dabei sollten die Beispiele vollständig sein, und auch alle notwendigen Dummies und/oder Userreadings beschreiben.
Beispiel von Reinerlein
Hier gebe ich mal mein Beispiel zum Besten. Es ist eine 3 Spalten x 5 Zeilen Integration mit der Möglichkeit einer Favoriten-, Playlisten- und Radioauswahl, sowie einer Titelauswahl und Gruppierungsanpassung.
Die Formatierung der Listen erfolgt mit einem | als Trenner der Elemente, da dieses Zeichen hier nie im Titel vorkommt.
Die Maskierung der Leerzeichen für die Schlüsselliste erfolgt auf den Punkt. Damit besteht die Möglichkeit, den Wert direkt als regulären Ausdruck an den entsprechenden Start-Befehl zu übermitteln. Es müssen nur noch die Schrägstriche / vorne und hinten angefügt werden.
Beim Antippen des Covers wird ein Vollbild-Popup geöffnet, welches das Cover in groß, den Abspielzustand und die Abspielposition darstellt.
Im Header jedes Players wird angezeigt, ob gerade irgendwelche Slaveplayer mitbedient werden, bzw. wer der aktuelle Masterplayer zu dieser Wiedergabe ist. Des Weiteren kann dort direkt ein Player zu der Wiedergabegruppe hinzugefügt oder aus ihr entfernt werden.
Im Header kann jetzt bei einer Gruppenwiedergabe auch der GroupMute-Zustand gesetzt werden.
Über dem Cover wird nun die aktuelle Quelle des Titels angezeigt (Playlist, Album o.ä.)
FTUI-Code
Der Code ist in zwei Bereiche aufgeteilt, damit die Templatemöglichkeiten für mehrere Player verwendet werden können.
Zunächst die Einbindung des Templates. Hier wird auch der Rahmen festgelegt. In diesem Fall der Gridster-Kasten mit 3x5 Feldgröße:
<li data-row="1" data-col="1" data-sizex="3" data-sizey="5" class="border-down-gray lesstransparent"> <div data-template="template_musik_sonos.html" data-parameter='{"Device":"Sonos_Wohnzimmer"}'></div> </li>
Dadurch, dass der Rahmen nicht mit im Template enthalten ist, könnte man z.B. auch mehrere Player nebeneinander in einem Rahmen darstellen, dabei aber nicht den umschließenden DIV-Tag um das Template vergessen, da sonst die Titelanzeigen rauswandern könnten. Hinweis: In der vorherigen Version gab es noch einen Parameter für den Raumnamen, und der Header wurde hier bei der Einbindung festgelegt. Das entfällt nun, da der Raumname per Reading ermittelt wird, und im Header nun Gruppierungsinformationen enthalten sind.
Für die Coverdarstellung ist ein neues Widget notwendig (welches momentan noch nicht offiziell ist), da in der neuen Sonosversion größere Radiocover geladen werden, und diese nicht unbedingt quadratisch orientiert sind.
Das Widget kann im Forum heruntergeladen werden: https://forum.fhem.de/index.php/topic,70265.0.html.
Für die Lauftext-Animation sind eigene CSS-Klassen, eine Javascript-Funktion und (momentan noch) eine Anpassung des JoinedLabel-Widgets notwendig.
Hier die notwendigen Styles und Javascript. Ich habe diese einfach in den Kopfbereich meiner index.html gepackt:
<!-- Anfang Styles und Javascript für die Scrolltexte in der Sonosplayer-Ansicht --> <style> .flowanimation { position: relative; white-space: nowrap; display: inline-block; animation: floatText 8s infinite alternate ease-in-out; } @keyframes floatText { from { left: 0px; } to { left: calc(355px - 100%); } } .mycenteredtext { position: relative; white-space: nowrap; display: inline-block; left: calc(355px / 2 - 50%); } </style> <script type="text/javascript"> function checkFlowAnimation(elemName) { if ($(elemName).innerWidth() >= 355) { $(elemName).addClass('flowanimation'); } else { $(elemName).addClass('mycenteredtext'); } } </script> <!-- Ende Styles und Javascript für die Scrolltexte in der Sonosplayer-Ansicht -->
Die Anpassungen in der Datei "widget_joinedlabel.js" beschränken sich auf zwei Zeilen:
- In der Funktion "init_attr()" als letztes Statement vor der abschließenden Log-Ausgabe:
elem.initData('onupdate', '');
- In der Funktion "update" als letztes Statement nach der "me.update_colorize()"-Anweisung:
eval(elem.data('onupdate'));
Hier nun der Inhalt der Datei template_musik_sonos.html:
<header> <div data-type="classchanger" data-device="Device" data-get="SlavePlayerNotBonded" data-get-on='["[]"]' data-on-class="hide" data-off-class="mini" class="inline"> <div data-type="switch" data-device="Device" data-get="GroupMute" data-set="GroupMute" data-icon="fa-deaf" data-background-icon="-" data-on-color="#aa6900" data-off-color="gray" data-get-on="1" data-get-off="0" data-set-on="1" data-set-off="0" class="mini" style="margin-right: -5px;"> </div> </div> <div data-type="joinedlabel" data-device="Device" data-mask="[$1][ ($2)]" data-get='["roomName","ZoneGroupNameDetails"]' class="truncate inline"></div> <div data-type="classchanger" data-device="Device" data-get="MasterPlayer" data-get-on="Device" data-on-class="hide" class="inline left-narrow"> <div data-type="push" data-device="Device" data-icon="fa-minus-circle" data-background-icon="-" data-set-on="MakeStandaloneGroup" class="inline mini gray"> </div> </div> <div data-type="classchanger" data-device="Device" data-get="MasterPlayer" data-get-on="Device" data-off-class="hide" class="inline left-narrow"> <div data-type="popup" class="" data-width="400px" data-height="110px"> <div data-type="symbol" data-icon="fa-chevron-circle-down" class="mini" style="height: 10px;"> </div> <div class="dialog"> <header><div data-type="joinedlabel" data-device="Device" data-mask="Wiedergabegruppe[ für $1] anpassen" data-get='["roomName"]' class="inline"></div></header> <div class="top-space-10 left-align left-space"> <div> <div class="large middle inline">Player hinzufügen: </div> <div data-type="select" data-device="Device" data-list="AvailablePlayerList" data-alias="AvailablePlayerListAlias" data-delimiter="|" data-get="-" data-set="AddMember" class="inline w3x" onchange="$('.dialog-close').trigger('click');"></div> </div> <div> <div class="large middle inline">Player entfernen: </div> <div data-type="select" data-device="Device" data-list="SlavePlayerNotBondedList" data-alias="SlavePlayerNotBondedListAlias" data-delimiter="|" data-get="-" data-set="RemoveMember" class="inline w3x" onchange="$('.dialog-close').trigger('click');"></div> </div> </div> </div> </div> </div> </header <div class=""> <div data-type="joinedlabel" data-device="Device" data-mask=" [~ $1 ~] " data-get='["currentSource"]' class="bottom-narrow mini white" style="padding-top: 3px; background: rgba(170, 105, 0, 0.6);"></div> <div data-type="popup" data-width="100%" data-height="100%"> <div style="margin-bottom: -40px;"> <div data-type="imagecover" data-device="Device" data-get="currentAlbumArtURL" data-opacity="1.0" data-width="350px" data-height="350px" class="" onclick="$('.dialog-close').trigger('click');" style="margin-left: 12px; margin-top: 12px; border: 1px solid rgba(170, 105, 0, 0.6);"> </div> <div data-type="classchanger" data-device="Device" data-get="currentTrackProviderIconRoundURL" data-get-on="" data-on-class="hide"> <div class="inline" style="width: 40px; height: 40px; background: rgba(0, 0, 0, 0.40); position: relative; top: -349px; left: -152px;"> <div data-type="imagecover" data-device="Device" data-get="currentTrackProviderIconRoundURL" data-opacity="1.0" data-width="30px" data-height="30px" class="" style="margin-left: 5px; margin-top: 5px;"> </div> </div> </div> <div data-type="classchanger" data-device="Device" data-get="currentTrackProviderIconRoundURL" data-get-on="" data-off-class="hide"> <div class="inline" style="width: 40px; height: 40px; position: relative; top: -349px; left: -152px;"> </div> </div> </div> <div class="dialog"> <header><div data-type="joinedlabel" data-device="Device" data-mask="Cover[ für $1]" data-get='["roomName"]' class="inline"></div></header> <div data-type="imagecover" data-device="Device" data-get="currentTrackProviderIconRoundURL" data-opacity="1.0" data-width="30px" data-height="30px" class="" style="position: absolute; top: 25px; left: 5px;" style="margin-left: 5px; margin-top: 5px;"> </div> <div data-type="switch" data-device="Device" data-get="transportState" data-states='["PLAYING","PAUSED_PLAYBACK","STOPPED"]' data-background-icon="-" data-background-colors='["white","white","white"]' data-colors='["white","white","white"]' data-icons='["fa-play","fa-pause","fa-pause"]' class="inline readonly" style="position: absolute; top: 10px; right: -10px;" onclick="$('.dialog-close').trigger('click');"> </div> <div data-type="imagecover" data-device="Device" data-get="currentAlbumArtURL" data-opacity="1.0" data-width="100%" data-height="calc(100vh - 60px)" class="" onclick="$('.dialog-close').trigger('click');" style=""> </div> <div data-type="classchanger" data-device="Device" data-get="currentNormalAudio" data-get-on="1" data-off-class="hide"> <div data-type="slider" data-device="Device" data-get="currentTrackPositionSimulatedSec" data-max="currentTrackDurationSec" data-min="0" data-step="1" data-handle-diameter="5" data-width="68%" class="horizontal top-narrow readonly centered"></div> </div> <div data-type="classchanger" data-device="Device" data-get="currentNormalAudio" data-get-on="1" data-off-class="hide"> <div data-type="joinedlabel" data-device="Device" data-mask="[$1][ ~ $2][ ~ $3]" data-get='["currentTitle","currentArtist","currentAlbum"]' class="truncate top-space"></div> </div> <div data-type="classchanger" data-device="Device" data-get="currentStreamAudio" data-get-on="1" data-off-class="hide"> <div data-type="joinedlabel" data-device="Device" data-mask="[$1 ~ ][$2][: $3]" data-get='["currentSenderInfo","currentSender","currentSenderCurrent"]' class="truncate top-space"></div> </div> </div> </div> <div data-type="classchanger" data-device="Device" data-get="currentNormalAudio" data-get-on="1" data-off-class="hide"> <div data-type="label" data-device="Device" data-get="currentTrackPositionSimulated" class="inline" style="width: 3em;"></div> <div data-type="slider" data-device="Device" data-set="CurrentTrackPosition" data-get="currentTrackPositionSimulatedSec" data-max="currentTrackDurationSec" data-min="0" data-step="1" data-handle-diameter="5" data-width="250" class="horizontal tap inline"> </div> <div data-type="label" data-device="Device" data-get="currentTrackDuration" class="inline" style="width: 3em;"></div> <div class="newline"> <div data-type="label" data-device="Device" data-get="currentTrack" class="inline center-align" style="width: 3em;"></div> <div data-type="slider" data-device="Device" data-set="Track" data-get="currentTrack" data-max="numberOfTracks" data-min="0" data-step="1" data-handle-diameter="5" data-width="250" class="horizontal tap inline"> </div> <div data-type="label" data-device="Device" data-get="numberOfTracks" class="inline center-align" style="width: 3em;"></div> </div> </div> <div data-type="classchanger" data-device="Device" data-get="currentStreamAudio" data-get-on="1" data-off-class="hide"> <div style="height: 40px;"> </div> <!-- Leerer Ersatz für die bei Streams fehlende Positionsanzeige --> </div> <div class="large top-space"> <div data-type="classchanger" data-device="Device" data-get="currentNormalAudio" data-get-on="1" data-off-class="hide"> <div style="height: 21px;"> <div style="width: 355px; position: absolute; overflow: hidden; height: 21px; margin-left: 10px; margin-right: 10px;"> <div style="position: absolute;"> <div id="Device_Title" data-type="joinedlabel" data-device="Device" data-mask="[$1]" data-get='["currentTitle"]' data-onupdate="checkFlowAnimation('#Device_Title');" class="bold"></div> </div> </div> </div> <div style="height: 21px;"> <div style="width: 355px; position: absolute; overflow: hidden; height: 21px; margin-left: 10px; margin-right: 10px;"> <div style="position: absolute;"> <div id="Device_Interpret" data-type="joinedlabel" data-device="Device" data-mask="[$1][ ~ $2]" data-get='["currentArtist","currentAlbum"]' data-onupdate="checkFlowAnimation('#Device_Interpret');" class=""> </div> </div> </div> </div> </div> <div data-type="classchanger" data-device="Device" data-get="currentStreamAudio" data-get-on="1" data-off-class="hide"> <div style="height: 21px;"> <div style="width: 355px; position: absolute; overflow: hidden; height: 21px; margin-left: 10px; margin-right: 10px;"> <div style="position: absolute;"> <div id="Device_SenderInfo" data-type="joinedlabel" data-device="Device" data-mask="[$1]" data-get='["currentSenderInfo"]' data-onupdate="checkFlowAnimation('#Device_SenderInfo');" class="bold"></div> </div> </div> </div> <div style="height: 21px;"> <div style="width: 355px; position: absolute; overflow: hidden; height: 21px; margin-left: 10px; margin-right: 10px;"> <div style="position: absolute;"> <div id="Device_Sender" data-type="joinedlabel" data-device="Device" data-mask="[$1][: $2]" data-get='["currentSender","currentSenderCurrent"]' data-onupdate="checkFlowAnimation('#Device_Sender');"class=""></div> </div> </div> </div> </div> </div> <div class="top-space"> <div data-type="switch" data-device="Device" data-get="Mute" data-set="Mute" data-icon="fa-deaf" data-background-icon="-" data-on-color="#aa6900" data-off-color="gray" data-get-on="1" data-get-off="0" data-set-on="1" data-set-off="0" class="inline mini"> </div> <div data-type="classchanger" data-device="Device" data-get="currentNormalAudio" data-get-on="1" data-off-class="hide" class="inline top-space"> <div data-type="switch" data-device="Device" data-get="Repeat" data-set="Repeat" data-icon="fa-repeat" data-background-icon="-" data-on-color="#aa6900" data-off-color="gray" data-get-on="1" data-get-off="0" data-set-on="1" data-set-off="0" class="inline mini"> </div> <div data-type="push" data-device="Device" data-icon="fa-step-backward" data-background-icon="-" data-off-color="#fff" data-on-color="#aa6900" data-set-on="Previous" class="inline mini"> </div> <div data-type="push" data-device="Device" data-set="CurrentTrackPosition" data-icon="fa-backward" data-background-icon="-" data-off-color="#fff" data-on-color="#aa6900" data-set-on="-30" class="inline mini"> </div> </div> <div data-type="switch" data-device="Device" data-get="transportState" data-states='["PLAYING","PAUSED_PLAYBACK","STOPPED"]' data-set-states='["Pause","Play","Play"]' data-background-icon="fa-circle-thin" data-background-colors='["#aa6900","white","white"]' data-colors='["#aa6900","white","white"]' data-icons='["fa-pause","fa-play","fa-play"]' class="inline small"> </div> <div data-type="classchanger" data-device="Device" data-get="currentNormalAudio" data-get-on="1" data-off-class="hide" class="inline"> <div data-type="push" data-device="Device" data-set="CurrentTrackPosition" data-icon="fa-forward" data-background-icon="-" data-off-color="#fff" data-on-color="#aa6900" data-set-on="+30" class="inline mini"> </div> <div data-type="push" data-device="Device" data-icon="fa-step-forward" data-background-icon="-" data-off-color="#fff" data-on-color="#aa6900" data-set-on="Next" class="inline mini"> </div> <div data-type="switch" data-device="Device" data-get="Shuffle" data-set="Shuffle" data-icon="fa-random" data-background-icon="-" data-on-color="#aa6900" data-off-color="gray" data-get-on="1" data-get-off="0" data-set-on="1" data-set-off="0" class="inline mini"> </div> </div> <div data-type="popup" class="inline" data-width="650px" data-height="210px"> <div data-type="push" data-icon="fa-list" data-background-icon="-" data-off-color="#fff" data-on-color="#aa6900" class="mini"> </div> <div class="dialog"> <header><div data-type="joinedlabel" data-device="Device" data-mask="Musikauswahl[ für $1]" data-get='["roomName"]' class="inline"></div></header> <div class="top-space-10 left-align left-space"> <div> <div class="large middle inline">Favoriten: </div> <div data-type="select" data-device="Device" data-list="FavouritesList" data-alias="FavouritesListAlias" data-delimiter="|" data-quote="/" data-get="currentFavouriteNameMasked" data-set="StartFavourite" class="inline w3x" onchange="$('.dialog-close').trigger('click');"></div> </div> <div> <div class="large middle inline">Playlists: </div> <div data-type="select" data-device="Device" data-list="PlaylistsList" data-alias="PlaylistsListAlias" data-delimiter="|" data-quote="/" data-get="currentPlaylistNameMasked" data-set="StartPlaylist" class="inline w3x" onchange="$('.dialog-close').trigger('click');"></div> </div> <div> <div class="large middle inline">Radios: </div> <div data-type="select" data-device="Device" data-list="RadiosList" data-alias="RadiosListAlias" data-delimiter="|" data-quote="/" data-get="currentRadioNameMasked" data-set="StartRadio" class="inline w3x" onchange="$('.dialog-close').trigger('click');"></div> </div> <div> <div class="large middle inline">Audio-Eingang: </div> <div data-type="select" data-device="Device" data-list="Sonos:LineInPlayerList" data-alias="Sonos:LineInPlayerListAlias" data-delimiter="|" data-get="currentAlbum" data-set="PlayURI" class="inline w3x" onchange="$('.dialog-close').trigger('click');"></div> </div> <div> <div class="large middle inline">Abspielliste: </div> <div data-type="select" data-device="Device" data-list="QueueList" data-alias="QueueListAlias" data-delimiter="|" data-get="currentTrack" data-set="Track" class="inline w3x" onchange="$('.dialog-close').trigger('click');"></div> </div> </div> </div> </div> </div> <div data-type="spinner" data-device="Device" data-get="Volume" data-set="Volume" data-max="50" data-step="1" data-width="350" data-icon-left="fa-volume-down tall" data-icon-right="fa-volume-up tall" data-gradient-color='["orange","red"]' class="tap value positiononly top-space centered"> </div> </div>
Notwendige Userreadings
Vorherige Version der Listenermittlung per Userreading
Für die Funktionalität der Favoriten- / Playlisten- / Radioauswahl werden u.U. Userreadings benötigt, die die entsprechenden Listen ermitteln, und für die Verwendung im FTUI aufbereiten. Außerdem gibt es ein Userreading für die Anzeige der Position innerhalb des Titels. Dieses kann man selber mittels eines wiederkehrenden AT- oder DOIF-Befehls aktualisieren lassen (ich verwende dafür eine 15 Sekündige Aktualisierung mittels DOIF, solange eine Wiedergabe läuft).
Userreading an jedem Sonosplayer-Device:
Favourites:LastActionResult.*?GetFavouritesWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } }, Radios:LastActionResult.*?GetRadiosWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } }, Playlists:LastActionResult.*?GetPlaylistsWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } }, currentTrackPosition:LastActionResult.*?GetCurrentTrackPosition.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } }, currentTrackPositionSec:currentTrackPosition.* { return SONOS_GetTimeSeconds(ReadingsVal($name, "currentTrackPosition", "00:00:00")); }, currentTrackDurationSec:currentTrackDuration.* { return SONOS_GetTimeSeconds(ReadingsVal($name, "currentTrackDuration", "00:00:00")); }, FavouritesList:LastActionResult.*?GetFavourites:.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { my @list = map { $_ =~ s/ /./g; $_ } map { substr($_, 1, -1) } split(',', $1); return join('|', @list); } }, FavouritesListAlias:LastActionResult.*?GetFavourites:.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { my @list = map { substr($_, 1, -1) } split(',', $1); return join('|', @list); } }, currentFavouriteNameMasked:currentFavouriteName.* { my $favouriteName = ReadingsVal($name, "currentFavouriteName", ""); $favouriteName =~ s/ /\./g; return $favouriteName; }, PlaylistsList:LastActionResult.*?GetPlaylists:.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { my @list = map { $_ =~ s/ /./g; $_ } map { substr($_, 1, -1) } split(',', $1); return join('|', @list); } }, PlaylistsListAlias:LastActionResult.*?GetPlaylists:.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { my @list = map { substr($_, 1, -1) } split(',', $1); return join('|', @list); } }, currentPlaylistNameMasked:currentPlaylistName.* { my $name = ReadingsVal($name, "currentPlaylistName", ""); $name =~ s/ /\./g; return $name; }, RadiosList:LastActionResult.*?GetRadios:.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { my @list = map { $_ =~ s/ /./g; $_ } map { substr($_, 1, -1) } split(',', $1); return join('|', @list); } }, RadiosListAlias:LastActionResult.*?GetRadios:.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { my @list = map { substr($_, 1, -1) } split(',', $1); return join('|', @list); } }, currentRadioNameMasked:currentRadioName.* { my $name = ReadingsVal($name, "currentRadioName", ""); $name =~ s/ /\./g; return $name; }, currentFavouriteNameMasked:currentFavouriteName.* { my $favouriteName = ReadingsVal($name, "currentFavouriteName", ""); $favouriteName =~ s/ /\./g; return $favouriteName; }, currentPlaylistNameMasked:currentPlaylistName.* { my $name = ReadingsVal($name, "currentPlaylistName", ""); $name =~ s/ /\./g; return $name; }, currentRadioNameMasked:currentRadioName.* { my $name = ReadingsVal($name, "currentRadioName", ""); $name =~ s/ /\./g; return $name; }, ZoneGroupNameDetails:(MasterPlayer|roomName|SlavePlayer).* { my $result = ReadingsVal(ReadingsVal($name, 'MasterPlayer', $name), 'roomName', 'k.A.'); $result = '' if ($name eq ReadingsVal($name, 'MasterPlayer', $name)); foreach my $slave (@{eval(ReadingsVal($name, 'SlavePlayer', '[]'))}) { $result .= ' + '.ReadingsVal($slave, 'roomName', $slave); } return $result; }, SlavePlayerList:SlavePlayer:.* { my @player = @{eval(ReadingsVal($name, 'SlavePlayer', '[]'))}; return (scalar(@player) ? '-|' : '').join('|', @player); }, SlavePlayerListAlias:SlavePlayer:.* { my @player = @{eval(ReadingsVal($name, 'SlavePlayer', '[]'))}; return (scalar(@player) ? 'Auswahl|' : '').join('|', map { $_ = ReadingsVal($_, 'roomName', $_); $_ } @player); }, AvailablePlayerList:(MasterPlayer|SlavePlayer):.* { my @player = @{eval(ReadingsVal('Sonos', 'MasterPlayer', '[]'))}; # Selber entfernen... splice(@player, SONOS_posInList($name, @player), 1); # Slaveplayer entfernen... foreach my $elem (@{eval(ReadingsVal($name, 'SlavePlayer', '[]'))}) { my $pos = SONOS_posInList($elem, @player); splice(@player, $pos, 1) if ($pos >= 0); } return (scalar(@player) ? '-|' : '').join('|', @player); }, AvailablePlayerListAlias:(MasterPlayer|SlavePlayer):.* { my @player = @{eval(ReadingsVal('Sonos', 'MasterPlayer', '[]'))}; # Selber entfernen... splice(@player, SONOS_posInList($name, @player), 1); # Slaveplayer entfernen... foreach my $elem (@{eval(ReadingsVal($name, 'SlavePlayer', '[]'))}) { my $pos = SONOS_posInList($elem, @player); splice(@player, $pos, 1) if ($pos >= 0); } return (scalar(@player) ? 'Auswahl|' : '').join('|', map { $_ = ReadingsVal($_, 'roomName', $_); $_ } @player); }
Damit werden bei einem Abruf der Favoriten / Playlists / Radios mittels entsprechendem Get-Befehl die entsprechenden Listen für alle Features aufbereitet und am Sonosplayer-Device bereitgestellt.
Aktuelle Userreading
Mit der aktuellen Modulversion werden hierfür keinerlei Userreadings mehr benötigt.
Mit dem Attribute getListsDirectlyToReadings werden alle möglichen Listen zu Favoriten, Playlists, Radios und der aktuellen Abspielliste (= Queue) automatisch in die richtigen Readings geschrieben.
Des Weiteren kann man mit dem Attribut simulateCurrentTrackPosition eine Simulation der aktuellen Titelposition aktivieren, sodass eine wiederkehrende Aktualisierung durch ein DOIF o.ä. nicht mehr notwendig ist.
Automatische Aktualisierung der Favoriten / Playlisten / Radios durch Notifies
Mit den folgenden Notifies kann man auf die Mitteilung der Sonosplayer über eine neue Version der jeweiligen Liste reagieren, und diese im Playerdevice automatisch aktualisieren lassen. Damit hat man stets die aktuellen und zum Sonos-System passenden Listen in den Userreadings.
define Sonos_GetNewFavouritesNotify notify Sonos_[^_]+:FavouritesVersion.* { fhem("get $NAME FavouritesWithCovers");; fhem("get $NAME Favourites");; } define Sonos_GetNewPlaylistsNotify notify Sonos_[^_]+:PlaylistsVersion.* { fhem("get $NAME PlaylistsWithCovers");; fhem("get $NAME Playlists");; } define Sonos_GetNewRadiosNotify notify Sonos_[^_]+:RadiosVersion.* { fhem("get $NAME RadiosWithCovers");; fhem("get $NAME Radios");; } define Sonos_GetNewQueueNotify notify Sonos_[^_]+:QueueVersion.* { fhem("get $NAME QueueWithCovers");; fhem("get $NAME Queue");; }