SSCal - Integration des Synology Calendar Servers

Aus FHEMWiki
SSCal
Zweck / Funktion
Integration des Synology Calendar Servers
Allgemein
Typ Gerätemodul
Details
Dokumentation EN / DE
Support (Forum) Unterstützende Dienste
Modulname 57_SSCal.pm
Ersteller DS_Starter
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref!


Zweckbeschreibung und Voraussetzungen

Mit diesem Modul erfolgt die Integration des Synology Calendar Servers in FHEM. Die Verbindung zum Kalenderserver erfolgt über eine Session ID nach erfolgreichem Login. Anforderungen/Abfragen des Servers werden intern in einer Queue gespeichert und sequentiell abgearbeitet. Dadurch gehen Kalenderabfragen auch dann nicht verloren, wenn der Synology Kalender zeitweise nicht zur Verfügung stehen sollte. Die Kalendereinträge werden im Klartext als Blockeinträge in den Readings aufgelistet. Der Synology Calendar Server ist für den Synology Server Besitzer ein Teil einer private Cloud Lösung.

Es können sowohl Terminkalender (Events) als auch Aufgabenlisten (ToDo's) abgefragt und verarbeitet werden. Für diese verschiedenen Kalenderarten kann das Modul unterschiedliche Device-Models definieren, Model Diary für Terminkalender und Model Tasks für Aufgabenlisten.

Voraussetzung ist ein installiertes Calendar Package und ein Nutzerkonto mit der Zugehörigkeit zur Gruppe Administratoren auf der Synology DS.

Das Modul benötigt einige FHEM und Perl Standardmodule die installiert sein müssen. Die Commandref zum Modul enthält diese Angaben aktuell. Mit dem Installer-Modul ist es ebenfalls möglich eventuell fehlende Perl-Module zu ermitteln und ggf. zu installieren.



Definition eines Synology Kalenderdevices

initiale Definition

Die Definition erfolgt mit:

define <Name> SSCal <Adresse Synology Server> [<Port>] [<Protokoll>] [Tasks]
  • Port: Port der Synology Diskstation (default 5000)
  • Protokoll: Protokoll zur Kommunikation mit dem Kalender-Server, http oder https (default http)
  • Zusatz Tasks: definiert eine Aufgabenliste anstatt eines Terminkalenders


Die Angaben Port, Protokoll und Tasks sind optional. Der Zusatz Tasks definiert ein Aufgabenlisten-Device mit MODEL=Tasks. Per default wird ein Terminkalender-Device mit MODEL=Diary, Port=5000 und Protokoll=http erstellt.


Beispieldefinitionen:

define Appointments SSCal 192.168.2.10               # Terminkalender mit Standardport
define Calendar SSCal 192.168.2.10 5001 https        # Terminkalender mit HTTPS-Protokoll
define Tasklist SSCAL ds.myds.org 5001 https Tasks   # Aufgabenliste mit HTTPS-Protokoll 


Nach der Definition des Devices gibt es zunächst nur den Set-Befehl credentials.

Kalenderabruf durchgeführt

Mit dem Befehl:

set <name> credentials <User> <Passwort>

ist im Kalender-Device der für den Kalenderzugriff verwendete Nutzer und dessen Paßwort zu speichern.


Hinweis:
Der Nutzer muß Mitglied der Administrator-Group auf der Synology Diskstation sein und muß zusätzlich auch die entsprechend benötigte Berechtigung zum Lesen und/oder Schreiben des/der relevanten Kalender haben. Die Kalenderberechtigungen können direkt in der Synology Kalenderapplikation eingestellt werden.


Sind die Credentials korrekt, werden die auf der Synology verfügbaren (und für den Nutzer freigegeben) Kalender automatisch abgerufen. Dieser Vorgang ist durch den state running und dem OPMODE listcal in den Internals gekennzeichnet. Nach einem erfolgreichen Abruf, der am Anfang etwas länger dauern kann, springt der Status des Devices auf done. Damit ist das Kalenderdevice grundsätzlich einsatzbereit.





Terminkalender und Aufgabenlisten auswählen und Einträge abrufen

Popup von getCalendars

Nach der initialen Definition des Kalenderdevices müssen ein oder mehrere Kalender ausgewählt werden, deren Termine (Events) abgerufen werden sollen. Welche Kalender vom Modul erkannt wurden, kann mit dem Befehl

get <name> getCalendars

ermittelt werden. Die angezeigte Liste enthält sowohl Terminkalender (Type Event) als auch Aufgabenkalender (Type ToDo).

Mit dem Attribut usedCalendars wählt man den/die relevanten Kalender über ein Popup aus. Alternativ kann dem nachfolgend ausgeführten calUpdate Befehl die abzurufende Kalenderliste direkt mitgegeben werden.

Ohne Änderung der Zeitabgrenzung werden die Termine 5 Tage vor und 5 Tage nach dem aktuellen Datum abgerufen. Um diese Zeitgrenzen zu verändern, werden die Attribute cutOlderDays bzw. cutLaterDays verwendet.

Mit dem Befehl:

set <name> calUpdate [Kalenderliste]
Kalendereinträge abgerufen

werden Terminkalendereinträge manuell abgerufen. Die optional anzugebende Kalenderliste ist eine durch Komma getrennte Liste von abzurufenden Kalendernamen. Die Kalendernamen können Leerzeichen enthalten, z.B.:

set <name> calUpdate Heikos Kalender,Abfall

Im Standard werden sowohl einmalige, als auch wiederkehrende Events abgerufen und dargestellt. Möchte man die wiederkehrenden Events vom Abruf ausschließen, muss das Attribut showRepeatEvent explizit auf false gestellt werden.

Mit dem Befehl calUpdate werden nur Kalender verarbeitet, die dem definierten Model, "Diary" oder "Tasks", entsprechen. Kalender abweichenden Typs werden ignoriert.

Aufgaben können Fälligkeitstermine enthalten. Sind diese enthalten, werden Aufgaben deren Fälligkeitstermine sich außerhalb der durch die Attribute cutOlderDays bzw. cutLaterDays festgelegten Zeitgrenzen befinden, gefiltert und nicht dargestellt.

Kalenderübersicht in Detailanzeige
Spalte "Map" mit GPS-Koordinaten Icon




Wurden Termin- bzw. Aufgabenlisten erfolgreich abgerufen, wird per default sowohl in der Raumansicht als auch in der Detailansicht eine Kalenderübersicht angezeigt. Mit den Attributen tableInRoom bzw. tableInDetail können diese Übersichten ausgeschaltet werden (setzen auf "0").





Ist in den Terminen ein GPS-Wert gespeichert, wird in der tabellarischen Terminübersicht per default ein Weltkugel-Icon angezeigt, vorausgesetzt man hat auch das Feld Map im Attribut tableFields mit ausgewählt. Ein "Klick" auf dieses Icon öffnet eine neue Browserseite mit den im Termin gespeicherten Koordinaten in Google Maps.


Alle Abrufaufgaben werden zunächst in eine Queue eingestellt, die sequentiell abgearbeitet wird. Sollte der Synology Kalender zum Beispiel während einer Wartung temporär nicht verfügbar sein, erfolgt eine Wiederholung der anstehenden Aufgaben nach einer gewissen Wartezeit. Diese Wartezeit vergrößert sich mit zunehmenden Fehlversuchen.

Wurde für eine Abrufaufgabe ein dauerhafter Fehler diagnostiziert, wird diese Aufgabe von der weiteren Abarbeitung ausgeschlossen und verbleibt zur Dokumentation in der Queue (siehe auch set <name> listSendqueue).


Das Reading QueueLenth zeigt die aktuelle Queue-Länge an. Sollten die Einträge nicht auf "0" abgebaut werden, sollte mit

set <name> listSendqueue 

die Queue aufgelistet und analysiert werden, durch welche Fehlerzustände die verbliebenen Einträge nicht abgearbeitet werden konnten.



non-blocking Verarbeitung

Das Kalendermodul ist non-blocking implementiert. In der Definition des Devices sollte die IP-Adresse der Synology Diskstation angegeben werden. Wird statt dessen ein DNS-Name verwendet, ist darauf zu achten im global Device einen validen DNS-Server im Attribut dnsServer zu hinterlegen.

In Abhängigkeit der Menge abgerufener Kalender und Termine kann allerdings die Aufbereitung der Daten sehr aufwändig sein und FHEM dennoch blockieren. Um das zu verhindern, kann das Parsing der Kalenderdaten in einen Hintergrundprozess verlagert werden. Dazu ist das Attribut asyncMode=1 zu setzen.


regelmäßiger automatischer Datenabruf

Über das Attribut interval wird ein regelmäßigen Abruf der Kalendereinträge ermöglicht. Es sind die Sekunden zwischen den Abrufen anzugeben. Mit 0 wird der automatische Datenabruf ausgeschaltet. Gleiches gilt wenn das Attribut wieder gelöscht wird.

Im Reading nextUpdate wird der Modus "Automatic" und die Zeit des nächsten Abrufes dargestellt, z.B.:

 nextUpdate  Automatic - next polltime: 09:49:59


FHEM Eventgenerierung und Empfehlung zu Attributen

Je nach Umfang der abgerufenen Daten können sehr viele Readings erstellt werden. Um eine zu umfangreiche Eventgenerierung in FHEM zu verhindern, ist nach der Definition des Kalenderdevices das Attribut event-on-update-reading voreingestellt auf:

attr <SSCal-Device> event-on-update-reading .*Summary.*,state

Es werden demzufolge nur Events für die Terminzusammenfassung und für state erzeugt. Der User kann die Einstellung natürlich seinen Erfordernissen entsprechend anpassen. Sollen Events für alle Readings erstellt werden, muss event-on-update-reading auf .* eingestellt werden.

Nach dem Abruf von Terminen oder Aufgaben wird per default eine tabellarische Übersicht sowohl in der Raumsicht als auch in der Datailansicht erstellt. Will man diese Übersichten abschalten, sind dazu die Attribute tableInRoom bzw. tableInDetail explizit auf "0" zu setzen.


Empfehlung für das Setzen des Attributs stateFormat:

 attr <SSCal-Device> stateFormat <b>Status:</b> done - <b>Last Update</b>: 2020-02-02 19:57:47 - <b>Next Update</b>: Automatic - next polltime: 20:57:46

Für die Funktionen des Moduls ist die UID eines Events nicht notwendig. Somit wird das Reading x_x_IcalUID nicht benötigt.

 attr <SSCal-Device> suppressReading .*_95_IcalUID



Schema der erzeugten Readings

Die Termine der abgerufenen Kalender werden in Blöcken erzeugt. Jeder Block steht für einen Termin, dessen einzelne Eigenschaften mit einer laufenden Nummer vor dem Readingnamen gekennzeichnet sind.

Diese laufende Nummer ist für den jeweiligen Readingnamen immer gleich. Da es für einen Termin eine oder auch mehrere Erinnerungstermine geben kann, wird das Reading notifyDateTime zusätzlich von einem laufenden Index angeführt.

Schema der Readings



Das allgemeine Schema der erzeugten Readings ist:

<Blocknummer>_<Readingnummer>_<Readingname>

Zum Beispiel für die Anfangszeit und Endezeit eines Termins:

0_02_Begin 2020-01-15 09:30:00
0_03_End   2020-01-15 10:30:00



Das Reading notifyDateTime wird noch um einen Index ergänzt:

<Blocknummer>_<Readingnummer>_<Index>_<notifyDateTime>

Zum Beispiel:

0_14_0_notifyDateTime 2020-01-15 09:25:00
0_14_1_notifyDateTime 2020-01-15 03:30:00
0_14_2_notifyDateTime 2020-01-14 09:30:00
0_14_3_notifyDateTime 2020-01-12 09:30:00
0_14_4_notifyDateTime 2020-01-11 09:30:00



Set-Befehle

calUpdate
Die Einträge der ausgewählten Kalender werden abgerufen. Die relevanten Kalender werden im Attribut usedCalendars angegeben. Alternativ können ein oder mehrere Kalender als eine durch Komma getrennte Liste dem Befehl direkt übergeben werden, z.B.:
set <name> calUpdate Heikos Kalender,Abfall
Die Kalendernamen können Leerzeichen enthalten. Welche Kalender erkannt wurden, kann mit dem Befehl
get <name> getCalendars
ermittelt werden. Es werden nur die Kalender abgerufen, deren Typ zum Model des SSCal-Devices passen. D.h. ist das Model Diary, werden Kalender vom Typ Event verarbeitet und das Model Tasks verarbeitet Kalender des Typs ToDo.


cleanCompleteTasks (nur Model "Tasks")
In den selektierten Aufgabenlisten (siehe Attribut usedCalendars) werden alle abgeschlossenen Aufgaben gelöscht.
deleteEventId
die angegebene Event Id (siehe Reading x_x_EventId) wird aus dem Kalender bzw. der Aufgabenliste gelöscht. Die aktuell ermittelten Event Id's werden über eine Drop-Down Liste zur Auswahl bereitgestellt.
credentials
Speicherung der Zugangsdaten.
set <name> credentials User Passwort
eraseReadings
Löscht alle Kalenderreadings
listSendqueue
Zeigt alle Einträge in der Sendqueue. Die Queue ist normalerweise nur kurzfristig gefüllt, kann aber im Problemfall dauerhaft Einträge enthalten. Dadurch kann der bei der jeweiligen Abrufaufgabe aufgetretene Fehler ermittelt werden.
logout
Der User wird ausgeloggt und die Session beendet
purgeSendqueue
löscht Einträge in der Sendequeue. Es stehen verschiedene Optionen ja nach Situation zur Verfügung:
-all- = löscht alle in der Sendequeue vorhandenen Einträge
-permError- = löscht alle Einträge, die durch einen permanenten Error von der weiteren Verarbeitung ausgeschlossen sind
-<Index>- = löscht einen eindeutigen Eintrag der Sendequeue
restartSendqueue
Die Abarbeitung der Einträge in der Sendequeue wird manuell neu angestoßen. Dies ist normalerweise nicht notwendig. Die Sendequeue wird bei der Initialisierung jeder neuen Aufgabe implizit neu gestartet.



Get-Befehle

get calAsHtml Popup
apiInfo
Ruft die API Informationen des Synology Calendars ab und öffnet ein Popup mit diesen Informationen.
calAsHtml
Zeigt ein Popup mit einer Übersicht der Termine/Aufgaben. In eigenen Perl-Routinen (z.B. bei Einbindung in weblink) kann die Übersicht abgerufen mit:
{ SSCal_calAsHtml ("<SSCal-Device>") }


getCalendars
Ruft die auf der Synology vorhandenen Kalender ab und öffnet ein Popup mit Informationen über die jeweiligen Kalender.
storedCredentials
zeigt die gespeicherten User/Passwort Kombination
versionNotes
Zeigt Informationen und Hilfen zum Modul



Attribute

asyncMode
wenn "1" wird das Datenparsing in einen Hintergrundprozess ausgelagert und vermeidet Blockierungssituationen
createATDevs
wenn "1" werden bei der Erkennung von FHEM-Kommandos bzw. auszuführenden Perl-Routinen im Kalendereintrag durch SSCal automatisiert at-Devices zur termingerechten Ausführung dieser Kommandos erstellt, geändert und gelöscht. Lesen sie bitte dazu die detailliierte Beschreibung im Abschnitt at-Devices für Steuerungen automatisch erstellen und verwalten lassen
cutOlderDays
Terminkalendereinträge und Aufgabenkalendereinträge mit Fälligkeitstermin älter als die angegeben Tage werden von der Verarbeitung ausgeschlossen (default: 5)
attr <name> cutOlderDays 30
cutLaterDays
Terminkalendereinträge und Aufgabenkalendereinträge mit Fälligkeitstermin später als die angegeben Tage werden von der Verarbeitung ausgeschlossen (default: 5)
attr <name> cutLaterDays 90
filterCompleteTask (nur Model "Tasks")
Es werden Einträge in Aufgabenkalendern entsprechend der Fertigstellung gefiltert:
1 = nur fertig gestellte Aufgaben werden angezeigt
2 = nur nicht fertige Aufgaben werden angezeigt
3 = es werden fertige und nicht fertige Aufgaben angezeigt (default)
filterDueTask (nur Model "Tasks")
Es werden Einträge in Aufgabenkalendern mit/ohne Fälligkeit gefiltert:
1 = nur Einträge mit Fälligkeitstermin werden angezeigt
2 = nur Einträge ohne Fälligkeitstermin werden angezeigt
3 = es werden Einträge mit und ohne Fälligkeitstermin angezeigt (default)
interval
Automatischer Abrufintervall der Kalendereintträge in Sekunden. Ist "0" agegeben, wird kein automatischer Datenabruf ausgeführt. Soll jede Stunde die Einträge der gewählten Kalender abgerufen werden, wird das Attribut wie folgt gesetzt:
attr <name> interval 3600
loginRetries
Anzahl der Versuche für das inititiale User login (default: 3)
showRepeatEvent (nur Model "Diary")
Wenn "true", werden neben einmaligen Terminen ebenfalls wiederkehrende Termine ausgewertet. (default: true)
showPassInLog
Wenn "1", wird das Passwort bzw. die SID im Log mit angezeigt. (default: 0)
tableColumnMap
Legt fest, wie der Link zur Karte in der Tabellspalte "Map" bzw. "Karte" gestaltet wird.
icon - es wird ein durch den User anpassbares Symbol angezeigt (default)
data - es werden die GPS-Daten angezeigt
text - es wird ein durch den Nutzer einstellbarer Text verwendet

Der Nutzer kann weitere Anpassungen des verwendeten Icons oder Textes in den Eigenschaften des Attributs "tableSpecs" vornehmen. Siehe dazu Kapitel Darstellung der Übersichtstabelle in Raum- und Detailsicht beeinflussen

tableInDetail
Eine Termin/Aufgabenübersicht wird in der Detailansicht erstellt (default: 1) bzw. ausgeschaltet (0).
tableInRoom
Eine Termin/Aufgabenübersicht wird in der Raumansicht erstellt (default: 1) bzw. ausgeschaltet (0).
tableFields
Auswahl der in der Termin/Aufgabenübersicht (Raum- bzw. Detailansicht) anzuzeigenden Felder über eine Drop-Down Liste
tableSpecs
Über verschiedene Schlüssel-Wertpaar Kombinationen kann die Darstellung der Informationen in der Übersichtstabelle angepasst werden. Das Kapitel Darstellung der Übersichtstabelle in Raum- und Detailsicht beeinflussen liefert detailiierte Informationen dazu.
timeout
Timeout für den Datenabruf in Sekunden. (default: 20)
usedCalendars
Auswahl der abzurufenden Kalender über ein Popup. Die Liste der Kalender wird beim Start des Moduls initial gefüllt, kann danach aber ebenfalls durch den Befehl "get <name> getCalendars" manuell ausgeführt werden. Wurde noch kein erfolgreicher Kalenderabruf ausgeführt, enthält dieses Attribut lediglich den Eintrag
--wait for Calendar list--



Darstellung der Übersichtstabelle in Raum- und Detailansicht beeinflussen

Im Standard wwird sowohl in der Raum- als auch Detailansicht eine Tabelle mit den aktuell abgerufenen Terminen bzw. Aufgaben angezeigt. Die verwendeten Spalten der Tabelle sind vorbelegt, können aber durch das Attribut:

attr <Device> tableFields 

verändert werden. Es wird eine Drop-Down-Liste mit einer Auswahl der möglichen Tabellenfelder bereitgestellt.

Das Attribut tableSpecs besteht aus Schlüssel-Wert Paaren, die in { } eingeschlossen werden müssen und miteinander kombiniert sein können. Weiterhin können Schlüssel auch Subschlüssel enthalten, die ebenfalls in { } eingeschlossen werden. In den nachfolgenden Beispielen wird die Verwendung vorgestellt.


Allgemeine Gestaltung des Tabellenheaders und der Spalten


Mit den Subschlüsseln noHeader => 1 kann die Headerzeile der Tabelle ausgeschaltet werden. Der Subschlüssel headerAlign dient der Ausrichtung der Headerspalten und columnAlign der Ausrichtung der Inhaltsspalten.


Inhalt Attribut tableSpecs:
Allgemeine Gestaltung des Tabellenheaders und der Spalten
Erläuterungen Aussehen
{ 						 
  "cellStyle"  => {
                    "noHeader"    => "1",
                    "headerAlign" => "center",
                    "columnAlign" => "left",
                  },
}
noHeader 1 verbirgt die Headerzeile, noHeader 0 zeigt sie an (Standard). Die Subschlüssel headerAlign und columnAlign können die Werte left, center und right annehmen und dienen der Ausrichtung der Spalten im Header bzw. Body der Tabelle.

Der Subschlüssel columnAlign legt zunächst die Ausrichtung für alle Spalten des Tabellbodys fest. Die Spaltenausrichtung kann aber zusätzlich für jede Spalte spezifisch eingestellt werden, wie im nachfolgenden Beispiel gezeigt.

Sscal25.PNG
{ 						 
  "cellStyle"             => {
                               "noHeader"            => "0",
                               "headerAlign"         => "center",
                               "columnAlign"         => "left",
                               "columnSymbolAlign"   => "center",
                               "columnDaysLeftAlign" => "center",
                             },
}
Die Ausrichtung jeder Spalte kann separat erfolgen. Die Subschlüssel dafür heißen column<Spaltenname>Align. Demzufolge betreffen die im Beispiel dargestellten Subschlüssel columnSymbolAlign und columnDaysLeftAlign die Spalten Symbol sowie DaysLeft und werden abweichend von Standard zentriert dargestellt. Die Werte können left, center oder right sein.

Die weiteren Subschlüssel zur Ausrichtung der Spalten heißen dementsprechend:

columnBeginAlign columnEndAlign
columnDaysLeftLongAlign columnWeekdayAlign
columnTimezoneAlign columnSummaryAlign
columnDescriptionAlign columnStatusAlign
columnCompletionAlign columnLocationAlign
columnMapAlign columnCalendarAlign
columnEventIdAlign
Sscal26.PNG



Gestaltung der Spalte "Map" bzw. "Karte"

In der Spalte Map bzw. Karte wird bei Vorhandensein von GPS-Daten ein Link zur Karte von Google Maps (default) oder OpenStreetMap angeboten. Die Auswahl, welcher Kartenprovider verwendet werden soll, erfolgt über den Schlüssel columnMapProvider im Attribut tableSpecs. Der Wert in der Spalte Map kann als Icon (default), Text oder der GPS-Daten selbst dargestellt werden. Das Attribut tableColumnMap legt fest, wie der Wert dargestellt wird:

 attr <Device> tableColumnMap <icon | data | text>


Über folgende Schüssel wird das verwendete Icon bzw. ein eigener Link-Text festgelegt und der Kartenprovider ausgewählt:


Inhalt Attribut tableSpecs:
Gestaltung Spalte "Map"
Erläuterungen Aussehen
{ 
  "columnMapIcon"         => "rc_WEB",
  "columnMapText"         => "Hier gehts zur Karte",
  "columnMapProvider"     => "GoogleMaps",
}
Der Icon-Dateiname im Schlüssel columnMapIcon wird ohne Endung angegeben. Im Schlüssel columnMapProvider kann "OpenStreetMap" oder "GoogleMaps" enthalten sein. Sscal10.PNG
{ 
  "columnMapIcon"         => "rc_WEB@red",
  "columnMapText"         => "Hier gehts zur Karte",
  "columnMapProvider"     => "GoogleMaps",
}
Das Icon kann eingefärbt werden. Entweder mit der Farbangabe hinter @ oder dem Farbcode wie @#DF0101 Sscal11.PNG
{ 
  "columnMapIcon"         => {
                               "Status" => "eq 'ended' ",
                               "icon"   => "rc_WEB@grey",                                
                             },
  "columnMapProvider"     => "GoogleMaps",
}
Das Icon wird in "rc_WEB geändert und grau eingefärbt, wenn eine zweite Bedingung wahr ist. Der Schlüssel der zweiten Bedingung ist ein Readingname ohne Block- und Readingnummer gefolgt von einer Bedingung ("eq") und einem Wert ("ended") auf den geprüft wird.

Ist die Bedingung unwahr, wird das Standardicon eingefügt.

Sscal12.PNG
{ 
  "columnMapIcon"     => [
                         {
                           "Status" => "eq 'ended' ",
                           "icon"   => "rc_WEB@grey",                                
                         },
                         {
                           "Status" => "eq 'upcoming' ",
                           "icon"   => "rc_WEB@red",
                         }
                         ], 
  "columnMapText"      => "Hier gehts zur Karte",
}
Es können mehrere Bedingungen angegeben werden. Diese werden in Gruppen angegeben. Die Gruppen werden von oben nach unten abgearbeitet. Ist eine Gruppe wahr, wird der Wert im Schlüssel "icon" zurück gegeben.

Hinweis: Eine Gruppe ist in [ ] einzufügen.

Es können je Gruppe weitere Bedingungen hinzugefügt werden, die alle "wahr" sein müssen um das in dieser Gruppe eingetragene Icon zurück zu geben. Der Schlüssel der Bedingung ist immer ein Readingname ohne Block- und Readingnummer gefolgt von einer Bedingung und dem Wert zum Vergleich. Zum Beispiel "daysLeft" wenn das Reading "x_x_daysLeft" ausgewertet werden soll. Das Modul übernimmt selbstständig die korrekte Zuweisung des Readings im aktuellen Block.


Sscal13.PNG


Mit dem Schlüssel columnMapText wird ein eigener Text für den Karten-Link in Spalte Map hinterlegt. Damit der Text anstatt eines Icon dargestellt wird, schaltet man diese Option mit dem Attribut

 attr <Device> tableColumnMap text

ein. Im Schlüssel columnMapText können verschiedene vordefinierte Variablen verwendet werden:

 $NAME - der Name des SSCal-Devices
 $BNR  - Blocknummer eines Readings
 $we   - siehe holiday2we
 $hms  - Zeit im sprintf-Format "hh:mm:ss"

 $sec, $min, $hour, $mday, $month, $year, $wday, $yday, $isdst - siehe Perl localtime

Der Schlüssel wird dann wie folgt definiert:


Inhalt Attribut tableSpecs:
Gestaltung Spalte "Map" als Text
Erläuterungen Aussehen
{ 						 
  "columnMapText"         => "Hier gehts zur Karte",
  "columnMapProvider"     => "OpenStreetMap",
}
Der Text im Schlüssel "columnMapText" wird als Linktext in der Spalte "Map" verwendet. Sscal14.PNG
{ 						 
  "columnMapText"         => "{ ReadingsVal('$NAME', '$BNR_35_Location','') }",
  "columnMapProvider"     => "OpenStreetMap",
}
Im Schlüssel "columnMapText" kann eine Perl-Routine (eingeschlossen in { }) hinterlegt werden, die einen Text zurückliefert. In diesem Beispiel wird als Linktext der Inhalt des Readings Location benutzt und wird als anklickbaren Text in der Spalte "Map" angezeigt. Die "35" vor dem Readingnamen "Location" ist die Readingnummer (siehe Kapitel Schema der erzeugten Readings). Sscal15.PNG



Gestaltung der Spalte "Days left" bzw. "Resttage"


Die Spalte "Resttage" zeigt die verbleibende Zeit bis zum Eintritt des Termins. Ist der Termin beendet bzw. in der Vergangenheit, bleibt diese Spalte leer.

Um diese Spalte als Icon darzustellen, wird der Schlüssel columnDaysLeftIcon verwendet. Es können mehrere Subschlüssel angewendet werden die logisch durch und verknüpft sind. D.h. alle Bedingungen der Subschlüssel müssen wahr werden damit die Gruppe wahr wird.

Dabei können mehrere Gruppen von Subschlüsseln verwendet werden um abhängig von unterschiedlichen Readingwerten das resultierende Icon zu wählen oder einzufärben.


Inhalt Attribut tableSpecs:
Gestaltung Spalte "Resttage" als Icon
Erläuterungen Aussehen
{ 						 
  "columnDaysLeftIcon"    => {
                               "Summary"  => "=~ /[Tt]onne|Restabfall/",
                               "Status"   => "ne 'ended' ",
                               "icon"     => "Tonne_green",
                             },
}
Der Text im Reading "x_x_Summary" wird ausgewertet und ergibt wahr wenn er "Tonne" oder "tonne" oder "Reastabfall" im String trägt.

Der Inhalt des Readings "x_x_Status" muß ungleich "ended" sein damit diese Auswertung wahr wird.

Beide Bedingen müssen wahr sein, damit das angegeben "Icon" in der Spalte angezeigt wird. Deswegen wird in den ersten zwei Zeilen der Tabelle kein Tonnen-Icon eingefügt.

Sscal16.PNG
{ 						 
  "columnDaysLeftIcon"    => [
                             {
                               "Summary"  => "=~ /Gelbe Tonne/",
                               "icon"     => "dustbin@#DF7401",    
                             },
                             {
                               "Summary"  => "=~ /Biotonne/",
                               "icon"     => "dustbin@brown",    
                             },	
                             {
                               "Summary"  => "=~ /Restabfall/",
                               "icon"     => "dustbin@black",
                             },
                             {
                               "Summary"  => "=~ /Papier/",
                               "icon"     => "dustbin@blue",
                             },
                             {
                               "Status"   => "=~ /ended/",
                               "icon"     => "dustbin@grey",
                             },
                             ],
}
Der Schlüssel columnDaysLeftIcon kann einen oder mehrere Subschlüssel enthalten.

Mehrere Subschlüssel werden wie hier dargestellt als Gruppe zusammengefasst und in [ ] eingeschlossen. Im Beispiel wird der Text im Reading "x_x_Summary" ausgewertet und wenn die Bedingung zutrifft das Icon und dessen Farbe entsprechend gesetzt.

Die Gruppen werden von oben nach unten abgearbeitet. Die letzte "wahre" Gruppe siegt.

Sscal17.PNG
{ 						 
  "columnDaysLeftIcon"    => [
                             {
                               "Status"   => "!~ /ended/ ",
                               "daysLeft" => ">= 2",
                               "icon"     => "10px-kreis-gruen",    
                             },
                             {
                               "Status"   => "!~ /ended/ ",
                               "daysLeft" => ">= 16",
                               "icon"     => "10px-kreis-gelb",    
                             },
							 {
                               "Status"   => "!~ /ended/ ",
                               "daysLeft" => ">= 30",
                               "icon"     => "10px-kreis-rot",
                             },
                             ]
}
Der Schlüssel columnDaysLeftIcon kann einen oder mehrere Subschlüssel enthalten.

Mehrere Subschlüssel werden wie hier dargestellt als Gruppe zusammengefasst und in [ ] eingeschlossen. Im Beispiel werden die Inhalte der Readings "x_x_Status" und "x_x_dayLeft" ausgewertet.

Wenn alle zwei Bedingungen wahr sind, wird die jeweilige Gruppe wahr und das angegebene Icon in der Spalte angezeigt.

Die Gruppen werden von oben nach unten abgearbeitet. Die letzte "wahre" Gruppe siegt.

Sscal18.PNG



Gestaltung der Spalte "State" bzw. "Status"


Die Spalte "Status" zeigt den aktuellen Status eines Termins an. Abhängig davon sowie den Inhalten weiterer Readings kann in dieser Spalte ein Icon anstatt des Statustextes angezeigt werden.

Um diese Spalte als Icon darzustellen, wird der Schlüssel columnStateIcon verwendet. Es können mehrere Subschlüssel angewendet werden die logisch durch und verknüpft sind. D.h. alle Bedingungen der Subschlüssel müssen wahr sein damit die Gruppe wahr wird.

Dabei können mehrere Gruppen von Subschlüsseln verwendet werden, um abhängig von unterschiedlichen Readingwerten das resultierende Icon zu wählen oder einzufärben.


Inhalt Attribut tableSpecs:
Gestaltung Spalte "Status" als Icon
Erläuterungen Aussehen
{ 						 
  "columnStateIcon"       => [
                             {
                               "Status"   => "eq 'ended' ",
                               "icon"     => "ios-off",
                             },
                             {
                               "Status"   => "eq 'upcoming' ",
                               "icon"     => "ios-on-for-timer-green",
                             },
                             {
                               "Status"   => "eq 'upcoming' ",
                               "daysLeft" => ">= 4",
                               "icon"     => "ios-on-for-timer-blue",
                             },
                             ],
}
Der Inhalt des Readings "x_x_Status" wird ausgewertet und abhängig von dessen Inhalt das Icon bestimmt.

In der untersten Gruppe muß außerdem der Inhalt von "x_x_daysLeft" größer/gleich "4" sein damit diese Gruppe wahr wird.

Alle Bedingungen in einer Gruppe müssen wahr sein, damit das angegebene "Icon" in der Spalte angezeigt wird. Die Gruppen werden der Reihe nach von oben nach unten ausgewertet. Die letzte wahre Gruppe gewinnt und deren Icon wird dargestellt.

Hinweis: Gruppen werden immer in [ ] eingeschlossen.

Sscal19.PNG



Gestaltung der Spalte "Symbol"


Sofern man mit dem Attribut tableFields die Spalte Symbol mit auswählt, wird in der tabellarischen Übersicht jede Tabellenzeile von einem Standardicon angeführt. Das Standardicon ist abhängig vom Internal MODEL des Kalenders, d.h. ob es sich um einen Terminkalender oder eine Aufgabenliste handelt.

Dieses Standardicon kann mit dem Schlüssel columnSymbolIcon den persönlichen Bedürfnissen entsprechend angepasst werden.


Inhalt Attribut tableSpecs:
Gestaltung der Spalte "Symbol"
Erläuterungen Aussehen
{ 						 
  "columnSymbolIcon" => "time_manual_mode", 
}
Mit einer einfachen Schlüssel - Wert Zuweisung kann das Ico geändert werden. Sscal22.PNG
{
 "columnSymbolIcon" => [
                       { 
                         "Weekday" => "eq 'Montag' ",
                         "icon" => "edit_numeric_1",
                       },
                       { 
                         "Weekday" => "eq 'Dienstag' ",
                         "icon" => "edit_numeric_2",
                       },
                       { 
                         "Weekday" => "eq 'Mittwoch' ",
                         "icon" => "edit_numeric_3",
                       },
                       { 
                         "Weekday" => "eq 'Donnerstag' ",
                         "icon" => "edit_numeric_4",
                       },
                       { 
                         "Weekday" => "eq 'Freitag' ",
                         "icon" => "edit_numeric_5",
                       },
                       { 
                         "Weekday" => "eq 'Samstag' ",
                         "icon" => "edit_numeric_6",
                       },
                       { 
                         "Weekday" => "eq 'Sontag' ",
                         "icon" => "edit_numeric_7",
                       },
                       ],
}
Durch die Auswertung des Readings "x_x_Weekday" wird in diesem Beispiel die Zeile des Kalendereintrags in der Spalte Symbol nummeriert.

Die Bedingung in einer Gruppe muß wahr sein, damit das angegebene "Icon" in der Spalte angezeigt wird. Die Gruppen werden der Reihe nach von oben nach unten ausgewertet.

Hinweis: Gruppen werden immer in [ ] eingeschlossen.

Sscal23.PNG



Optimierung der Tabelle für smallscreen Styles


Für bestimmte Styles ist es sinnvoll die Tabellengestaltung flexibel zu gestalten, sodass z.B. Spalten umgebrochen werden können um Platz zu sparen. In dem Schlüssel smallScreenStyles wird hinterlegt, für welche Styles die optimierte Anpassung gelten soll.


Inhalt Attribut tableSpecs:
Optimierung der Tabelle für Smallscreen Styles
Erläuterungen Aussehen
{ 						 
  "smallScreenStyles" => "darksmallscreen,smallscreen,default",
}
Es wird als Schlüsselwert eine durch Komma getrennte Liste der Styles eingetragen, für eine optimierte Anpassung der Tabelle vorgenommen werden soll. Sscal20.PNG



Beispiele mit Kombinationen von Schlüsseln


Alle oben genannten Schlüssel und Varianten können miteinander kombiniert werden. Im Ergebnis werden die jeweiligen Spalten der Übersichtstabelle entsprechend der Auswertungergebnisse ihrer Definitionen dargestellt.


Inhalt Attribut tableSpecs:
Schlüsselkombinationen
Erläuterungen Aussehen
{
  "columnMapIcon"         => [{
                               "Status" => "eq 'ended' ",
                               "icon"   => "rc_WEB@grey",                                
                             },
                             {
                               "daysLeft" => ">= 1 ",
                               "icon"   => "rc_WEB",                                
                             }],
  "columnMapProvider"     => "GoogleMaps",
  "columnMapText"         => "{ ReadingsVal('$NAME', '$BNR_35_Location','') }",
  "smallScreenStyles"     => "darksmallscreen,smallscreen",
  "columnStateIcon"       => [
                             {
                               "Status"   => "eq 'ended' ",
                               "icon"     => "ios-off",   
                             },
                             {
                               "Status"   => "eq 'upcoming' ",
                               "icon"     => "ios-on-for-timer-green",   
                             },
                             {
                               "Status"   => "eq 'upcoming' ",
                               "daysLeft" => ">= 4",
                               "icon"     => "ios-on-for-timer-blue",   
                             },							 
                             ],
  "columnDaysLeftIcon"    => [
                             {
                               "Summary"  => "=~ /Gelbe Tonne/",
                               "icon"     => "dustbin@#DF7401",    
                             },
                             {
                               "Summary"  => "=~ /Biotonne/",
                               "icon"     => "dustbin@brown",    
                             },	
                             {
                               "Summary"  => "=~ /Restabfall/",
                               "icon"     => "dustbin@black",
                             },
                             {
                               "Summary"  => "=~ /Papier/",
                               "icon"     => "dustbin@blue",
                             },
                             {
                               "Status"   => "=~ /ended/",
                               "icon"     => "dustbin@grey",
                             },
                             ],
}
Zusätzlich zu der aufgezeigten Definition ist das Attribut tableColumnMap auf icon gestellt um in der Spalte Map nicht den im Schüssel columnMapText definierten Text (Auswertung von ReadingsVal) zu zeigen, sondern das im Schlüssel columnMapIcon angegebene Icon. Sscal21.PNG
{
  "smallScreenStyles"  => "dark,default",
  "columnSymbolIcon"   => [ 
                          {
                            "Summary"  => "eq 'Biotonne' ",
                            "icon"     => "message_garbage@brown",
                          },
                          {
                            "Summary"  => "eq 'Gelbe Tonne' ",
                            "icon"     => "message_garbage@orange",
                          },
                          {
                            "Summary"  => "eq 'Papiertonne' ",
                            "icon"     => "message_garbage@blue",
                          },
                          {
                            "Summary"  => "=~ /Restabfall/ ",
                            "icon"     => "message_garbage@Wheat",
                          },
                          ],
  "columnDaysLeftIcon" => [	
                          {
                            "Summary"  => "=~ /[Tt]onne|Restabfall/",
                            "Status"   => "ne 'ended' ",
                            "daysLeft" => "<= 4",
                            "icon"     => "message_garbage_collection@orange",
                          },
                          {
                            "Summary"  => "=~ /[Tt]onne|Restabfall/",
                            "Status"   => "ne 'ended' ",
                            "daysLeft" => "<= 2",
                            "icon"     => "message_garbage_collection@green",
                          },
                          {
                            "Summary"  => "=~ /[Tt]onne|Restabfall/",
                            "Status"   => "ne 'ended' ",
                            "daysLeft" => "> 4",
                            "icon"     => "bag@grey",
                          },
                          ],
  "columnStateIcon"       => [
                             {
                               "Status"   => "eq 'ended' ",
                               "icon"     => "1px-spacer",
                             },
                             {
                               "Status"   => "eq 'started' ",
                               "icon"     => "10px-kreis-gruen",
                             },
                             {
                               "Status"   => "eq 'upcoming' ",
                               "icon"     => "10px-kreis-gelb",
                             },
                             {
                               "Status"   => "eq 'alarmed' ",
                               "icon"     => "10px-kreis-rot",
                             },
                             ],
}
Dieses Beispiel zeigt eine Konfiguration zur Anzeige eines Abfallkalenders. Es werden nur die minimal notwendigen Informationsspalten angezeigt. Sscal24.PNG



Termintabelle als Weblink einfügen

Zur Einbindung in ein Weblink-Device oder zur Verwendung in eigenen Perl-Routinen stellt SSCal die Subroutine SSCal_calAsHtml zur Verfügung. Sie liefert ein HTML-Output zurück, welches dem eingestellten Tabellenaufbau in der Detail- bzw. Raumübersicht entspricht.

Spaltensteuerung Tabelle bei weblink Einbindung

Die Definition des Weblink-Devices erfolgt:

define SynCal.Abfall.WBL weblink htmlCode { SSCal_calAsHtml ("SynCal1") }

SynCal1 ist der Name des SSCal-Devices dessen Ausgabetabelle eingebunden werden soll.

Möglicherweise sollen die Spalten Start/Ende jeweils nur als eine und nicht zwei (Datum/Zeit) Spalten dargestellt werden. Im Attribut tableSpecs steuert der Schlüssel smallScreenStyles den Aufbau dieser Spalten in Abhängigkleit vom verwendeten Style des aufrufenden FHEMWEB Devices. Bei einer programmtechnischen Verwendung muss diese Information explizit mitgegeben werden.

Verwendet z.B. das FHEMWEB Device "WEB.BLACK" das Style "dark" und dieses ist im Schlüssel hinterlegt ("smallScreenStyles" => "dark"), erfolgt die Definition des Weblink-Devices in dieser Form:

define SynCal.Abfall.WBL weblink htmlCode { SSCal_calAsHtml ("SynCal1","WEB.BLACK") }

Dadurch simuliert man gegenüber der SSCal_calAsHtml Routine den Aufruf über das FHEMWEB-Device "WEB.BLACK" und die Routine wertet für dieses Device den eventuell vorhandenen Schlüssel "smallScreenStyles" => "dark" aus, was zur Darstellung der optimierten Ansicht führt.



Reagieren auf Events und eine FHEM-Aktivität erstellen


Das SSCal-Modul bietet für den Anwender zusätzliche Hilfsmittel an, um aus einem Kalendereintrag Steuerungen für Geräte oder Mitteilungen aufzubauen. Die wesentlichen sind nachfolgend beschrieben.

at-Devices für Steuerungen automatisch erstellen und verwalten lassen

Um aus FHEM-Befehlen (z.B. "set lampe on") oder Perl-Routine Aufrufen (z.B. checkit()) automatisch eine zeitgesteuerte FHEM-Aktion zu erstellen, kann diese Funktionalität mit dem Attribut:

attr <SSCal> createATDevs 1

eingeschaltet werden.

Es wird der Eintrag im Reading Description ausgewertet, was dem Feld Beschreibung im Synology Kalender WebUI entspricht. Um als FHEM-Befehl erkannt zu werden, muss der Text in der Beschreibung in { } eingefasst sein bzw. in doppelte {{ }} zur Kennzeichnung einer Perl-Routine. Der Kalendereintrag muss ebenfalls eine defininierte Anfangszeit in der Zukunft enthalten. Für beendete oder bereits gestartete Ereignisse wird kein at-Device erstellt.

Sind die Voraussetzungen erfüllt, wird für jedes erkannte Befehls-Ereignis ein at-Device erstellt und die Werte aus dem Kalendereintrag übernommen:


Begin Starttermin im at-Device
Description der FHEM-Befehl bzw. die auszuführende Perl-Routine
Summary wird in das alias-Attribut des at übernommen
Location wird als room-Attribut im at verwendet falls gesetzt. Sonst wird das room-Attribut des SSCal-Devices übernommen


Der Name der erstellten at-Devices folgenden dem Schema:

SSCal.<SSCal-Device>.<Event-ID>.<ISO-Startzeit>


Bei jedem erneuten Einlesen des Kalenders werden eventuell bereits vorhandene at-Devices gelöscht, die durch das <SSCal-Device> erstellt wurden. Dadurch werden im Kalender vorgenommene Änderungen bestehender Termine und deren Inhalte übernommen. Im Kalender gelöschte Termine werden ebenfalls erkannt und die referenzierten at-Devices in FHEM gelöscht.


Beipiel:


Ein Kalendereintrag mit den Readings:

     2_01_Summary          bald beginnend
     2_03_Description      {{ Perl-Routine }}
     2_05_Begin            2020-02-17 20:45:00
     2_10_End              2020-02-17 21:45:00
     2_15_Timezone         Europe/Berlin
     2_17_Status           alarmed
     2_20_daysLeft         0
     2_25_daysLeftLong     in 0 Tagen
     2_30_Weekday          Montag
     2_50_isAllday         0
     2_55_isRepeatEvt      0
     2_80_0_notifyDateTime 2020-02-16 20:45:00
     2_90_calName          Testkalender
     2_98_EventId          2000

führt zur Erstellung des at-Devices SSCal.SynCal3.2000.20200217T204500 mit der Definition:

defmod SSCal.SynCal3.2000.20200217T204500 at 2020-02-17T20:45:00 { Perl-Routine }
attr SSCal.SynCal3.2000.20200217T204500 comment created automatic by SSCal "SynCal3" 
attr SSCal.SynCal3.2000.20200217T204500 alias bald beginnend" 
attr SSCal.SynCal3.2000.20200217T204500 room SSCal

setstate SSCal.SynCal3.2000.20200217T204500 Next: 2020-02-17 20:45:00
setstate SSCal.SynCal3.2000.20200217T204500 2020-02-17 19:44:09 state Next: 2020-02-17 20:45:00

zusätzliches composite-Event für eigene Logiken


Für jedes Ereignis, welches einen Begin-Zeitpunkt enthält, werden zuätzliche composite-Events bei jedem erneuten Einlesen eines Kalenders erstellt. Der Event composite enthält die Informationsfelder:

  • Blocknummer des Termins
  • Event-ID des Termins
  • Kennzeichen für ein Serientermin (0=kein Serientermin oder 1=Serientermin)
  • Startzeitpunkt im ISO 8601 Format
  • Status des Events
  • den Text in Description (entspricht dem Feld Beschreibung im Synology Kalender WebUI) bzw. den Text in Summary falls Description nicht gesetzt ist


Der Event compositeBlockNumbers enthält die Blocknummern aller Termine des Kalenders. Sind keine Termine vorhanden, enthält dieser Event nur den Wert none.


Ausschnitt aus dem Eventmonitor:

2020-02-14 13:19:11 SSCal SynCal2 compositeBlockNumbers: 00 01 02 03 04 05 06 07 08 09 10                # alle Block-Nr
2020-02-14 13:19:11 SSCal SynCal2 composite: 00 1983 0 2020-02-14T13:15:00 started {set lampe on}        # FHEM-Befehl
2020-02-14 13:19:11 SSCal SynCal2 composite: 01 1984 0 2020-02-14T15:15:00 alarmed {set lampe off}       # FHEM-Befehl 
2020-02-14 13:35:31 SSCal SynCal2 composite: 02 1985 1 2020-02-14T18:00:00 upcoming {{ <Perl-Routine> }} # Perl-Routine

Das ISO Format des Zeitstempels kann unmittelbar zur Erstellung eines at verwendet werden. Um die Verwendung des Kalenderinhaltes als FHEM-Befehl zu deklarieren, kann bei der Erstellung des Kalendereintrages das Ereignis in { } eingefasst werden um z.B. in einem notify darauf zu filtern.

Die nachfolgende Definition eines notify-Devices zeigt eine mögliche Verfahrensweise um bei Erkennung eines FHEM-Befehls automatisch ein at-Device mit einem entsprechenden Startzeitpunkt für die Ausführung des angegebenen Befehls zu definieren:

SynCal.*:.*composite.* 
{ 
  my ($PART0, $PART1)                     = split(": ", $EVENT,2);; 
  my ($bnr,$id,$repeat,$isot,$tate,$cmd)  = split(" ",  $PART1,6);;
  if ($tate =~ /upcoming|alarmed/ && $cmd =~ /^\s*\{(.*)\}\s*$/) {
    $cmd    = $1;
    if(!$repeat) {
        Log3($NAME, 3, "$NAME - Command received. Create/modify \"SSCal.$id\" - Timestamp: $isot, Command: $cmd");;
        fhem("defmod SSCal.$id at $isot $cmd");;
    } else {
        my $ao = $isot;
        $ao    =~ s/[-:]//g;
        Log3($NAME, 3, "$NAME - Command received. Create/modify \"SSCal.$id.$ao\" - Timestamp: $isot, Command: $cmd");;
        fhem("defmod SSCal.$id.$ao at $isot $cmd");;	    
    }
  }
}

Funktionsweise:

Wird ein composite-Event eines SSCal-Devices mit dem Betreff eingeschlossen in { } erkannt und ist der Status dieses Termins "upcoming" oder "alarmed", wird ein at-Device mit dem Startzeitpunkt und dem Befehl (ohne die einschließenden { }) aus dem Event erstellt. Ist das Device bereits vorhanden, wird das Device aktualisiert. Durch eine eindeutige Zuordung des Kalendereintrags zu dem at-Device über die Event-ID im Namen wird in dem Fall, dass es kein Serientermin ist, der Start des FHEM-Befehl automatisch angepasst wenn man den Zeitpunkt im Kalender verändert.

Zusätzlich wird ein Logeintrag mit verbose 3 zur Protokollierung erstellt. Soll statt FHEM-Befehl eine Perl-Routine ausgeführt werden, schließt man den Betreff des Kalendereintrags in doppelte {{ }} ein.



Urlaub/Abwesenheiten automatisiert in holiday Device Steuerdatei übernehmen

Mit Hilfe des Events compositeBlockNumbers können Urlaubs- oder allgemeine Abwesenheitstermine aus einem Kalender automatisch in ein holiday Device bzw. die Steuerdatei des holiday Devices übertragen werden.

Zu diesem Zweck werden zwei Subroutinen in der 99_myUtils.pm erstellt und ein Notify um auf den Event zu reagieren und die Subroutine SSCalToHoliday auszuführen.

In dem Beispiel wird davon ausgegangen:

  • das holiday Device verwendet die Datei (HOLIDAYFILE) ./FHEM/central.holiday
  • die Abwesenheiten werden durch die Signalwörter Urlaub bzw. Abwesend gekennzeichnet
  • das Kalenderdevice, welches die Urlaubsdaten enthält, heißt SynCal2


Es werden die Routinen SSCalToHoliday und SSCalWriteHoliday in die Datei 99_myUtils.pm eingefügt.


###################################################################################################
###    Urlaubstermine auswerten mit 57_SSCal.pm
###    Aufruf der Funktion aus Notify
###    
###    $event = compositeBlockNumbers-$EVENT und enthält alle Blocknummern des Kalenders, z.B.
###    compositeBlockNumbers: 00 01 02 03 04 05 06 07 08 09 10 11 12 13
###
####################################################################################################
sub SSCalToHoliday($$$) {
   my ($name,$fName,$event) = @_;
   my $hash           = $defs{$name};
   my ($reading,$evt) = split(": ",$event,2);
   my (@bnr)          = split(" ",$evt);
    
   my @SigList        = qw/Urlaub Abwesend/;                             # Signalwörter im Kalender für "Abwesenheit"
   my @ul;   

   foreach my $bnr (@bnr) {
       last if($bnr eq "none");
       my $status  = ReadingsVal($name, $bnr."_17_Status",  "");         # Status
       my $summary = ReadingsVal($name, $bnr."_01_Summary", "");         # Summary
       my $begin   = ReadingsVal($name, $bnr."_05_Begin",   "");         # Starttermin
       my $end     = ReadingsVal($name, $bnr."_10_End",     "");         # Endtermin
   
       if($status =~ /upcoming|alarmed|started/) {                       # Termine beginnen in Zukunft, Signalwort aus 
                                                                         # Liste enthalten ?               
           if (grep {$summary =~ /$_/} @SigList) {               
               my ($sy,$sm,$sd,$sh,$smin,$ss) = ($begin =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/);
               my ($ey,$em,$ed,$eh,$emin,$es) = ($end   =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/);
               
               if($sy != $ey) {                                          # wenn Jahreswechsel vorliegt zwei Sätze erzeugen
                   push(@ul, "4 $sm-$sd 12-31 $summary");                # 4 12-09 12-31 Urlaub Teil1
                   push(@ul, "4 01-01 $em-$ed $summary");                # 4 01-01 01-05 Urlaub Teil2
                    
               } else {
                   my $ue = "4 $sm-$sd $em-$ed $summary";
                   push(@ul, $ue);
               }
           } 
       }
   }
   
   if (@ul) {
       Log3 ($name, 4, "$name - Argument list for SSCalWriteHoliday:");
       foreach my $i (@ul) {
           Log3 ($name, 4, "$name - $i");
       }
   } else {
       Log3 ($name, 4, "$name - No absence time detected. All absence will be deleted.");
   }
   
   SSCalWriteHoliday($name,$fName,@ul);
       
return;
}

############################################################################
###    Schreibroutine Urlaub in File (central.holiday) 
############################################################################
sub SSCalWriteHoliday(@) {
  my ($name,$fName,@ul) = @_;
  $fName = $attr{global}{modpath}."/FHEM/".$fName;

  my $param = {
               FileName   => $fName,
               ForceType  => "file",
              };
  
  my ($err, @old) = FileRead($param);
  if($err) {
      Log3 ($name, 2, "$name - Couldn't read file: $err");
      return;
  }
  
  my @new;                                                             # neue Liste zum Schreiben
  my $del = 0;
  
  foreach my $l (@old) {
      if($l =~ m/^# Time of absence from Calendar $name/i) {
          $del = 1;
      }
	  
      if($l =~ m/^# End Time of absence from Calendar $name/i) {
          $del = 0;
		  next;
      }
      
      if ($del) {
          next;     
      } else {
          push (@new, $l);
          Log3 ($name, 4, "$name - add line: $l"); 
      }  
  }
  
  unshift (@ul, "# Time of absence from Calendar $name, updated: ".TimeNow());
  push    (@ul, "# End Time of absence from Calendar $name");
  push    (@new, @ul);
 
  Log3 ($name, 4, "$name - -> Start new list write into $fName <-");
  foreach my $i (@new) {
      Log3 ($name, 4, "$name - $i");
  }
  Log3 ($name, 4, "$name - -> End new list <-");

  $err = FileWrite($param, @new);
  if($err) {
      Log3 ($name, 2, "$name - Couldn't write holiday data into $fName: $err");
  }
  
return;
}


Das folgende Notify (Raw-Definition) wird verwendet:

define N.SSCalWriteHolidays notify SynCal2:compositeBlockNumbers:.* { SSCalToHoliday($NAME,"central.holiday",$EVENT) }
attr N.SSCalWriteHolidays devStateIcon active:remotecontrol/black_btn_GREEN:inactive inactive:remotecontrol/black_btn_RED:active


Funktionsweise:
Wird der Event compositeBlockNumbers durch das Device SSCal2 ausgelöst, wird die Subroutine SSCalToHoliday ausgeführt. Dieser Routine werden der auslösende Devicename ($NAME = SSCal2 in dem Beispiel), das HOLIDAYFILE und der komplette Event übergeben.

Das Event compositeBlockNumbers enthält die Blocknummern aller Termine im Kalenderdevice. Im Array @SigList werden alle Signalwörter hinterlegt, die bei Vorhandensein im Reading x_x_Summary eine Abwesenheit kennzeichnen. Wird eines dieser Signalwörter erkannt und ist der dazu gehörige Termin nicht vergangen, erfolgt die Übersetzung in das durch holiday verarbeitbare Format und der Termineintrag in die Datei central.holiday.

Beispiel für einen Eintrag:

# Time of absence from Calendar SynCal2, updated: 2020-03-05 21:20:47
4 03-28 04-04 Urlaub - Nordsee
# End Time of absence from Calendar SynCal2

Änderungen oder Löschen des Termins im Synology-Kalender führen ebenfalls zu einer automatischen Anpassung oder Löschen des Eintrags in der holiday-Steuerdatei.

Damit können Zeiten der Abwesenheiten über Kalendereinträge an FHEM übermittelt und durch holiday ausgewertet werden (Stichwort holiday2we bzw. $we).



Beschränkungen und Known Bugs


Weiterentwicklungen und Testversionen

Weiterentwicklungen und Testversionen stelle ich in meinem contrib-Verzeichnis bereit.

Eine Entwicklungsversion kann aus dem diesem Verzeichnis einfach per Download mit diesem Befehl in der FHEM Kommandozeile bezogen werden. Bitte so komplett mit den Ausführungszeichen am Anfang und Ende eingeben:

 "wget -qO ./FHEM/57_SSCal.pm https://svn.fhem.de/fhem/trunk/fhem/contrib/DS_Starter/57_SSCal.pm"

Danach FHEM restarten.

Durch Weiterentwicklung können sich jederzeit Änderungen ergeben. Im Zweifel das Forum konsultieren.



Links

Forumthread zu diesem Modul: https://forum.fhem.de/index.php/topic,106963.0.html
Synology KnowledgeBase: https://www.synology.com/de-de/knowledgebase/DSM/help/Calendar/calendar_desc