AT kleine Helferlein: Unterschied zwischen den Versionen

Aus FHEMWiki
Keine Bearbeitungszusammenfassung
(2 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 69: 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. Als Wochentag wird 1-7 angegeben, wobei Montag der Wochentag 1 ist. Danach kommen als getrennte Parameter Stunde, Minute und Sekunde.
</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.


== AT alle x Wochen ausführen ==
== AT alle x Wochen ausführen ==
Zeile 96: Zeile 101:
}
}


</syntaxhighlight>Dabei wird der erste Ausführungstermin im FHEM-üblichen Format ("yyyy-mm-ddThh:mm:ss") übergeben. Die Variable $delta enthält das Intervall in Sekunden. Es kann entsprechend angepasst werden. Die Neuberechnung erfolgt ausgehend vom aktuellen Datum/Uhrzeit. Es kann also als erster Termin nur ein Termin in der Zukunft angegeben werden.  
</syntaxhighlight>Dabei wird der erste Ausführungstermin im FHEM-üblichen Format ("yyyy-mm-ddThh:mm:ss") übergeben. Die Variable $delta enthält das Intervall in Sekunden. Es kann entsprechend angepasst werden. Die Neuberechnung erfolgt ausgehend vom aktuellen Datum/Uhrzeit. Es kann also als erster Termin nur ein Termin in der Zukunft angegeben werden. 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_sixweek("2024-05-29T18:45:00")} {\
fhem("set TRV_Laden temp 21.0");;\
fhem("defmod at_heat_off_Lasse at +02:00:00 set TRV_Laden temp 15.0");;\
}
</syntaxhighlight>
[[Kategorie:Code Snippets]]
[[Kategorie:Code Snippets]]

Version vom 22. April 2024, 19:14 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 Wochen 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 sechs Wochen

sub at_sixweek($) {
my ($tm) = @_;
my $delta = 3628800;   # Zeit zwischen den Terminen in Sekunden, hier 6 Wochen

  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);

  if ($data{AT_RECOMPUTE}){
    # bei Neuberechnung sechs Wochen zur aktuellen Zeit addieren
    my $now = int(time);
    $abstime = $now+$delta;
  }

  return $abstime;
}

Dabei wird der erste Ausführungstermin im FHEM-üblichen Format ("yyyy-mm-ddThh:mm:ss") übergeben. Die Variable $delta enthält das Intervall in Sekunden. Es kann entsprechend angepasst werden. Die Neuberechnung erfolgt ausgehend vom aktuellen Datum/Uhrzeit. Es kann also als erster Termin nur ein Termin in der Zukunft angegeben werden. 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_sixweek("2024-05-29T18:45:00")} {\
fhem("set TRV_Laden temp 21.0");;\
fhem("defmod at_heat_off_Lasse at +02:00:00 set TRV_Laden temp 15.0");;\
}