neue Features: ereignisgesteuertes Perl - DOIF-Perl

Begonnen von Damian, 25 Februar 2018, 21:29:16

Vorheriges Thema - Nächstes Thema

Damian

Wie bereits hier diskutiert https://forum.fhem.de/index.php/topic,84692.0.html habe ich eine neue DOIF-Version erstellt, die neue Syntax (Perlmodus) unterstützt. Sie ist im Anhang hinterlegt.

Der neue Perlmodus im DOIF kommt ohne Attribute aus. Er ist nicht mit dem bisherigen Modus (MODE: FHEM) kombinierbar. Der aktuelle Device-Modus wird automatisch aufgrund der Syntax vom Modul erkannt und im Internal MODE: Perl/FHEM abgelegt.

Im Perlmodus lassen sich insb. komplexere Abläufe innerhalb eines DOIF-Devices programmieren. Der Anwender hat mehr Einfluss auf den Ablauf, er muss sich dafür selbst um die möglichen Zustände kümmern, dafür gibt es keine vorgegebenen Abhängigkeiten im Modul, die man beachten müsste.

Maximale Performance: Zum Zeitpunkt der Definition, werden alle DOIF-spezifischen Angaben in Perl übersetzt, zum Zeitpunkt der Ausführung wird nur noch Perl ausgeführt.

Die Doku zum Perl-Modus lässt sich in wenigen Zeilen aufschreiben:

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

Damian

Was kann man nun mit einem DOIF-Perl machen, was man mit einem DOIF nicht kann?

z. B. Einknopffernbedienung:

defmod di_shutter DOIF init {$hash->{var}{Timer}=0}\
{if ([FS:"on"] and $hash->{var}{Timer}==0){\
   set_Timer("Timer shutter",2);;$hash->{var}{Timer}=1\
} else {\
   fhem"set shutter up";;$hash->{var}{Timer}=0;;del_Timer("Timer shutter")\
}\
}\
{if ([$SELF:"Timer shutter"]){$hash->{var}{Timer}=0;;fhem"set shutter down"}}


Wenn FS innerhalb von zwei Sekunden zwei mal betätigt wird, wird "set shutter up" ausgeführt, bei einmaligem Tastendruck "set shutter down".
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Ellert

Zitat von: Damian am 03 März 2018, 16:53:51
Was kann man nun mit einem DOIF-Perl machen, was man mit einem DOIF nicht kann?

z. B. Einknopffernbedienung:

defmod di_shutter DOIF init {$hash->{var}{Timer}=0}\
{if ([FS:"on"] and $hash->{var}{Timer}==0){\
   set_Timer("Timer shutter",2);;$hash->{var}{Timer}=1\
} else {\
   fhem"set shutter up";;$hash->{var}{Timer}=0;;del_Timer("Timer shutter")\
}\
}\
{if ([$SELF:"Timer shutter"]){$hash->{var}{Timer}=0;;fhem"set shutter down"}}


Wenn FS innerhalb von zwei Sekunden zwei mal betätigt wird, wird "set shutter up" ausgeführt, bei einmaligem Tastendruck "set shutter down".
Es geht auch mit einem DOIF ;)
defmod updown DOIF ([FS:"on"])\
  (setreading $SELF counter {([$SELF:counter,"0"] + 1)})\
DOELSEIF ([$SELF:state] eq "cmd_1")\
  (\
  IF ([$SELF:counter] == 1)\
    (set shutter up, setreading $SELF counter 0) \
  ELSE \
    (set shutter down, setreading $SELF counter 0)\
  )
attr updown checkReadingEvent 1
attr updown do resetwait
attr updown room 0_Test
attr updown selftrigger wait
attr updown wait 0.1:2

setstate updown initialized
setstate updown 2018-03-03 20:35:37 cmd 0
setstate updown 2018-03-03 20:34:43 counter 0
setstate updown 2018-03-03 20:35:37 mode enabled
setstate updown 2018-03-03 20:35:37 state initialized

Damian

#3
Zitat von: Ellert am 03 März 2018, 20:38:18
Es geht auch mit einem DOIF ;)
defmod updown DOIF ([FS:"on"])\
  (setreading $SELF counter {([$SELF:counter,"0"] + 1)})\
DOELSEIF ([$SELF:state] eq "cmd_1")\
  (\
  IF ([$SELF:counter] == 1)\
    (set shutter up, setreading $SELF counter 0) \
  ELSE \
    (set shutter down, setreading $SELF counter 0)\
  )
attr updown checkReadingEvent 1
attr updown do resetwait
attr updown room 0_Test
attr updown selftrigger wait
attr updown wait 0.1:2

setstate updown initialized
setstate updown 2018-03-03 20:35:37 cmd 0
setstate updown 2018-03-03 20:34:43 counter 0
setstate updown 2018-03-03 20:35:37 mode enabled
setstate updown 2018-03-03 20:35:37 state initialized


Es ging mir in erster Linie um die Attribute waitsame und waitdel, die sich in diesem Fall nicht kombinieren lassen (siehe Commandref-Beispiele: https://fhem.de/commandref_DE.html#DOIF_waitsame)

Deine Lösung ist, wie meine auch, weitgehend "programmiert". Für deine muss man DOIF-Experte sein. Im DOIF-Perl-Modus muss man dagegen etwas Perl und die beiden DOIF-spezifischen Aufrufe kennen (hier: set_Time, del_Timer), dafür muss man keine Kenntnis über DOIF-spezifische Attribute haben. DOIF-Perl ist natürlich um einiges performanter. Da muss jeder für sich entscheiden, was ihm besser liegt. Beides ist möglich. Ich denke der Programmierer wird zu der Perl-Variante greifen.

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

Damian

#4
Ich habe noch eine Funktion get_Timer spendiert (v0.5 im ersten Post). Damit kann man erkennen, ob ein Timer noch läuft, bzw. in wie viel Sekunden er abläuft. Damit lässt sich die Einknopffernbedienung noch einfacher gestalten:

defmod di_shutter DOIF {if ([FS:"on"] and get_Timer("Timer shutter")==0){\
  set_Timer("Timer shutter",2)} else {fhem"set shutter up";;del_Timer("Timer shutter")}\
}\
{if ([$SELF:"Timer shutter"]){fhem"set shutter down"}}
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Hier ein Beispiel mit mehreren wait-Timern in einem DOIF: verzögerte Fenster-offen-Meldung mit Wiederholung, für alle Fenster, die mit "Fenster" enden.

defmod di_window DOIF { if (["Fenster$:open"]) {set_Timer ("WINDOW $DEVICE",600)}}\
{ if (["Fenster$:closed"]) {del_Timer ("WINDOW $DEVICE")}}\
{ if (["^$SELF:^WINDOW"]) {my ($window,$device)=split(" ","$EVENT");;Log 3,"Fenster offen, bitte schließen: $device";;set_Timer ("WINDOW $device",1800)}}

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

Damian

#6
Ich habe die Nutzung von Instanzvariablen $hash->{var}{<varname>} etwas vereinfacht. Variablen, die mit $_ beginnen können als Instanzvariablen genutzt werden. Die Perl-Sondervariable $_ kann wie üblich im Perlcode trotzdem benutzt werden.

Was macht wohl dieses kleine Programmchen?

defmod di_var DOIF init {$_i=0}\
{if ([FS]) {set_Reading ("state",$_i++,1)}}


Im konventionellen DOIF nur umständlich über Readings mit setreading umsetzbar.

Edit:

Ebenso funktionieren hash-Variablen z.B.

$_betrag{heute}=100;

Die Instanzvariablen müssen nicht deklariert werden, sie sind am Anfang nicht definiert, wenn man sie nicht vorbelegt. Man kann sie abfragen, ob sie definiert sind  z. B. mit if (defined $_...) ...

Ebenso lassen sich Instanzvariablen indizieren, z. B.:

my $i=0;
$_betrag{$i}=100;


Instanzvariablen überleben nicht den Neustart, sie können aber z.B. im init-Block aus Readings vorbelegt werden:

init {$_status=[?$SELF:state]}

oder einfach

init {$_status=ReadingsVal("$SELF","state",0)}
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Zum Thema Selbsttriggerung:

Im bisherigen DOIF-FHEM-Modus ist Selbsttriggerung, zum Schutz des Users, unterbunden und muss über das Attribut selftrigger erlaubt werden.

Im DOIF-Perl-Modus wird eine andere Strategie verfolgt: Die Selbsttriggerung ist grundsätzlich erlaubt, sie wird vom Modul nicht unterbunden.  Hinter set_Event(<Event>) verbirgt sich set_Timer(<Event>, 0). Damit wird sogar die Unterbindung von Loops seitens FHEM umgangen und es entstehen keine rekursiven Aufrufe im Modul selbst, D.h. hier können mehr als 2 Loops programmiert werden, was durchaus sinnvoll sein kann. Der User hat hier volle Kontrolle über das Geschehen, muss sich aber dessen bewusst sein, was er "programmiert" hat, um Endlos-Loops nicht zu erzeugen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

choenig

Hi,

ich habe gerade bemerkt, dass auf einmal diverse "normale" DOIFs als Perl-Mode erkannt werden. Betroffen scheinen solche mit Kommentaren am Anfang zu sein:


##
## Updated die sysTime auf allen Wandthermostaten und Heizungsthermostaten
##

([05:05])
(set model=(HM-TC-IT-WM-W-EU|HM-CC-RT-DN):FILTER=chanNo= sysTime)


Ich glaube, ich setze noch die Version 0.4 ein. Kann grad nicht besser nachsehen.

LG
Christian

Damian

Zitat von: choenig am 10 März 2018, 18:46:43
Hi,

ich habe gerade bemerkt, dass auf einmal diverse "normale" DOIFs als Perl-Mode erkannt werden. Betroffen scheinen solche mit Kommentaren am Anfang zu sein:


##
## Updated die sysTime auf allen Wandthermostaten und Heizungsthermostaten
##

([05:05])
(set model=(HM-TC-IT-WM-W-EU|HM-CC-RT-DN):FILTER=chanNo= sysTime)


Ich glaube, ich setze noch die Version 0.4 ein. Kann grad nicht besser nachsehen.

LG
Christian

Du musst die aktuelle Version (v0.6) aus dem ersten Post nehmen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

#10
Bei folgendem Problem, welches in der Automatisation durchaus häufig auftritt, müsste man beim konventionellen DOIF schon etwas nachdenken.

Anforderung: Wenn innerhalb einer Zeitspanne (hier eine Stunde) ein bestimmtes Ereignis mehr als x mal eintritt (hier 10 mal), dann führe eine Aktion aus (hier ein Log-Eintrag).

So sieht es mit DOIF-Perl aus (performant, da ohne FHEM-Befehle, in einer Definition gekapselt und ohne Attribute):

defmod di_count DOIF {if (["FS:on"] and get_Timer("Timer counter")==0){$_count=1;;set_Timer("Timer counter",3600)} else {$_count++}}\
{if ([$SELF:"Timer counter"]) {if ($_count > 10) {Log 3,"count: $_count action"}}}
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Aktuelle Version v0.10 im ersten Post. Laufende Timer werden jetzt in Readings festgehalten. Ich habe angefangen die Doku im Modul zu aktualisieren. Der Countdown zum Einchecken läuft.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Version v.12 im Anhang. Neues FHEM-Feature implementiert: https://forum.fhem.de/index.php/topic,85868.0.html . Abhängig vom Modus, wird aufgrund der Definition die Attributliste automatisch angepasst, dh. im Perl-Modus lassen sich nur noch sinnvolle Attribute für diesen Modus auswählen.

Doku ist weitgehend fertig. Es kommen nur noch ein paar weitere Anwendungsbeispiele hinzu.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

DOIF-Perl eingecheckt. Bitte beachten, dass diese Version nur mit der aktuellen fhem.pl Version funktioniert.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Ellert

commandref_join liefert für # $Id: 98_DOIF.pm 16471 2018-03-23 11:42:27Z Damian $
Zitat98_DOIF.pm: negative tagcount for code, line 3830

In Zeile 3827 wird der code-tag zu früh geschlossen er müsste gelöscht werden.