Die Grundlage schaffen - ein Calendar Device
Für dieses Beispiel: ein Google Kalender. Als Grundlage brauchen wir die "Privatadresse" im iCal Format (Google Kalender Einstellungen/<Kalendername>/Kalendereinstellungen).Diese URL wird einfach in die Calendar Definition eingesetzt, das Aktualisierungsintervall setze ich auf einen Tag. Man kann jederzeit ein reload des Kalenders durchführen. Man muss bedenken, dass vor allem viele Serientermine, eine nicht unerheblich Zeit beim reload beanspruchen. Das kann schnell mal mehrere Minuten dauern. In der Grundeinstellung erfolgt das blockierend. Je nach Kalender, kann also nach dem define die Oberfläche für ein paar Minuten "stehen"!
define TestKalender Calendar ical url https://calendar.google.com/calendar/ical/xxx/basic.ics 86400Abfragen machen
Die Abfrage der Termine ist nicht offensichtlich, es gibt aber einige Beispiele in der englischen Doku. Als Ausgangspunkt für mein Beispiel nehme ich mal die Weboberfläche. In der zweiten Auswahlbox in der get Zeile wählt man einfach events aus.Als Ergebnis bekommt man in einer Box eine Liste der Kalendereinträge (events), ich habe heute (6.1.) drei Einträge drin. Wie man sieht, auch vergangene.
04.01.2019 08:00 4h Sprechstunde
06.01.2019 08:00 14h Heute frei
07.01.2019 08:00 11h SprechstundeDas Ziel in diesem Beispiel soll sein, auf einen ganz bestimmten Eintrag im Kalender zur Startzeit des Termins etwas auszulösen: z.B. den Server an den Tagen wo Sprechstunde ist, kurz vor Arbeitsbeginn zu starten.
Event auswählen
Dazu erzeugt man am Besten einen Termin in naher Zukunft und schaut sich mit dem Eventmonitor die Events an:2019-01-06 20:00:00 Calendar TestKalender changed: 79vs3fq7siulo1hskdn4gtht7kgooglecom start
2019-01-06 20:00:00 Calendar TestKalender start: 79vs3fq7siulo1hskdn4gtht7kgooglecom 
2019-01-06 20:00:00 Calendar TestKalender modeUpcoming: 7fcbh4r7snu7iqovask7l8oq9qgooglecom
2019-01-06 20:00:00 Calendar TestKalender modeAlarmOrStart: 44318rlssm81janveuga0olanpgooglecom;79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:00:00 Calendar TestKalender modeChanged: 79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:00:00 Calendar TestKalender modeStart: 44318rlssm81janveuga0olanpgooglecom;79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:00:00 Calendar TestKalender modeStarted: 79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:00:00 Calendar TestKalender triggered
2019-01-06 20:00:00 Calendar TestKalender nextWakeup: 2019-01-06 20:05:00
2019-01-06 20:05:00 Calendar TestKalender changed: 79vs3fq7siulo1hskdn4gtht7kgooglecom end
2019-01-06 20:05:00 Calendar TestKalender end: 79vs3fq7siulo1hskdn4gtht7kgooglecom 
2019-01-06 20:05:00 Calendar TestKalender modeAlarmOrStart: 44318rlssm81janveuga0olanpgooglecom
2019-01-06 20:05:00 Calendar TestKalender modeStart: 44318rlssm81janveuga0olanpgooglecom
2019-01-06 20:05:00 Calendar TestKalender modeStarted: 
2019-01-06 20:05:00 Calendar TestKalender modeEnd: 26aq76ljdgjfmo444466faml09googlecom;79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:05:00 Calendar TestKalender modeEnded: 79vs3fq7siulo1hskdn4gtht7kgooglecom
2019-01-06 20:05:00 Calendar TestKalender triggered
2019-01-06 20:05:00 Calendar TestKalender nextWakeup: 2019-01-06 22:00:00TestKalender:changed:.*
TestKalender:changed:.*start
TestKalender:start:.*Exakte Abfrage auf einen Termin
Jetzt kann man im Code noch exakt abfragen, ob es sich um den richtigen Kalendereintrag handelt.fhem('get '.$NAME.' events filter:uid=="'.$EVTPART1.'",field(summary)=~"(?i)sprechstunde" limit:count=1,from=0',1){fhem("set Server on") if defined fhem('get '.$NAME.' events filter:uid=="'.$EVTPART1.'",field(summary)=~"(?i)sprechstunde|notdienst" limit:count=1,from=0',1)}Starte das Gerät zum Zeitpunkt
Ein notify, welches zu Beginn eines Kalenderevents, der den Begriff "Sprechstunde" in der Terminbeschreibung enthält, den Server startet:define n_TestKalender notify TestKalender:changed:.*start {\
fhem("set Server on") if defined fhem('get '.$NAME.' events filter:uid=="'.$EVTPART1.'",field(summary)=~"(?i)sprechstunde" limit:count=1,from=0',1)\
}attr TestKalender onCreateEvent { $e->{alarm}= $e->{start}-3600 if($e->{summary} =~ m/Sprechstunde/i)}
Starte das Gerät vor dem Zeitpunkt
Der Trigger im notify muss lediglich von start auf alarm geändert werden, der Ausführungsteil bleibt identisch.defmod n_TestKalender notify TestKalender:changed:.*alarm {}Noch ein paar zusätzliche Tipps und Infos
Serientermine einer Serie (z.B. jeden Mittwoch 8:00) haben alle die gleiche UID. Bei einem Einzeltermin hätte man im notify über die uid den konkreten Zugriff auf genau den Termin, beim Serientermin erscheinen alle Termine der Serie, auch vergangene! Diese uid bleibt auch erhalten wenn man mal einen Termin der Serie modifiziert (Beschreibung, Zeit usw.)Die Modi (alarm|start|end|upcoming) sind transient und geben quasi Auskunft über den aktuellen Status eines Termins (get <Kalender> events filter:mode=="<modus>").
- upcoming - der Termin liegt in der Zukunft
- end - der Termin ist abgelaufen und liegt in der Vergangenheit
- start - der Termin ist gerade aktiv
- alarm - die Alarmphase ist aktiv, also der Event alarm ist vorüber, der Event start noch nicht erreicht.
Achtung: will man auf end triggern und den Termin überprüfen (z.B. Inhalt von summary) dann darf  hideOlderThan nicht auf 0 stehen! Man kann sich leicht mit 1 oder 2 (in sec) behelfen. Nach dem end Event ist der Termin aus der Liste verschwunden und nicht mehr lesbar! 
Noch ein paar Codebeispiele
toDoTipp: Die Abfrage der Alarmzeit funktioniert z.B: mit
get TestKalender events filter:mode=="alarm" format:full limit:count=1,from=0{my $day = int((fhem('get '.$name.' events format:custom="$t1" limit:from=0,count=1',1) + 86399 - time)/86400);
$day?eval{$day>1?$day:"morgen"}:"heute"} 
Dieser Blogbeitrag hat mir sehr gut weitergeholfen, weil ich bei allen Versuchen, FHEM-Devices über Kalenderereignisse zu schalten bisher kläglich gescheitert bin.
AntwortenLöschenAber gibt es eine Erklärung dafür, warum das nicht auch mit "end" und "off" funktioniert? Nach Ende der Sprechstunde könnte es ja auch Sinn machen, den Server wieder auszuschalten.
define n_TestKalender notify TestKalender:changed:.*end {\
fhem("set Server off") if defined fhem('get '.$NAME.' events filter:uid=="'.$EVTPART1.'",field(summary)=~"(?i)sprechstunde" limit:count=1,from=0',1)\
Ja, deswegen: end - der Termin ist abgelaufen und liegt in der Vergangenheit.
LöschenMit der Tatsache muss man den Filterteil "limit:count=1,from=0" anders setzen! Denn diese Bedingung ist nun nicht mehr wahr. Vielleicht braucht man die Zeiteinschränkung gar nicht, er liest ja nur die uid aus dem Event. Lass ",from=0" einfach weg? Oder versuch einfach auch das Beispiel aus der C-Ref mit $actor.
Respekt und Hut ab! Zweieinhalb Jahre nach einem Blogbeitrag ein erster Kommentar und dann Reaktion innerhalb von weniger als drei Stunden.
AntwortenLöschenMit dem Filterteil "limit:count=1,from=0" habe ich alle denkbaren Varianten - auch weglassen - ausprobiert, allerdings ohne Erfolg. Für weiterreichende Eingriffe fehlen mir leider die Kenntnisse. Das Beispiel mit $actor aus der commandref mag funktionieren, aber wer schreibt schon die Namen von FHEM-Devices in seinen Terminkalender. Der besondere Reitz an deinem Beispiel ist, dass es auch auf "Zahnarztsprechstundenhelfer" reagiert.
Also werde ich noch etwas tüfteln und versuchen, mich irgendwo schlau zu lesen. Danke nach Leipzig.
Ich befürchte ich weiß warum, habe aber noch keine Lösung: Wenn man die *OlderThan Attribute im Calendar Device gesetzt hat, ist der Termin nach dem end ja quasi raus und wird nicht mehr angezeigt. Damit wird der Test nicht wahr. Das Beispiel mit dem Aktor meinte ich ja nur, weil es analog aufgebaut ist. Dort wird nur auf summary Inhalt getestet. Aber auch das dürfte nicht funktionieren, wenn man *OlderThan gesetzt hat.
LöschenBesser wäre es das Thema im Forum zu diskutieren.
Meine Vermutung war richtig, die Lösung "einfach":
LöschenAnstatt hideOlderThan 0 auf hideOlderThan 2 setzen.
Damit funktioniert ein notify auf end mit Abfrage der Eintrages.
Ja, das war die Lösung. Wenn man dann noch den Filterteil "limit:count=1,from=0" ganz weglässt, funktioniert es.
AntwortenLöschenIch könnte zu diesem Thema zwar im Forum eine Diskussion beginnen. Es fehlt mir aber an Kompetenz, um dort wirklich konstruktiv mitzuwirken. Ich weiß, dass du dort sehr aktiv bist. Evtl. könntest du das bei Bedarf übernehmen. Aber es gab ja zweieinhalb offensichtlich Jahre keinen Bedarf.
Herzlichen Dank und Grüße nach Leipzig
Scheitere an der Ical-Verbindung zur Nextcloud. Kennt jemand einen Weg? Evtl. eine Beispiel-URL? Von meinen Äpfeln klappt das ohne Probleme.
AntwortenLöschenDamit geht es mit der Nextcloud und dem fhem-Kalender
AntwortenLöschenical url https://@/remote.php/dav/calendars//?export
attr timeout 60
Super Beitrag. Den Google-Kalender kann ich schon mal auslesen. Jetzt würde ich gerne täglich um 04:00 Uhr die Termine vom aktuellen und nächsten Tag per Telegram versenden.
AntwortenLöschenDa würde ich ein at definieren und beim get die Limits auf so etwas wie from=0,to=+44h setzen.
Löschen