mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-03 23:06:37 +00:00
99_sonos2mqttUtils: code and functional improvements
git-svn-id: https://svn.fhem.de/fhem/trunk@23978 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
621466cb4a
commit
73dda72e4d
@ -10,11 +10,11 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
sub
|
sub
|
||||||
sonos2mqttUtils_Initialize($$)
|
sonos2mqttUtils_Initialize
|
||||||
{
|
{
|
||||||
my ($hash) = @_;
|
my $hash = shift;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Enter you functions below _this_ line.
|
# Enter you functions below _this_ line.
|
||||||
|
|
||||||
##### Responses for getList and setList commands
|
##### Responses for getList and setList commands
|
||||||
@ -38,8 +38,26 @@ if ($NAME eq $bridge){
|
|||||||
fhem("setreading $tts text ".ReadingsVal($tts,'text',' ').' '.$text.";sleep 0.4 tts;set $tts tts [$tts:text];sleep $tts:playing:.0 ;set $NAME notifyall [$tts:vol] [$tts:httpName];deletereading $tts text");
|
fhem("setreading $tts text ".ReadingsVal($tts,'text',' ').' '.$text.";sleep 0.4 tts;set $tts tts [$tts:text];sleep $tts:playing:.0 ;set $NAME notifyall [$tts:vol] [$tts:httpName];deletereading $tts text");
|
||||||
}
|
}
|
||||||
if($cmd eq 'Favorites') {return "$devicetopic/".ReadingsVal((devspec2array('a:model=sonos2mqtt_speaker'))[0],'uuid','').q(/control {"command": "adv-command","input": {"cmd": "GetFavorites","reply": "Favorites"}})}
|
if($cmd eq 'Favorites') {return "$devicetopic/".ReadingsVal((devspec2array('a:model=sonos2mqtt_speaker'))[0],'uuid','').q(/control {"command": "adv-command","input": {"cmd": "GetFavorites","reply": "Favorites"}})}
|
||||||
if($cmd eq 'setplayFav') {sonos2mqtt_mod_list('a:model=sonos2mqtt_speaker','setList','playFav:'.ReadingsVal($NAME,'favlist','').' {sonos2mqtt($NAME,$EVENT)}')}
|
if($cmd eq 'setplayFav') {sonos2mqtt_mod_list('a:model=sonos2mqtt_speaker','setList','playFav:'.sonos2mqtt_getList($bridge,'Favorites').' {sonos2mqtt($NAME,$EVENT)}')}
|
||||||
if($cmd eq 'setjoinGroup') {sonos2mqtt_mod_list('a:model=sonos2mqtt_speaker','setList','joinGroup:'.ReadingsVal($NAME,'grouplist','').' {sonos2mqtt($NAME,$EVENT)}')}
|
if($cmd eq 'setjoinGroup') {sonos2mqtt_mod_list('a:model=sonos2mqtt_speaker','setList','joinGroup:'.ReadingsVal($NAME,'grouplist','').' {sonos2mqtt($NAME,$EVENT)}')}
|
||||||
|
if($cmd eq 'Reply'){
|
||||||
|
my $topic = "$devicetopic/".ReadingsVal((devspec2array('a:model=sonos2mqtt_speaker'))[0],'uuid','')."/control";
|
||||||
|
my $advc = qq("command": "adv-command","input":);
|
||||||
|
my $ccmd = qq("cmd": "ContentDirectoryService.BrowseParsed","val":);
|
||||||
|
my $cval = qq("ObjectID": "SQ:","BrowseFlag": "BrowseDirectChildren","Filter": "*","StartingIndex": 0,"RequestedCount": 0,"SortCriteria": "");
|
||||||
|
my $creply = qq("reply": "Reply");
|
||||||
|
my $payload = qq( { $advc { $ccmd { $cval },$creply }} );
|
||||||
|
if ($arr[1] eq 'Favorites'){
|
||||||
|
$ccmd = qq("cmd": "GetFavorites");
|
||||||
|
$payload= qq( { $advc { $ccmd ,$creply }} );
|
||||||
|
}
|
||||||
|
if ($arr[1] eq 'Radios'){
|
||||||
|
$ccmd = qq("cmd": "GetFavoriteRadioStations");
|
||||||
|
$payload= qq( { $advc { $ccmd ,$creply }} );
|
||||||
|
}
|
||||||
|
#Log 1, $EVENT;
|
||||||
|
return qq($topic $payload);
|
||||||
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
# from here cmds for speaker
|
# from here cmds for speaker
|
||||||
@ -47,18 +65,55 @@ if($cmd eq 'sayText') { ($cmd,$text) = split(' ', $EVENT,2)}
|
|||||||
my $uuid = ReadingsVal($NAME,'uuid','error');
|
my $uuid = ReadingsVal($NAME,'uuid','error');
|
||||||
my $topic = "$devicetopic/$uuid/control";
|
my $topic = "$devicetopic/$uuid/control";
|
||||||
my $payload = $EVENT;
|
my $payload = $EVENT;
|
||||||
|
my ($search,$fav);
|
||||||
if (@arr == 1){$payload = "leer"} else {$payload =~ s/$cmd //}
|
if (@arr == 1){$payload = "leer"} else {$payload =~ s/$cmd //}
|
||||||
|
|
||||||
# if Radio next Station
|
# if Radio next Station from favlist
|
||||||
my $Input = ReadingsVal($NAME,'Input','');
|
# no Idea to detect automatically difference between Favorites and Radios
|
||||||
if($cmd eq 'next' and $Input eq 'Radio') {
|
if($cmd eq 'next' and ReadingsVal($NAME,'Input','') eq 'Radio') {
|
||||||
fhem("set $NAME playFav {(Each('$bridge',ReadingsVal('$bridge','favlist','')))}");
|
if (ReadingsVal($NAME,'transportState','') eq 'PLAYING'){ fhem("sleep 1;set $NAME play") }
|
||||||
|
fhem("set $NAME play Favorite {(Each('$bridge',ReadingsVal('$bridge','favlist',sonos2mqtt_getList ('$bridge','Favorites'))))}");
|
||||||
|
# fhem("set $NAME play Radio {(Each('$bridge',ReadingsVal('$bridge','favlist',sonos2mqtt_getList ('$bridge','Radios'))))}");
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
my @easycmd = ('stop','play','pause','toggle','volumeUp','volumeDown','next','previous');
|
my @easycmd = ('stop','pause','toggle','volumeUp','volumeDown','next','previous');
|
||||||
if (grep { $_ eq $cmd } @easycmd) {return lc( qq($topic { "command": "$cmd" }) )}
|
if (grep { $_ eq $cmd } @easycmd) {return lc( qq($topic { "command": "$cmd" }) )}
|
||||||
|
|
||||||
if($cmd eq 'volume') {return qq($topic { "command": "volume", "input": $payload })}
|
# normally set will fading the volume or could set finalVolume startVolume: set <player> volume <0..100> [startValue]
|
||||||
|
#if($cmd eq 'volume') {return qq($topic { "command": "volume", "input": $payload })}
|
||||||
|
if($cmd eq 'volume') {
|
||||||
|
my $vol = ReadingsNum($NAME,'volume',0);
|
||||||
|
my $d = abs $arr[1] - $vol;
|
||||||
|
my $s = $arr[1] <=> $vol;
|
||||||
|
if ($arr[2] or ($d == 1)) {
|
||||||
|
$payload = $arr[2] || $payload;
|
||||||
|
if ($arr[2] and ($arr[1] != $arr[2])) {fhem("sleep 2;set $NAME volume $arr[1]")}
|
||||||
|
return qq($topic { "command": "volume", "input": $payload })
|
||||||
|
} else {
|
||||||
|
for (1..$d) {fhem("sleep $_;set $NAME volume {([$NAME:volume]+$s)}")}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cmd eq 'play') {
|
||||||
|
if (@arr == 1) { $payload = qq({ "command": "$cmd" }) }
|
||||||
|
else {
|
||||||
|
if (grep { $_ eq $arr[1] } ('Radio','Favorite','Playlist')) {$search = (split(' ', $EVENT,3))[2] ;$fav = $arr[1].'s'}
|
||||||
|
my ($uri,$ItemId,$UpnpClass,$CdUdn)=sonos2mqtt_searchList($search,$fav);
|
||||||
|
if ($arr[1] eq 'Playlist') {
|
||||||
|
$payload = qq({"command": "adv-command","input": { "cmd": "AVTransportService.RemoveAllTracksFromQueue" }});
|
||||||
|
fhem("set $NAME x_raw_payload $payload");
|
||||||
|
fhem("set $NAME input Queue");
|
||||||
|
$payload = qq({"UpnpClass": "$UpnpClass","ItemId": "$ItemId","CdUdn": "$CdUdn"});
|
||||||
|
$payload = qq({ "InstanceID": 0,"DesiredFirstTrackNumberEnqueued": 0,"EnqueueAsNext": true,"EnqueuedURI":"$uri","EnqueuedURIMetaData": $payload});
|
||||||
|
$payload = qq({ "command": "adv-command","input": {"cmd": "AVTransportService.AddURIToQueue","val": $payload}});
|
||||||
|
}
|
||||||
|
else { $payload = qq({ "command": "setavtransporturi", "input": "$uri"}) }
|
||||||
|
}
|
||||||
|
#Log 1, qq(play Kommando $topic $payload);
|
||||||
|
return qq($topic $payload);
|
||||||
|
}
|
||||||
|
|
||||||
if($cmd eq 'joinGroup') {return qq($topic { "command": "joingroup", "input": "$payload"})}
|
if($cmd eq 'joinGroup') {return qq($topic { "command": "joingroup", "input": "$payload"})}
|
||||||
if($cmd eq 'setAVTUri') {return qq($topic { "command": "setavtransporturi", "input": "$payload"})}
|
if($cmd eq 'setAVTUri') {return qq($topic { "command": "setavtransporturi", "input": "$payload"})}
|
||||||
if($cmd eq 'notify') {return qq($topic { "command":"notify","input":{"trackUri":"$arr[2]","onlyWhenPlaying":false,"timeout":100,"volume":$arr[1],"delayMs":700}})}
|
if($cmd eq 'notify') {return qq($topic { "command":"notify","input":{"trackUri":"$arr[2]","onlyWhenPlaying":false,"timeout":100,"volume":$arr[1],"delayMs":700}})}
|
||||||
@ -89,27 +144,55 @@ if($cmd eq 'speak') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($cmd eq 'playFav') {
|
if($cmd eq 'playFav') {
|
||||||
use JSON;use HTML::Entities;use Encode qw(encode decode);
|
fhem("set $NAME play Favorite $payload");
|
||||||
my $enc = 'UTF8';my $uri='';my $search=(split(' ', $EVENT,2))[1];
|
fhem("sleep 1;set $NAME play");
|
||||||
$search=~s/[\/()]/./g;
|
|
||||||
my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];
|
|
||||||
my $decoded = decode_json(ReadingsVal($dev,'Favorites',''));
|
|
||||||
my @array=@{$decoded->{'Result'}};
|
|
||||||
for (@array) {
|
|
||||||
if (encode($enc, decode_entities($_->{'Title'}))=~/$search/i)
|
|
||||||
{$uri = $_->{'TrackUri'} }
|
|
||||||
}
|
|
||||||
fhem("set $NAME playUri $uri") if ($uri ne '');
|
|
||||||
}
|
}
|
||||||
if($cmd eq 'sleep') {
|
if($cmd eq 'sleep') {
|
||||||
$payload = strftime("%H:%M:%S",gmtime($payload*60));
|
$payload = strftime("%H:%M:%S",gmtime($payload*60));
|
||||||
return qq($topic { "command": "sleep", "input": "$payload" })
|
return qq($topic { "command": "sleep", "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"}
|
# something for playing the queue
|
||||||
|
if($cmd eq 'queue') {
|
||||||
|
if ($arr[1] eq 'clear') {return qq($topic {"command": "adv-command","input": { "cmd": "AVTransportService.RemoveAllTracksFromQueue" }})}
|
||||||
|
if ($arr[1] eq 'add') {
|
||||||
|
my ($uri,$ItemId,$UpnpClass,$CdUdn)=sonos2mqtt_searchList((split(' ', $EVENT,3))[2],'Playlists');
|
||||||
|
$payload = qq({"UpnpClass": "$UpnpClass","ItemId": "$ItemId","CdUdn": "$CdUdn"});
|
||||||
|
$payload = qq({ "InstanceID": 0,"DesiredFirstTrackNumberEnqueued": 0,"EnqueueAsNext": true,"EnqueuedURI":"$uri","EnqueuedURIMetaData": $payload});
|
||||||
|
$payload = qq({ "command": "adv-command","input": {"cmd": "AVTransportService.AddURIToQueue","val": $payload}});
|
||||||
|
return qq($topic $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"}
|
||||||
|
if($cmd eq 'test') {Log 1, (split(' ', $EVENT,3))[2]}
|
||||||
if($cmd eq 'x_raw_payload') {return qq($topic $payload)}
|
if($cmd eq 'x_raw_payload') {return qq($topic $payload)}
|
||||||
# if return for other reasons, the response had to be '' 0 or undef
|
# if return for other reasons, the response had to be '' 0 or undef
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
# search in Readings of SonosBridge title and return uri and metaclass items
|
||||||
|
sub sonos2mqtt_searchList
|
||||||
|
{
|
||||||
|
use JSON;use HTML::Entities;use Encode qw(encode decode);
|
||||||
|
my $regex = shift //return'';
|
||||||
|
my $list = shift //return'';
|
||||||
|
my $enc = 'UTF8';
|
||||||
|
my $uri = '';my $UpnpClass = '';my $ItemId = '';my $CdUdn = '';
|
||||||
|
my $dev = (devspec2array('model=sonos2mqtt_bridge'))[0];
|
||||||
|
my $decoded = decode_json(ReadingsVal($dev,$list,''));
|
||||||
|
my @array=@{$decoded->{'Result'}};
|
||||||
|
$regex=~s/[\/()]/./g;
|
||||||
|
for (@array) {
|
||||||
|
if (encode($enc, decode_entities($_->{'Title'}))=~/$regex/i)
|
||||||
|
{
|
||||||
|
$uri = $_->{'TrackUri'};
|
||||||
|
$ItemId = $_->{'ItemId'} || '';
|
||||||
|
$UpnpClass= $_->{'UpnpClass'} || '';
|
||||||
|
$CdUdn= $_->{'CdUdn'} || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ($uri,$ItemId,$UpnpClass,$CdUdn);
|
||||||
|
}
|
||||||
|
|
||||||
####### devStateIcon
|
####### devStateIcon
|
||||||
sub sonos2mqtt_devStateIcon
|
sub sonos2mqtt_devStateIcon
|
||||||
{
|
{
|
||||||
@ -181,6 +264,7 @@ if ($devspec eq 'a:model=sonos2mqtt_bridge'){
|
|||||||
sonos2mqtt_mod_list($devspec,'setList','announcementall:textField'.q( {sonos2mqtt($NAME,$EVENT)}));
|
sonos2mqtt_mod_list($devspec,'setList','announcementall:textField'.q( {sonos2mqtt($NAME,$EVENT)}));
|
||||||
sonos2mqtt_mod_list($devspec,'readingList',AttrVal($bridge,"devicetopic",'sonos').'/RINCON_([0-9A-Z]+)/Favorites:.* Favorites');
|
sonos2mqtt_mod_list($devspec,'readingList',AttrVal($bridge,"devicetopic",'sonos').'/RINCON_([0-9A-Z]+)/Favorites:.* Favorites');
|
||||||
sonos2mqtt_mod_list($devspec,'readingList',AttrVal($bridge,"devicetopic",'sonos').'/RINCON_([0-9A-Z]+)/Reply:.* Reply');
|
sonos2mqtt_mod_list($devspec,'readingList',AttrVal($bridge,"devicetopic",'sonos').'/RINCON_([0-9A-Z]+)/Reply:.* Reply');
|
||||||
|
sonos2mqtt_mod_list($devspec,'getList','Reply:Favorites,Radios,Playlists Reply'.q( {sonos2mqtt($NAME,$EVENT)}));
|
||||||
return undef
|
return undef
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,20 +278,19 @@ for ('stop:noArg','play:noArg','pause:noArg','toggle:noArg','volume:slider,0,1,1
|
|||||||
my @tv = ("S14","S11","S9");
|
my @tv = ("S14","S11","S9");
|
||||||
my @line = ("S5","Z90","ZP120");
|
my @line = ("S5","Z90","ZP120");
|
||||||
# to get the Favorites at this point is only a workaround. Bad for the first player
|
# to get the Favorites at this point is only a workaround. Bad for the first player
|
||||||
if (!ReadingsVal($bridge,'favlist',0)) {my $fav = fhem("get $bridge Favorites")}
|
#if (!ReadingsVal($bridge,'favlist',0)) {my $fav = fhem("get $bridge Favorites")}
|
||||||
for (devspec2array($devspec)) {
|
for (devspec2array($devspec)) {
|
||||||
my $mn = ReadingsVal($_,'modelNumber','');
|
my $mn = ReadingsVal($_,'modelNumber','');
|
||||||
if (grep {/$mn/} @tv) {sonos2mqtt_mod_list($_,'setList','input:Queue,TV'.q( {sonos2mqtt($NAME,$EVENT)}))}
|
if (grep {/$mn/} @tv) {sonos2mqtt_mod_list($_,'setList','input:Queue,TV'.q( {sonos2mqtt($NAME,$EVENT)}))}
|
||||||
if (grep {/$mn/} @line) {sonos2mqtt_mod_list($_,'setList','input:Queue,Line_In'.q( {sonos2mqtt($NAME,$EVENT)}))}
|
if (grep {/$mn/} @line) {sonos2mqtt_mod_list($_,'setList','input:Queue,Line_In'.q( {sonos2mqtt($NAME,$EVENT)}))}
|
||||||
sonos2mqtt_mod_list($_,'setList','joinGroup:'.ReadingsVal($bridge,'grouplist','').q( {sonos2mqtt($NAME,$EVENT)}));
|
sonos2mqtt_mod_list($_,'setList','joinGroup:'.ReadingsVal($bridge,'grouplist','').q( {sonos2mqtt($NAME,$EVENT)}));
|
||||||
sonos2mqtt_mod_list($_,'setList','playFav:'.ReadingsVal($bridge,'favlist','').q( {sonos2mqtt($NAME,$EVENT)}));
|
# sonos2mqtt_mod_list($_,'setList','playFav:'.ReadingsVal($bridge,'favlist','').q( {sonos2mqtt($NAME,$EVENT)}));
|
||||||
fhem("set $_ volumeUp; set $_ volumeDown"); # trick to initiate the userReadings
|
fhem("set $_ volumeUp; set $_ volumeDown"); # trick to initiate the userReadings
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
#### code for notify for two different triggers: defined and IPAddress is responded
|
#### code for notify for two different triggers: defined and IPAddress is responded
|
||||||
# delete n_configSonos.
|
|
||||||
# defmod n_configSonos notify global:DEFINED.MQTT2_RINCON_[A-Z0-9]+|MQTT2_RINCON_[A-Z0-9]+:IPAddress:.* {sonos2mqtt_nty($NAME,$EVENT)}
|
# defmod n_configSonos notify global:DEFINED.MQTT2_RINCON_[A-Z0-9]+|MQTT2_RINCON_[A-Z0-9]+:IPAddress:.* {sonos2mqtt_nty($NAME,$EVENT)}
|
||||||
# for Test use "test $EVENT"
|
# for Test use "test $EVENT"
|
||||||
sub sonos2mqtt_nty
|
sub sonos2mqtt_nty
|
||||||
@ -249,18 +332,7 @@ if ($reading eq 'grouplist'){
|
|||||||
return join(',', sort @out)
|
return join(',', sort @out)
|
||||||
}
|
}
|
||||||
if ($reading eq 'favlist'){
|
if ($reading eq 'favlist'){
|
||||||
use JSON;
|
sonos2mqtt_getList ($name,'Favorites')
|
||||||
use HTML::Entities;
|
|
||||||
use Encode qw(encode decode);
|
|
||||||
my $enc = 'UTF8';
|
|
||||||
my $decoded = decode_json(ReadingsVal($name,'Favorites',''));
|
|
||||||
my @arr = @{$decoded->{'Result'}};
|
|
||||||
for (@arr) {
|
|
||||||
my $dec = encode($enc, decode_entities($_->{'Title'}));
|
|
||||||
$dec =~ s/\s/./g;
|
|
||||||
if ($_->{'TrackUri'} =~ /x-sonosapi-stream/) {push @out,$dec}
|
|
||||||
}
|
|
||||||
return join ',', sort @out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($reading eq 'Input') {
|
if ($reading eq 'Input') {
|
||||||
@ -272,6 +344,31 @@ if ($reading eq 'Input') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# return a list of Titles from the favorite json Arrays
|
||||||
|
# the Favorites Array will be filtered and returns only Radio stations
|
||||||
|
sub sonos2mqtt_getList
|
||||||
|
{
|
||||||
|
my $name = shift // return '';
|
||||||
|
my $reading = shift || 'Favorites';
|
||||||
|
my @out;
|
||||||
|
use JSON;
|
||||||
|
use HTML::Entities;
|
||||||
|
use Encode qw(encode decode);
|
||||||
|
my $enc = 'UTF8';
|
||||||
|
my $decoded = decode_json(ReadingsVal($name,$reading,''));
|
||||||
|
my @arr = @{$decoded->{'Result'}};
|
||||||
|
for (@arr) {
|
||||||
|
my $dec = encode($enc, decode_entities($_->{'Title'}));
|
||||||
|
$dec =~ s/\s/./g;
|
||||||
|
if ($reading eq 'Favorites') {
|
||||||
|
if ( $_->{'TrackUri'} =~ /x-sonosapi-stream/) {
|
||||||
|
push @out,$dec
|
||||||
|
}
|
||||||
|
} else {push @out,$dec}
|
||||||
|
}
|
||||||
|
return join ',', sort @out
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
=pod
|
=pod
|
||||||
=begin html
|
=begin html
|
||||||
|
Loading…
x
Reference in New Issue
Block a user