Kombiniertes Status Reading stateAV und Structure für SONOS

Begonnen von Loredo, 11 Oktober 2015, 19:57:25

Vorheriges Thema - Nächstes Thema

Loredo

Da ich mit den Standardwerten von state/STATE des SONOS Moduls nicht zufrieden war, habe ich mir per userReading ein eigenes Reading "stateAV" gebaut. Damit kann man dann devStateIcon so konfigurieren, dass sich das Icon so bedient und verhält, wie der Hardware Button an den Sonos Geräten selbst. Dabei werden auch Gruppen berücksichtigt.

stateAV kann folgende Werte haben:
- on
- mute
- pause
- off
- disappeared
- initialized




Umsetzung

Dies hier kommt in 99_myUtils.pm

sub mySonosStateAV($) {
    my ($name) = @_;
    my $MasterPlayer = ReadingsVal($name, "MasterPlayer", $name);
    my $IsMaster = ReadingsVal($name, "IsMaster", "0");
    my $transportState = ReadingsVal( $name, "transportState", "STOPPED" );

    if ( $transportState ne "PLAYING" && $IsMaster eq "0" && $MasterPlayer ne $name ) {
        Log3 $name, 4, "SONOSPLAYER $name stateAV: Missmatch between MasterPlayer and transportState - assuming standalone";
        $MasterPlayer = $name;
        $IsMaster = 1;
    }

    if ( $IsMaster eq "1" ) {
        my $SlavePlayer = ReadingsVal($name, "SlavePlayer", "[]");

        foreach my $player ( @{ eval $SlavePlayer } ) {
            my $SlavePlayerMaster = ReadingsVal($player, "MasterPlayer", $player);
            if($SlavePlayerMaster ne $name) {
                Log3 $player, 4, "SONOSPLAYER $player stateAV: MasterPlayer does not match $name";
                next;
            }
            readingsSingleUpdate( $defs{$player}, "stateAV", mySonosStateAV($player), 1 );
        }
    }

    my $MasterPlayerTstate = ReadingsVal( $MasterPlayer, "transportState", "" );

    if ( ReadingsVal( $name, "presence", "disappeared" ) ne "appeared" ) {
        Log3 $name, 4, "SONOSPLAYER $name stateAV: Result = disappeared";
        return "disappeared";
    }
    elsif ($MasterPlayerTstate eq "PLAYING")
    {
        if   ( ReadingsVal( $name, "Mute", "0" ) eq "1" ) {
            Log3 $name, 4, "SONOSPLAYER $name stateAV: Result = mute";
            return "mute";
        }
        else {
            Log3 $name, 4, "SONOSPLAYER $name stateAV: Result = on";
            return "on";
        }
    }
    elsif ($MasterPlayerTstate eq "PAUSED_PLAYBACK")
    {
        Log3 $name, 4, "SONOSPLAYER $name stateAV: Result = pause";
        return "pause";
    }
    else {
        Log3 $name, 4, "SONOSPLAYER $name stateAV: Result = off";
        return "off";
    }
}


Bei jedem SONOSPLAYER Device sind dann folgende Attribute zu setzen:


attr Sonos_.* cmdIcon MuteT:rc_MUTE.svg Previous:rc_PREVIOUS.svg Next:rc_NEXT.svg
attr Sonos_.* event-on-change-reading Volume,presence,transportState,Mute,currentAlbum,currentAlbumArtURL,infoSummarize1,infoSummarize2,infoSummarize3,infoSummarize4,stateAV
attr Sonos_.* event-on-update-reading LastActionResult
attr Sonos_.* generateVolumeEvent 1
attr Sonos_.* userReadings stateAV:(presence|transportState|Mute).* {mySonosStateAV($name)},Favourites:LastActionResult.*?GetFavouritesWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } },Radios:LastActionResult.*?GetRadiosWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } },Playlists:LastActionResult.*?GetPlaylistsWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } },currentTrackPosition:LastActionResult.*?GetCurrentTrackPosition.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } }
attr Sonos_.* devStateIcon off:rc_STOP.svg:Play pause:rc_PAUSE.svg:Play MuteT:rc_MUTE.svg@orange mute:rc_MUTE.svg@red:MuteT on:rc_PLAY.svg@green:pause disappeared|initialized:rc_RED.svg
attr Sonos_.* eventMap Stop:off Play:on
attr Sonos_.* minVolume 0
attr Sonos_.* room Sonos
attr Sonos_.* stateFormat stateAV
attr Sonos_.* webCmd MuteT:Previous:Next:Volume
deleteattr Sonos_.*RG.* g_audio
deleteattr Sonos_.*RG.* g_audio_map
deleteattr Sonos_.*RG.* structexclude
deleteattr Sonos_.*RG.* userattr
deleteattr Sonos_.*RG.* group
deleteattr Sonos_.*RG.* webCmd
deleteattr Sonos_.*RC.* g_audio
deleteattr Sonos_.*RC.* g_audio_map
deleteattr Sonos_.*RC.* structexclude
deleteattr Sonos_.*RC.* userattr
deleteattr Sonos_.*RC.* group
deleteattr Sonos_.*RC.* webCmd


Das Attribut event-on-change-reading kann man auch auf .* setzen oder ganz weglassen, wenn man die Flut an sonstigen Events haben will oder braucht...

Die letzten deleteattr Befehle löschen das webCmd Attribut bei den Standard Sonos readingGroup und remotecontrol Devices wieder weg, da es sonst zu Darstellungsfehlern in FHEMWEB kommt. Ich verwende diese nicht, daher ist das hier nur rein informativ zu sehen. Schließlich habe ich alle Funktion, die ich brauche jetzt direkt am jeweiligen Sonos Device verfügbar.




Structure für Sonos

Wer möchte, kann nun alle Sonos Geräte auch mit einer Structure zusammenfassen. Dafür sind zunächst folgende zusätzliche Attribute an jedem Sonos Gerät notwendig (es wird davon ausgegangen, dass die Structure später den Devicenamen g_HSE_Audio haben wird):


attr Sonos_.* userattr g_audio g_audio_map structexclude
attr Sonos_.* g_audio g_HSE_Audio
attr Sonos_.* g_audio_map stateAV:mute:mute stateAV:on:on stateAV:pause:pause stateAV:off:off stateAV:disappeared:off stateAV:initialized:off
attr Sonos_.* group Media
attr Sonos_.* structexclude g_HSE_Audio:devStateIcon|group|structexclude|icon|eventMap|userReadings|event-on-change-reading|sortby


Nun legen wir noch die Structure an. Hier wird davon ausgegangen, dass es 4 Sonos Geräte gibt, die im Define-Befehl alle mit ihrem Fhem Devicenamen aufgeführt werden müssen:


define g_HSE_Audio structure g_audio Sonos_Bathroom Sonos_Bedroom Sonos_Kitchen Sonos_Living_Room
attr g_HSE_Audio alias Sonos System
attr g_HSE_Audio clientstate_behavior relative
attr g_HSE_Audio clientstate_priority on mute pause off
attr g_HSE_Audio cmdIcon MuteT:rc_MUTE.svg Previous:rc_PREVIOUS.svg Next:rc_NEXT.svg
attr g_HSE_Audio devStateIcon off:rc_STOP.svg:Play pause:rc_PAUSE.svg:Play MuteT:rc_MUTE.svg@orange mute:rc_MUTE.svg@red:MuteT on:rc_PLAY.svg@green:pause disappeared|initialized:rc_RED.svg
attr g_HSE_Audio event-on-change-reading state
attr g_HSE_Audio group Media
attr g_HSE_Audio icon audio_sound
attr g_HSE_Audio room Sonos
attr g_HSE_Audio sortby 0
attr g_HSE_Audio webCmd MuteT


Das Ergebnis sieht dann so aus wie im Screenshot "stateAV" zu sehen (zum Vergleich auch die Anzeige des Sonos Controllers im Screenshot "Sonos_Controller").

Man kann nun bei Verlassen des Hauses ganz elegant alle Sonos Geräte ausschalten, indem man einfach folgenden Befehl schickt:


set g_HSE_Audio [FILTER:stateAV!=off] off


Man kann aber auch einfach z.B. bei Öffnung der Haustür alle Geräte leiser stellen und nach schließen der Tür wieder zurücksetzen, damit es nicht so in den Hausflur schallt:


set g_HSE_Audio [FILTER:stateAV=on] VolumeRestore
set g_HSE_Audio [FILTER:stateAV=on] VolumeSave 5


... oder ganz stumm schalten:


set g_HSE_Audio [FILTER:stateAV=on] Mute 1
set g_HSE_Audio [FILTER:stateAV=mute] Mute 0


Diese Set-Anweisungen kann man natürlich auch in ähnlicher Form einfach direkt auf eine Komma-separierte Liste aller Sonos Geräte machen.
Der Nachteil  dabei ist aber, wenn ich solche Anweisungen überall verstreut in meiner Konfiguration habe, dann muss ich das an mehreren Stellen ändern, wenn sich meine Geräte-Konstellation verändert. So muss ich nur zentral die Structure ändern und mein ganzer Automationscode (alle notify, alle DOIF etc.) bleiben wie sie sind  ;)
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

Loredo

#1
Ich habe diesen Codeschnipsel gerade überarbeitet.


Beim wechseln der Gruppenzusammensetzungen gibt es jetzt keine Probleme mehr und Loops werden auch vermieden.


Weiterhin werden jetzt die neuen Readings wie IsMaster, MasterPlayer und SlavePlayer verwendet statt der internen Funktionen vom SONOS Modul, die auch wohl nicht mehr richtig funktioniert haben in letzter Zeit.
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

50watt

@Loredo: Sehr cool! Danke!

Ich habe versucht das per copy&paste bei mir nachzubauen.

Folgendes ist mir aufgefallen:
attr Sonos_.* CmdIcon MuteT:rc_MUTE.svg Previous:rc_PREVIOUS.svg Next:rc_NEXT.svg
sollte
attr Sonos_.* cmdIcon MuteT:rc_MUTE.svg Previous:rc_PREVIOUS.svg Next:rc_NEXT.sv
sein.

define g_HSE_Audio g_audio Sonos_Bathroom Sonos_Bedroom Sonos_Kitchen Sonos_Living_Room
sollte
define g_HSE_Audio structure g_audio Sonos_Bathroom Sonos_Bedroom Sonos_Kitchen Sonos_Living_Room
sein.

Per Copy&paste konnte ich attr Sonos_.* userReadings stateAV:(presence|transportState|Mute).* {mySonosStateAV($name)},Favourites:LastActionResult.*?GetFavouritesWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } },Radios:LastActionResult.*?GetRadiosWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } },Playlists:LastActionResult.*?GetPlaylistsWithCovers.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } },currentTrackPosition:LastActionResult.*?GetCurrentTrackPosition.* { if (ReadingsVal($name, "LastActionResult", "") =~ m/.*?: (.*)/) { return $1; } },

nicht in die Befehlszeile einfügen, es fehlten immer die letzten paar Zeichen ; } },

Die Attribute, die vor der Structure angelegt werden, z.B. mit attr Sonos_.* userattr g_audio g_audio_map structexclude sollten aus den Sonos_.*RC und Sonos_.*RG devices wieder raus (oder besser erst gar nicht rein):

deleteattr Sonos_.*RG.* userattr
deleteattr Sonos_.*RG.* g_audio
deleteattr Sonos_.*RG.* g_audio_map
deleteattr Sonos_.*RG.* group
deleteattr Sonos_.*RG.* structexclude
deleteattr Sonos_.*RC.* userattr
deleteattr Sonos_.*RC.* g_audio
deleteattr Sonos_.*RC.* g_audio_map
deleteattr Sonos_.*RC.* group
deleteattr Sonos_.*RC.* structexclude


Das Attribute "sort" gibt es für die "structure" g_HSE_Audio nicht, daher liefert
attr g_HSE_Audio sort 0 einen Fehler.
RaspberryPi, EnOcean PI
Sonos Play1, Connect
Eltako FT55, FSB61, FAM12, FSR12-4x

Loredo

Danke, habe ich oben angepasst. Kommt davon, wenn man die generischen Schnipsel aus der eigenen dann doch leicht anderen Config nur in der Theorie zusammensetzt ;-)
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

dferch

Hi,

ich hab Deine Anpassung für Sonos bei mir eingerichtet und es klappt prima. Das gefällt mir so viel besser, als die Standard-Devices des Sonos-Moduls und jetzt sieht es auf dem iPhone (mit FHEM-Control) und dem Browser fast gleich aus. Auch die Lösung zum zentralen Abschalten aller Sonos-Player ist genial. Vielen Dank dafür !

Gruß,
David