Sonos2mqtt: Unterschied zwischen den Versionen

Aus FHEMWiki
(→‎Befehle nachrüsten: Sprachausgabe umgebaut und auf sayText erweitert)
K (Forenlinks auf Wiki-Vorlage geändert; Quelltext leicht umformatiert; Kategorie ergänzt; diverse kleine Korrekturen)
Zeile 8: Zeile 8:
== Tipps zur Verwendung ==
== Tipps zur Verwendung ==
Die automatische Konfiguration setzt den alias entsprechend dem Namen im Sonos vergeben. Die langen MQTT2_RINCON_ Namen sind unhandlich und schlecht lesbar. Man kann Player mit einem devspec ansprechen, das simpelste ist:
Die automatische Konfiguration setzt den alias entsprechend dem Namen im Sonos vergeben. Die langen MQTT2_RINCON_ Namen sind unhandlich und schlecht lesbar. Man kann Player mit einem devspec ansprechen, das simpelste ist:
 
:<code>set alias=Büro play</code>
set alias=Büro play
 
Oder alle Player
Oder alle Player
 
:<code>set model=sonos2mqtt_speaker leaveGroup</code>
set model=sonos2mqtt_speaker leaveGroup


== Ansicht der Player ==
== Ansicht der Player ==
Im Template wird nur ein simples devStateIcon ausgeliefert. Dort kann man sehr viel mehr reinpacken. Hier mal die aktuelle Arbeitsvariante zum nachrüsten in der [[Import von Code Snippets|Raw Definition]]:<syntaxhighlight lang="perl">
Im Template wird nur ein simples [[devStateIcon]] ausgeliefert. Dort kann man sehr viel mehr reinpacken. Hier mal die aktuelle Arbeitsvariante zum nachrüsten in der [[Import von Code Snippets|Raw Definition]]:
<syntaxhighlight lang="perl">
attr a:model=sonos2mqtt_speaker devStateIcon {\
attr a:model=sonos2mqtt_speaker devStateIcon {\
my $wpix = '250px';;\
my $wpix = '250px';;\
Zeile 99: Zeile 97:
Um Befehle nicht manuell in die setList / readingList Einträge jedes Players machen zu müssen, wird diese Routine verwendet.  
Um Befehle nicht manuell in die setList / readingList Einträge jedes Players machen zu müssen, wird diese Routine verwendet.  


Der Code ist für die Raw Definition gedacht. Die ersten drei Zeilen sind jeweils anzupassen!  
Der Code ist für die [[Raw definition]] gedacht. Die ersten drei Zeilen sind jeweils anzupassen!  


Hier im Beispiel wird der setter für den folgenden Speak Befehl eingefügt bzw. ersetzt. <syntaxhighlight lang="perl">
Hier im Beispiel wird der setter für den folgenden Speak Befehl eingefügt bzw. ersetzt. <syntaxhighlight lang="perl">
Zeile 115: Zeile 113:
  return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
  return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
}
}
</syntaxhighlight>Vorhandenen Zeilen werden ersetzt. Identifiziert wird nur der erste Teil.  
</syntaxhighlight>
Vorhandenen Zeilen werden ersetzt. Identifiziert wird nur der erste Teil.  


== Sprachausgabe ==
== Sprachausgabe ==
Man hat zwei Möglichkeiten dies umzusetzen:  
Man hat zwei Möglichkeiten, dies umzusetzen:  
# Text2Speech FHEM intern
# Text2Speech FHEM intern
# Mit dem sonos text to speech Server https://svrooij.io/sonos2mqtt/
# Mit dem sonos text to speech Server https://svrooij.io/sonos2mqtt/


=== Text2Speech Variante einrichten ===
=== Text2Speech Variante einrichten ===
Zeile 128: Zeile 127:
'''Hinweis''': Für die vollständige Funktion und Installation von Text2Speech ist die Commandref zu beachten! Für das unten im Beispiel verwendete Feature UseMP3Wrap muss das Tool mp3wrap installiert werden (z.B. <code>apt install mp3wrap</code>). Dies ist bei längeren Texten und bei der Verwendung von eingebetteten festen Sounds existenziell!
'''Hinweis''': Für die vollständige Funktion und Installation von Text2Speech ist die Commandref zu beachten! Für das unten im Beispiel verwendete Feature UseMP3Wrap muss das Tool mp3wrap installiert werden (z.B. <code>apt install mp3wrap</code>). Dies ist bei längeren Texten und bei der Verwendung von eingebetteten festen Sounds existenziell!


Für die Funktion ist wichtig, dass das Sonos System den Host im Link zur Datei richtig auflösen kann. Deshalb wird der Hostname und Port des Servers im Reading host des TTS Device als Name oder IP Adresse abgelegt! Dies kann entweder mit dem hier gezeigten Befehl oder vollständig manuell erfolgen. Für FHEM innerhalb Docker muss man die Adresse des Docker Host angeben.<syntaxhighlight lang="perl">
Für die Funktion ist wichtig, dass das Sonos System den Host im Link zur Datei richtig auflösen kann. Deshalb wird der Hostname und Port des Servers im Reading host des TTS Device als Name oder IP Adresse abgelegt! Dies kann entweder mit dem hier gezeigten Befehl oder vollständig manuell erfolgen. Für FHEM innerhalb Docker muss man die Adresse des Docker Host angeben.
<syntaxhighlight lang="perl">
defmod SonosTTS Text2Speech none
defmod SonosTTS Text2Speech none
attr SonosTTS TTS_UseMP3Wrap 1
attr SonosTTS TTS_UseMP3Wrap 1
Zeile 139: Zeile 139:


defmod SonosSpeakWeb HTTPSRV cache cache SonosSpeakWeb
defmod SonosSpeakWeb HTTPSRV cache cache SonosSpeakWeb
</syntaxhighlight>Der Sprachausgabe Befehle im Player Device läuft in 3 Schritten:
</syntaxhighlight>
Der Sprachausgabe Befehle im Player Device läuft in 3 Schritten:
# mit dem TTS Gerät wird die mp3 Datei erzeugt,
# mit dem TTS Gerät wird die mp3 Datei erzeugt,
# mit dem sleep wird auf die Fertigstellung gewartet,
# mit dem sleep wird auf die Fertigstellung gewartet,
# die Datei wird mit set Player notify volume uri abgespielt.
# die Datei wird mit <code>set Player notify volume uri</code> abgespielt.
Durch den "sonos2mqtt notify" Befehl wird die laufende Umgebung wiederhergestellt.
Durch den "sonos2mqtt notify" Befehl wird die laufende Umgebung wiederhergestellt.
* Wird der Sprach Befehl an den Gruppenmaster gesendet wird die mp3 Datei in der gesamten Gruppe gespielt.  
* Wird der Sprachbefehl an den Gruppenmaster gesendet wird die mp3 Datei in der gesamten Gruppe gespielt.  
* Wird der Sprach Befehl an ein Mitglied einer Gruppe gesendet (nicht den Master) wird die Gruppe aufgetrennt und später wieder hergestellt.
* Wird der Sprachbefehl an ein Mitglied einer Gruppe gesendet (nicht den Master) wird die Gruppe aufgetrennt und später wieder hergestellt.
''Im derzeitigen attrTemplate steht beim notify Befehl "timeout":10 drin. Sollte die Sprachausgabe immer mal abbrechen kann man diesen Wert erhöhen (100).''  
''Im derzeitigen attrTemplate steht beim [[notify]] Befehl "timeout":10 drin. Sollte die Sprachausgabe immer mal abbrechen, kann man diesen Wert erhöhen (100).''  


=== sayText Befehl ===
=== sayText Befehl ===
Dieser Befehl orientiert sich an den FHEM [[DevelopmentGuidelinesAV|DevelopmentGuidelines]] und sammelt "gleichzeitig" eintreffende Sprachnachrichten damit nichts verloren geht. Abschnitt im Thread dazu [https://forum.fhem.de/index.php/topic,111711.msg1100112.html#msg1100112]
Dieser Befehl orientiert sich an den FHEM [[DevelopmentGuidelinesAV|DevelopmentGuidelines]] und sammelt "gleichzeitig" eintreffende Sprachnachrichten, damit nichts verloren geht. Informationen im Forum dazu in {{Link2Forum|Topic=111711|Message=1100112|LinkText=diesem Beitrag}}.


Die Lautstärke wird separat in SonosTTS gesetzt: <code>setreading SonosTTS vol 15</code> ebenso die Sprache (einmalig bei der Einrichtung oder bei Bedarf zwischendurch) <code>attr SonosTTS TTS_Language Deutsch</code>  
Die Lautstärke wird separat in SonosTTS gesetzt: <code>setreading SonosTTS vol 15</code>ebenso die Sprache (einmalig bei der Einrichtung oder bei Bedarf zwischendurch) <code>attr SonosTTS TTS_Language Deutsch</code>  


''Hinweis: Der Befehl set SonosTTS volume xx hat im Servermodus des Devices keine Wirkung!''  
''Hinweis: Der Befehl <code>set SonosTTS volume xx</code> hat im Servermodus des Devices keine Wirkung!''  


Der Befehl selbst ist eine Erweiterung der setList im MQTT2 Player Device sieht wie folgt aus. Man kann den Befehl einfach bei allen Playern mit dem obigen [[Sonos2mqtt#Befehle nachr.C3.BCsten|Codeschnipsel]] nachrüsten ( ; vorher verdoppeln). <syntaxhighlight lang="perl">
Der Befehl selbst ist eine Erweiterung der setList im MQTT2 Player Device und sieht wie folgt aus. Man kann den Befehl einfach bei allen Playern mit dem obigen [[Sonos2mqtt#Befehle nachr.C3.BCsten|Codeschnipsel]] nachrüsten ( ; vorher verdoppeln).  
<syntaxhighlight lang="perl">
sayText:textField { my $tts=ReadingsVal('SonosBridge','tts','SonosTTS');my ($cmd,$text)=split(' ', $EVENT,2);fhem("setreading $tts text ".ReadingsVal($tts,'text',' ').' '.$text.";sleep 0.4 tts;set $tts tts [$tts:text];sleep $tts:playing:.0 ;set $NAME notify [$tts:vol] [$tts:httpName];deletereading $tts text")}
sayText:textField { my $tts=ReadingsVal('SonosBridge','tts','SonosTTS');my ($cmd,$text)=split(' ', $EVENT,2);fhem("setreading $tts text ".ReadingsVal($tts,'text',' ').' '.$text.";sleep 0.4 tts;set $tts tts [$tts:text];sleep $tts:playing:.0 ;set $NAME notify [$tts:vol] [$tts:httpName];deletereading $tts text")}
</syntaxhighlight>
</syntaxhighlight>


=== Speak Befehl ===
=== Speak Befehl ===
Verwendet wird ein Befehl ähnlich wie in der Sonos Umgebung:
Verwendet wird ein Befehl ähnlich wie in der Sonos Umgebung:
:<code>set Player speak <volume> text</code>


set Player speak <volume> text
Die Erweiterung der setList im MQTT2 Player Device sieht wie folgt aus. Man kann den Befehl einfach bei allen Playern mit dem obigen [[Sonos2mqtt#Befehle nachr.C3.BCsten|Codeschnipsel]] nachrüsten.
 
<syntaxhighlight lang="perl">
Die Erweiterung der setList im MQTT2 Player Device sieht wie folgt aus. Man kann den Befehl einfach bei allen Playern mit dem obigen [[Sonos2mqtt#Befehle nachr.C3.BCsten|Codeschnipsel]] nachrüsten.<syntaxhighlight lang="perl">
speak:textField { my $tts="SonosTTS";my ($cmd,$vol,$text)=split(' ', $EVENT,3);fhem("set $tts tts $text;sleep $tts:playing:.0 ;set $NAME notify $vol [$tts:httpName]")}
speak:textField { my $tts="SonosTTS";my ($cmd,$vol,$text)=split(' ', $EVENT,3);fhem("set $tts tts $text;sleep $tts:playing:.0 ;set $NAME notify $vol [$tts:httpName]")}
</syntaxhighlight>Will man keine laufenden Sendung unterbrechen sondern einfach eine Ansage machen und danach etwas starten, kann man so vorgehen:<syntaxhighlight lang="perl">
</syntaxhighlight>
Will man keine laufenden Sendung unterbrechen sondern einfach eine Ansage machen und danach etwas starten, kann man so vorgehen:
<syntaxhighlight lang="perl">
set SonosTTS tts Hier steht die Ansage;sleep SonosTTS:playing:.0 ; set alias=PlayerAlias playUri [SonosTTS:httpName]
set SonosTTS tts Hier steht die Ansage;sleep SonosTTS:playing:.0 ; set alias=PlayerAlias playUri [SonosTTS:httpName]
</syntaxhighlight>
</syntaxhighlight>
Zeile 174: Zeile 177:
Generell kann man feste mp3 Dateien (Klingeltöne, Klänge usw.) auch im cache Verzeichnis ablegen und direkt mit dem Link starten.  
Generell kann man feste mp3 Dateien (Klingeltöne, Klänge usw.) auch im cache Verzeichnis ablegen und direkt mit dem Link starten.  


Es gibt zahlreiche Soundquellen im Internet, ist der gewünschte Sound dabei kann man ihn innerhalb FHEM herunterladen und an Ort und Stelle platzieren. (Beispiel ohne und mit Umbennung)<syntaxhighlight lang="perl">
Es gibt zahlreiche Soundquellen im Internet, ist der gewünschte Sound dabei, kann man ihn innerhalb FHEM herunterladen und an Ort und Stelle platzieren. (Beispiel ohne und mit Umbennung)
<syntaxhighlight lang="perl">
"wget -qP ./cache https://cdn.smartersoft-group.com/various/pull-bell-short.mp3"
"wget -qP ./cache https://cdn.smartersoft-group.com/various/pull-bell-short.mp3"
"wget -qO ./cache/KlingelTon.mp3 https://cdn.smartersoft-group.com/various/pull-bell-short.mp3"
"wget -qO ./cache/KlingelTon.mp3 https://cdn.smartersoft-group.com/various/pull-bell-short.mp3"
</syntaxhighlight>Vergewissern ob der gewünschte Sound auch da ist: {qx(ls -lha ./cache)}
</syntaxhighlight>
Vergewissern ob der gewünschte Sound auch da ist: {qx(ls -lha ./cache)}


Mit set magic kann man dabei einfach Teile aus anderen Readings holen.<syntaxhighlight lang="perl">
Mit set magic kann man dabei einfach Teile aus anderen Readings holen.
<syntaxhighlight lang="perl">
set alias=Büro notify 25 {('http://[SonosTTS:host]/fhem/cache/KlingelTon.mp3')}
set alias=Büro notify 25 {('http://[SonosTTS:host]/fhem/cache/KlingelTon.mp3')}
</syntaxhighlight>Man kann auch den setter im Gerät erweitern:<syntaxhighlight lang="perl">
</syntaxhighlight>
Man kann auch den setter im Gerät erweitern:
<syntaxhighlight lang="perl">
playSound:textField {my $tts="SonosTTS";my ($cmd,$vol,$file)=split(' ', $EVENT,3);$file=($file=~m/.*\.mp3$/)?"$file":"$file.mp3";fhem("set $NAME notify $vol http://[$tts:host]/fhem/[a:$tts:TTS_CacheFileDir]/$file")}
playSound:textField {my $tts="SonosTTS";my ($cmd,$vol,$file)=split(' ', $EVENT,3);$file=($file=~m/.*\.mp3$/)?"$file":"$file.mp3";fhem("set $NAME notify $vol http://[$tts:host]/fhem/[a:$tts:TTS_CacheFileDir]/$file")}
</syntaxhighlight>Damit sind dann dieser Syntax möglich:<syntaxhighlight lang="perl">
</syntaxhighlight>
Damit sind dann dieser Syntax möglich:
<syntaxhighlight lang="perl">
set alias=Büro playSound 40 KlingelTon.mp3
set alias=Büro playSound 40 KlingelTon.mp3
</syntaxhighlight>oder ohne Dateiendung (wird auf mp3 gesetzt)<syntaxhighlight lang="perl">
</syntaxhighlight>
oder ohne Dateiendung (wird auf mp3 gesetzt)
<syntaxhighlight lang="perl">
set alias=Büro playSound 40 KlingelTon
set alias=Büro playSound 40 KlingelTon
</syntaxhighlight>
</syntaxhighlight>


=== SonosBridge aufrüsten ===
=== SonosBridge aufrüsten ===
Einige zentrale Dinge sind im SonosBridge Device gut aufgehoben. Seit der Beta 3.1.0-beta.1 ist es möglich die Sonos Umgebung zu aktualisieren ohne sonos2mqtt neu starten zu müssen.
Einige zentrale Dinge sind im SonosBridge Device gut aufgehoben. Seit der Version 3.1.0-beta.1 ist es möglich, die Sonos Umgebung zu aktualisieren ohne sonos2mqtt neu starten zu müssen.


Die setList stattet die Bridge mit der Möglichkeit aus alle Player zu stoppen und die Umgebung neu einzulesen (das ist nützlich wenn man Player on/off betreibt)<syntaxhighlight lang="perl">
Die setList stattet die Bridge mit der Möglichkeit aus, alle Player zu stoppen und die Umgebung neu einzulesen (das ist nützlich wenn man Player on/off betreibt).
<syntaxhighlight lang="perl">
PauseAll:noArg sonos/cmd/pauseall
PauseAll:noArg sonos/cmd/pauseall
CheckSubscription:noArg sonos/cmd/check-subscriptions
CheckSubscription:noArg sonos/cmd/check-subscriptions
</syntaxhighlight>Die Favoritenliste kann einmal zentral in der SonosBridge abgelegt werden. Dazu müssen wird dort die readingList ergänzen.<syntaxhighlight lang="perl">
</syntaxhighlight>
  sonos/RINCON_([0-9A-Z]+)/Favorites:.* Favorites
Die Favoritenliste kann einmal zentral in der SonosBridge abgelegt werden. Dazu müssen wird dort die readingList ergänzen.
</syntaxhighlight>Für eine einfache Abholung der aktuellen Favoriten kann der SonosBridge eine getList spendiert werden, man muss dazu einen Player eintragen (RINCON_).<syntaxhighlight lang="perl">
<syntaxhighlight lang="perl">
sonos/RINCON_([0-9A-Z]+)/Favorites:.* Favorites
</syntaxhighlight>
Für eine einfache Abholung der aktuellen Favoriten kann der SonosBridge eine getList spendiert werden, man muss dazu einen Player eintragen (RINCON_).
<syntaxhighlight lang="perl">
Favorites:noArg Favorites sonos/RINCON_XXXXXXXXXXXXX/control {"command": "adv-command","input": {"cmd": "GetFavorites","reply": "Favorites"}}
Favorites:noArg Favorites sonos/RINCON_XXXXXXXXXXXXX/control {"command": "adv-command","input": {"cmd": "GetFavorites","reply": "Favorites"}}
</syntaxhighlight>ToDo: Code straffen und setList mit einbauen.
</syntaxhighlight>
ToDo: Code straffen und setList mit einbauen.


Wer das nicht per Hand machen will hier zwei Codeblöcke für die Raw Definition:<syntaxhighlight lang="perl">
Wer das nicht per Hand machen will hier zwei Codeblöcke für die Raw Definition:<syntaxhighlight lang="perl">
Zeile 215: Zeile 233:
  return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
  return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
}
}
</syntaxhighlight>Achtung dieser Code schreibt eine neue getList in die SonosBridge, zum Ergänzen müsste der Code analog der bisherigen Beispiele verändert werden.<syntaxhighlight lang="perl">
</syntaxhighlight>
Achtung: dieser Code schreibt eine neue getList in die SonosBridge, zum Ergänzen müsste der Code analog der bisherigen Beispiele verändert werden.
<syntaxhighlight lang="perl">
{my @devlist2 = devspec2array('MQTT2_RINCON_.*');;\
{my @devlist2 = devspec2array('MQTT2_RINCON_.*');;\
  my @arr2;;\
  my @arr2;;\
Zeile 227: Zeile 247:
Wenn nicht schon geschehen muss man jetzt die Favoriten zum ersten Mal einlesen: get SonosBridge Favorites
Wenn nicht schon geschehen muss man jetzt die Favoriten zum ersten Mal einlesen: get SonosBridge Favorites


Nachdem die SonosBridge "aufgerüstet" ist kann man allen Playern die Favoritenliste zum Auswählen eintragen. Dieser Code ist etwas umfangreicher und wieder ein "Script" für die Raw Def.<syntaxhighlight lang="perl">
Nachdem die SonosBridge "aufgerüstet" ist kann man allen Playern die Favoritenliste zum Auswählen eintragen. Dieser Code ist etwas umfangreicher und wieder ein "Script" für die Raw Def.
<syntaxhighlight lang="perl">
{use JSON;;use HTML::Entities;;use Encode qw(encode decode);;\
{use JSON;;use HTML::Entities;;use Encode qw(encode decode);;\
  my $enc = 'UTF8';;\
  my $enc = 'UTF8';;\
Zeile 254: Zeile 275:
  return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
  return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
}
}
</syntaxhighlight>Der erste Teil des Codes erzeugt aus den Favoriten ein Komma separierte, sortierte Liste der Titel und ersetzt die Leerzeichen durch Punkte. Damit eignet sich diese Liste für die Auswahlbox. Dies wird als Ergänzung der setList im zweiten Teil des Codes erzeugt und bei allen Playern eingetragen.
</syntaxhighlight>
Der erste Teil des Codes erzeugt aus den Favoriten ein Komma separierte, sortierte Liste der Titel und ersetzt die Leerzeichen durch Punkte. Damit eignet sich diese Liste für die Auswahlbox. Dies wird als Ergänzung der setList im zweiten Teil des Codes erzeugt und bei allen Playern eingetragen.


Man kann den playFav Befehl auch mit im set Befehl mit einem Teil des Favoriten Namen verwenden. Enthält die Favoritenliste z.B. Radio Leipzig würde der auch mit diesem Befehl angesteuert werden:<syntaxhighlight lang="perl">
Man kann den playFav Befehl auch im set Befehl mit einem Teil des Favoriten Namen verwenden. Enthält die Favoritenliste z.B. Radio Leipzig würde der auch mit diesem Befehl angesteuert werden:
<syntaxhighlight lang="perl">
set alias=Bad playFav leipzig
set alias=Bad playFav leipzig
</syntaxhighlight>
</syntaxhighlight>
Zeile 263: Zeile 286:
Will man eine Liste von bestimmten Radiostation mit einem Taster "durchtasten" kann man das wie folgt tun:
Will man eine Liste von bestimmten Radiostation mit einem Taster "durchtasten" kann man das wie folgt tun:


Eigene Radio Liste in ein Reading schreiben (Die Namen müssen zumindest in Teilen mit den Favoriten Titeln übereinstimmen)<syntaxhighlight lang="perl">
Eigene Radio Liste in ein Reading schreiben (Die Namen müssen zumindest in Teilen mit den Favoriten Titeln übereinstimmen)
<syntaxhighlight lang="perl">
setreading model=sonos2mqtt_bridge favRadios Deutschlandfunk Kultur,Radio Leipzig,Radio Station 3  
setreading model=sonos2mqtt_bridge favRadios Deutschlandfunk Kultur,Radio Leipzig,Radio Station 3  
</syntaxhighlight>Der Befehl zum weiterschalten. Jedesmal wenn dieser Befehl ausgeführt wird, wird der nächste Favorit gestartet.<syntaxhighlight lang="perl">
</syntaxhighlight>
Der Befehl zum weiterschalten. Jedesmal wenn dieser Befehl ausgeführt wird, wird der nächste Favorit gestartet.
<syntaxhighlight lang="perl">
set alias=Arbeitszimmer playFav {(my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];;Each($dev,ReadingsVal($dev,'favRadios','')))}
set alias=Arbeitszimmer playFav {(my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];;Each($dev,ReadingsVal($dev,'favRadios','')))}
</syntaxhighlight>
</syntaxhighlight>
Zeile 271: Zeile 297:
Will man vor dem Radiostart noch die Ansage des Senders haben, geht das zwar auch mit dem speak Befehl, die direkte Ausgabe ohne Restore der Umgebung (sonos2mqtt notify) ist aber effektiver.
Will man vor dem Radiostart noch die Ansage des Senders haben, geht das zwar auch mit dem speak Befehl, die direkte Ausgabe ohne Restore der Umgebung (sonos2mqtt notify) ist aber effektiver.


Damit das funktioniert müssen wir die Events einschränken: <syntaxhighlight lang="perl">
Damit das funktioniert müssen wir die Events einschränken:  
<syntaxhighlight lang="perl">
attr model=sonos2mqtt_speaker event-on-change-reading .*
attr model=sonos2mqtt_speaker event-on-change-reading .*
{my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];;my $r=Each($dev,ReadingsVal($dev,'favRadios',''));;my $play = (devspec2array('alias=Büro'))[0];;my $tts="SonosTTS";;fhem("set $tts tts Es folgt $r;;sleep $tts:playing:.0;;set $play playUri [$tts:httpName];;sleep $play:play;;sleep $play:PLAYING;;sleep $play:STOPPED;;set $play playFav $r")}
{my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];;my $r=Each($dev,ReadingsVal($dev,'favRadios',''));;my $play = (devspec2array('alias=Büro'))[0];;my $tts="SonosTTS";;fhem("set $tts tts Es folgt $r;;sleep $tts:playing:.0;;set $play playUri [$tts:httpName];;sleep $play:play;;sleep $play:PLAYING;;sleep $play:STOPPED;;set $play playFav $r")}
</syntaxhighlight>Kurze Erklärung zum Code  
</syntaxhighlight>
Kurze Erklärung zum Code  
* ermittelt den nächsten Radiosender in der Liste,
* ermittelt den nächsten Radiosender in der Liste,
* erzeugt die Ansage "Es folgt SenderXY",
* erzeugt die Ansage "Es folgt SenderXY",
Zeile 280: Zeile 308:
* es wird eine Eventfolge abgewartet -> play / PLAYING / STOPPED,
* es wird eine Eventfolge abgewartet -> play / PLAYING / STOPPED,
* danach wird der Radiosender gestartet.
* danach wird der Radiosender gestartet.
Der Code ist so einfach und relativ "steif" für die Kommandozeile. Man kann das auch in einen Setter packen:<syntaxhighlight lang="perl">
Der Code ist so einfach und relativ "steif" für die Kommandozeile. Man kann das auch in einen Setter packen:
<syntaxhighlight lang="perl">
toggleRadio:noArg {my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];my $r=Each($dev,ReadingsVal($dev,'favRadios',''));my $tts="SonosTTS";fhem("set $tts tts Es folgt $r;sleep $tts:playing:.0;set $NAME playUri [$tts:httpName];sleep $NAME:play;sleep $NAME:PLAYING;sleep $NAME:STOPPED;set $NAME playFav $r")}
toggleRadio:noArg {my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];my $r=Each($dev,ReadingsVal($dev,'favRadios',''));my $tts="SonosTTS";fhem("set $tts tts Es folgt $r;sleep $tts:playing:.0;set $NAME playUri [$tts:httpName];sleep $NAME:play;sleep $NAME:PLAYING;sleep $NAME:STOPPED;set $NAME playFav $r")}
</syntaxhighlight>
</syntaxhighlight>
Zeile 286: Zeile 315:
== Dokumentationen und weitere Entwicklungen ==
== Dokumentationen und weitere Entwicklungen ==
ToDo
ToDo
[[Kategorie:MQTT]]

Version vom 18. Februar 2021, 12:00 Uhr

Grundeinrichtung

Die Grundeinrichtung ist bereits im Artikel MQTT2-Module - Praxisbeispiele beschrieben. Hier soll es um die praktische Verwendung und Erweiterung gehen.

Für alle Erweiterungen wird versucht vorhandene Devices in FHEM zu verwenden.

Viele Dinge werden derzeit noch entwickelt und können frei gestaltet werden - der Vorteil von generischen FHEM Devices.

Tipps zur Verwendung

Die automatische Konfiguration setzt den alias entsprechend dem Namen im Sonos vergeben. Die langen MQTT2_RINCON_ Namen sind unhandlich und schlecht lesbar. Man kann Player mit einem devspec ansprechen, das simpelste ist:

set alias=Büro play

Oder alle Player

set model=sonos2mqtt_speaker leaveGroup

Ansicht der Player

Im Template wird nur ein simples devStateIcon ausgeliefert. Dort kann man sehr viel mehr reinpacken. Hier mal die aktuelle Arbeitsvariante zum nachrüsten in der Raw Definition:

attr a:model=sonos2mqtt_speaker devStateIcon {\
my $wpix = '250px';;\
my $groupname = ReadingsVal($name,'groupName','0');;\
my $sgroupname = (split(' ',ReadingsVal($name,'groupName','')))[0];;\
my $uuidtoname = (devspec2array('DEF='.ReadingsVal($name,'coordinatorUuid','0')))[0];;\
my $vol = ReadingsVal($name,'volume','');;\
my $img = ReadingsVal($name,'currentTrack_AlbumArtUri','');;\
my $mystate = $name eq $uuidtoname \
  ? ReadingsVal($name,'state','FEHLER') : ReadingsVal($uuidtoname,'state','');;\
my $playpic = $mystate eq 'PLAYING'\
  ? 'rc_PAUSE@red'    : $mystate eq 'PAUSED_PLAYBACK'\
  ? 'rc_PLAY@green'   : $mystate eq 'STOPPED'\
  ? 'rc_PLAY@green'   : $mystate eq 'TRANSITIONING'\
  ? 'rc_PLAY@blue'    : $mystate eq 'set_next'\
  ? 'rc_NEXT@blue'    : $mystate eq 'set_previous'\
  ? 'rc_PREVIOUS@blue': $mystate eq 'set_volumeUp'\
  ? 'rc_VOLUP@blue'   : $mystate eq 'set_volumeDown'\
  ? 'rc_VOLDOWN@blue' : $mystate eq 'set_mute'\
  ? 'rc_MUTE@blue'    : 'rc_PLAY@yellow';;\
my $mutecmd = ReadingsVal($name,'mute','0') eq 'false'?'true':'false';;\
my $mutepic = $mutecmd eq 'on'?'rc_MUTE':'rc_VOLUP';;\
my $show = 'FEHLER';;\
my $currentTrack_Artist = ReadingsVal($name,'currentTrack_Artist','FEHLER');;\
my $currentTrack_Title = ReadingsVal($name,'currentTrack_Title','FEHLER');;\
if ($currentTrack_Title =~ 'x-sonosapi-stream:'){$currentTrack_Title=''};;\
my $currentTrack = $mystate eq 'TRANSITIONING'\
  ? 'Puffern...' : $currentTrack_Artist.' - '.$currentTrack_Title;;\
my $nextTrack_Artist = ReadingsVal($name,'nextTrack_Artist','FEHLER');;\
my $nextTrack_Title = ReadingsVal($name,'nextTrack_Title','FEHLER');;\
my $nextTrack = $nextTrack_Artist.' - '.$nextTrack_Title;;\
my $previouspic = 'rc_PREVIOUS';;\
my $nextpic = 'rc_NEXT';;\
my $voldownpic = 'rc_VOLDOWN';;\
my $voluppic = 'rc_VOLUP';;\
my $leavegrouppic = 'rc_LEFT';;\
my $showlg = ReadingsVal($name,"name","0") ne $groupname ? "<a href=\"/fhem?cmd.dummy=set $name leaveGroup&XHR=1\">".FW_makeImage($leavegrouppic)."</a>" : "";;\
if (($mystate eq 'PLAYING')\
  || ($mystate eq 'TRANSITIONING' )\
  || ($mystate eq 'set_next' )\
  || ($mystate eq 'set_previous' )\
  || ($mystate eq 'set_volumeUp' )\
  || ($mystate eq 'set_volumeDown' )\
  || ($mystate eq 'set_mute' )) { \
    my $shownp = ReadingsVal($name,'name','') eq $sgroupname \
    ? "<a href=\"/fhem?cmd.dummy=set $name previous&XHR=1\">".FW_makeImage($previouspic)."</a>\
       <a href=\"/fhem?cmd.dummy=set $name next&XHR=1\">".FW_makeImage($nextpic)."</a>" : "";;  \
    $show = "$showlg <a href=\"/fhem?cmd.dummy=set $name toggle&XHR=1\">".FW_makeImage($playpic)."</a>\
    <a href=\"/fhem?cmd.dummy=set $name volumeDown&XHR=1\">".FW_makeImage($voldownpic)."</a>\
    $shownp\
    <a href=\"/fhem?cmd.dummy=set $name volumeUp&XHR=1\">".FW_makeImage($voluppic)."</a>\
    &nbsp;;&nbsp;;&nbsp;;&nbsp;;\
    <a href=\"/fhem?cmd.dummy=set $name mute $mutecmd&XHR=1\">".FW_makeImage($mutepic)."</a><br>";;\
  \
    if (ReadingsVal($name,'name','') eq $sgroupname) {\
      $show = ReadingsVal($name,'currentTrack_TrackUri','') =~ 'spdif'\
      ? 'TV': ReadingsVal($name,'enqueuedMetadata_UpnpClass','FEHLER') ne 'object.item.audioItem.audioBroadcast'\
      ? "$show<marquee style='width: $wpix'>Aktueller Track: $currentTrack<br>Nächster Track: $nextTrack</marquee>"\
      : "$show<marquee style='width: $wpix'>Radio: $currentTrack</marquee>"\
    }\
    elsif (ReadingsVal($name,'name','') ne $groupname) {\
      $show = "$show Master: $sgroupname"}\
    }\
    else {\
      $show = $name eq $uuidtoname\
      ? "$showlg <a href=\"/fhem?cmd.dummy=set $name toggle&XHR=1\">".FW_makeImage($playpic)."</a>"\
      : "$showlg <a href=\"/fhem?cmd.dummy=set $name toggle&XHR=1\">".FW_makeImage($playpic)."</a><br>Master: $sgroupname"\
    }\
  "<div>\
   <table>\
     <tr>\
       <td><div style='display: inline-block;; margin-right: 5px;; border: 1px solid lightgray;;\
              height: 4.00em;; width: 4.00em;; background-image: url($img);; background-size: contain;;'></div></td>\
       <td>$show</td>\
     </tr>\
   </table>\
   </div>"\
}

Befehle nachrüsten

Um Befehle nicht manuell in die setList / readingList Einträge jedes Players machen zu müssen, wird diese Routine verwendet.

Der Code ist für die Raw definition gedacht. Die ersten drei Zeilen sind jeweils anzupassen!

Hier im Beispiel wird der setter für den folgenden Speak Befehl eingefügt bzw. ersetzt.

{my @devlist = devspec2array('MQTT2_RINCON_.*');;\
 my $attr = 'setList';;\
 my $item = q(  speak:textField { my $tts="SonosTTS";;my ($cmd,$vol,$text)=split(' ', $EVENT,3);;fhem("set $tts tts $text;;sleep $tts:playing:.0 ;;set $NAME notify $vol [$tts:httpName]")});;\
 my ($first,$sec)=split(' ',$item,2);;\
 $first=~s/^\s+//;;\
 foreach (@devlist) {\
   my @arr = grep {$_ !~ $first} split("\n",AttrVal($_,$attr,''));;\
   push @arr,$item;;\
   my $val = join "\n",@arr;;\
   $val =~ s/;;/;;;;/g;;\
   fhem("attr $_ $attr $val")}\
 return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
}

Vorhandenen Zeilen werden ersetzt. Identifiziert wird nur der erste Teil.

Sprachausgabe

Man hat zwei Möglichkeiten, dies umzusetzen:

  1. Text2Speech FHEM intern
  2. Mit dem sonos text to speech Server https://svrooij.io/sonos2mqtt/

Text2Speech Variante einrichten

Zwei zusätzliche Geräte sind notwendig:

  • Text2Speech im Servermodus, erzeugt mp3 Dateien im cache Verzeichnis und legt einen Link im Reading httpName ab.
  • Ein HTTP Server stellt die Dateien im gleichen Verzeichnis bereit

Hinweis: Für die vollständige Funktion und Installation von Text2Speech ist die Commandref zu beachten! Für das unten im Beispiel verwendete Feature UseMP3Wrap muss das Tool mp3wrap installiert werden (z.B. apt install mp3wrap). Dies ist bei längeren Texten und bei der Verwendung von eingebetteten festen Sounds existenziell!

Für die Funktion ist wichtig, dass das Sonos System den Host im Link zur Datei richtig auflösen kann. Deshalb wird der Hostname und Port des Servers im Reading host des TTS Device als Name oder IP Adresse abgelegt! Dies kann entweder mit dem hier gezeigten Befehl oder vollständig manuell erfolgen. Für FHEM innerhalb Docker muss man die Adresse des Docker Host angeben.

defmod SonosTTS Text2Speech none
attr SonosTTS TTS_UseMP3Wrap 1
attr SonosTTS TTS_Language Deutsch
attr SonosTTS userReadings httpName:lastFilename.* {'http://'.ReadingsVal($name,'host','set host:port first').'/fhem/'.ReadingsVal($name,'lastFilename','')}
attr SonosTTS TTS_CacheFileDir cache
setreading SonosTTS host {(qx(hostname -s|tr -d '\n').':'.InternalVal('WEB','PORT','8083'))}
#setreading SonosTTS host {((split(' ', qx(hostname -I)))[0].':'.InternalVal('WEB','PORT','8083'))}
#setreading SonosTTS host <hostname>:<port>

defmod SonosSpeakWeb HTTPSRV cache cache SonosSpeakWeb

Der Sprachausgabe Befehle im Player Device läuft in 3 Schritten:

  1. mit dem TTS Gerät wird die mp3 Datei erzeugt,
  2. mit dem sleep wird auf die Fertigstellung gewartet,
  3. die Datei wird mit set Player notify volume uri abgespielt.

Durch den "sonos2mqtt notify" Befehl wird die laufende Umgebung wiederhergestellt.

  • Wird der Sprachbefehl an den Gruppenmaster gesendet wird die mp3 Datei in der gesamten Gruppe gespielt.
  • Wird der Sprachbefehl an ein Mitglied einer Gruppe gesendet (nicht den Master) wird die Gruppe aufgetrennt und später wieder hergestellt.

Im derzeitigen attrTemplate steht beim notify Befehl "timeout":10 drin. Sollte die Sprachausgabe immer mal abbrechen, kann man diesen Wert erhöhen (100).

sayText Befehl

Dieser Befehl orientiert sich an den FHEM DevelopmentGuidelines und sammelt "gleichzeitig" eintreffende Sprachnachrichten, damit nichts verloren geht. Informationen im Forum dazu in diesem Beitrag.

Die Lautstärke wird separat in SonosTTS gesetzt: setreading SonosTTS vol 15, ebenso die Sprache (einmalig bei der Einrichtung oder bei Bedarf zwischendurch) attr SonosTTS TTS_Language Deutsch

Hinweis: Der Befehl set SonosTTS volume xx hat im Servermodus des Devices keine Wirkung!

Der Befehl selbst ist eine Erweiterung der setList im MQTT2 Player Device und sieht wie folgt aus. Man kann den Befehl einfach bei allen Playern mit dem obigen Codeschnipsel nachrüsten ( ; vorher verdoppeln).

sayText:textField { my $tts=ReadingsVal('SonosBridge','tts','SonosTTS');my ($cmd,$text)=split(' ', $EVENT,2);fhem("setreading $tts text ".ReadingsVal($tts,'text',' ').' '.$text.";sleep 0.4 tts;set $tts tts [$tts:text];sleep $tts:playing:.0 ;set $NAME notify [$tts:vol] [$tts:httpName];deletereading $tts text")}

Speak Befehl

Verwendet wird ein Befehl ähnlich wie in der Sonos Umgebung:

set Player speak <volume> text

Die Erweiterung der setList im MQTT2 Player Device sieht wie folgt aus. Man kann den Befehl einfach bei allen Playern mit dem obigen Codeschnipsel nachrüsten.

speak:textField { my $tts="SonosTTS";my ($cmd,$vol,$text)=split(' ', $EVENT,3);fhem("set $tts tts $text;sleep $tts:playing:.0 ;set $NAME notify $vol [$tts:httpName]")}

Will man keine laufenden Sendung unterbrechen sondern einfach eine Ansage machen und danach etwas starten, kann man so vorgehen:

set SonosTTS tts Hier steht die Ansage;sleep SonosTTS:playing:.0 ; set alias=PlayerAlias playUri [SonosTTS:httpName]

Spiele feste Sounds

Generell kann man feste mp3 Dateien (Klingeltöne, Klänge usw.) auch im cache Verzeichnis ablegen und direkt mit dem Link starten.

Es gibt zahlreiche Soundquellen im Internet, ist der gewünschte Sound dabei, kann man ihn innerhalb FHEM herunterladen und an Ort und Stelle platzieren. (Beispiel ohne und mit Umbennung)

"wget -qP ./cache https://cdn.smartersoft-group.com/various/pull-bell-short.mp3"
"wget -qO ./cache/KlingelTon.mp3 https://cdn.smartersoft-group.com/various/pull-bell-short.mp3"

Vergewissern ob der gewünschte Sound auch da ist: {qx(ls -lha ./cache)}

Mit set magic kann man dabei einfach Teile aus anderen Readings holen.

set alias=Büro notify 25 {('http://[SonosTTS:host]/fhem/cache/KlingelTon.mp3')}

Man kann auch den setter im Gerät erweitern:

playSound:textField {my $tts="SonosTTS";my ($cmd,$vol,$file)=split(' ', $EVENT,3);$file=($file=~m/.*\.mp3$/)?"$file":"$file.mp3";fhem("set $NAME notify $vol http://[$tts:host]/fhem/[a:$tts:TTS_CacheFileDir]/$file")}

Damit sind dann dieser Syntax möglich:

set alias=Büro playSound 40 KlingelTon.mp3

oder ohne Dateiendung (wird auf mp3 gesetzt)

set alias=Büro playSound 40 KlingelTon

SonosBridge aufrüsten

Einige zentrale Dinge sind im SonosBridge Device gut aufgehoben. Seit der Version 3.1.0-beta.1 ist es möglich, die Sonos Umgebung zu aktualisieren ohne sonos2mqtt neu starten zu müssen.

Die setList stattet die Bridge mit der Möglichkeit aus, alle Player zu stoppen und die Umgebung neu einzulesen (das ist nützlich wenn man Player on/off betreibt).

PauseAll:noArg sonos/cmd/pauseall
CheckSubscription:noArg sonos/cmd/check-subscriptions

Die Favoritenliste kann einmal zentral in der SonosBridge abgelegt werden. Dazu müssen wird dort die readingList ergänzen.

 sonos/RINCON_([0-9A-Z]+)/Favorites:.* Favorites

Für eine einfache Abholung der aktuellen Favoriten kann der SonosBridge eine getList spendiert werden, man muss dazu einen Player eintragen (RINCON_).

Favorites:noArg Favorites sonos/RINCON_XXXXXXXXXXXXX/control {"command": "adv-command","input": {"cmd": "GetFavorites","reply": "Favorites"}}

ToDo: Code straffen und setList mit einbauen.

Wer das nicht per Hand machen will hier zwei Codeblöcke für die Raw Definition:

{my @devlist = devspec2array('model=sonos2mqtt_bridge');;\
 my $attr = 'readingList';;\
 my $item = q(  sonos/RINCON_([0-9A-Z]+)/Favorites:.* Favorites);;\
 my ($first,$sec)=split(' ',$item,2);;\
 $first=~s/^\s+//;;\
 foreach (@devlist) {\
   my @arr = grep {$_ !~ $first} split("\n",AttrVal($_,$attr,''));;\
   push @arr,$item;;\
   my $val = join "\n",@arr;;\
   $val =~ s/;;/;;;;/g;;\
   fhem("attr $_ $attr $val")}\
 return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
}

Achtung: dieser Code schreibt eine neue getList in die SonosBridge, zum Ergänzen müsste der Code analog der bisherigen Beispiele verändert werden.

{my @devlist2 = devspec2array('MQTT2_RINCON_.*');;\
 my @arr2;;\
 foreach (@devlist2) {push @arr2,InternalVal($_,'DEF','')};;\
 my $item= q(Favorites:noArg Favorites sonos/).$arr2[int(rand(@arr2))].q(/control  {"command": "adv-command","input": {"cmd": "GetFavorites","reply": "Favorites"}});;\
 fhem("attr model=sonos2mqtt_bridge getList $item")\
}

Player mit Favoritenliste ausstatten

Wenn nicht schon geschehen muss man jetzt die Favoriten zum ersten Mal einlesen: get SonosBridge Favorites

Nachdem die SonosBridge "aufgerüstet" ist kann man allen Playern die Favoritenliste zum Auswählen eintragen. Dieser Code ist etwas umfangreicher und wieder ein "Script" für die Raw Def.

{use JSON;;use HTML::Entities;;use Encode qw(encode decode);;\
 my $enc = 'UTF8';;\
 my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];;\
 my $read = 'Favorites';;\
 my $decoded = decode_json(ReadingsVal($dev,$read,''));;\
 my @arr  = @{$decoded->{'Result'}};;\
 my @out;;\
 foreach (@arr) {\
   my $dec=encode($enc, decode_entities($_->{'Title'}));;\
   $dec =~ s/\s/./g;;\
   push @out,$dec}\
 my $favliste= join ',', sort @out;;\
 \
 my @devlist = devspec2array('MQTT2_RINCON_.*');;\
 my $attr = 'setList';;\
 my $item = '  playFav:'.$favliste.q( {use JSON;;use HTML::Entities;;use Encode qw(encode decode);;my $enc = 'UTF8';;my $uri='';;my $search=(split(' ', $EVENT,2))[1];;$search=~s/[\/()]/./g;;my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];;my $read='Favorites';;my $decoded = decode_json(ReadingsVal($dev,$read,''));;my @arr=@{$decoded->{'Result'}};;foreach (@arr) {if (encode($enc, decode_entities($_->{'Title'}))=~/$search/i){$uri = $_->{'TrackUri'} }};;fhem("set $NAME playUri $uri") if ($uri ne '')});;\
 my ($first,$sec)=split(':',$item,2);;\
  $first=~s/^\s+//;;\
 foreach (@devlist) {\
   my @arr = grep {$_ !~ $first} split("\n",AttrVal($_,$attr,''));;\
   push @arr,$item;;\
   my $val = join "\n",@arr;;\
   $val =~ s/;;/;;;;/g;;\
   fhem("attr $_ $attr $val")}\
 return "$attr in ".scalar(@devlist)." Definitionen modifiziert"\
}

Der erste Teil des Codes erzeugt aus den Favoriten ein Komma separierte, sortierte Liste der Titel und ersetzt die Leerzeichen durch Punkte. Damit eignet sich diese Liste für die Auswahlbox. Dies wird als Ergänzung der setList im zweiten Teil des Codes erzeugt und bei allen Playern eingetragen.

Man kann den playFav Befehl auch im set Befehl mit einem Teil des Favoriten Namen verwenden. Enthält die Favoritenliste z.B. Radio Leipzig würde der auch mit diesem Befehl angesteuert werden:

set alias=Bad playFav leipzig

Radioliste durchtasten

Will man eine Liste von bestimmten Radiostation mit einem Taster "durchtasten" kann man das wie folgt tun:

Eigene Radio Liste in ein Reading schreiben (Die Namen müssen zumindest in Teilen mit den Favoriten Titeln übereinstimmen)

setreading model=sonos2mqtt_bridge favRadios Deutschlandfunk Kultur,Radio Leipzig,Radio Station 3

Der Befehl zum weiterschalten. Jedesmal wenn dieser Befehl ausgeführt wird, wird der nächste Favorit gestartet.

set alias=Arbeitszimmer playFav {(my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];;Each($dev,ReadingsVal($dev,'favRadios','')))}

Will man vor dem Radiostart noch die Ansage des Senders haben, geht das zwar auch mit dem speak Befehl, die direkte Ausgabe ohne Restore der Umgebung (sonos2mqtt notify) ist aber effektiver.

Damit das funktioniert müssen wir die Events einschränken:

attr model=sonos2mqtt_speaker event-on-change-reading .*
{my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];;my $r=Each($dev,ReadingsVal($dev,'favRadios',''));;my $play = (devspec2array('alias=Büro'))[0];;my $tts="SonosTTS";;fhem("set $tts tts Es folgt $r;;sleep $tts:playing:.0;;set $play playUri [$tts:httpName];;sleep $play:play;;sleep $play:PLAYING;;sleep $play:STOPPED;;set $play playFav $r")}

Kurze Erklärung zum Code

  • ermittelt den nächsten Radiosender in der Liste,
  • erzeugt die Ansage "Es folgt SenderXY",
  • wenn die mp3 Datei fertig erzeugt ist wird sie mit dem Befehl playUri an den Player gesendet,
  • es wird eine Eventfolge abgewartet -> play / PLAYING / STOPPED,
  • danach wird der Radiosender gestartet.

Der Code ist so einfach und relativ "steif" für die Kommandozeile. Man kann das auch in einen Setter packen:

toggleRadio:noArg {my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];my $r=Each($dev,ReadingsVal($dev,'favRadios',''));my $tts="SonosTTS";fhem("set $tts tts Es folgt $r;sleep $tts:playing:.0;set $NAME playUri [$tts:httpName];sleep $NAME:play;sleep $NAME:PLAYING;sleep $NAME:STOPPED;set $NAME playFav $r")}

Dokumentationen und weitere Entwicklungen

ToDo