FHEM - Hausautomations-Systeme > Kalendermodule

[gelöst] (kein) Bedarf für 57_Calendar2holiday.pm

(1/6) > >>

Beta-User:
Hallo zusammen,

beim Review meiner alten Codes und Geräte aus der ersten Zeit ist mir eine Sache aufgefallen, von der ich noch nicht so richtig weiß, wie ich damit umgehen soll. Ich vereinfache daher mal etwas:

Es soll jeder Ferientag wie ein Tag am Wochenende behandelt werden. Dafür bestehen (mindestens) folgende Möglichkeiten:

- Abfrage bei jedem Befehl, ob (neben $we auch) die Variable "Ferientag" (gesetzt über ein Calendar-notify, z.B. in einem Dummy) wahr ist
- Erstellen einer entsprechenden "holiday"-Datei ("ferien.holiday") und Einbinden über eine 2. holiday2we-Angabe ("attr global holiday2we bw,ferien")
- Ersetzen der $we-Abfrage durch eine eigene Variable/perl-Funktion, wie z.B. hier beschrieben (habe noch nicht getestet, ob z.B. ein WeekdayTimer das einfach so akzeptieren würde).
- Einsatz von HOMEMODE&Co - das ist mir aber eigentlich zu viel drumrum für den eigentlich simplen task

Bislang besteht zwischen den Lösungen Calendar und holiday jedenfalls nur sowas wie eine Art friedlicher Koexistenz, den ziemlich letzten Stand der Dinge sehe ich hier gut zusammengefasst, auch im Wiki oder hier steht nichts, was auf anderes hinweist.

Die Idee: Ein Modul, das ähnlich wie CALVIEW und MÜLL aus einem (oder mehreren) Calendardevices die erforderlichen Daten entnimmt und so in eine holiday-Datei schreibt, dass holiday2we was damit anfangen kann. Im Prinzip würde ja immer heute und (sicherheitshalber) morgen ausreichen (analyzePerlCommand() in fhem.pl scheint das ja immer bei einem entsprechenden Aufruf zu prüfen, es reicht insoweit eigentlich, wenn der aktuelle Tag paßt). Aber man könnte genauso gut natürlich immer bis zum YE nehmen, mind. aber die nächsten 30 Tage usw..
Über die Definition bzw. entsprechende Attribute wäre zu steuern, welche Schlüsselwörter wo enthalten sein müssen ("Urlaub", aber das z.B. nur, wenn im Ort auch "zuhause" steht usw.).

Fragen dazu:
- Fehlt da was und die Aufgabe ist viel einfacher zu lösen?
- Gibt es evtl. jemanden, der mich beim Entwickeln eines solchen Moduls coachen wollte (oder das als so einfach empfindet, dass der Aufwand geringer wäre, das selbst direkt zu erledigen ::) )?

Gruß, Beta-User

Beta-User:
Hallo zusammen,

habe das "Problem" zwischenzeitlich mit einem "at" gelöst.

Das liest jeden Freitag einen Kalender ein, in dem u.A. die Ferientermine drin sind.


--- Code: ---defmod a_make_holiday at *23:30 {return undef unless($wday == 5);;\
my @holidaysraw = split(/\n/,(fhem 'get Familienkalender events format:custom="4 $T1 $T2 $S" timeFormat:"%m-%d" limit:count=10 filter:field(summary)=~".*[fF]erie.*"'));;\
my @holidays;;\
foreach (@holidaysraw) {\
    unless ($_ =~ /[Ww]eihnacht/) {\
        push (@holidays, $_);; \
    } else { my @tokens = split (" ",$_);;\
        my $lines = "4 $tokens[1] 12-31 $tokens[3]";;\
        push (@holidays,$lines);;\
        $lines = "4 01-01 $tokens[2] $tokens[3]";;\
        unshift (@holidays,$lines);;\
    }\
} \
my $today = strftime "%d.%m.%y, %H:%M", localtime(time);;\
my $idstring = "# Created by at a_make_holiday on $today";;\
unshift (@holidays, $idstring);; \
my $filename ="./FHEM/ferien.holiday";;\
FileDelete($filename);;\
FileWrite($filename,@holidays);;\
}
--- Ende Code ---
Die Datenlimits am Calendar-Device sollten natürlich sinnvoll (< 1 Jahr gesamt) gesetzt sein. Die so erzeugte holiday-Datei muss als holiday-Device definiert und in global mit holiday2we zusätzlich eingebunden werden, Beispiel:


--- Code: ---defmod ferien holiday
attr global holiday2we bw,ferien

--- Ende Code ---

Wie immer: Nutzung des Codes auf eigene Gefaht, Verbesserungsvorschläge sind willkommen.

Viel Spaß damit!

Beta-User

Beta-User:
So,

nachdem nach den neuesten Erkenntnissen zum Jahreswechsel mal meine derzeitige erweiterte Fassung (RAW-Code), mit Kommentaren:


--- Code: ---defmod a_make_holiday at *23:30 {return undef unless($wday == 5);;\
\
#Ferienkalender\
my @holidaysraw = split(/\n/,(fhem 'get Familienkalender events format:custom="4 $T1 $T2 $S" timeFormat:"%m-%d" limit:count=10 filter:field(summary)=~".*[fF]erie.*"'));;\
my @holidays;;\
foreach (@holidaysraw) {\
    unless ($_ =~ /[Ww]eihnacht/) {\
        push (@holidays, $_);; \
    } else { my @tokens = split (" ",$_);;\
        my $lines = "4 $tokens[1] 12-31 $tokens[3]";;\
        push (@holidays,$lines) if $month == 12;;\
        $lines = "4 01-01 $tokens[2] $tokens[3]";;\
        unshift (@holidays,$lines);;\
    }\
} \
my $today = strftime "%d.%m.%y, %H:%M", localtime(time);;\
my $idstring = "# Created by at a_make_holiday on $today";;\
unshift (@holidays, $idstring);; \
my $filename ="./FHEM/ferien.holiday";;\
FileDelete($filename);;\
FileWrite($filename,@holidays);;\
\
#Mülltonnen\
my @tonnen = split(/\n/,(fhem 'get Familienkalender events format:custom="1 $T1 $S" timeFormat:"%m-%d" series:next limit:count=4 filter:field(summary)=~".*(Bioabfall|Restmuell).*"'));;\
unshift (@tonnen, $idstring);; \
$filename ="./FHEM/muell.holiday";;\
FileDelete($filename);;\
FileWrite($filename,@tonnen);;\
}

--- Ende Code ---


--- Code: ---defmod a_make_holiday at *23:30 {return undef unless($wday == 5);;\
--- Ende Code ---
=jeden Tag aufrufen, aber nur am Freitag den nachfolgenden Code auch durchlaufen
Zwei verschiedene Durchläufe durch denselben Kalender (ein ical, lokal gespeichert; der wird täglich aus dem inet geholt). Dessen Attribute "hideOlderThan" und "hideLaterThan" sind großzügig gesetzt (010d/0100d).

1. Durchlauf zur Erstellung eines Ferienkalenders im holiday-Format:

--- Code: ---#Ferienkalender\
my @holidaysraw = split(/\n/,(fhem 'get Familienkalender events format:custom="4 $T1 $T2 $S" timeFormat:"%m-%d" limit:count=10 filter:field(summary)=~".*[fF]erie.*"'));;\
--- Ende Code ---

Holt max. 10 Kalendereinträge aus dem Kalender, die Einträge kommen dabei schon in dem Grundformat, das einem .holiday entspricht (das get kann man mit dem eigenen Kalendernamen so in die Kommandozeile eingeben!). Das Ergebnis landet in einem Array.

--- Code: ---my @holidays;;\
foreach (@holidaysraw) {\
    unless ($_ =~ /[Ww]eihnacht/) {\
        push (@holidays, $_);; \
    } else { my @tokens = split (" ",$_);;\
        my $lines = "4 $tokens[1] 12-31 $tokens[3]";;\
        push (@holidays,$lines) if $month > 9;;\
        $lines = "4 01-01 $tokens[2] $tokens[3]";;\
        unshift (@holidays,$lines);;\
    }\
} \
--- Ende Code ---
Es wird ein weiteres Array initialisiert, und dann zeilenweise jeder Eintrag aus dem ersten Array geschrieben wird. Da allerdings holiday nicht mit Jahreswechseln umgehen kann, bekommen die Weihnachtsferien eine Sonderbehandlung und werden in zwei Abschnitte geteilt. Dabei wird nur zum Jahresende hin der Dezember noch geschrieben, im Januar ist das Geschichte...

Dann bilden wir eine Kennung, damit wir im .holiday auch sehen, wie die Datei entstanden ist und schreiben die Daten in eine neue Datei:

--- Code: ---my $today = strftime "%d.%m.%y, %H:%M", localtime(time);;\
my $idstring = "# Created by at a_make_holiday on $today";;\
unshift (@holidays, $idstring);; \
my $filename ="./FHEM/ferien.holiday";;\
FileDelete($filename);;\
FileWrite($filename,@holidays);;\
--- Ende Code ---

Dann dasselbe für die Mülltonnen, wobei das eher eine Spielerei ist (die Tonnen werden im Sommer am selben Tag geleert, und damit kann holiday evtl. nicht umgehen; für meine Zwecke reicht es, wenn ich sehe, dass überhaupt was ist, der Rest steht ja im Kalender...

--- Code: ---\#Mülltonnen\
my @tonnen = split(/\n/,(fhem 'get Familienkalender events format:custom="1 $T1 $S" timeFormat:"%m-%d" series:next limit:count=4 filter:field(summary)=~".*(Bioabfall|Restmuell).*"'));;\
unshift (@tonnen, $idstring);; \
$filename ="./FHEM/muell.holiday";;\
FileDelete($filename);;\
FileWrite($filename,@tonnen);;\
}

--- Ende Code ---

Hoffe, das ist jetzt etwas klarer. Die Vorgehenweise eignet sich eher für längerfristig planende Themen, die potentiell alle Bewohner treffen, nicht für tages- oder stundenaktuelles Reagieren...

Beta-User:
Aus gegebenem Anlass hier mein aktualisierter Code.

Aufgerufen wird jetzt mit
--- Code: ---define a_make_holiday at *23:30 { return undef  if !$wday == 5;; myCalendar2Holiday('Familienkalender','.*[fF]erie.*','ferien','summary',10,'[Ww]eihnacht');; myCalendar2Holiday('Familienkalender','.*(Bioabfall|Restmüll).*','muell','summary',4,'') }
--- Ende Code ---
Aufruf also mit
- "Name des Calendar-Devices",
- "Suchmuster" (für filter),
- "Name des zu erstellenden .holiday-Devices",
- "Suchfeld" für filter,
- max. Anzahl der Treffer,
- "regex": für Zeiträume, die über das Jahresende hinausgehen (hier typischerweise die Weihnachtsferien).

Pflicht sind nur die ersten beiden.

Der eigentliche neue Code für myUtils:

--- Code: ---sub myCalendar2Holiday {
  my $calname    = shift // return;
  my $regexp     = shift // return;
  my $targetname = shift // $calname;
  my $field      = shift // "summary";
  my $limit      = shift // 10;
  my $yearEndRe  = shift;
 
  my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) =  localtime(gettimeofday());
  my $getstring = $calname . ' events format:custom="4 $T1 $T2 $S" timeFormat:"%m-%d" limit:count=' . $limit." filter:field($field)=~\"$regexp\"";
  my @holidaysraw = split( /\n/, CommandGet( undef, "$getstring" ));
 
  my @holidays;
  for my $holiday (@holidaysraw) {
    if ( !$yearEndRe || $holiday !~ m/$yearEndRe/) {
      push (@holidays, $holiday);
    } else { my @tokens = split (" ",$holiday);
      my $lines = "4 $tokens[1] 12-31 $tokens[3]";
      push (@holidays,$lines) if $month > 9;
      $lines = "4 01-01 $tokens[2] $tokens[3]";
      unshift (@holidays,$lines);
    }
  }
  unshift (@holidays, "# get $getstring");
  my $today = strftime "%d.%m.%y, %H:%M", localtime(time);;\
  unshift (@holidays, "# Created by myCalendar2Holiday on $today");
  FileWrite("./FHEM/${targetname}.holiday",@holidays);
}
--- Ende Code ---
So sollte es jetzt für praktisch alle denkbaren Fälle generisch nutzbar sein, ich hoffe, es hilft jemandem, in jedem Fall:

Viel Spaß damit :) .

hydrotec:
Hallo Beta-User,

jetzt habe ich mich etwas mehr in .holiday eingelesen. (noch nie verwendet)
Die Funktion in 99_myUtils_calendar2holiday.pm kopiert,
und den Aufruf der Funktion nach meinen Gegebenheiten angepasst.

--- Code: ---defmod AT_make_test_holiday at *23:30 { return undef  if !$wday == 5;; myCalendar2Holiday('Cal_Test','.*(Homeoffice|Urlaub)*','test','summary',10,'') }
attr AT_make_test_holiday DbLogExclude .*
attr AT_make_test_holiday room Kalender

--- Ende Code ---
Eine test.holiday wurde mit dem gewünschten Inhalt erstellt.
Übrigens, Dank deiner hervorragenden Arbeit, alles ohne Probleme.
Dann das holiday-device angelegt, um zu sehen was ausgegeben wird.
und in global noch das attr holiday2we mit test gesetzt.

So wie ich das Ganze jetzt verstehe, ergeben sich mir folgende Möglichkeiten.
 - generelle Abfrage ob WT oder WE (Beispiele wird mit "ja/nein" quittiert.
 - definierte Abfrage auf die readings des holiday-device was morgen, heute oder gestern beinhaltet.
 - und noch weitere Funktionen, die ich vermutlich für mein Szenario (noch) nicht brauchen werde.

Eine Frage hätte ich noch dazu.
Kann es sein, das wenn gestern Urlaub war, und heute Homeoffice, im reading state (heute?) beides (state Urlaub, Homeoffice) drin steht?

Bin mir jetzt nicht sicher, ob die Funktion meine userReadings ersetzen kann.
Bzw. nicht der gleiche Aufwand vorhanden wäre, den ich hier mal etwas genauer beschrieben habe.

Grüße, Karsten

Navigation

[0] Themen-Index

[#] Nächste Seite

Zur normalen Ansicht wechseln