ich werte schon seit Jahren meinen Google-Kalender zum Setzen bestimmter Systemvariablen (Urlaub, Abwesenheit) aus. Hierfür läuft auf Google-Servern ein Makro, welches ich selbst per URL abfragen kann. Diese Lösung wurde hier schon mal vor Jahren veröffentlicht. Grundsätzlich läuft das immer noch, aber trotzdem habe ich mir mal inspiriert durch diese Umsetzung eine eigene Lösung zusammengestrickt, die lokal auf der CCU läuft und den freigegebenen Kalender direkt ohne Google-Makro ausliest und entsprechende Sytemvariablen auf der CCU setzt, die ich weiter in Programmen verwenden kann.
Vorteil der Nutzung eines Online-Kalenders ist, dass man diesen ganz einfach per Smartphone, Tablet oder Rechner pflegen und auch für andere Zwecke (z.B. Terminerinnerungen) verwenden kann. Auch eine Einbindung in eine Visualisierung ist recht einfach parallel machbar. Wie Kalender freigeben werden, ist relativ einfach zu finden. Daher lasse ich diese Beschreibung hier weg. Ich empfehle für solche Dinge einen zusätzlichen anonymen Kalender zu führen, in dem nicht gerade private Termine vorgehalten werden. Das hält die Lösung schlank und den Scriptlauf schnell. Auf meiner CCU/RM auf RaspberryPi3-Basis läuft das Script in unter 0,5 Sekunden. Außderem ist es dem Schutz privater Daten dienlich, wenn mal die Abfrage-URL durch irgendetwas (z.B. Supportanfrage - Beispiele mit persönlichen Daten habe ich hier im Forum schon öfter gesehen) unbeabsichtigt geleakt wird.
Das Script liest die .ics-Datei aus und speichert sie in einer Scriptvariable, anschließend wird er erste Identifier eines Termineintrages gesucht und danach startet die Auswertung auf die Suchworte "Urlaub" und "Abwesend". Ich werte diese Status unterschiedlich aus. "Urlaub" bedeutet, dass ich zu Hause bin und "Abwesend" bedarf keiner Erklärung. Mit diesen Status kann ich u.a. Einfluss auf die Heizungssteuerung nehmen. Diese Suchworte werden in den Daten des aktuellen und des Folgetages gesucht und die Ergebnisse in Merkervariablen (z.B. "urlaub_m") zwischengespeichert. Am Ende des Scripts werden die Sytemvariablen analog zum Status der zwischengespeicherten Status gesetzt. Ich habe beide Möglichkeiten zur Abfrage (CUxD und system.Exec) implementiert. Die jeweilige Abfrageart kann durch das Entfernen und Setzen der Kommentarausrufezeichen de-/aktiviert werden.
Die hier vorgestellte Lösung benötigt nur täglich einen Scriptlauf nach dem Datumswechsel. Die Termine im Kalender müssen zwingend als Ganztagestermine gesetzt sein. Auch mehrere Tage (ohne explizite Uhrzeiten) sind möglich. Ich plane nicht, die Abfrage um Uhrzeiten zu erweitern, denn zur zeitnahen Auswertung müsste dieses Script zyklisch laufen. Dieses häufige externe Kommunikation möchte ich unbedingt vermeiden und ist für den geplanten Anwendungszweck auch nicht notwendig. Für die Auswertung und Verarbeitung in der CCU sind folgende boolsche Systemvariablen notwendig "Z_Urlaub", "Z_UrlaubMorgen", "Z_Abwesend" und "Z_AbwesendMorgen". Somit können die Status für den aktuellen und den Folgetag gesetzt werden. Die Namen können im unteren Teil des Scripts an die eigenen ggf. abweichenden Namen angepasst werden. Ich habe mich zur besseren Nachvollziehbarkeit bemüht, die einzelnen Schritte im Script selbst zu dokumentieren.
Hier nun das Script:
Code: Alles auswählen
! ##### Abfrage eines Online-Kalenders und Setzen von Systemvariablen ######
! Stand 03.11.2023 Quelle: https://homematic-forum.de/forum/viewtopic.php?f=31&t=80441#p783128
! ----------------------------------------------------------
! Es ist möglich, eigene Google-Kalender freizugeben und auch von extern einzulesen.
! Die URL zum eigenen freigegebenen Kalender kann unter "url=..." angepasst werden.
! Dieser Kalender kann sowohl vom Smartphone als auch per Rechner gepflegt werden.
! Somit ist eine Online-Datenpflege relativ einfach.
! Funktion:
! - Das Script liest die .ics Datei aus
! - holt sich das Systemdatum
! - ermittelt einen auf das Systemdatum passenden Eintrag
! - vergleicht Einträge mit dem Suchstings (Urlaub/Abwesend)
! - setzt Systemvariablen entsprechen der Suchworte
! Das Script enthält die Möglichkeit der Abfrage per system.Exec und per CUxD-Gerät.
! Für die Alternative Abfrage die Ausrufezeichen zwichen "Abfrage per..." und "Ende Abfrage"-Zeile entfernen und bei der anderen Variante setzen.
! Für die Auswertung in der CCU sind folgende boolsche Systemvariablen notwendig "Z_Urlaub", "Z_UrlaubMorgen", "Z_Abwesend" und "Z_AbwesendMorgen".
! Werden eigene Namen verwendet, sind diese im letzten Teil des Scripts anzupassen.
! -----------------------------------------------------------
! +++++ Definition der verwendeten Scritptvariablen +++++
! bei Verwendung anderer Quelldaten als Google-Kalender die ...ID-Variablen anpassen, abweichende Bezeichnungen werden durch .Length() im Script berücksichtigt
string startID = "DTSTART;VALUE=DATE:"; ! Identifier für das Startdatum
string endID = "DTEND;VALUE=DATE:"; ! Identifier für das Enddatum
string beginEventID = "BEGIN:VEVENT"; ! Identifier für Termineintragsbeginn
string endeEventID = "END:VEVENT"; ! Identifier für Termineintragsende
var url = "https://calendar.google.com/calendar/ical/googleigenegheimekennung%40group.calendar.google.com/private-hiermuessenauchdieeigenendatenrein/basic.ics";
! Ab hier nichts mehr ändern
integer laenge ;
integer vevent_start;
integer vevent_ende;
string vevent_single;
integer vevent_dtstart;
integer vevent_dtend;
boolean urlaub_m;
boolean urlaubf_m;
boolean abwesend_m;
boolean abwesendf_m;
! +++++ Abfrage der Datei mit CUxD und Einlesen in Variable / Dateilänge in Variable +++++
! Abfrage per CUxD-Gerät
! dom.GetObject("CUxD.CUX2801001:1.CMD_SETS").State("timeout 10 wget --timeout=10 --no-check-certificate -q -O - '"#url#"'");
! dom.GetObject("CUxD.CUX2801001:1.CMD_QUERY_RET").State(1);
! string ics_quelldaten = dom.GetObject("CUxD.CUX2801001:1.CMD_RETS").State();
! Ende Anfrage per CUxD
! +++++ Abfrage per system.Exec() +++++
string stdout; string stderr;
system.Exec("timeout 10 wget --timeout=10 -q -O - '"#url#"'", &stdout, &stderr);
if (stderr <> "") { quit; } ! Scriptabbruch, wenn Kalenderabfrage einen Fehler gemeldet hat
string ics_quelldaten = stdout;
! Ende Abfrage per system.Exec()
laenge = ics_quelldaten.Length();
if (laenge < 1) { WriteLine("Keine Quelldaten vorhanden, Verarbeitung beendet."); quit; }
! +++++ Lokalzeit einlesen, und 90000 (nicht 86400) Sekunden zur Berücksichtigung der Sommerzeit für das Enddatum aufaddieren +++++
integer datum_a = localtime.Format("%Y%m%d").ToInteger(); ! aktuelles Datum als Startwert
integer datum_e = (localtime+90000).Format("%Y%m%d").ToInteger(); ! Datum des Terminende und Start des Folgetages
integer datum_f = (localtime+176400).Format("%Y%m%d").ToInteger();! Datum des Terminende des Folgetages
vevent_start = ics_quelldaten.Find(beginEventID); ! Suche des ersten Event-Beginn-Ifentifiers
while (vevent_start > 0) {
vevent_ende = ics_quelldaten.Find(endeEventID); ! Suche des ersten Event-Ende-Identifiers
vevent_single = ics_quelldaten.Substr(vevent_start,((endeEventID.Length())+vevent_ende-vevent_start)); ! Kürzung auf Einzeltermineintrag
vevent_dtstart = vevent_single.Substr((startID.Length())+(vevent_single.Find(startID)),8).ToInteger();! Auslesen des Startdatums des Termins
vevent_dtend = vevent_single.Substr((endID.Length())+(vevent_single.Find(endID)),8).ToInteger(); ! Auslesen des Enddatum des Termins
if ((datum_a >= vevent_dtstart) && (datum_e <= vevent_dtend)) { ! Prüfung ob aktuelles Datum zwischen Terminanfang und -ende liegt
integer urlaub = vevent_single.Find("SUMMARY:Urlaub"); ! Suche nach "Urlaub" und Setzen des Status
if ((urlaub > 0) && (urlaub < vevent_ende)){
urlaub_m = true;
if ((urlaub > 0) && (datum_e < vevent_dtend)) { urlaubf_m = true;}! Berücksichtigung Mehrtagestermin
}
integer abwesend = vevent_single.Find("SUMMARY:Abwesend"); ! Suche nach "Abwesend" und Setzen des Status
if ((abwesend > 0) && (abwesend < vevent_ende)) {
abwesend_m = true;
if ((abwesend > 0) && (datum_e < vevent_dtend)) { abwesend_m = true;} ! Berücksichtigung Mehrtagestermin
}
ics_quelldaten = ics_quelldaten.Substr((endeEventID.Length())+vevent_ende, (endeEventID.Length())-laenge - vevent_ende); ! Kürzen der Quelldatei
laenge = ics_quelldaten.Length();
vevent_start = ics_quelldaten.Find(beginEventID);
}
elseif ((datum_e >= vevent_dtstart) && (datum_f <= vevent_dtend)) {! Prüfung ob Datum des Folgetags zwischen Terminanfang und -ende liegt
integer urlaub = vevent_single.Find("SUMMARY:Urlaub"); ! Suche nach "Urlaub" und Setzen des Status für den Folgetag
if ((urlaub > 0) && (urlaub <= vevent_dtend)){
urlaubf_m = true;}
integer abwesend = vevent_single.Find("SUMMARY:Abwesend"); ! Suche nach "Abwesend" und Setzen des Status
if ((abwesend > 0) && (abwesend <= vevent_dtend)) { abwesendf_m = true;}
ics_quelldaten = ics_quelldaten.Substr((endeEventID.Length())+vevent_ende, (endeEventID.Length())-laenge - vevent_ende); ! Kürzen der Quelldatei
laenge = ics_quelldaten.Length();
vevent_start = ics_quelldaten.Find(beginEventID);
}
else {ics_quelldaten = ics_quelldaten.Substr((endeEventID.Length())+vevent_ende, (endeEventID.Length())-laenge - vevent_ende);
! Kürzen der Quelldatei
laenge = ics_quelldaten.Length();
vevent_start = ics_quelldaten.Find(beginEventID);
}
} ! Ende while
! +++++ Abfrage der zwischengespeicherten Status und Setzen der Systemvariablen
if (urlaub_m > 0) { dom.GetObject(ID_SYSTEM_VARIABLES).Get("Z_Urlaub").State("true");}
else { dom.GetObject(ID_SYSTEM_VARIABLES).Get("Z_Urlaub").State("false");}
if (urlaubf_m > 0) { dom.GetObject(ID_SYSTEM_VARIABLES).Get("Z_UrlaubMorgen").State("true");}
else { dom.GetObject(ID_SYSTEM_VARIABLES).Get("Z_UrlaubMorgen").State("false");}
if (abwesend_m > 0) { dom.GetObject(ID_SYSTEM_VARIABLES).Get("Z_Abwesend").State("true");}
else { dom.GetObject(ID_SYSTEM_VARIABLES).Get("Z_Abwesend").State("false");}
if (abwesendf_m > 0) { dom.GetObject(ID_SYSTEM_VARIABLES).Get("Z_AbwesendMorgen").State("true");}
else { dom.GetObject(ID_SYSTEM_VARIABLES).Get("Z_AbwesendMorgen").State("false");}
! +++++ Aufräumen
ics_quelldaten = ""; ! Leeren der Scriptvariable
vevent_single = ""; ! Leeren der Scriptvariable
! ===== ENDE =====
Gruß Xel66