mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-01 20:20:10 +00:00
98_DOIF.pm: perl mode: new functions: set_Exec, get_Exec, del_Exec, more perl compatibility for [DOIF-Syntax] in perl mode
git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@17155 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
503d2f777d
commit
80c081ca8e
207
FHEM/98_DOIF.pm
207
FHEM/98_DOIF.pm
@ -35,7 +35,7 @@ sub DOIF_delTimer($)
|
||||
RemoveInternalTimer (\$hash->{triggertime}{$key});
|
||||
}
|
||||
foreach my $key (keys %{$hash->{ptimer}}) {
|
||||
RemoveInternalTimer ($key);
|
||||
RemoveInternalTimer (\$hash->{ptimer}{$key});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1451,10 +1451,14 @@ sub ReplaceAllReadingsDoIf
|
||||
}
|
||||
} elsif ($condition >= 0) {
|
||||
($timer,$err)=DOIF_CheckTimers($hash,$block,$condition,$trigger);
|
||||
return($timer,$err) if ($err);
|
||||
if ($timer) {
|
||||
$block=$timer;
|
||||
$event=1 if ($trigger);
|
||||
if ($err eq "no timer") {
|
||||
$block="[".$block."]";
|
||||
} else {
|
||||
return($timer,$err) if ($err);
|
||||
if ($timer) {
|
||||
$block=$timer;
|
||||
$event=1 if ($trigger);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$block="[".$block."]";
|
||||
@ -1570,6 +1574,11 @@ DOIF_CheckTimers($$$$)
|
||||
my $result;
|
||||
my $end;
|
||||
my $intervaltimer;
|
||||
|
||||
if ($timer !~ /^\s*(\[.*\]|\{.*\}|\(.*\)|\+.*|[0-9][0-9]:.*|:[0-5][0-9])$/ and $hash->{MODEL} eq "Perl") {
|
||||
return ($timer,"no timer");
|
||||
}
|
||||
|
||||
$timer =~ s/\s//g;
|
||||
($timer,$days)=SplitDoIf('|',$timer);
|
||||
$days="" if (!defined $days);
|
||||
@ -2799,6 +2808,66 @@ DOIF_SleepTrigger ($)
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub DOIF_set_Exec
|
||||
{
|
||||
my ($hash,$timername,$seconds,$subname,$param)=@_;
|
||||
$param="" if (!defined $param);
|
||||
my $current = gettimeofday();
|
||||
my $next_time = $current+$seconds;
|
||||
$hash->{ptimer}{$timername}{time}=$next_time;
|
||||
$hash->{ptimer}{$timername}{name}=$timername;
|
||||
$hash->{ptimer}{$timername}{subname}=$subname;
|
||||
$hash->{ptimer}{$timername}{param}=$param;
|
||||
$hash->{ptimer}{$timername}{hash}=$hash;
|
||||
RemoveInternalTimer(\$hash->{ptimer}{$timername});
|
||||
if ($seconds > 0) {
|
||||
readingsSingleUpdate ($hash,"timer_$timername",strftime("%d.%m.%Y %H:%M:%S",localtime($next_time)),0);
|
||||
}
|
||||
InternalTimer($next_time, "DOIF_ExecTimer",\$hash->{ptimer}{$timername}, 0);
|
||||
}
|
||||
|
||||
|
||||
sub DOIF_get_Exec
|
||||
{
|
||||
my ($hash,$timername)=@_;
|
||||
my $current = gettimeofday();
|
||||
if (defined $hash->{ptimer}{$timername}{time}) {
|
||||
my $sec=$hash->{ptimer}{$timername}{time}-$current;
|
||||
if ($sec > 0) {
|
||||
return ($sec);
|
||||
} else {
|
||||
delete ($hash->{ptimer}{$timername}{time});
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
sub DOIF_del_Exec
|
||||
{
|
||||
my ($hash,$timername)=@_;
|
||||
RemoveInternalTimer(\$hash->{ptimer}{$timername});
|
||||
delete $hash->{ptimer}{$timername};
|
||||
delete ($defs{$hash->{NAME}}{READINGS}{"timer_$timername"});
|
||||
}
|
||||
|
||||
sub DOIF_ExecTimer
|
||||
{
|
||||
my ($timer)=@_;
|
||||
my $hash=${$timer}->{hash};
|
||||
my $timername=${$timer}->{name};
|
||||
my $name=$hash->{NAME};
|
||||
my $subname=${$timer}->{subname};
|
||||
my $param=${$timer}->{param};
|
||||
eval ("$subname(\"$param\")");
|
||||
if ($@) {
|
||||
Log3 ($defs{$name}{NAME},1 , "$name error in $subname: $@");
|
||||
readingsSingleUpdate ($hash, "error", "in $subname: $@",0);
|
||||
}
|
||||
delete ($defs{$name}{READINGS}{"timer_$timername"});
|
||||
}
|
||||
|
||||
sub DOIF_set_Timer
|
||||
{
|
||||
my ($hash,$event,$seconds)=@_;
|
||||
@ -2815,6 +2884,8 @@ sub DOIF_set_Timer
|
||||
InternalTimer($next_time, "DOIF_PerlTimer", $timername, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub DOIF_get_Timer
|
||||
{
|
||||
my ($hash,$event)=@_;
|
||||
@ -2890,6 +2961,9 @@ CmdDoIfPerl($$)
|
||||
$tail =~ s/set_Timer[ \t]*\(/DOIF_set_Timer\(\$hash,/g;
|
||||
$tail =~ s/get_Timer[ \t]*\(/DOIF_get_Timer\(\$hash,/g;
|
||||
$tail =~ s/del_Timer[ \t]*\(/DOIF_del_Timer\(\$hash,/g;
|
||||
$tail =~ s/set_Exec[ \t]*\(/DOIF_set_Exec\(\$hash,/g;
|
||||
$tail =~ s/get_Exec[ \t]*\(/DOIF_get_Exec\(\$hash,/g;
|
||||
$tail =~ s/del_Exec[ \t]*\(/DOIF_del_Exec\(\$hash,/g;
|
||||
$tail =~ s/set_Event[ \t]*\(/DOIF_set_Event\(\$hash,/g;
|
||||
$tail =~ s/set_Reading[ \t]*\(/readingsSingleUpdate\(\$hash,/g;
|
||||
$tail =~ s/\$_(\w+)/\$hash->\{var\}\{$1\}/g;
|
||||
@ -2897,12 +2971,22 @@ CmdDoIfPerl($$)
|
||||
while ($tail ne "") {
|
||||
($beginning,$perlblock,$err,$tail)=GetBlockDoIf($tail,'[\{\}]');
|
||||
return ($perlblock,$err) if ($err);
|
||||
($perlblock,$err)=ReplaceAllReadingsDoIf($hash,$perlblock,$i,0);
|
||||
return ($perlblock,$err) if ($err);
|
||||
$hash->{condition}{$i}=$perlblock;
|
||||
if ($beginning =~ /(\w*)[\s]*$/) {
|
||||
$hash->{perlblock}{$i}=$1;
|
||||
if ($1 eq "init") {
|
||||
my $blockname=$1;
|
||||
if ($blockname eq "subs") {
|
||||
$perlblock =~ s/\$SELF/$hash->{NAME}/g;
|
||||
$perlblock ="no warnings 'redefine';".$perlblock;
|
||||
eval ($perlblock);
|
||||
if ($@) {
|
||||
return ("error in defs block",$@);
|
||||
}
|
||||
next;
|
||||
}
|
||||
($perlblock,$err)=ReplaceAllReadingsDoIf($hash,$perlblock,$i,0);
|
||||
return ($perlblock,$err) if ($err);
|
||||
$hash->{condition}{$i}=$perlblock;
|
||||
$hash->{perlblock}{$i}=$blockname;
|
||||
if ($blockname eq "init") {
|
||||
$hash->{perlblock}{init}=$i;
|
||||
if ($init_done) {
|
||||
if (($ret,$err)=DOIF_CheckCond($hash,$hash->{perlblock}{init})) {
|
||||
@ -5403,7 +5487,8 @@ Syntax Perl-Modus:<br>
|
||||
<ol><code>define <name> DOIF <Blockname> {<Perl mit DOIF-Syntax in eckigen Klammern>} <Blockname> {<Perl mit DOIF-Syntax in eckigen Klammern>} ...</code></ol><br>
|
||||
<br>
|
||||
Ein Perlblock wird ausgeführt, wenn dieser, bedingt durch DOIF-spezifischen Angaben in eckigen Klammern innerhalb des Blocks, getriggert wird.
|
||||
Es wird die vollständige Perl-Syntax unterstützt. Es können beliebig viele Perlblöcke definiert werden. Der Name eines Blocks ist optional. Wird ein Perlblock mit dem Namen "init" benannt, so wird er bereits zum Definitionszeitpunkt ausgeführt.<br>
|
||||
Es wird die vollständige Perl-Syntax unterstützt. Es können beliebig viele Perlblöcke definiert werden. Der Name eines Blocks ist optional. Wird ein Perlblock mit dem Namen "init" benannt, so wird er ausgeführt, nachdem das FHEM-System hochgefahren wurde. Er bietet sich insb. an, um Instatnzvariablen des Moduls vorzubelegen.<br>
|
||||
Ein besonderer Perlblock ist der Block namens "subs". Dieser Block wird nur zum Definitionszeitpunkt ausgeführt. In diesem Block sollten vornehmlich Perlfunktionen definiert werden, die innerhalb des DOIFs genutzt werden. Um eine möglichst hohe Kompatibilität zu Perl sicherzustellen, wird keine DOIF-Syntax in eckigen Klammern unterstützt, insb. gibt es keine Trigger, die den Block ausführen können.<br>
|
||||
<br>
|
||||
FHEM-Befehle werden durch den Aufruf der Perlfunktion <code>fhem"..."</code> ausgeführt. Im Gegensatz zum FHEM-Modus können im Perl-Modus mehrere Blöcke unabhängig voneinander, ausgelöst durch einen Ereignis- oder Zeit-Trigger, ausgeführt werden. So kann die Funktionalität mehrer DOIF-Module im FHEM-Modus innerhalb eines DOIF-Moduls im Perl-Moduls realisiert werden.<br>
|
||||
<br>
|
||||
@ -5426,6 +5511,8 @@ Bemerkung: Im Gegensatz zum FHEM-Modus arbeitet der Perl-Modus ohne Zustandsausw
|
||||
<a name="DOIF_Spezifische_Perl-Funktionen_im_Perl-Modus"></a>
|
||||
<b>Spezifische Perl-Funktionen im Perl-Modus</b><br>
|
||||
<br>
|
||||
<u>Ereignistimer</u><br>
|
||||
<br>
|
||||
Timer setzen: <code><b>set_Timer(<TimerEvent>, <seconds>)</code></b>, mit <TimerEvent>: beliebige Angabe, sie spezifiziert eindeutig einen Timer und ist gleichzeitig ein Ereignis,
|
||||
welches nach Ablauf des Timers in FHEM erzeugt wird. Auf dieses Ereignis kann wie üblich mit der DOIF-Syntax durch die Angabe [$SELF:"^<TimerEvent>$"] reagiert werden.
|
||||
Wird set_Timer mit dem gleichen <TimerEvent> vor seinem Ablauf erneut aufgerufen, so wird der laufender Timer gelöscht und neugesetzt.<br>
|
||||
@ -5434,11 +5521,21 @@ Timer holen: <code><b>get_Timer(<TimerEvent>)</code></b>, Returnwert: 0, w
|
||||
<br>
|
||||
Laufenden Timer löschen: <code><b>del_Timer(<TimerEvent>)</code></b><br>
|
||||
<br>
|
||||
<u>Funktionstimer</u><br>
|
||||
<br>
|
||||
Timer setzen: <code><b>set_Exec(<timerName>, <seconds>, <function>, <parameter>)</code></b>, mit <timerName>: beliebige Angabe, sie spezifiziert eindeutig einen Timer,
|
||||
welcher nach Ablauf die angegebene Perl-Funktion <function> mit optionalen Parameter <parameter> aufruft. Die Perlfunkion muss eindeutig sein und in FHEM zuvor deklariert worden sein.
|
||||
Wird set_Exec mit dem gleichen <timerName> vor seinem Ablauf erneut aufgerufen, so wird der laufender Timer gelöscht und neugesetzt.<br>
|
||||
<br>
|
||||
Timer holen: <code><b>get_Exec(<timerNamet>)</code></b>, Returnwert: 0, wenn Timer abgelaufen oder nicht gesetzt ist, sonst Anzahl der Sekunden bis zum Ablauf des Timers<br>
|
||||
<br>
|
||||
Laufenden Timer löschen: <code><b>del_Exec(<timerName>)</code></b><br>
|
||||
<br>
|
||||
Ein beliebiges FHEM-Event absetzen: <code><b>set_Event(<Event>)</code></b><br>
|
||||
<br>
|
||||
Reading schreiben: <code><b>set_Reading(<readingName>,<content>,<trigger>)</code></b>, mit <trigger>: 0 ohne Trigger, 1 mit Trigger<br>
|
||||
<br>
|
||||
Es können alle in FHEM vorhanden Funktionen genutzt werden. Größere Perlblöcke können in eigene Funktionen (z. B. in myUtils) ausgelagert werden.
|
||||
Es können alle in FHEM vorhanden Funktionen genutzt werden. Größere Perlblöcke sollten in eigene Funktionen im subs-Block ausgelagert werden.
|
||||
Der Anwender hat die Möglichkeit Instanzvariablen beginnen mit $_ zu nutzen. Sie müssen nicht deklariert werden. Deren Gültigkeitsbereich ist ein definiertes DOIF-Device. Wenn sie nicht vorbelegt werden, gelten sie als nicht definiert. Das lässt sich abfragen mit:<br>
|
||||
<code>if (defined $_...) ...</code><br>
|
||||
<br>
|
||||
@ -5483,17 +5580,17 @@ Ebenso funktionieren hash-Variablen z. B.: <br>
|
||||
Anforderung: Wenn eine Taste innerhalb von zwei Sekunden zwei mal betätig wird, soll der Rollladen nach oben, bei einem Tastendruck nach unten.<br>
|
||||
<br>
|
||||
<code>
|
||||
define di_shutter DOIF { #Perlblock zur Auswertung des Tastendruckes<br>
|
||||
if (["FS:^on$"] and get_Timer("Timer_shutter")==0){ #wenn Taste betätigt wird und kein Timer läuft<br>
|
||||
set_Timer("Timer_shutter",2) #Timer für zwei Sekunden setzen<br>
|
||||
} else { #wenn Timer läuft, d.h. ein weitere Tastendruck innerhalb von zwei Sekunden<br>
|
||||
del_Timer("Timer_shutter") #Timer löschen<br>
|
||||
fhem"set shutter up"; #Rollladen hoch<br>
|
||||
define di_shutter DOIF { # Block zur Auswertung des Tastendruckes<br>
|
||||
if (["FS:^on$"] and get_Timer("Timer_shutter")==0){ # wenn Taste betätigt wird und kein Timer läuft<br>
|
||||
set_Timer("Timer_shutter",2); # Timer für zwei Sekunden setzen<br>
|
||||
} else { # wenn Timer läuft, d.h. ein weitere Tastendruck innerhalb von zwei Sekunden<br>
|
||||
del_Timer("Timer_shutter") # Timer löschen<br>
|
||||
fhem"set shutter up"; # Rollladen hoch<br>
|
||||
}<br>
|
||||
}<br>
|
||||
{ #Perlblock für die Bearbeitung des Timerevents<br>
|
||||
if ([$SELF:"Timer_shutter"]){ #Wenn nach zwei Sekunden Timer abläuft, d.h. nur ein Tastendruck<br>
|
||||
fhem"set shutter down" #Rollladen runter<br>
|
||||
{ # Block für die Bearbeitung des Timerevents<br>
|
||||
if ([$SELF:"Timer_shutter"]){ # wenn nach zwei Sekunden Timer abläuft, d.h. nur ein Tastendruck<br>
|
||||
fhem"set shutter down"; # Rollladen runter<br>
|
||||
}<br>
|
||||
}<br>
|
||||
</code>
|
||||
@ -5503,57 +5600,65 @@ define di_shutter DOIF { #Perlblock zur Auswertung des Tastendr
|
||||
Im folgenden Beispiel wird die Nutzung von Instanzvariablen demonstriert.<br>
|
||||
<br>
|
||||
<code>
|
||||
define di_count DOIF { #Perlblock zur Auswertung des Ereignisses<br>
|
||||
if (["FS:on"] and get_Timer("Timer_counter")==0){ #wenn Ereignis (hier "FS:on") eintritt und kein Timer läuft<br>
|
||||
$_count=1; #setze count-Variable auf 1<br>
|
||||
set_Timer("Timer_counter",3600) #setze Timer auf eine Stunde<br>
|
||||
define di_count DOIF { # Block zur Auswertung des Ereignisses<br>
|
||||
if (["FS:on"] and get_Timer("Timer_counter")==0){ # wenn Ereignis (hier "FS:on") eintritt und kein Timer läuft<br>
|
||||
$_count=1; # setze count-Variable auf 1<br>
|
||||
set_Timer("Timer_counter",3600); # setze Timer auf eine Stunde<br>
|
||||
} else {<br>
|
||||
$_count++ #wenn Timer bereits läuft zähle Ereignis<br>
|
||||
$_count++; # wenn Timer bereits läuft zähle Ereignis<br>
|
||||
}<br>
|
||||
}<br>
|
||||
{ #Perlblock für die Auswertung nach Ablauf des Timers<br>
|
||||
if ([$SELF:"Timer_counter"]) { #wenn Timer nach einer Stunde abläuft<br>
|
||||
if ($_count > 10) {Log 3,"count: $_count action"}} #protokolliere im Log die Anzahl der Ereignisse, wenn sie über 10 ist<br>
|
||||
{ # Block für die Auswertung nach Ablauf des Timers<br>
|
||||
if ([$SELF:"Timer_counter"]) { # wenn Timer nach einer Stunde abläuft<br>
|
||||
if ($_count > 10) {<br>
|
||||
Log 3,"count: $_count action"; # protokolliere im Log die Anzahl der Ereignisse, wenn sie über 10 ist<br>
|
||||
}<br>
|
||||
}<br>
|
||||
}<br>
|
||||
</code><br>
|
||||
<br>
|
||||
<a name="DOIF_Treppenhauslicht mit Bewegungsmelder"></a>
|
||||
<u>Treppenhauslicht mit Bewegungsmelder</u><br>
|
||||
<br><code>
|
||||
define di_light DOIF bewegung { #Perlblock namens "bewegung" reagiert auf Bewegung von FS<br>
|
||||
if (["FS:motion"]) {<br>
|
||||
if ([?lamp:state] ne "on") { #wenn Lampe aus ist<br>
|
||||
fhem"set lamp on"; #Lampe einschalten<br>
|
||||
set_Reading ("state","on",1); #setze Status des DOIF-Moduls auf "on"<br>
|
||||
<br><code><br>
|
||||
define di_light DOIF<br>
|
||||
subs { # Block "subs" zur Definition eigener Perl-Funktionen, hier ist nur Perl erlaubt ohne DOIF-Syntax<br>
|
||||
sub ein { # Perlfunktion "ein" zum Einschalten wird definiert<br>
|
||||
if (ReadingsVal ("lamp","state","") ne "on") {<br>
|
||||
fhem"set lamp on";<br>
|
||||
set_Reading ("state","on",1);<br>
|
||||
}<br>
|
||||
set_Timer("lamp_off",30); #Timer wird gesetzt bzw. verlängert<br>
|
||||
}<br>
|
||||
sub aus { # Perlfunkton "aus" zum Ausschalten wird definiert<br>
|
||||
fhem"set lamp off";<br>
|
||||
set_Reading ("state","off",1);<br>
|
||||
}<br>
|
||||
}<br>
|
||||
ausschalten { #Perlblock namens "ausschalten" reagiert auf Trigger vom des Timers "lamp_off"<br>
|
||||
if ([$SELF:"lamp_off"]) { #Wenn Timer lamp_off abläuft<br>
|
||||
fhem"set lamp off"; #schalte Lampe aus<br>
|
||||
set_Reading ("state","off",1); #setze Status des DOIF-Modus auf "off"<br>
|
||||
bewegung { # Block namens "bewegung" reagiert auf Bewegung von FS<br>
|
||||
if (["FS:motion"]) {<br>
|
||||
ein(); # Perlfunktion "ein" wird ausgeführt<br>
|
||||
set_Exec("light_off",10,"aus"); # Timer namens "light_off"für das Ausschalten über Perlfunktion "aus" wird gesetzt bzw. verlängert<br>
|
||||
}<br>
|
||||
}<br></code>
|
||||
}<br>
|
||||
</code>
|
||||
<br>
|
||||
<a name="DOIF_Fenster_offen_Meldung"></a>
|
||||
<u>Verzögerte Fenster-offen-Meldung mit Wiederholung für mehrere Fenster</u><br>
|
||||
<br>
|
||||
<code>define di_window DOIF { <br>
|
||||
if (["_window$:open"]) { #wenn ein Fensterdevice endend mit "_window" geöffnet wird<br>
|
||||
set_Timer ("WINDOW_$DEVICE",600) #setze einen Timer auf 10 Minuten<br>
|
||||
<code>define di_window DOIF { # Block zum Auswerten des Ereignisses: "Fenster geöffnet"<br>
|
||||
if (["_window$:open"]) { # wenn ein Fensterdevice endend mit "_window" geöffnet wird<br>
|
||||
set_Timer ("WINDOW_$DEVICE",600) # setze einen Timer auf 10 Minuten<br>
|
||||
}<br>
|
||||
}<br>
|
||||
{ #Timer löschen, wenn Fenster geschlossen wird<br>
|
||||
{ # Block zum Auswerten des Ereignisses: "Fenster gechlossen"<br>
|
||||
if (["_window$:closed"]) {<br>
|
||||
del_Timer ("WINDOW_$DEVICE")<br>
|
||||
del_Timer ("WINDOW_$DEVICE") # Timer löschen, wenn Fenster geschlossen wird<br>
|
||||
}<br>
|
||||
}<br>
|
||||
{ #Auswertung eines Timers<br>
|
||||
if (["^$SELF:^WINDOW_"]) { #wenn ein Timerevent kommt<br>
|
||||
my ($window,$device)=split("_","$EVENT"); #bestimme das Device aus dem Timerevent "WINDOW_$DEVICE"<br>
|
||||
Log 3,"Fenster offen, bitte schließen: $device"; #Meldung wird protokolliert<br>
|
||||
set_Timer ("WINDOW_$device",1800) #setze einen neuen Timer für das Fenster für eine erneute Meldung in 30 Minuten<br>
|
||||
{ # Block zur Auswertung des zuvor gesetzten Timers<br>
|
||||
if (["^$SELF:^WINDOW_"]) { # wenn das zuvor gesetzte Timerevent kommt<br>
|
||||
my ($window,$device)=split("_","$EVENT"); # bestimme das Device aus dem Timerevent "WINDOW_$DEVICE"<br>
|
||||
Log 3,"Fenster offen, bitte schließen: $device"; # Meldung wird protokolliert<br>
|
||||
set_Timer ("WINDOW_$device",1800) # setze einen neuen Timer für das Fenster für eine erneute Meldung in 30 Minuten<br>
|
||||
}<br>
|
||||
}<br>
|
||||
</code>
|
||||
|
Loading…
x
Reference in New Issue
Block a user