Sonos2mqtt - vielleicht hat jemand Lust mitzumachen

Begonnen von Otto123, 31 Mai 2020, 18:30:55

Vorheriges Thema - Nächstes Thema

Mitch

Ich fand die Laufschrift besser  ;D

Wenn ich etwas testen soll, lass es mich bitte wissen.
FHEM im Proxmox Container

Otto123

Ja ich glaube mit dem devStateIcon kann man sich fast beliebig austoben.

ich habe jetzt erstmal  noch im Wiki die Sprachausgabe mit sayText ergänzt. Wäre schön wenn es jemand kritisiert :)

Als nächstes will ich das Template anpassen damit die Readings passen.
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

kjmEjfu

Zitat von: Otto123 am 17 Februar 2021, 12:52:21
ich habe jetzt erstmal  noch im Wiki die Sprachausgabe mit sayText ergänzt. Wäre schön wenn es jemand kritisiert :)

Sieht gut aus.

Auch wenn ich noch immer dafür bin, dass wir per Attribut festlegen sollten, ob FHEM oder Sonos TTS genutzt wird und dann entsprechend den passenden Befehl aussuchen ;-) Aber ich glaube, dass ist was für später.
Migriere derzeit zu Home Assistant

Otto123

Moin,

ich habe mal mit der Utils begonnen, wer Lust hat mit zu schauen hier das "Setup - für die Raw Def". Ihr könnt mir auch sagen im bin auf dem Holzweg ;)
"wget -qO ./FHEM/99_sonos2mqttUtils.pm https://raw.githubusercontent.com/heinz-otto/scripts/master/fhem/99_sonos2mqttUtils.pm"
sleep 10;reload 99_sonos2mqttUtils.pm
attr a:model=sonos2mqtt_speaker devStateIcon {sonos2mqtt($name,'devStateIcon')}
attr a:model=sonos2mqtt_speaker setList stop:noArg {sonos2mqtt($NAME,$EVENT)}\
play:noArg {sonos2mqtt($NAME,$EVENT)}\
pause:noArg {sonos2mqtt($NAME,$EVENT)}\
toggle:noArg {sonos2mqtt($NAME,$EVENT)}\
volumeUp:noArg {sonos2mqtt($NAME,$EVENT)}\
volumeDown:noArg {sonos2mqtt($NAME,$EVENT)}\
volume:slider,0,1,100 {sonos2mqtt($NAME,$EVENT)}\
mute:true,false {sonos2mqtt($NAME,$EVENT)}\
next:noArg {sonos2mqtt($NAME,$EVENT)}\
previous:noArg {sonos2mqtt($NAME,$EVENT)}\
joinGroup:textField {sonos2mqtt($NAME,$EVENT)}\
leaveGroup:noArg {sonos2mqtt($NAME,$EVENT)}\
setAVTUri:textField {sonos2mqtt($NAME,$EVENT)}\
playUri:textField {sonos2mqtt($NAME,$EVENT)}\
input:Queue,TV {sonos2mqtt($NAME,$EVENT)}\
notify:textField {sonos2mqtt($NAME,$EVENT)}\
x_raw_payload:textField {sonos2mqtt($NAME,$EVENT)}\
sayText:textField {sonos2mqtt($NAME,$EVENT)}\
speak:textField {sonos2mqtt($NAME,$EVENT)}\
test:textField {sonos2mqtt($NAME,$EVENT)}

Voraussetzung wären noch die userReadings und leicht geänderten Mapping, wenn das neue Template noch nicht aktiv war:
# stateFormat nicht mehr nach state mappen, stateFormat auf transportState setzen
attr a:model=sonos2mqtt_speaker jsonMap volume_Master:volume mute_Master:mute
attr a:model=sonos2mqtt_speaker stateFormat transportState

# Master Name und Status isMaster und inGroup ermitteln - 
attr a:model=sonos2mqtt_speaker userReadings Master:groupName.* {(split(' +',ReadingsVal($name,'groupName','')))[0]},\
isMaster:coordinatorUuid.* {ReadingsVal($name,'coordinatorUuid','') eq ReadingsVal($name,'uuid','')?1:0},\
inGroup:groupName.* {ReadingsVal($name,'groupName','') =~ / \+ /?1:0},\
inCouple:coordinatorUuid.* {(ReadingsVal($name,'coordinatorUuid','') ne ReadingsVal($name,'uuid','') and (index(ReadingsVal($name,'groupName',''), ReadingsVal($name,'name','')) != -1))?1:0},\
Input:currentTrack_TrackUri.* {my $currentTrack_TrackUri = ReadingsVal($name,'currentTrack_TrackUri','');;\
   $currentTrack_TrackUri =~ 'x-rincon-stream'\
      ? 'LineIn': $currentTrack_TrackUri =~ 'spdif'\
      ? 'TV'    : ReadingsVal($name,'enqueuedMetadata_UpnpClass','') eq 'object.item.audioItem.audioBroadcast'\
      ? 'Radio' : 'Playlist'}

# Ein Trick um die Readings neu zu schreiben, auch die vom Stereopaar
set a:model=sonos2mqtt_speaker volume {(ReadingsVal($DEV,'volume',''))}

Die Erzeugung des playFav Setter muss ich noch machen, funktioniert aber nach gleichem Prinzip.
Der Code ist erstmal ziemlich 1:1 umgesetzt - das funktionierte aber erstmal gut. Da werde ich noch etwas feilen. Ich hoffe ich die "guten Perl Regeln" halbwegs verstanden. :-[

Wer aufmerksam hinschaut bemerkt, dass beim devStateIcon $name und bei der setList $NAME funktioniert - das hält eben auch im Alter jung :)

Jetzt muss mir noch einer verraten wie wir die 99_sonos2mqttUtils.pm auf offiziellen FHEM Wegen an zum User bekommen.

Gruß Otto
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

kjmEjfu

Sehr cool :-) Tolle Arbeit!

Lässt sich die setList eventuell auch noch komplett auslagern?

Als Idee, keine Ahnung ob umsetzbar:
- In der 99_sonos2mqttUtils.pm  eine weitere Sub sonos2mqtt_setList ergänzen,
- dort den Inhalt von setList aufbauen lassen und per return(?) zurückgeben
- im Device dann nur noch {sonos2mqtt_setList()} aufrufen
Also eigentlich analog zu sonos2mqtt_devStateIcon, wenn ich mich gerade nicht täusche.

Hätte den Vorteil, dass wir bei Ergänzung am pm-File die Devices nicht mehr anpacken müssen. Ich tue mich immer schwer, wenn es darum geht die Attribute in anderen Installationen anzupacken, dort könnte ja jemand was ergänzt haben, was danach fehlt.

Eventuell gleiches für userReadings?



Danach wäre es vielleicht eine Idee, wenn wir uns https://wiki.fhem.de/wiki/DevelopmentGuidelinesAV tatsächlich genauer anschauen und entscheiden, was davon wir wie umsetzen wollen.
Vielleicht dazu auch in deinem git ein File hinterlegen, in dem wir die Readings und Befehle (setter) auflisten und mit Ideen zur Umsetzung hinterlegen, bevor wir darauf basierend Patches für die 99_sonos2mqttUtils.pm erzeugen?
Migriere derzeit zu Home Assistant

Otto123

setList komplett auslagern ist mMn nicht vorgesehen:
ZitatsetList cmd [topic|perl-Expression] ...
When the FHEM command cmd is issued, publish the topic. Multiple tuples can be specified, each of them separated by newline, the newline does not have to be entered in the FHEMWEB frontend. Example:
Der Teil cmd und widget ist direkt anzugeben.
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

Otto123

#831
Deswegen muss man die Erzeugung von solchen Systemspezifischen Klapplisten auch "extern" machen. Ich habe noch die joinGroup Liste zur Auswahl gebaut. Das schreit natürlich noch nach "Utils"
Aber ich will natürlich auch Meinung/Ideen einholen.
Vorschlag: Zwei userReadings für die Bridge als zentraler Punkt. Und den Einbau der Setter muss ich noch anders machen ;)
# Favoriten und Gruppen Liste erzeugen
attr a:model=sonos2mqtt_bridge userReadings favlist:Favorites.* {use JSON;;use HTML::Entities;;use Encode qw(encode decode);;\
my $enc = 'UTF8';;\
my @out;;\
my $decoded = decode_json(ReadingsVal($name,'Favorites',''));;\
my @arr  = @{$decoded->{'Result'}};;\
foreach (@arr) {\
   my $dec = encode($enc, decode_entities($_->{'Title'}));;\
   $dec =~ s/\s/./g;;\
   push @out,$dec}\
return join ',', sort @out},\
grouplist:Favorites.* {my @out;;\
foreach (devspec2array('a:model=sonos2mqtt_speaker')) {push @out,ReadingsVal($_,'name','')}\
return join(',', sort @out)}

# playFav erzeugen
{\
my $bridge = (devspec2array('a:model=sonos2mqtt_bridge'))[0];;\
my @devlist = devspec2array('a:model=sonos2mqtt_speaker');;\
my $attr = 'setList';;\
my $item = 'playFav:'.ReadingsVal($bridge,'favlist','').q( {sonos2mqtt($NAME,$EVENT)});;\
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"\
}

# joinGroup modifizieren
{\
my $bridge = (devspec2array('a:model=sonos2mqtt_bridge'))[0];;\
my @devlist = devspec2array('a:model=sonos2mqtt_speaker');;\
my $attr = 'setList';;\
my $item = 'joinGroup:'.ReadingsVal($bridge,'grouplist','').q( {sonos2mqtt($NAME,$EVENT)});;\
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"\
}
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

kjmEjfu

Frage: wenn man alte und neue Sonos-Geräte nach https://forum.fhem.de/index.php/topic,111711.msg1123332.html#msg1123332 installiert, dann hat man eine Bridge. Das macht auch keine Probleme, allerdings funktionieren die Gruppenfunktionen dann nicht über alt/neu hinweg. Jedenfalls habe ich es auch darüber nicht hinbekommen, eine alte Play 5 mit einer "neuen" Play 1 in die gleiche Gruppe zu packen.
Müssen/sollten wir das irgendwie berücksichtigen? Also z.B. das nur Hardwareversion über 1.16 gemeinsam in eine Gruppe darf (und umgekehrt) oder anhand der Softwareversion.
Migriere derzeit zu Home Assistant

Otto123

ZitatMüssen/sollten wir das irgendwie berücksichtigen?
Klares "sicherlich" ;) , mein Problem ist derzeit auch ein simples Stereo Paar in einer Umgebung. Das ist bei der Gruppenauswahl auch schon wieder ein Problem. 

Das mit der Sonos1 / Sonos2 Umgebung wollte ich mir noch anschauen.
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

Papaloewe

#834
Zitat von: PatrickR am 18 August 2020, 21:17:29
Mahlzeit!

Nachdem die Subscriptions nun funktionieren habe ich mich an die weitere Einrichtung gemacht.

Ich verwende für TTS den nativen sonos2mqtt-Weg über einen sonos-tts-polly-Container.

Dafür habe ich die setList wie folgt erweitert:

speak:textField { my (undef, $lang, $voice, $volume, @text) = split(/ /, $EVENT); sprintf('house/general/sonos/RINCON_949F3E14224A01400/control {"command":"speak","input":{"lang": "%s", "name":"%s", "volume":%s, "text": "%s","delayMs":700}}', $lang, $voice, $volume, join(" ", @text))}

Mit

set EG.KU.Sonos speak de-DE Vicki 25 Test

funktioniert das einwandfrei und klingt sogar noch gut.

Patrick

Hallo,
super Arbeit. Endlich laufen meine Sonos Kisten wieder mit fhem vernünftig.

Könnte man vielleicht die Einbindung, wie Patrick sie kurz beschrieben hat, auch noch ins Wiki aufnehmen?
Ich habe es jetzt inmitten dieses superlangen Threads gefunden.

Vielen Dank für dieses Projekt.

LG
Thomas

Otto123

Hallo Thomas,

Mach ich, ich will es noch was umbauen und ergänzen.

Gruß Otto
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

TomLee

ZitatDa werde ich noch etwas feilen.

Hi,

was ich mittlerweile erstmal sehe ist das man diese if:

if($cmd eq 'stop') {return qq(sonos/$uuid/control { "command": "stop" })}
if($cmd eq 'play') {return qq(sonos/$uuid/control { "command": "play" })}
if($cmd eq 'pause') {return qq(sonos/$uuid/control { "command": "pause" })}
if($cmd eq 'toggle') {return qq(sonos/$uuid/control { "command": "toggle" })}
if($cmd eq 'volumeUp') {return qq(sonos/$uuid/control { "command": "volumeup" })}
if($cmd eq 'volumeDown') {return qq(sonos/$uuid/control { "command": "volumedown" })}
if($cmd eq 'next') {return qq(sonos/$uuid/control { "command": "next" })}
if($cmd eq 'previous') {return qq(sonos/$uuid/control { "command": "previous" })}


mit einem Hash lösen kann, zwischen diesen Zeilen eingefügt und die entsprechenden alten if Befehle auskommentiert klappt das problemlos:

if($cmd eq 'test') {Log 1, "Das Device $NAME hat ausgeloest, die uuid ist >$uuid< der Befehl war >$cmd< der Teil danach sah so aus: $payload"}

my %sl1name2cmnd = (
'stop' => 'stop',
'play' => 'play',
'pause' => 'pause',
'toggle' => 'toggle',
'volumeUp' => 'volumeUp',
'volumeDown' => 'volumeDown',
'next' => 'next',
'previous' => 'previous');
my $sl1cmnd = %sl1name2cmnd{$cmd};

return if !$sl1cmnd;
return qq(sonos/$uuid/control { "command": "$sl1cmnd" });

return undef;
}


Schonmal um einige Zeichen kürzer und übersichtlicher.

Wozu ich zu doof bin und bisher kein Verständnis zu habe warum es nicht klappt, wie man die nächsten gleichen Befehle durch einen  Hash ersetzt/ergänzt:

if($cmd eq 'volume') {return qq(sonos/$uuid/control { "command": "volume", "input": $payload })}
if($cmd eq 'joinGroup') {return qq(sonos/$uuid/control { "command": "joingroup",  "input": "$payload"})}
if($cmd eq 'setAVTUri') {return qq(sonos/$uuid/control { "command": "setavtransporturi",  "input": "$payload"})}


if($cmd eq 'test') {Log 1, "Das Device $NAME hat ausgeloest, die uuid ist >$uuid< der Befehl war >$cmd< der Teil danach sah so aus: $payload"}

my %sl1name2cmnd = (
'stop' => 'stop',
'play' => 'play',
'pause' => 'pause',
'toggle' => 'toggle',
'volumeUp' => 'volumeUp',
'volumeDown' => 'volumeDown',
'next' => 'next',
'previous' => 'previous');
my $sl1cmnd = %sl1name2cmnd{$cmd};

return if !$sl1cmnd;
return qq(sonos/$uuid/control { "command": "$sl1cmnd" });


my %sl2name2cmnd = (
'volume' => 'volume',
'joinGroup' => 'joingroup',
'setAVTUri' => 'setavtransporturi');
my $sl2cmnd = %sl2name2cmnd{$cmd};

return if !$sl2cmnd;
return qq(sonos/$uuid/control { "command": "$sl2cmnd", "input": "$payload" });

return undef;


Klappt nicht und hab für heute keine Lust mehr, denke du verstehst das aber schon und hoffe du weißt wie mans richtig macht.

Otto123

cooler Ansatz. Ballwechsel :) Du weißt meine Test laufen immer in der FHEM Kommandozeile - so in der Art noch kürzer - man braucht ja nicht erst a auf a mappen
{my $cmd='play';;my @a=('stop','play','pause','toggle','volumeUp','volumeDown','next','previous');;if (grep { $_ eq $cmd } @a) {qq(/control { "command": "$cmd" })}}
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

TomLee

Ja, habs noch nicht ausprobiert, meine aber es zu verstehen, wollte noch erwähnen das ich mir unsicher bin das der Hash hier die richtige Wahl ist, war schon auf so eine Antwort gefasst  :P

Klappt dann aber nicht mehr bei joinGroup->joingroup und setAVTUri->setavtransporturi.



Otto123

Ich behalte das im Kopf, ich bastle erstmal noch an den anderen Routinen, die Auswahlsetter und das setup - ich will erstmal den ganzen Krempel in der Utils haben.
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz