Nextcloud-Kalender -> über Ganztagestermine -> Zeitplan aufrufen

Begonnen von hydrotec, 21 Oktober 2020, 16:57:48

Vorheriges Thema - Nächstes Thema

hydrotec

Hallo miteinander,

in diesem thread würde ich gerne eure Meinung zu dem Thema sammeln.

Angefangen hat es mit 99_myUtils_calendar - Perl Code
im Laufe der Postings kam die Frage auf, ob es denn nicht einfacher wäre mit Calendar2Holiday zu arbeiten.

Daraufhin habe ich mich entschlossen einfach mal meine (funktionierende) Vorgehensweise zu posten.


Mein Ziel:
Einen Timer, der unter Zuhilfenahme von Ganztagesterminen in einem Nextcloud-Kalender, ein- oder ausgeschaltet wird.

Hintergrund:
Bei mir gibt es diverse Geräte, die nach einem bestimmten Zeitplan an oder aus geschaltet werden sollen.
Es gibt ja schon einige Lösungen dazu, doch ich habe keine gefunden, welche meinen Bedürfnissen entspricht.
(Vielleicht habe ich auch die ein oder andere Lösung übersehen)
Je nachdem was am morgigen Tag stattfindet, was sich jedoch wärend des Tages ändern kann, soll sich mein Zeitplan anpassen.
Ein ganz vereinfachtes Beispiel mit zwei Zuständen (tatsächlich sind es mehr).
Wenn Morgen ein Arbeitstag ist, dann sollen heute die Geräte um 21:00 Uhr abschalten,
wenn Morgen aber frei ist, dann heute erst um 23:00 Uhr.


Etwas detailliertere Darstellung meiner bisherigen Lösung.

Bei mir sind zwei Kalender in Nextcloud angelegt, die ich auch auf diversen mobiles verwende.
- Cal_Anwesenheit (Aktualisierung stündlich)
    - hier beschreibe ich drei Zustände
       - Regelbetrieb = Werktags auf Arbeit, Wochenende zu Hause (kein Eintrag)
        - Homeoffice   = Werktags Arbeit zu Hause
                         (währe auch am WE möglich, aber z.Z. eher nicht)
        - Urlaub       = allgemein freier Tag zu Hause
                         (derzeit leider eher Kurzarbeit, aber Urlaub liest sich schöner ;-) )
- Cal_Feiertage (Aktualisierung über at einmal am Tag, kurz nach Mitternacht)
    - selbsterklärend  = allgemein freie(r) Tag(e) zu Hause

defmod Cal_Anwesenheit Calendar ical url https://{USERNAME}:{PASSWORD}@192.168.78.33:31443/remote.php/dav/calendars/{USERNAME}/anwesenheit?export 3600
attr Cal_Anwesenheit DbLogExclude .*
attr Cal_Anwesenheit event-on-change-reading Homeoffice_.*,Urlaub_.*
attr Cal_Anwesenheit event-on-update-reading state,lastUpdate
attr Cal_Anwesenheit hideLaterThan 030d
attr Cal_Anwesenheit hideOlderThan 00:15
attr Cal_Anwesenheit room Kalender
attr Cal_Anwesenheit stateFormat Status: state  T: lastUpdate<br/>\
Homeoffice in: Homeoffice_at Tag(en), Heute: Homeoffice_today, Morgen: Homeoffice_tomorrow<br/>\
Urlaub in: Urlaub_at Tag(en), Heute: Urlaub_today, Morgen: Urlaub_tomorrow
attr Cal_Anwesenheit synchronousUpdate 0
attr Cal_Anwesenheit userReadings Homeoffice_at:triggered.* {Cal_at($NAME, 'Homeoffice')},\
Homeoffice_tomorrow:triggered.* {Cal_tm($NAME, 'Homeoffice')},\
Homeoffice_today:triggered.* {Cal_td($NAME, 'Homeoffice')},\
Urlaub_at:triggered.* {Cal_at($NAME, 'Urlaub')},\
Urlaub_tomorrow:triggered.* {Cal_tm($NAME, 'Urlaub')},\
Urlaub_today:triggered.* {Cal_td($NAME, 'Urlaub')}
attr Cal_Anwesenheit verbose 3


defmod Cal_Feiertage Calendar ical url https://{USERNAME}:{PASSWORD}@192.168.78.33:31443/remote.php/dav/calendars/{USERNAME}/feiertage?export 99999
attr Cal_Feiertage DbLogExclude .*
attr Cal_Feiertage event-on-change-reading Feiertag_.*
attr Cal_Feiertage event-on-update-reading state,lastUpdate
attr Cal_Feiertage hideLaterThan 200d
attr Cal_Feiertage hideOlderThan 00:15
attr Cal_Feiertage room Kalender
attr Cal_Feiertage stateFormat Status: state  T: lastUpdate<br/>\
Feiertag_name in: Feiertag_at Tag(en), Heute: Feiertag_today, Morgen: Feiertag_tomorrow
attr Cal_Feiertage synchronousUpdate 0
attr Cal_Feiertage userReadings Feiertag_name:triggered.* {Cal_na($NAME)},\
Feiertag_at:triggered.* {Cal_at($NAME)},\
Feiertag_tomorrow:triggered.* {Cal_tm($NAME)},\
Feiertag_today:triggered.* {Cal_td($NAME)}
attr Cal_Feiertage verbose 3



Auf Basis dieser Kalender werte ich dann einen Zustand aus.
Um das umzusetzen, benötige ich die hier besprochenen userReadings (tm/td).

Kurzform
(H_td=0) and (H_tm=0) and (U_td or F_td=0) and (U_tm or F_tm=0) ==0
(H_td=0) and (H_tm=1) and (U_td or F_td=0) and (U_tm or F_tm=0) ==1
(H_td=1) and (H_tm=1) and (U_td or F_td=0) and (U_tm or F_tm=0) ==2
(H_td=1) and (H_tm=0) and (U_td or F_td=0) and (U_tm or F_tm=0) ==3
(H_td=0) and (H_tm=0) and (U_td or F_td=0) and (U_tm or F_tm=1) ==4
(H_td=0) and (H_tm=0) and (U_td or F_td=1) and (U_tm or F_tm=1) ==5
(H_td=0) and (H_tm=0) and (U_td or F_td=1) and (U_tm or F_tm=0) ==6
(H_td=1) and (H_tm=0) and (U_td or F_td=0) and (U_tm or F_tm=1) ==7
(H_td=0) and (H_tm=1) and (U_td or F_td=1) and (U_tm or F_tm=0) ==8

defmod DI_Anwesenheit_Status DOIF (([Cal_Anwesenheit:Homeoffice_today] == 0) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 0) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 0) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 0)) (set DU_Anwesenheit_Status 0)\
DOELSEIF (([Cal_Anwesenheit:Homeoffice_today] == 0) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 1) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 0) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 0)) (set DU_Anwesenheit_Status 1)\
DOELSEIF (([Cal_Anwesenheit:Homeoffice_today] == 1) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 1) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 0) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 0)) (set DU_Anwesenheit_Status 2)\
DOELSEIF (([Cal_Anwesenheit:Homeoffice_today] == 1) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 0) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 0) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 0)) (set DU_Anwesenheit_Status 3)\
DOELSEIF (([Cal_Anwesenheit:Homeoffice_today] == 0) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 0) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 0) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 1)) (set DU_Anwesenheit_Status 4)\
DOELSEIF (([Cal_Anwesenheit:Homeoffice_today] == 0) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 0) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 1) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 1)) (set DU_Anwesenheit_Status 5)\
DOELSEIF (([Cal_Anwesenheit:Homeoffice_today] == 0) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 0) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 1) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 0)) (set DU_Anwesenheit_Status 6)\
DOELSEIF (([Cal_Anwesenheit:Homeoffice_today] == 1) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 0) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 0) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 1)) (set DU_Anwesenheit_Status 7)\
DOELSEIF (([Cal_Anwesenheit:Homeoffice_today] == 0) and ([Cal_Anwesenheit:Homeoffice_tomorrow] == 1) and (([Cal_Anwesenheit:Urlaub_today] or [Cal_Feiertage:Feiertag_today]) == 1) and (([Cal_Anwesenheit:Urlaub_tomorrow] or [Cal_Feiertage:Feiertag_tomorrow]) == 0)) (set DU_Anwesenheit_Status 8)
attr DI_Anwesenheit_Status DbLogExclude .*
attr DI_Anwesenheit_Status devStateIcon cmd_1:rc_0 cmd_2:rc_1 cmd_3:rc_2 cmd_4:rc_3 cmd_5:rc_4 cmd_6:rc_5 cmd_7:rc_6 cmd_8:rc_7 cmd_9:rc_8
attr DI_Anwesenheit_Status do always
attr DI_Anwesenheit_Status icon helper_doif
attr DI_Anwesenheit_Status room Kalender



Den ausgewerteten Zustand (0-8) übergebe ich an einen dummy
defmod DU_Anwesenheit_Status dummy
attr DU_Anwesenheit_Status DbLogExclude .*
attr DU_Anwesenheit_Status devStateIcon 0:rc_0 1:rc_1 2:rc_2 3:rc_3 4:rc_4 5:rc_5 6:rc_6 7:rc_7 8:rc_8
attr DU_Anwesenheit_Status event-on-change-reading state
attr DU_Anwesenheit_Status readingList state
attr DU_Anwesenheit_Status room Kalender
attr DU_Anwesenheit_Status setList state:0,1,2,3,4,5,6,7,8

Könnte man auch direkt abrufen, und auf den dummy verzichten.


Dann noch einen dummy angelegt (der eigentliche Timer).
defmod DU_Anwesenheit_Timer dummy
attr DU_Anwesenheit_Timer DbLogExclude .*
attr DU_Anwesenheit_Timer devStateIcon on:general_an_fuer_zeit:off off|initialized:general_aus:on
attr DU_Anwesenheit_Timer genericDeviceType switch
attr DU_Anwesenheit_Timer room Kalender
attr DU_Anwesenheit_Timer setList on off
attr DU_Anwesenheit_Timer webCmd on:off



Anschließend werden die Schaltzeiten dem Timer (dummy) zugeordnet.
defmod DI_Anwesenheit_Timer DOIF ((([05:00-07:30|Mo Di Mi Do Fr] or [16:00-21:30|Mo Di Mi Do] or [15:00-23:00|Fr] or [06:00-23:00|Sa] or [06:00-21:30|So]) and ([?DU_Anwesenheit_Status] =~"0|1")) \
or (([05:00-21:30|Mo Di Mi Do] or [05:00-23:00|Fr] or [06:00-23:00|Sa] or [06:00-21:30|So]) and ([?DU_Anwesenheit_Status] =~"2|3")) \
or (([05:00-07:30|Mo Di Mi Do Fr] or [16:00-23:00|Mo Di Mi Do] or [15:00-23:00|Fr] or [06:00-23:00|Sa So]) and ([?DU_Anwesenheit_Status] =~"4")) \
or (([06:00-23:00|Mo Di Mi Do Fr Sa So]) and ([?DU_Anwesenheit_Status] =~"5")) \
or (([06:00-21:30|Mo Di Mi Do So] or [06:00-23:00|Fr Sa]) and ([?DU_Anwesenheit_Status] =~"6|8")) \
or (([05:00-23:00|Mo Di Mi Do Fr] or [06:00-23:00|Sa So]) and ([?DU_Anwesenheit_Status] =~"7"))) (set DU_Anwesenheit_Timer on) \
DOELSE (set DU_Anwesenheit_Timer off)\

attr DI_Anwesenheit_Timer DbLogExclude .*
attr DI_Anwesenheit_Timer devStateIcon cmd_1:general_an_fuer_zeit:cmd_2 cmd_2|initialized:general_aus:cmd_1
attr DI_Anwesenheit_Timer icon helper_doif
attr DI_Anwesenheit_Timer room Kalender
attr DI_Anwesenheit_Timer weekdays So,Mo,Di,Mi,Do,Fr,Sa



Und damit kann ich dann nach Belieben die verschiedensten devices nach Auswertung des dummy (DU_Anwesenheit_Timer) schalten.
z.B.: (([DU_Anwesenheit_Timer] eq "on") and ([DU_ZuHause_geo] eq "on")) (set MyXperia screen on) DOELSE (set MyXperia screen off)

Ich weiß, ich verwende sehr viele dummys, das ist noch der Anfangszeit geschuldet.
War damals, und stellenweise auch heute, für mich einfacher und verständlicher.



Über eure Meinung, Kritik oder euer Wissen würde ich mich freuen.

Freundliche Grüße, Karsten


betateilchen

Oh mein Gott... geht es nicht noch komplizierter?

Meine Partnerin arbeitet im Schichtdienst im Krankenhaus, da gibt es noch ein paar mehr Zustände, nach denen sich in ihrer Wohnung die Heizung richten soll.
Gelöst habe ich das Ganze mit 1 Kalender + 1 at + 1 Funktion in der 99_myUtils.pm


  • jeden Tag um 00:01 Uhr wird die Funktion in der 99_myUtils.pm gestartet.
  • 1. die Funktion liest den Kalender aus und findet darin den für den Tag gültigen Dienst (oder sonstigen Status wie "frei" "Freizeitausgleich" "Urlaub" "verreist"
  • 2. anhand des gefundenen Ergebnisses werden aus einer in der Funktion definierten Wertetabelle die benötigten Ein- und Ausschaltzeiten für bestimmte Aktoren (z.B. Heizungsregler) gelesen.
  • 3. mit diesen Ein- und Ausschaltzeiten werden automatisch die benötigten at für diesen Tag angelegt, mit denen dann die Aktoren gesteuert werden.

Beispiel: Für den Frühdienst ist in der Wertetabelle festgelegt, dass


  • die Heizung im Bad von 04:00 - 05:30 Uhr laufen soll
  • die Heizung im Bad von 18:00 - 21:00 Uhr laufen soll
  • die Heizung im Wohnzimmer von 14:00 - 21:00 laufen soll
  • die Schaltsteckdose für die Kaffeemaschine wird um 05:30 Uhr zwangsweise ausgeschaltet, (für den Fall, dass die Maschine angeschaltet und das Ausschalten vergessen wurde.)
  • die Schaltsteckdose für die Kaffeemaschine wird um 22:00 Uhr zwangsweise ausgeschaltet.

Im Beispiel werden also 8 einmalig auszuführende at devices automatisch generiert. Funktioniert seit Jahren völlig problemlos.

Einzige Annahme: Der zugeteilte Dienst ändert sich ab 00:01 des jeweiligen Tages nicht mehr.
Sollte dies doch einmal der Fall sein, ließe sich die "Neuprogrammierung" für den Tag durch manuellen Aufruf der Funktion erneut vornehmen. Kam aber bisher noch nicht vor.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

hydrotec

#2
Hallo betateilchen,

Danke für deine Rückmeldung, wie du es gelöst hast.

Der feine Unterschied ist wohl der.
Zitat von: betateilchen am 21 Oktober 2020, 17:20:52
Einzige Annahme: Der zugeteilte Dienst ändert sich ab 00:01 des jeweiligen Tages nicht mehr.
Sollte dies doch einmal der Fall sein, ließe sich die "Neuprogrammierung" für den Tag durch manuellen Aufruf der Funktion erneut vornehmen. Kam aber bisher noch nicht vor.
Bei mir kann es durchaus häufiger vorkommen, das morgige Termine an einem heutigen Tag getauscht werden.
Dann wird der dementsprechende Zeitplan für heute automatisch angewählt.

Gruß Karsten