AT kleine Helferlein: Unterschied zwischen den Versionen
F Klee (Diskussion | Beiträge) (Inhalt eingefügt) |
F Klee (Diskussion | Beiträge) (Anker hinzu gefügt) |
||
(10 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
Ein AT kann statt einer Uhrzeit bzw. eines Datums mit einer Uhrzeit auch eine Perl-Funktion nutzen. Beispiel solcher Funktionen sind [[At#at ultimo|at_ultimo]] oder das Modul [[SUNRISE_EL]]. Hier sollen weitere Funktionen | Ein AT kann statt einer Uhrzeit bzw. eines Datums mit einer Uhrzeit auch eine Perl-Funktion nutzen. Beispiel solcher Funktionen sind [[At#at ultimo|at_ultimo]] oder das Modul [[SUNRISE_EL]]. Hier sollen weitere Funktionen vorgestellt werden. | ||
Der Code kann in der [[99 myUtils anlegen|99 myUtils]] untergebracht werden. | Der Code kann in der [[99 myUtils anlegen|99 myUtils]] untergebracht werden. | ||
== | == {{Anker|AT am x-ten Wochentag im Monat ausführen}}AT am x-ten Wochentag im Monat ausführen == | ||
Aufgabe ist es, das at z.B. an jedem 2. Montag im Monat auszuführen. Zusätzlich gibt es auch die Möglichkeit, das at immer am z.B. letzten Montag im Monat auszuführen.<syntaxhighlight lang="perl"> | Aufgabe ist es, das at z.B. an jedem 2. Montag im Monat auszuführen. Zusätzlich gibt es auch die Möglichkeit, das at immer am z.B. letzten Montag im Monat auszuführen.<syntaxhighlight lang="perl"> | ||
######################################## | ######################################## | ||
Zeile 68: | Zeile 69: | ||
} | } | ||
</syntaxhighlight>Als Parameter benötigt die Funktion, welches Vorkommen des Wochentags berechnet werden soll (1-4). Soll das letzte Vorkommen berechnet werden, übergibt man 9. | </syntaxhighlight>Als Parameter benötigt die Funktion, welches Vorkommen des Wochentags berechnet werden soll (1-4). Soll das letzte Vorkommen berechnet werden, übergibt man 9. Als Wochentag wird 1-7 angegeben, wobei Montag der Wochentag 1 ist. Danach kommen als getrennte Parameter Stunde, Minute und Sekunde. Die Definition sieht dann so aus<syntaxhighlight lang="perl"> | ||
defmod at_heat1_Treffen_FG_Radverkehr at *{at_xwday(1,2,17,45,0)} {\ | |||
fhem("set TRV_Laden temp 21.0");;\ | |||
fhem("defmod at_heat_off_FG_Radverkehr at +02:00:00 set TRV_Laden temp 15.0");;\ | |||
} | |||
</syntaxhighlight>Die Heizung wird für das Treffen der Fachgruppe Radverkehr am ersten Dienstag im Monat auf 21 Grad gestellt. Gleichzeitig wird ein AT gestartet, das die Heizung zwei Stunden später wieder auf 15 Grad reduziert. Kleiner Tipp: Man kann im AT auch zwei FHEM-Befehle hintereinander senden. Klappte in diesem Fall aber nur über den kleinen Umweg über Perl. | |||
== {{Anker|AT alle x Tage ausführen}}AT alle x Tage ausführen == | |||
Soll ein Termin z.B. alle sechs Wochen stattfinden, so kann folgende Funktion genutzt werden.<syntaxhighlight lang="perl"> | Soll ein Termin z.B. alle sechs Wochen stattfinden, so kann folgende Funktion genutzt werden.<syntaxhighlight lang="perl"> | ||
######################################## | ######################################## | ||
# | # | ||
# Berechnung des Datums des | # Berechnung des Datums des | ||
# nächsten Treffens in | # nächsten Treffens in x Tagen | ||
sub | sub at_xdays($$) { | ||
my ($tm) = @_; | my ($tm,$days) = @_; | ||
my $delta = | my $delta = $days * DAYSECONDS; # Nächster Termin in sec | ||
return "Wrong timespec, use \"yyyy-mm-ddThh:mm:ss\"" if($tm !~ m/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)$/); | |||
my ($y,$m,$d,$h,$m2,$s) = ($1,$2,$3,$4,$5,$6); | |||
my $abstime = mktime($s,$m2,$h,$d,$m-1,$y-1900, 0,0,-1); | |||
my $now = int(time); | |||
my $diff = $now-$abstime; | |||
if ($diff>0){ | |||
# bei Neuberechnung sechs Wochen zur aktuellen Zeit addieren | |||
# wird auch bei Erstberechnung aufgerufen, wenn Timestamp in der Vergangenheit | |||
my $temp = ((int($diff/$delta)+1)*$delta)+$abstime; | |||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($temp); | |||
return mktime($s,$m2,$h,$mday,$mon,$year); | |||
} else {return $abstime;} | |||
} | |||
</syntaxhighlight>Dabei wird der erste Ausführungstermin im FHEM-üblichen Format ("yyyy-mm-ddThh:mm:ss") und das Intervall in Tagen übergeben. Die Variable $delta enthält dann das Intervall in Sekunden. Es wird zwar mit dem Timestamp gerechnet. Zurückgegeben wird aber das berechnete Datum und die der Funktion übergebene Uhrzeit. Das verhindert Probleme mit der Zeitumstellung. Hier die Definition für einen Termin alle sechs Wochen, beginnend am 29.05.2024 um 18:45 Uhr. Auch hier wird die Heizung zwei Stunden später wieder herunter gestellt.<syntaxhighlight lang="perl"> | |||
defmod at_heat2_Lasse at *{at_xdays("2024-05-29T18:45:00",42)} {\ | |||
fhem("set TRV_Laden temp 21.0");;\ | |||
fhem("defmod at_heat_off_Lasse at +02:00:00 set TRV_Laden temp 15.0");;\ | |||
} | } | ||
</syntaxhighlight> | |||
</syntaxhighlight> | |||
[[Kategorie:Code Snippets]] | [[Kategorie:Code Snippets]] |
Aktuelle Version vom 25. Juli 2024, 19:05 Uhr
Ein AT kann statt einer Uhrzeit bzw. eines Datums mit einer Uhrzeit auch eine Perl-Funktion nutzen. Beispiel solcher Funktionen sind at_ultimo oder das Modul SUNRISE_EL. Hier sollen weitere Funktionen vorgestellt werden.
Der Code kann in der 99 myUtils untergebracht werden.
AT am x-ten Wochentag im Monat ausführen
Aufgabe ist es, das at z.B. an jedem 2. Montag im Monat auszuführen. Zusätzlich gibt es auch die Möglichkeit, das at immer am z.B. letzten Montag im Monat auszuführen.
########################################
#
# Berechnung des Datums des
# x.ten Wochentags im Monat
#
# x=1-4 x.ter Wochentag im Monat
# x=9 letzter Wochentag im Monat
# w=1-7 Wochentag, 1=Montag
# h,m,s Uhrzeit Stunde, Minute, Sekunde
#
sub at_xwday($$$$$) {
my ($x,$w,$h,$m,$s) = @_;
my $ziel_tag = 0;
# akt. Datum und Uhrzeit in Variablen aufteilen
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time);
# bei Neuberechnung einen Monat addieren
my $add = $data{AT_RECOMPUTE} ? 1 : 0;
$mon = $mon + $add;
my ($nm, $ny) = ($mon == 12) ? (0,$year+1) : ($mon,$year);
# Letztes Vorkommen des Wochentags berechnen?
if ($x == 9) {
# Berechnen des letzten Tags des Monats
# ersten Tag des Folgemonats als timestamp
my ($xm, $xy) = ($mon == 11) ? (0,$year+1) : ($mon+1,$year);
my $nt = mktime(0, 0, 0, 1, $xm, $xy);
# letzter Tag des aktuellen Monats = erster Tag des Folgemonats minus ein Tag
my ($letzter_tag_des_monats, $letzter_wochentag) = (localtime($nt - DAYSECONDS))[3,6];
# Prüfen, ob der letzte Wochentag im Monat mit dem gewünschten Wochentag übereinstimmt
$ziel_tag = $letzter_tag_des_monats;
if ($letzter_wochentag > $w) {
# Falls der letzte Wochentag später im Monat ist, subtrahiere die Differenz
my $differenz = $letzter_wochentag - $w;
$ziel_tag -= $differenz;
} elsif ($letzter_wochentag < $w) {
# Falls der letzte Wochentag früher im Monat ist, subtrahiere 7 plus die Differenz
my $differenz = $w - $letzter_wochentag;
$ziel_tag -= (7 - $differenz);
}
} else {
# Berechne den Tag des ersten Vorkommens des Wochentags im Monat
my $erster_tag = 1;
my $erster_tag_des_monats = (localtime(mktime(0,0,0,$erster_tag,$nm,$ny)))[6];
my $erstes_vorkommen = ($w - $erster_tag_des_monats + 7) % 7 + 1;
# Berechne den Tag des x.ten Vorkommens des Wochentags im Monat
$ziel_tag = $erstes_vorkommen + 7 * ($x - 1);
# Überprüfe, ob das Datum im gültigen Bereich liegt
if ($ziel_tag > 31 || $ziel_tag < 1) {
return "Ungültiges Datum";
}
}
return mktime($s,$m,$h,$ziel_tag,$nm,$ny);
}
Als Parameter benötigt die Funktion, welches Vorkommen des Wochentags berechnet werden soll (1-4). Soll das letzte Vorkommen berechnet werden, übergibt man 9. Als Wochentag wird 1-7 angegeben, wobei Montag der Wochentag 1 ist. Danach kommen als getrennte Parameter Stunde, Minute und Sekunde. Die Definition sieht dann so aus
defmod at_heat1_Treffen_FG_Radverkehr at *{at_xwday(1,2,17,45,0)} {\
fhem("set TRV_Laden temp 21.0");;\
fhem("defmod at_heat_off_FG_Radverkehr at +02:00:00 set TRV_Laden temp 15.0");;\
}
Die Heizung wird für das Treffen der Fachgruppe Radverkehr am ersten Dienstag im Monat auf 21 Grad gestellt. Gleichzeitig wird ein AT gestartet, das die Heizung zwei Stunden später wieder auf 15 Grad reduziert. Kleiner Tipp: Man kann im AT auch zwei FHEM-Befehle hintereinander senden. Klappte in diesem Fall aber nur über den kleinen Umweg über Perl.
AT alle x Tage ausführen
Soll ein Termin z.B. alle sechs Wochen stattfinden, so kann folgende Funktion genutzt werden.
########################################
#
# Berechnung des Datums des
# nächsten Treffens in x Tagen
sub at_xdays($$) {
my ($tm,$days) = @_;
my $delta = $days * DAYSECONDS; # Nächster Termin in sec
return "Wrong timespec, use \"yyyy-mm-ddThh:mm:ss\"" if($tm !~ m/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)$/);
my ($y,$m,$d,$h,$m2,$s) = ($1,$2,$3,$4,$5,$6);
my $abstime = mktime($s,$m2,$h,$d,$m-1,$y-1900, 0,0,-1);
my $now = int(time);
my $diff = $now-$abstime;
if ($diff>0){
# bei Neuberechnung sechs Wochen zur aktuellen Zeit addieren
# wird auch bei Erstberechnung aufgerufen, wenn Timestamp in der Vergangenheit
my $temp = ((int($diff/$delta)+1)*$delta)+$abstime;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($temp);
return mktime($s,$m2,$h,$mday,$mon,$year);
} else {return $abstime;}
}
Dabei wird der erste Ausführungstermin im FHEM-üblichen Format ("yyyy-mm-ddThh:mm:ss") und das Intervall in Tagen übergeben. Die Variable $delta enthält dann das Intervall in Sekunden. Es wird zwar mit dem Timestamp gerechnet. Zurückgegeben wird aber das berechnete Datum und die der Funktion übergebene Uhrzeit. Das verhindert Probleme mit der Zeitumstellung. Hier die Definition für einen Termin alle sechs Wochen, beginnend am 29.05.2024 um 18:45 Uhr. Auch hier wird die Heizung zwei Stunden später wieder herunter gestellt.
defmod at_heat2_Lasse at *{at_xdays("2024-05-29T18:45:00",42)} {\
fhem("set TRV_Laden temp 21.0");;\
fhem("defmod at_heat_off_Lasse at +02:00:00 set TRV_Laden temp 15.0");;\
}