Sonos2mqtt
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 MQTT2_RINCON_.* 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'?'on':'off';;\
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>\
; ; ; ;\
<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 Einträge jedes Players machen zu müssen, wird diese Routine verwendet. Sie ist wieder für die Raw Definition gedacht.
{my @devlist = devspec2array('MQTT2_RINCON_.*');;\
my $attr = 'setList';;\
my $search = 'speak:textField';;\
my $item = q( speak:textField { my $tts="SonosTTS";;my $payload = $EVENT;;$payload =~ s/$EVTPART0 $EVTPART1 //g;; fhem("setreading $tts Player $NAME;;setreading $tts volume $EVTPART1;;set $tts tts $payload");;"{}"});;\
foreach (@devlist) {\
my @arr = grep {$_ !~ $search} 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 ergänzt"\
}
Hier im Beispiel wird der setter für den folgenden Speak Befehl eingefügt bzw. ersetzt. Die Variablen $search und $item sind jeweils anzupassen!
Speak Befehl
Verwendet wird ein Befehl ähnlich wie in der Sonos Umgebung:
set Player speak <volume> text
Drei Geräte sind notwendig:
- Text2Speech im Servermodus, erzeugt mp3 Dateien im cache Verzeichnis
- Ein HTTP Server stellt die Dateien im gleichen Verzeichnis bereit
- Ein notify übergibt dem Player die mp3 Datei als http Link
Wichtig ist, dass das Sonos System den Host im Link zur Datei richtig auflösen kann. Deshalb wird der Hostname des Servers im Readings host des TTS Device als Name oder IP Adresse abgelegt! Dies kann entweder mit dem hier gezeigten Befehl oder vollständig selbst definiert (z.B. mit IP Adresse) erfolgen.
defmod SonosTTS Text2Speech none
attr SonosTTS TTS_UseMP3Wrap 1
attr SonosTTS userReadings httpName:lastFilename.* {'http://'.ReadingsVal($name,'host','set host first').':8083/fhem/'.ReadingsVal($name,'lastFilename','')}
deleteattr SonosTTS TTS_CacheFileDir
setreading SonosTTS host {(qx(hostname -s|tr -d '\n'))}
#setreading SonosTTS host {((split(' ', qx(hostname -I)))[0])}
defmod SonosSpeakWeb HTTPSRV cache cache SonosSpeakWeb
defmod n_SonosSpeak notify SonosTTS:playing:.0 {fhem("set ".ReadingsVal($NAME,"Player","")." notify ".ReadingsVal($NAME,"volume","")." ".ReadingsVal($NAME,"httpName",""))}
Favoriten starten
ToDo
Radioliste durchtasten
ToDo
Dokumentationen und weiter Entwicklungen
ToDo