############################################## # $Id$ # from myUtilsTemplate.pm 21509 2020-03-25 11:20:51Z rudolfkoenig # utils for sonos2mqtt Implementation # They are then available in every Perl expression. package main; use strict; use warnings; sub sonos2mqttUtils_Initialize { my $hash = shift; return; } # Enter you functions below _this_ line. ##### Responses for getList and setList commands sub sonos2mqtt { my ($NAME,$EVENT)=@_; my @arr = split(' ',$EVENT); my ($cmd,$vol,$text,$value); my $speak_json; $cmd = $arr[0]; # quick response for devStateIcon if($cmd eq 'devStateIcon') {return sonos2mqtt_devStateIcon($NAME)} if($cmd eq 'speak') { if ($arr[1] =~ /^[a-z]{2}-[A-Z]{2}$/) { my (undef, $lang, $voice, $volume, @text) = split(/ /, $EVENT); $speak_json = sprintf('{"lang": "%s", "name":"%s", "volume":%s, "text": "%s","delayMs":700}', $lang, $voice, $volume, join(" ", @text)); } } my $bridge = (devspec2array('a:model=sonos2mqtt_bridge'))[0]; my $devicetopic = ReadingsVal($bridge,'devicetopic','sonos'); my $tts = ReadingsVal($bridge,'tts','SonosTTS'); # special cmds for the bridge if ($NAME eq $bridge){ if($cmd eq 'notifyall') {return qq($devicetopic/cmd/notify {"trackUri":"$arr[2]","onlyWhenPlaying":false,"timeout":100,"volume":$arr[1],"delayMs":700})} if($cmd eq 'announcementall') { ($cmd,$text) = split(' ', $EVENT,2); fhem("set $bridge speak 20 $text"); } if($cmd eq 'speak') { if ($arr[1] =~ /^[a-z]{2}-[A-Z]{2}$/) { return sprintf('%s %s', "$devicetopic/cmd/speak", $speak_json); } else { ($cmd,$vol,$text) = split(' ', $EVENT,3); fhem("set $tts tts $text;sleep $tts:playing:.0 ;set $NAME notifyall $vol [$tts:httpName]") ; } } 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 'listalarms') {fhem("sleep $bridge:Alarms:.* ;{sonos2mqtt_alarm(\"$bridge\",'alarmlist')}");return "$devicetopic/cmd/listalarm"} 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 '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 '' } # from here cmds for speaker if($cmd eq 'sayText') { ($cmd,$text) = split(' ', $EVENT,2)} my $uuid = ReadingsVal($NAME,'uuid','error'); my $topic = "$devicetopic/$uuid/control"; my $payload = $EVENT; my ($search,$fav); if (@arr == 1){$payload = "leer"} else {$payload =~ s/$cmd //} # if Radio next Station from favlist # no Idea to detect automatically difference between Favorites and Radios if($cmd eq 'next' and ReadingsVal($NAME,'Input','') eq 'Radio') { 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 '' } my @easycmd = ('stop','pause','toggle','volumeUp','volumeDown','next','previous'); if (grep { $_ eq $cmd } @easycmd) {return lc( qq($topic { "command": "$cmd" }) )} # special volume handling fading: second value is startvalue, if -1 start is actual value if($cmd eq 'volume') { if ($arr[2]) { if ($arr[2] == -1) { $arr[2] = ReadingsNum($NAME,'volume',0) } my $d = abs $arr[1] - $arr[2]; my $s = $arr[1] <=> $arr[2]; $arr[1] = $arr[2]; if ($d) { for (1..$d) { $vol = $arr[1] + $_*$s; fhem("sleep $_;set $NAME volume $vol") } } } return qq($topic { "command": "volume", "input": $arr[1] }) } 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 '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}})} #my %t=('true'=>'mute','false'=>'unmute','on'=>'mute','off'=>'unmute'); my %t=('true'=>'mute','false'=>'unmute','on'=>'mute','off'=>'unmute','toggle'=>ReadingsVal($NAME,'mute','') eq 'true' ? 'unmute' : 'mute'); if($cmd eq 'mute') {return qq(sonos/$uuid/control { "command": "$t{$payload}" } )} if($cmd eq 'input') { $value = $payload eq "TV" ? "tv" : $payload eq "Line_In" ? "line" : "queue"; return qq($topic { "command": "switchto$value" } ) } if($cmd eq 'leaveGroup') { $value = ReadingsVal($uuid,"groupName","all"); return qq($topic { "command": "leavegroup", "input": "$value" } ) } if($cmd eq 'playUri') {fhem("set $NAME setAVTUri $payload; sleep 1; set $NAME play")} if($cmd eq 'sayText') {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")} # for tts-polly command set EG.KU.Sonos speak de-DE Vicki 25 Test # test first of String like de-DE if($cmd eq 'speak') { if ($arr[1] =~ /^[a-z]{2}-[A-Z]{2}$/) { return sprintf('%s {"command":"speak","input":%s}', $topic, $speak_json); } else { ($cmd,$vol,$text) = split(' ', $EVENT,3); fhem("set $tts tts $text;sleep $tts:playing:.0 ;set $NAME notify $vol [$tts:httpName]"); } } if($cmd eq 'playFav') { fhem("set $NAME play Favorite $payload"); fhem("sleep 1;set $NAME play"); } if($cmd eq 'sleep') { $payload = strftime("%H:%M:%S",gmtime($payload*60)); return qq($topic { "command": "sleep", "input": "$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 'snoozeAlarm') {return qq($topic ).sonos2mqtt_command('AVTransportService.SnoozeAlarm','InstanceID',0,'Duration',$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 return for other reasons, the response had to be '' 0 or undef 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 sub sonos2mqtt_devStateIcon { my $name = shift // return''; my $wpix = '210px'; my $master = ReadingsVal($name,'Master',$name); my $inGroup = ReadingsNum($name,'inGroup','0'); my $isMaster = ReadingsNum($name,'isMaster','0'); my $inCouple = ReadingsNum($name,'inCouple','0'); my $Input = ReadingsVal($name,'Input',''); my $cover = ReadingsVal($name,'currentTrack_AlbumArtUri',''); my $mutecmd = ReadingsVal($name,'mute','0') eq 'false'?'true':'false'; my $mystate = $isMaster ? Value($name) : Value((devspec2array('DEF='.ReadingsVal($name,'coordinatorUuid','0')))[0]); 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' : 'rc_PLAY@yellow'; my $mutepic = $mutecmd eq 'true'?'rc_MUTE':'rc_VOLUP'; my $line2 = ''; my $title = $mystate eq 'TRANSITIONING' ? 'Puffern...' : ReadingsVal($name,'enqueuedMetadata_Title','FEHLER'); my $linePic = ($inGroup and !$isMaster and !$inCouple) ? "".FW_makeImage('rc_LEFT')."" : ""; if ($isMaster) {$linePic .= " ".FW_makeImage($playpic).""}; $linePic .= "  " ."".FW_makeImage('rc_VOLDOWN')."" ."".FW_makeImage('rc_PREVIOUS')."" ."".FW_makeImage('rc_NEXT')."" ."".FW_makeImage('rc_VOLUP')."" ."  " ."".FW_makeImage($mutepic).""; if ($isMaster and $mystate eq 'PLAYING') {$line2 = $Input =~ /LineIn|TV/ ? $Input : "$title"} elsif ($inGroup and !$isMaster or $inCouple) {$line2 .= $inCouple ? "Stereopaar":"Steuerung: $master"} my $style = 'display:inline-block;margin-right:5px;border:1px solid lightgray;height:4.00em;width:4.00em;background-size:contain;background-image:'; my $style2 ='background-repeat: no-repeat; background-size: contain; background-position: center center'; return "
$linePic
$line2
" } # usage sonos2mqtt_mod_list(devspec,attrName,line) # usage {sonos2mqtt_mod_list('a:model=sonos2mqtt_bridge','readingList','sonos/RINCON_([0-9A-Z]+)/Reply:.* Reply')} sub sonos2mqtt_mod_list { my ($devspec,$attr,$item) = @_; my @devlist = devspec2array($devspec); my ($first,$sec)=split(':',$item,2); $first=~s/^\s+//; for (@devlist) { my @arr = grep {$_ !~ /\Q$first\E/} split("\n",AttrVal($_,$attr,'')); # grep searches exactly for the string between \Q...\E push @arr,$item; my $val = join "\n",sort @arr; $val =~ s/;/;;/g; fhem("attr $_ $attr $val") } return '' } #### Setup some additional features in speaker and bridge sub sonos2mqtt_setup { my $devspec = shift || 'a:model=sonos2mqtt_speaker'; my $bridge = (devspec2array('a:model=sonos2mqtt_bridge'))[0]; if ($devspec eq 'a:model=sonos2mqtt_bridge'){ sonos2mqtt_mod_list($devspec,'setList','notifyall:textField'.q( {sonos2mqtt($NAME,$EVENT)})); sonos2mqtt_mod_list($devspec,'setList','announcementall:textField'.q( {sonos2mqtt($NAME,$EVENT)})); sonos2mqtt_mod_list($devspec,'setList','speak:textField'.q( {sonos2mqtt($NAME,$EVENT)})); sonos2mqtt_mod_list($devspec,'setList','setalarm:textField $DEVICETOPIC/cmd/setalarm'); 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').'/alarms:.* Alarms'); sonos2mqtt_mod_list($devspec,'getList','Reply:Favorites,Radios,Playlists Reply'.q( {sonos2mqtt($NAME,$EVENT)})); sonos2mqtt_mod_list($devspec,'getList','listalarms:noArg Alarms'.q( {sonos2mqtt($NAME,$EVENT)})); return undef } fhem("attr $devspec".q( devStateIcon {sonos2mqtt($name,'devStateIcon')})); for ('stop:noArg','play:noArg','pause:noArg','toggle:noArg','volume:slider,0,1,100','volumeUp:noArg','volumeDown:noArg', 'mute:true,false','next:noArg','previous:noArg','leaveGroup:noArg','setAVTUri:textField','playUri:textField', 'notify:textField','x_raw_payload:textField','sayText:textField','speak:textField','input:Queue', 'sleep:selectnumbers,0,15,120,0,lin') { sonos2mqtt_mod_list($devspec,'setList',$_.q( {sonos2mqtt($NAME,$EVENT)})); } my @tv = ("S14","S11","S9"); my @line = ("S5","Z90","ZP120"); # 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")} for (devspec2array($devspec)) { my $mn = ReadingsVal($_,'modelNumber',''); 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)}))} sonos2mqtt_mod_list($_,'setList','joinGroup:'.ReadingsVal($bridge,'grouplist','').q( {sonos2mqtt($NAME,$EVENT)})); sonos2mqtt_mod_list($_,'setList','alarm:textField { sonos2mqtt_alarm($NAME,$EVENT) }'); sonos2mqtt_mod_list($_,'setList','snoozeAlarm:textField { sonos2mqtt($NAME,$EVENT) }'); sonos2mqtt_mod_list($_,'readingList','$DEVICETOPIC/status/(.*)/avtransport:.* { sonos2mqtt_reading($NAME,$EVENT,$TOPIC) }'); # sonos2mqtt_mod_list($_,'setList','playFav:'.ReadingsVal($bridge,'favlist','').q( {sonos2mqtt($NAME,$EVENT)})); fhem("set $_ volumeUp; set $_ volumeDown"); # trick to initiate the userReadings } return '' } #### code for notify for two different triggers: defined and IPAddress is responded # 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" sub sonos2mqtt_nty { my ($NAME,$EVENT) = @_; my @arr = split(' ',$EVENT); if ($arr[0] eq 'test') {Log 1, "Device $NAME, EVENT >$EVENT<";shift @arr} if ($NAME eq 'global'){ fhem(qq(sleep 1; set $arr[1] attrTemplate sonos2mqtt_speaker)) } else{ my $url="http://$arr[1]:1400"; my $xmltext = GetFileFromURL("$url/xml/device_description.xml"); my ($mn)=$xmltext =~ /([SZ]P?[0-9]{1,3})/; my ($img)=$xmltext =~ /(.*)<\/url>/; my $icon="Sonos2mqtt_icon-$mn"; fhem("setreading $NAME modelNumber $mn"); fhem("\"wget -qO ./www/images/default/$icon.png $url$img\""); fhem("attr $NAME icon $icon;sleep 4 WI;set WEB rereadicons"); sonos2mqtt_setup($NAME); } return '' } #### sub for userReadings # sub sonos2mqtt_ur { my $name = shift // return ''; my $reading = shift || 'reading'; my @out; if ($reading eq 'grouplist'){ for (devspec2array('a:model=sonos2mqtt_speaker')) { if (ReadingsVal($_,'isMaster','')) { push @out,ReadingsVal($_,'name','') } } return join(',', sort @out) } if ($reading eq 'favlist'){ return sonos2mqtt_getList ($name,'Favorites') } if ($reading eq 'Input') { my $currentTrack_TrackUri = ReadingsVal($name,'currentTrack_TrackUri',''); return $currentTrack_TrackUri =~ 'x-rincon-stream' ? 'LineIn': $currentTrack_TrackUri =~ 'spdif' ? 'TV' : (ReadingsVal($name,'enqueuedMetadata_UpnpClass','') eq 'object.item.audioItem.audioBroadcast' or $currentTrack_TrackUri =~ 'x-.*radio') ? 'Radio' : 'Playlist' } } # 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/ or $_->{'TrackUri'} =~ /x-sonosapi-radio/ or $_->{'TrackUri'} =~ /x-rincon-mp3radio/) { push @out,$dec } } else {push @out,$dec} } return join ',', sort @out } # return json String for x_raw_payload for some advanced commands # sonos2mqtt_command ([cmdName]<,ValueName,Value,ValueName,Value>) # {sonos2mqtt_command ('SetLEDState','DesiredLEDState','On')} # {sonos2mqtt_command ('SetBass','DesiredBass',8)} # {sonos2mqtt_command ('SetEQ','EQType','DialogLevel','DesiredValue',1)} sub sonos2mqtt_command { use JSON; my (%h_value,%h_input) = (); my $acmd = shift // return 'error'; if ($acmd !~ /\w+\.\w+/) { if ($acmd eq 'SetLEDState' or $acmd eq 'SetButtonLockState') { $acmd = 'DevicePropertiesService.'.$acmd} else { $acmd = 'RenderingControlService.'.$acmd} } if ($acmd =~ /RenderingControlService/) {%h_value = ('InstanceID' => 0,'Channel' => 'Master')} $h_input{'cmd'} = $acmd; while (defined(my $key = shift)) { my $val = shift; $h_value{$key} = $val; $h_input{'val'} = {%h_value} } return encode_json {'command' => 'adv-command','input' => {%h_input}}; } ####### handle alarms # # syntax: # set SonosBridge listalarms # set Speaker alarm enable|disable|update all|id[,id]|json [volume=xx] # ####### sub sonos2mqtt_alarm { use JSON; my ($NAME,$EVENT)=@_; my $bridge = (devspec2array('a:model=sonos2mqtt_bridge'))[0]; my $alarms = ReadingsVal($bridge,'Alarms',''); my $decoded = decode_json(ReadingsVal($bridge,'Alarms','')); my @array=@{$decoded}; # part using with bridge if ($NAME eq $bridge) { my @speakers = devspec2array('a:model=sonos2mqtt_speaker'); foreach my $speaker (@speakers) { my @ids; my @als; for (@array) { if (ReadingsVal($speaker,'uuid','') eq $_->{'RoomUUID'}) { push @ids, $_->{'ID'} ; push @als, to_json($_); } } my $AlarmListIDs = join ",", @ids; my $AlarmList = join ",", @als; if ($AlarmListIDs) { fhem("setreading $speaker AlarmListIDs $AlarmListIDs") } else {fhem("deletereading $speaker AlarmListIDs")} if ($AlarmList) { fhem("setreading $speaker AlarmList $AlarmList") } else {fhem("deletereading $speaker AlarmList")} } return ''; } # part using with speakers my @arr = split(' ',$EVENT); my $cmd = lc shift @arr; if ($cmd eq 'alarm') { my $annex = ""; $arr[-1] =~ /^[Vv]olume.([0-9]+)$/; if (defined($1)) { $annex .= ',"Volume":'.$1; pop @arr; } my $acmd = lc shift @arr; my $ids = shift @arr //return 'all|id[,id]|json missing, usage alarm enable|disable|update all|id[,id]|json [volume=xx]'; my %t=('enable'=>'true','disable'=>'false'); if ($acmd eq 'update') { fhem(qq(set $bridge setalarm $ids)); return ''; } elsif ($acmd eq 'enable' or $acmd eq 'disable') { if ($ids eq "all") { $ids = ReadingsVal($NAME,"AlarmListIDs","")} for (split ',',$ids) { fhem(qq(set $bridge setalarm {"ID":$_,"Enabled":$t{$acmd}$annex})); } return ''; } } else {return 'usage alarm enable|disable|update all|id[,id]|json [volume=xx]'} } sub sonos2mqtt_reading { my ($NAME,$EVENT,$TOPIC)=@_; my $uuid = ReadingsVal($NAME,'uuid',''); my $player = lc( ReadingsVal($NAME,'name','') ); $TOPIC =~ m,.*/status/(.*)/avtransport,; if ( $1 eq $uuid or $1 eq $player ) { my %hash; if ($EVENT =~ m/"AlarmRunning":(true|false)/) {$hash{"AlarmRunning"}=$1} if ($EVENT =~ m/"SleepTimerGeneration":(\d+)/) {$hash{"SleepTimerGeneration"}=$1} if ($EVENT =~ m/"SnoozeRunning":(true|false)/) {$hash{"SnoozeRunning"}=$1} return \%hash } } 1; =pod =item summary generic MQTT2 Sonos Devices based on sonos2mqtt. =item summary_DE generische MQTT2 Sonos Geraete auf Basis von sonos2mqtt =begin html Some Subroutines for generic MQTT2 Sonos Devices based on sonos2mqtt. =end html =begin html_DE Enthaelt einige Subroutinen fuer generische MQTT2 Sonos Geraete auf Basis von sonos2mqtt. =end html_DE =cut