[Perl-Mode] Autopause bei Medienwiedergabe und Verlassen des Raumes

Begonnen von Ellert, 19 September 2018, 18:08:36

Vorheriges Thema - Nächstes Thema

Ellert

Das Ziel ist, die Medienwiedergabe zu pausieren, wenn eine Person den Raum verlässt und die Medienwiedergabe wieder aufzunehmen, wenn eine Person den Raum wieder betritt.

Voraussetzungen
2 Bewegungsmelder SR501 an GPIOs eines RPi und 2 RPI_GPIO-Instanzen
1 Kodi-Instanz
optional 2 PRESENCE-Instanzen zur Anwesenheitserkennung

Bezeichnungen
PIR24 und PIR25 sind 2 Bewegungsmelder, sie werden beim Verlassen des Raumes in der Reiehnfolge PIR25 und PIR24 aktiviert. die Bewegungsmelder sind auf eine Totzeit von ca. 25 s eingestellt.
Die Bewegungsmelder müssen so angeordnet werden, dass sie nur beim Verlassen oder Betreten des Raumes reagieren können und sie nacheinander in Bewegungsrichtung reagieren.
Das Gerät osmc ist die KODI-Instanz, die automatisch pausiert wird.
Das Gerät pirDirection ist der Eventhandler, eine DOIF-Instanz im Perl-Mode.
Optional sind zwei PRESENCE-Instanzen PaulAn und GerdaAn, die über G-Tags die Anwesendheit erkennen.

Funktionsweise
Nur wenn osmc connected ist und die Bewegungsmelder nacheinander innerhalb einer einstellbaren Erkennungszeitspanne (6 s) auslösen, wird das Gehen und Kommen gezählt.
Wenn die Differenz zwischen Gehen und Kommen größer null ist, dann wird pausiert, wenn die Differenz wieder null wird, dann wird die Pause beendet. Sie wird auch nach einem einstellbaren Timeout (7 min) beendet.
Optional wird die Automatik bei Heimkehr eines Bewohners für eine einstellbare Zeitspanne deaktiviert.

Eventhandler

defmod pirDirection DOIF subs {\
  sub pirDirReset {\
    readingsBeginUpdate($hash);;\
      readingsBulkUpdate($hash, "C_in", 0);;\
      readingsBulkUpdate($hash, "C_out", 0);;\
      readingsBulkUpdate($hash, "C_diff",0);;\
    readingsEndUpdate($hash,1);;\
    if (ReadingsVal("osmc","state","disconnected") eq "opened" and ReadingsVal("osmc","type","none") =~ "movie|episode|unknown" and ReadingsVal("osmc","playStatus","none") eq "paused") {\
  fhem "set osmc play";;\
    }\
  }\
  \
  sub pirDirDirection {\
    my $pn = "$SELF";;\
    my $t = gettimeofday();;\
    my $pir24sec = InternalVal("PIR24", "lasttrg", $t);;\
    my $pir25sec = InternalVal("PIR25", "lasttrg", $t);;\
    my $pirdiff = $pir25sec - $pir24sec;;\
    my $cin = ReadingsNum($pn,"C_in",0);;\
    my $cout = ReadingsNum($pn,"C_out",0);;\
    my $ms = ReadingsNum($pn,"P_play_after",7) * 60;;\
    my $maxdiff = ReadingsNum($pn,"P_maxdiff_triggertimes",6);;\
    if ($pirdiff > 0 and $pirdiff < $maxdiff and $cin < $cout) {\
      $cin++;;\
      readingsBeginUpdate($hash);;\
        readingsBulkUpdate($hash, "C_in", $cin);;\
        readingsBulkUpdate($hash, "C_diff",($cout-$cin));;\
      readingsEndUpdate($hash,1);;\
      if ($cin > 0 and $cout > 0 and $cin == $cout) {\
        pirDirReset();;\
        del_Exec($pn."_pirdir");;\
      }\
    } elsif ($pirdiff < 0 and $pirdiff > -$maxdiff) {\
      $cout++;;\
      set_Reading("C_out",$cout,1);;\
      if ($cout > 0 and $cout > $cin) {\
        if (Value("osmc") eq "opened" and ReadingsVal("osmc","type","none") =~ "movie|episode|unknown" and ReadingsVal("osmc","playStatus","none") eq "playing") {\
fhem "set osmc pause";;\
        }\
        set_Exec($pn."_pirdir", $ms , "pirDirReset");;\
      }\
    }\
  }\
}\
\
mediapausebreak {\
  my $pn = "$SELF";;\
  if (["^(Paul|Gerda)An$:^presence: present$"] and ReadingsVal($pn,"S_state","inactive") eq "active") {\
    set_Reading("S_state", "inactive",0);;\
    set_Exec("mediapausebreak",ReadingsVal($pn,"P_inactive_duration",20)*60,'set_Reading("S_state", "active",1) if (ReadingsVal("'.$pn.'","S_state","inactive") eq "inactive" and ReadingsVal("osmc","state","disconnected") eq "opened");;');;\
  }\
}\
\
getdirection {\
  if (ReadingsVal("$SELF","S_state","inactive") eq "active" and ["^PIR2(4|5)$:^Counter: "]){\
    pirDirDirection();;\
  }\
}\
\
setS_state {\
  if(["^osmc$:^DISCONNECTED$"]){\
    set_Reading("S_state","inactive",0);; ## Pause bei Raum verlassen AUS\
  } elsif (["^osmc$:^CONNECTED$"]){\
    set_Reading("S_state","active",0);; ## Pause bei Raum verlassen EIN\
  }\
}\

attr pirDirection icon helper_doif
attr pirDirection readingList P_maxdiff_triggertimes,P_play_after,P_inactive_duration,S_state
attr pirDirection setList P_inactive_duration:selectnumbers,1,1,60,0,lin\
S_state:active,inactive \
P_play_after:selectnumbers,1,.5,20,1,lin\
P_maxdiff_triggertimes:selectnumbers,1,.5,10,1,lin
attr pirDirection webCmd P_inactive_duration:P_play_after:P_maxdiff_triggertimes
attr pirDirection webCmdLabel Inaktivt&auml;;tsdauer bei Heimkehr/min:Autoreset/min:Erkennungszeitspanne/s

setstate pirDirection 2018-09-18 23:19:40 C_diff 0
setstate pirDirection 2018-09-18 23:19:40 C_in 0
setstate pirDirection 2018-09-18 23:19:40 C_out 0
setstate pirDirection 2018-09-16 19:21:56 P_inactive_duration 20
setstate pirDirection 2018-09-18 19:47:26 P_maxdiff_triggertimes 6.0
setstate pirDirection 2018-09-16 20:19:37 P_play_after 7.0
setstate pirDirection 2018-09-18 23:12:56 S_state inactive



Bewegungsmelder

defmod PIR24 RPI_GPIO 24
attr PIR24 direction input
attr PIR24 interrupt rising

defmod PIR25 RPI_GPIO 25
attr PIR25 direction input
attr PIR25 interrupt rising



KODI-Instanz

defmod osmc KODI xxx.xxx.xxx.xx tcp
attr osmc event-on-change-reading type
attr osmc event-on-update-reading playStatus
attr osmc fork enable
attr osmc offMode shutdown
attr osmc updateInterval 60

Damian

Schön, wenn sich solche Aufgaben neuerdings in einem DOIF umsetzen lassen.

Ich würde allerdings auf das unnötige Parsen von fhem-Befehlen verzichten, wenn die gleiche Funktionalität mit Perl-Funktionen umsetzbar ist, wenn man ohnehin auf der Perlebene ist.

z. B.
statt
fhem "setreading $pn C_in $cin;;setreading $pn C_diff ".($cout-$cin);

kann man Perlfunktion nutzen:

set_Reading("C_in",$cin,0);
set_Reading("C_diff",$cout-$cin,0);


Dahinter verbirgt sich die Perl-Funktion: readingsSingleUpdate

Es ist performanter, man braucht nicht den Devicenamen (hier $pn) anzugeben und man kann mit dem letzten Parameter entscheiden, ob ein Event erzeugt werden soll oder nicht.


Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Ellert

Danke für die Vorschläge , ich hatte nur 2 DOIF und die Subs aus myUtils zu Perl-Mode migriert.

readingsSingleUpdate ruft readingsBeginnUpdate und readingsEndUpdate auf, es ist daher noch permormanter das Update mehrerer Readings zusammenzufassen und dann readingsBulkUpdate zu verwenden.

Ich habe die Optimierungen im ersten Beitrag eingebaut.

Damian

Zitat von: Ellert am 20 September 2018, 09:02:46
readingsSingleUpdate ruft readingsBeginnUpdate und readingsEndUpdate auf, es ist daher noch permormanter das Update mehrerer Readings zusammenzufassen und dann readingsBulkUpdate zu verwenden.

ja, nur gut, dass $hash bekannt ist :) Das ist aber kein Zufall, sonst würden auch andere Dinge nicht funktionieren.

Edit:
Wichtig zu wissen ist noch die Funktionsweise von set_Exec im Zusammenhang mit $hash

z. B.

set_Exec("bla",1,"readingsBeginUpdate($hash)...") würde nicht funktionieren, weil der $hash vorzeitig ersetzt wird, er darf erst nach Ablauf der Verzögerung in eval ausgewertet werden.

Daher:
set_Exec("bla",1,'readingsBeginUpdate($hash)...')
angeben

oder 
set_Exec("bla",1,"readingsBeginUpdate(\$hash)...")
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF