Wochenende, Feiertage und Schulferien

Aus FHEMWiki
(Weitergeleitet von Holiday)

FHEM bietet die Möglichkeit, Komponenten in Abhängigkeit von Wochenenden und Schulferien sowie Feiertagen zu steuern. Hier soll beschrieben werden, wie Schulferien einbezogen werden.

Wochenendermittlung mit $we

Um am Wochenende (Samstag und Sonntag) länger schlafen zu können, kann diese Steuerung durch Nutzung der Variable $we erweitert werden. Diese hat am Wochenende den Wert 1, an sonstigen Tagen den Wert 0. In if-Abfragen wird die 0 als false/falsch interpretiert, andere numerische Werte als true/wahr. Man kann mittels if ($we) also ganz einfach prüfen, ob Wochenende ist und entsprechend steuern (oder auch nicht).

Eine simple Rollladensteuerung um 7 Uhr morgens für jeden Tag sieht beispielsweise wie folgt aus:

define RolloHoch at *07:00 set Rollo hoch

Dieses Beispiel kann entsprechend ergänzt werden, so dass am Wochenende nicht um 7 Uhr das Rollo nach oben gefahren wird:

 define RolloHoch at *07:00 { if (!($we)) { fhem("set Rollo hoch");; } }

Das ! in der if-Abfrage negiert den dahinter folgenden Ausdruck in der Klammer, ist also "nicht Wochenende". Der Inhalt der äußeren geschweiften Klammern stellt echten Perl-Code dar (der hinter jeder Anweisung gerne ein Semikolon stehen hat, das in FHEM durch ein weiteres Semikolon maskiert/escaped werden muss). Aus dem Perl-Code kann man mittels des Befehls fhem() wiederum FHEM-Code ausführen (hier der Befehl, um das Rollo nach oben zu fahren). Das (Doppel-)Semikolon ist in diesem Beispiel nicht zwingend notwendig, da es sich nur um eine einzige (und somit letzte) Anweisung handelt - man sollte sich jedoch aneignen, jede Anweisung im Perl-Code mit einem (Doppel-)Semikolon abzuschließen (eine schließende geschweifte Klammer stellt auch das Ende eine Anweisung bzw. eines Anweisungsblocks dar).

Intern wird für die Ermittlung, ob die FHEM-Variable $we wahr ist, die Funktion IsWe() verwendet.

IsWe()

Statt der obigen Schreibweise kann man auch direkt die Funktion IsWe() aufrufen. Eine andere Schreibweise für obiges Beispiel wäre daher:

 define RolloHoch at *07:00 { if (!(IsWe())) { fhem("set Rollo hoch");; } }

Der Vorteil dieser Vorgehensweise ist, dass IsWe() weitere Parameter kennt. Es kann zum einen nicht nur für den heutigen Tag (IsWe()), sondern auch für gestern (IsWe("yesterday")) und morgen (IsWe("tomorrow")) abgefragt werden. Dabei werden die in holiday2we angegebenen Geräte nacheinander durchgegangen und ermittelt, ob ein Reading mit diesem Namen vorhanden ist und etwas anderes liefert als "none". IsWe() ohne Parameter fragt den Inhalt des Readings "state" ab, für eigene Routinen kann auch IsWe("today") verwendet werden. Die Funktionsweise ist dann identisch zu den Abfragen nach "yesterday" und "tomorrow".

Ebenso kann die Behandlung von Samstagen und Sonntagen durch Verwendung eines zweiten Arguments mit einer Zahl >6 abgeschaltet werden, so dass nur noch ein positives Ergebnis zurückgeliefert wird, wenn tatsächlich ein Feiertag ist (siehe nachfolgenden Abschnitt):

{IsWe("tomorrow",7)} ist also nur dann wahr, wenn morgen ein Feiertag in einem in holiday2we angegebenen Device eingetragen ist.

(Fehlt: was passiert bei Angabe von kleineren Zahlen?)

IsWe() ohne Parameter wird intern von diversen Modulen verwendet, um den Wert von $we zu ermitteln, u.a. von AutoShuttersControl, DOIF und WeekdayTimer.

Feiertage mittels holiday-Datei

Allgemeines zu holiday2we

Samstags und Sonntags bleibt das Rollo nun unten und man kann länger schlafen. Um diesen Komfort auch an Feiertagen zu haben, können in FHEM mittels holiday-Dateien Feiertage definiert werden. Sinnvollerweise erstellt man sich für sein jeweiliges Bundesland eine eigene Datei, die Definitionen für feste Feiertage (z.B. Weihnachten oder der Tag der Deutschen Einheit) und solche in Abhängigkeit zu Ostern (z.B. Ostermontag oder Pfingsten, im Rheinland auch der Karneval) beinhaltet. Eine gutes Beispiel mit Erklärung findet sich in der FHEM-Übersicht für Anfänger. Nachdem beispielsweise die BW_Feiertag.holiday-Datei im FHEM-Ordner erstellt/abgelegt wurde, kann diese in die Konfiguration eingebunden werden. Mittels holiday2we können die darin definierten Feiertage mit der Variable $we "verheiratet" werden. if ($we) ist danach immer wahr, sobald Wochenende oder ein Feiertag ist:

 attr global holiday2we BW_Feiertag
 define BW_Feiertag holiday

In dem Attribut können mehrere Geräte angegeben werden:

 attr global holiday2we BW_Feiertag,meinUrlaubsdummy,Schulferien

Dabei wird bei echten holiday-Dateien (die auch seit Ende 2018 auch rechnen können[1]) jeweils eine entsprechende Auswertung durchgeführt, für alle anderen Devices (wie z.B. einem Dummy) wird entweder state für heute verwendet oder die Readings "tomorrow" bzw. "yesterday", wenn diese vorhanden sind. Dabei werden nicht vorhandene Werte als "kein Feiertag" behandelt, und alle anderen Werte mit Ausnahme von "none" als Feiertag.

weekEnd und noWeekend

Dies sind spezielle Einträge in holiday2we: Das Wort weekEnd als Eintrag bewirkt, dass grundsätzlich Samstage und Sonntage nicht mehr als $we angesehen werden, sondern nur noch die in einem der angegebenen Devices (mit Ausnahme von noWeekEnd) eingetragenen Feiertage bzw. Rückmeldungen für gestern, heute und morgen berücksichtigt werden. weekEnd selbst kann, muß aber nicht zugleich ein Gerät des Typs holiday sein. Ein noWeekEnd-Eintrag sollte dagegen mit einem Device verknüpft sein, denn alle Tage, die von diesem Gerät nach der üblichen Syntax als Treffer zurückgeliefert werden, werden abschließend als kein Feiertag' behandelt. Damit könnte man z.B. den ersten Weihnachtsfeiertag zum normalen Wochentag machen, egal, was andere holiday2we'-Einträge dazu melden, und auch gleichgültig, ob dies zugleich ein Sonntag ist.

Mitgelieferte holiday-Dateien

FHEM liefert eine Reihe von vordefinierten holiday-Dateien mit:

  • Dateien für die deutschen Bundesländer (abgekürzt laut amtlicher Liste), z.B. hh.holiday für Hamburg.
  • Feiertage in Österreich: aut.holiday
  • Feiertage im Vereinigten Königreich und Nordirland: en.holiday
  • Islamische Feiertage: islam20xx.holiday

Feiertage mittels Internet-Kalender

Info green.pngAlle x Stunden -wie hier dargestellt- einen unveränderten Jahres-Ferienkalender aus dem Internet erneut abzurufen ist nicht sinnvoll, da unnötige Abhängigkeiten des FHEM-Servers zur Verfügbarkeit des externen Servers entstehen. Zudem erzeugt dies unnötige Last auf dem externen Server. Besser ist es, nur einmal jährlich den Ferienkalender abzurufen und auf dem eigenen FHEM-Server zu speichern. Das Vorgehen ist beispielhaft in Beitrag beschrieben.

Theoretisch kann man in o.a. Datei auch seine persönlichen Urlaube oder die Schulferien definieren. Hier eignet sich jedoch die Calendar-Funktion wesentlich besser. V.a. die Schulferien der einzelnen Bundesländer sind im Internet (z.B. unter ferienwiki.de oder unter schulferien-online.de) als iCal-Datei verfügbar und können wie folgt in FHEM eingebunden werden:

define BW_Ferien Calendar ical url https://www.ferienwiki.de/exports/ferien/2020/de/baden-wuerttemberg 86400

Das Intervall von 86400 Sekunden (entspricht 24 Stunden) für die Aktualisierung der Schulferien sollte im Normalbetrieb mehr als ausreichen. Wenn eigene Kalender (z.B. bei Google) für Urlaubstage genutzt werden, muss man individuell abwägen, wie oft dieser aktualisiert werden soll. Nach dem Einbinden des Kalenders kann man sich die Termine anzeigen lassen:

get BW_Ferien events

Den Kalender kann man nun z.B. nutzen, um einen dummy zu setzen, der später entsprechend abgefragt werden kann. Man braucht dazu noch ein notify, welches direkt auf die Events des Kalenders reagiert.

define Ferientag dummy

define n_Ferien notify BW_Ferien:changed:.*start|BW_Ferien:changed:.*end {\
   my $stat=($EVTPART2 eq "start")?1:0;;\
   fhem("set Ferientag $stat") if defined fhem('get '.$NAME.' events filter:uid=="'.\
         $EVTPART1.'",field(summary)=~"(?i)ferien" limit:count=1',1)\
}

Der Ferientag ist in diesem Beispiel der angesprochene dummy und kann mittels Value("Ferientag") abgefragt werden. Im notify wird der Wert auf 1 gesetzt, sobald der Kalenderevent startet und auf 0 sobald der Event endet. (vgl. commandref/Calendar )

Um die Funktion zu testen, kann man sich aus dem Kalender Reading modeUpcoming die erste ID herauskopieren (Beispiel im April, Kalender 2020 Baden-Würtemberg) und mit dem trigger Befehl die Events des Calendar Devices einmal simulieren.

trigger BW_Ferien changed: 28f0d17b082149c3a6ef99c04153e937 start
trigger BW_Ferien changed: 28f0d17b082149c3a6ef99c04153e937 end

Um ein Rollo nun weder am Wochenende, an Feiertagen, noch zu Schulferien morgens hochfahren zu lassen, lautet das Beispiel:

 define RolloHoch at *07:00 { if ( !($we) && !(Value("Ferientag")) ) { fhem("set Rollo hoch");; } }

Ausgehend von diesem Artikel ist unter Google-Kalender zur Steuerung von Dummies eine Vorgehensweise zur Steuerung von FHEM mit dem Google-Kalender veröffentlicht.

Diese Methode unterstützt jedoch nicht die Feiertagserkennung des DOIF-Moduls, speziell im Abschnitt Wochentagssteuerung. Hier wird nur der Status der $we-Variable abgefragt und die Methode mit dem eigenen Holiday-Kalender empfohlen.

Links / Referenzen