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

Begonnen von Beta-User, 15 März 2018, 10:48:23

Vorheriges Thema - Nächstes Thema

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
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Beta-User

#1
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.

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

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:

defmod ferien holiday
attr global holiday2we bw,ferien


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

Viel Spaß damit!

Beta-User
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Beta-User

#2
So,

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

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


defmod a_make_holiday at *23:30 {return undef unless($wday == 5);;\=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:
#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.*"'));;\

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.

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);;\
    }\
} \
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:
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);;\


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...
\#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);;\
}


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...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Beta-User

Aus gegebenem Anlass hier mein aktualisierter Code.

Aufgerufen wird jetzt mit
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,'') }

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

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 :) .
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

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.
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

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


Beta-User

Vorab mal Danke für die Blumen :) .

Zitat von: hydrotec am 21 Oktober 2020, 17:02:04
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?
Das kommt mir komisch vor. Ohne list (und vermutlich ohne den (auszugsweisen) Inhalt der .holiday) ist das schwierig.
Eventuell ist es ein Problem mit den ganztägigen Kalenderzeiten, v.a., wenn die Uhren der beiden Systeme (FHEM und dein Nextcloud-Server) nicht gleich gehen bzw. denselben zeitlichen Bezugspunkt haben. Das erinnert mich an Synchronisationsprobleme mit dem Handy, da waren teils auch 1 bzw. 2 Stunden Versatz drin, wenn der eine UTC sprach und der andere CET verstanden hat...

ZitatBin 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.
Abschließend sagen kann ich das auch nicht, denn zum einen habe ich keinen Schimmer von DOIF und zum anderen ist das mAn. so verschachtelt, dass man das vermutlich nicht mal als "Selbstnutzer" dann noch verstehen kann, wenn man sich mal 4 Wochen nicht damit beschäftigt hatte.
Ich vermute immer noch, dass .holiday+holiday2we eigentlich der einfachere Weg sind, um sowas umzusetzen. Wie dem auch sei: Mindestens der WeekdayTimer kann z.B. auch mit "durch $we übersteuerten Wochentagen" umgehen, und grade, wenn du das ggf. zur Heizungssteuerung nutzen willst, kann auch weekprofile (ggf. iVm. WeekdayTimer) vieles vereinfachen. Muß man sich zwar auch einlesen/eindenken, aber dafür ist man auf einer Standardfunktionalität, die ggf. auch andere durchschauen.

Allg. vielleicht noch ein Hinweis: Da du irgendwie zu versuchen scheinst, eine Art Bewohnerstatus abzubilden, wäre ggf. auf RESIDENTS&Co. was, was einen Blick wert ist. Das fügt sich tendenziell natloser in ein FHEM-System ein als dummy-TYPE Devices.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

hydrotec

Hallo Beta-User,

Anbei die lists der verwendeten devices, und der Inhalt der test.holiday.


Internals:
   DEF        ical url https://{USERNAME}:{PASSWORD}@192.168.78.33:31443/remote.php/dav/calendars/{USERNAME}/test?export 3600
   FUUID      5f8ea543-f33f-e864-04c0-74ae841d0d761686
   NAME       Cal_Test
   NOTIFYDEV  global
   NR         266
   NTFY_ORDER 50-Cal_Test
   STATE      triggered
   TYPE       Calendar
   READINGS:
     2020-10-23 07:16:10   calname         Test
     2020-10-23 07:16:10   lastUpdate      2020-10-23 07:16:08
     2020-10-20 10:52:22   modeAlarm       
     2020-10-23 00:00:00   modeAlarmOrStart 2ad3b71da69d4eeb879d99e193ea5a0e
     2020-10-20 10:52:22   modeAlarmed     
     2020-10-23 00:56:09   modeChanged     
     2020-10-23 06:56:10   modeEnd         6528e59c5f944028961c58470d1e0a04;94fb1aa1d95745aea7eb9bc75ce5b6dd;a677ec4c64624979b7265549b63d8ca1;0f2e16d03c0542b59f63560cb8662eab;941271100eaf4e3c852f01a029e901df;527ae32ff9974c13837a675f4fc75d09;cc9da3ed361e4a51bb9b60601cffb3e8;c292eddd3b704fc6b3bf768214e675b1;da82f87e979d424f86444043d8b6e261
     2020-10-23 00:56:09   modeEnded       
     2020-10-23 00:00:00   modeStart       2ad3b71da69d4eeb879d99e193ea5a0e
     2020-10-23 00:56:09   modeStarted     
     2020-10-23 07:16:10   modeUpcoming    31ff297d9af74e39a7d3b55b701855fc;51797570c12e4fda9f0ffdf8accb2bfa;2985b597ab5f428db379f0ecaa335b20;0b2fac924a254a069bf7690872154439;f072d50b73a6432e9f2d4a26e2fbc043;10e7f81e97b042c5bd96dd08e2ce805f;c418252459144d3ab0633de5d0a35fd3;cbba40d82ec348a98e7a5194471657c9;b1259d68edb8432ea70e0a243bc1e3e8;24aa54f8f5404feab019eabe766412a8;1170f3732036485a8a953c945e543152;70652de40a28402ea14b368856dad40f
     2020-10-23 07:16:10   nextUpdate      2020-10-23 08:16:08
     2020-10-23 07:16:10   nextWakeup      2020-10-23 08:16:08
     2020-10-23 07:16:10   state           triggered
Attributes:
   DbLogExclude .*
   hideLaterThan 030d
   hideOlderThan 001d
   room       Kalender




Internals:
   COMMAND    { return undef  if !$wday == 5; myCalendar2Holiday('Cal_Test','.*(Homeoffice|Urlaub)*','test','summary',10,'') }
   DEF        *23:30 { return undef  if !$wday == 5; myCalendar2Holiday('Cal_Test','.*(Homeoffice|Urlaub)*','test','summary',10,'') }
   FUUID      5f8eb953-f33f-e864-0595-7fd902b72c882560
   NAME       AT_make_test_holiday
   NR         267
   PERIODIC   yes
   RELATIVE   no
   REP        -1
   STATE      Next: 23:30:00
   TIMESPEC   23:30
   TRIGGERTIME 1603488600
   TRIGGERTIME_FMT 2020-10-23 23:30:00
   TYPE       at
   READINGS:
     2020-10-22 23:30:00   state           Next: 23:30:00
Attributes:
   DbLogExclude .*
   room       Kalender




Internals:
   FUUID      5f8eb9da-f33f-e864-8db2-9cef16713bcf2906
   HOLIDAYFILE ./FHEM/test.holiday
   NAME       test
   NR         268
   READONLY   0
   STATE      Urlaub , Homeoffice
   TRIGGERTIME 1603490402.10749
   TYPE       holiday
   READINGS:
     2020-10-23 07:19:48   state           Urlaub , Homeoffice
     2020-10-23 07:19:48   tomorrow        Homeoffice, Urlaub
     2020-10-23 07:19:48   yesterday       Urlaub
Attributes:
   DbLogExclude .*
   room       Kalender




# Created by myCalendar2Holiday on 23.10.20, 07:17
# get Cal_Test events format:custom="4 $T1 $T2 $S" timeFormat:"%m-%d" limit:count=10 filter:field(summary)=~".*(Homeoffice|Urlaub)*"
4 10-22 10-23 Urlaub
4 10-23 10-24 Homeoffice
4 10-24 10-25 Urlaub
4 10-25 10-26 Homeoffice
4 10-26 10-27 Urlaub
4 10-27 10-28 Homeoffice
4 10-28 10-29 Homeoffice
4 10-29 10-30 Homeoffice
4 10-30 10-31 Homeoffice
4 11-02 11-03 Urlaub



An der Zeit kann es eigentlich nicht liegen, zumindest nicht offensichtlich.
Beide Server synchronisieren ihre Zeit über die Fritzbox (CET).


Danke noch für deinen Hinweis, RESIDENTS verwende ich in Verbindung mit Homebridge.
Zitat von: hydrotec am 21 Oktober 2020, 16:57:48
z.B.: (([DU_Anwesenheit_Timer] eq "on") and ([DU_ZuHause_geo] eq "on")) (set MyXperia screen on) DOELSE (set MyXperia screen off)
Der in dem Beispiel verwendete dummy ist noch der Anfangszeit geschuldet, aber funktioniert ;)


Gruß, Karsten

Beta-User

Ah, Mist...

Da muß ich nochmal ran, denn die Ferienabfrage liefert Zeiträume (Typ 4), mein Müll-Kalender dagegen einzelne Tage (Typ 1). Wenn man letztere in Zeiträume umwandelt, kommt nichts vernünftiges raus.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Beta-User

So, hier dann mal Code, der zumindest bei ersten Tests ganz ok war, um eintägige von mehrtägigen Einträgen zu unterscheiden. Kann aber sein, dass der Probleme hat, denn ein Stundentermin über den Tageswechsel dauert; das müßte man dann noch anders abfangen, wenn man sowas braucht... Bei meiner Art Kalender mit ganztägigen 00:00Uhr-24:00 Uhr-Einträgen klappt das jedenfalls :) .

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 $D" timeFormat:"%m-%d" limit:count=' . $limit." filter:field($field)=~\"$regexp\"";
  my @holidaysraw = split( /\n/, CommandGet( undef, "$getstring" ));

  my @holidays;
  my @singledays;
  for my $holiday (@holidaysraw) {
    my @tokens = split (" ",$holiday);
    #my @elements = split( " ", $holiday );
    my $duration = pop @tokens;
   
    my $severalDays = $duration =~ m,[0-9]+h, ? 0 : 1;
   
    $holiday = join(' ', @tokens);
    if (!$severalDays) {
      $tokens[0] = 1;
      splice @tokens, 2, 1;
      $holiday = join(' ', @tokens);
      push (@singledays, $holiday);
    } elsif ( !$yearEndRe || $holiday !~ m/$yearEndRe/) {
      push (@holidays, $holiday);
    } else {
      $holiday = "4 $tokens[1] 12-31 $tokens[3]";
      push (@holidays,$holiday) if $month > 9;
      $holiday = "4 01-01 $tokens[2] $tokens[3]";
      unshift (@holidays,$holiday);
    }
  }
  push @holidays, @singledays;
  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);
}
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

hydrotec

Hallo Beta-User,

entschuldige bitte das es mit der Rückmeldung etwas gedauert hat.


Zitat von: Beta-User am 26 Oktober 2020, 19:38:48
Bei meiner Art Kalender mit ganztägigen 00:00Uhr-24:00 Uhr-Einträgen klappt das jedenfalls :) .
Kann ich nur bestätigen, klappt einwandfrei. TOP  8)

Mit freundlichen Grüßen,
Karsten

eldrik

Hallo zusammen,

habe die Codebeispiele im Zuge von AutoShuttersControl aufgetan (im Wiki verlinkt).

Leider wird bei meinen ganztägigen Terminen (eingetragen über den iPhone Kalender) die bis zum 31.12 oder auch testweise bis zum 04.01 gingen, die holiday Datei folgend gefüllt.

# Created by myCalendar2Holiday on 30.11.20, 12:47
# get Calendar_Jens  events format:custom="4 $T1 $T2 $S $D" timeFormat:"%m-%d" limit:count=10 filter:field(summary)=~".*[uU]rlau.*"
4 11-03 01-05 Urlaub


dadurch, dass das Jahr hier hicht mit 12-31 beendet wird erkennt das holiday Device keine Einträge. Ändere ich die Datei manuell auf 

4 11-03 12-31 Urlaub

ab werden problemlos am holiday device die Werte, tomorrow, yesterday gefüllt.

Ich habe testweise mal einen Termin erstellt (ohne die Option "Ganztägig) vom 30.06.20 00:00 - 06.01.2021 00:00, dieser wird als

# Created by myCalendar2Holiday on 30.11.20, 12:58
# get Calendar_Jens  events format:custom="4 $T1 $T2 $S $D" timeFormat:"%m-%d" limit:count=10 filter:field(summary)=~".*[uU]rlau.*"
1 06-30 Urlaub2 190d


angezeigt und hat zur Folge, dass auch keine Readings im holiday Device erzeugt werden.

Muss ich meine Termine nun bis zum 30.12 eintragen und dann wieder erst vom 01.01 beginnend? Das kann ich mir höchstwahrscheinlich merken, meiner bessere Hälfte wird das bestimmt nicht kümmern  ;D

Greetz
Eldrik

Beta-User

Na ja, das erste "Problem" mit dem Jahreswechsel ist bekannt und dafür ist eigentlich der letzte Parameter gedacht ($yearEndRe):
Zitat von: Beta-User am 13 Oktober 2020, 14:25:19
Aufgerufen wird jetzt mit
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,'') }

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

Auf das andere Thema ohne den "ganztägig"-Marker hatte ich eigentlich auch schon gewartet, kommt bei meinen Kalendern halt so auch nicht vor, "entwickelt" hatte ich das ganze mal für ein paar ganz spezifische Kalendertypen, und bisher war die Resonanz auch eher spärlich.

Aber da jetzt doch ein paar Leute Interesse zu haben scheinen, bin ich grade am überlegen, ob man das nicht auch noch generischer lösen könnte...

Betr. den Jahreswechsel könnte man auch die schlichte Frage zugrundelegen, ob denn der Endemonat kleiner ist als der Startmonat, damit bekäme man vermutlich dann wenigstens "Urlaube" bis knapp unter 11 Monate in den Griff und das wäre noch vergleichsweise einfach.

Und da die letzte Code-Variante sowieso die Dauer abruft, könnte man auch noch eine "matcht auf ...d"-Variante einbauen. Da gibt es aber ein paar Unwägbarkeiten, angefangen damit, dass ein um 00:00 Uhr beginnender Temin mit nd eben an einem andern Tag endet wie einer, der eine Sekunde später beginnt. Da man das an den abgerufenen Daten m.e. nicht mehr erkennen kann, muss man hier ggf. mit der Vereinfachung leben, dass eben ein "1d"-Eintrag zwei holiday-Tage bedeutet, nämlich den Beginn-Tag und den folgenden, ganz unabhängig, ob er jetzt - exakt betrachtet - um 00:00 Uhr beginnt oder nicht... (Rechnen mit Tagen muss ich mir aber ansehen, das ist m.E. ohne Hilfsmittel nicht ganz trivial, da z.B. Sommer- und Winterzeitumstellungen einen Einfluss haben können und man daher vermutlich nicht einfach in DAYSECONDS denken sollte).

Ich mache mir bei Gelegenheit Gedanken, es wäre aber hilfreich zu wissen, ob nicht einfach der Kalendereintrag YE-Urlaub heißen kann oder so...?
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

eldrik

Hi und großes sorry,

ich hatte das ganze wohl zu sehr überflogen :)

- "regex": für Zeiträume, die über das Jahresende hinausgehen (hier typischerweise die Weihnachtsferien).

Hat tatsächlich den gewünschten Effekt erzielt und nun löppt es auch mit dem Jahreswechsel ;)

Besten Dank dafür.

Zitatob nicht einfach der Kalendereintrag YE-Urlaub heißen kann oder so...?

wäre eine Überlegung Wert, wenngleich es für die bestimmte Situation bestimmt bei nächster Gelegenheit wieder vergessen wird ::) wahrscheinlich ist für die meisten Anwendungsfälle tatsächlich weiterhin die regex die einfachste Lösung wenn man sie denn nicht überliest  :P

Greetz
Eldrik

Beta-User

#13
Also gut....

Hier ein generalisierter Versuch, der dann gleich auch kennzeichnet, was nächstes Jahr erst ist und _vielleicht_ auch mit Rückgaben ohne Ende-Datum klarkommt (den Teil habe ich mangels passendem Kalender nicht getestet, $yearEndRe braucht man dann eigentlich nicht mehr):
sub myCalendar2Holiday {
  use Time::Local qw(timelocal);
  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 $nextYear = $year + 1901;
  my $today = strftime('%m-%d', localtime(gettimeofday()));
  my $getstring = $calname . ' events format:custom="4 $T1 $T2 $S $D" timeFormat:"%m-%d" limit:count=' . $limit." filter:field($field)=~\"$regexp\"";
  my @holidaysraw = split( /\n/, CommandGet( undef, "$getstring" ));

  my @holidays;
  my @singledays;
  my @start;
  my @stop;

  for my $holiday (@holidaysraw) {
    my @tokens = split (" ",$holiday);
    my $duration = pop @tokens;
   
    my $severalDays = $duration =~ m,[0-9]+h, ? 0 : 1;
   
    #$duration of several days preprocessing, code base: https://stackoverflow.com/a/56125332
    if ($duration =~ m,([0-9]+)d, && !defined $tokens[2]) {
      @start = split('-',$tokens[1], 2);
      # Get the epoch seconds for midday today
      # (we use midday to eliminate potential problems
      # when entering or leaving daylight savings time)      my $midday = timelocal(0, 0, 12, $start[1], $start[0]-1, $year);
      my $midday_end = $midday + HOURSECONDS * $1;
      $tokens[2] = strftime('%m-%d', localtime($midday_end));
    }
   
    $holiday = join(' ', @tokens);
    $holiday .= " ($nextYear)" if $today gt $tokens[2];
     
    if (!$severalDays) {
      $tokens[0] = 1;
      splice @tokens, 2, 1;
      $holiday = join(' ', @tokens);
      push (@singledays, $holiday);
    } elsif ($tokens[1] gt $tokens[2] ) {
      $holiday = "4 $tokens[1] 12-31 $tokens[3]";
      push (@holidays,$holiday);
      $holiday = "4 01-01 $tokens[2] $tokens[3] ($nextYear part)";
      unshift (@holidays,$holiday);
    } elsif ( !$yearEndRe || $holiday !~ m/$yearEndRe/ ) {
      push (@holidays, $holiday);
    } else {
      $holiday = "4 $tokens[1] 12-31 $tokens[3]";
      push (@holidays,$holiday) if $month > 9;
      $holiday = "4 01-01 $tokens[2] $tokens[3]";
      unshift (@holidays,$holiday);
    }
  }
  push @holidays, @singledays;
  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);
}

EDIT (x2): code nochmal geändert (u.a. wg. use)
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

m8ichael

Zitat von: hydrotec am 30 Oktober 2020, 05:25:30
Hallo Beta-User,

entschuldige bitte das es mit der Rückmeldung etwas gedauert hat.

Kann ich nur bestätigen, klappt einwandfrei. TOP  8)

Ich habe in meinem Kalender auch stets ganztägige Termine eingetragen (Zeiträume), bei der Auswertung wird jedoch immer ein Tag zuviel berücksichtigt (Beispiel: Zeitraum 01.01. bis 08.01. --> Ausgabe 4 01-01 01-09 ...). Insofern müsste ich jeweils einen Tag abziehen.

Gruß

Michael