Hausautomatisierung

Über Google Kalender Ereignisse schalten

Einbindung des eigenen Google Kalender

In Zeiten des Smartphones nutzen auch sehr viele die integrierte Terminverwaltung. Hierzu gibt es mehrere Varianten, die Termine zu pflegen.  Sobald man nicht nur das Smartphone zur Terminverwaltung nutzt, sondern noch ein Tablet oder einen PC, so macht es Sinn, die Termine zentral zu verwalten. Hierzu nutze ich den Google Kalender, da die Einbindung in beinahe alle Applikationen problemlos möglich ist.

In Verbindung mit der Haussteuerung FHEM ist es ein Leichtes, den Google Kalender einzubinden.

Was ist das Ziel?

Über die Einbindung des Google Kalender wollen wir in FHEM eine oder mehrere Dummyvariablen setzen. Beispielsweise wollen wir eine Variable für „Urlaub“ setzen. Aufgrund eines Termineintrags im Google Kalender geht die Variable Urlaub_dummy von nein auf ja. Nun könnte man aufgrund der Änderung dieser Variable verschiedene Aktionen auslösen. Dementsprechend könnten wir im Winter die Heizkörper im Hobbyraum für diesen Tag einschalten oder die Medienzentrale im Wohnzimmer schon am Vormittag einschalten anstatt abends.

Hard-und Software-Voraussetzungen

Zuerst brauchen wir einen Raspberry Pi mit entsprechendem Netzteil. Hierzu habe ich auch entsprechende Empfehlungen gegeben.
Genauso sollte man sich über die Vernetzung Gedanken machen, ob man die Raspberry Pis per Netzkabel oder per WLAN anbinden möchte. Dafür habe ich hier in meinen Artikeln über die Grundkonfiguration Tipps gegeben:

Einrichtung des Google Kalenders

Wir wollen unseren Google Kalender in FHEM integrieren. Oftmals ist es aber sinnvoll einen zweiten Google Kalender zu benutzen, um die Termine für die Haussteuerung von normalen Terminen zu unterscheiden. Das ist wirklich ganz einfach:

Google Anmeldung

Man meldet sich bei Google über sein Profil an. Falls noch nicht vorhanden, erstellt man ein eigenes Profil. Anschließend ruft man den Online-Kalender auf. Dort erstellen wir einen eigenen Kalender namens „Haussteuerung„.

In vielen Beschreibungen der Einbindung wird empfohlen, den Kalender einfach öffentlich zu machen, damit die Haussteuerung auch darauf problemlos zugreifen kann. Das mag ja einfach sein, aber „öffentlich“ heißt nunmal, dass auch jeder diesen Kalender lesen könnte. Deswegen nie das Häkchen setzen bei „Diesen Kalender öffentlich machen„:

Google Kalender öffentlich

Nun drücken wir noch auf „Kalender erstellen“ und haben hiermit den Kalender angelegt. Wir müssen uns jetzt noch die Kalender-ID besorgen. Diese finden wir bei den Details unter „Privatadresse“.

Google Kalender Privatadresse

Drücken wir auf den grünen „ICAL„-Button, öffnet sich ein Fenster mit der URL, die wir uns in den Zwischenspeicher kopieren sollten.

Einbinden des Google Kalenders in FHEM

Im Folgenden müssen wir mit ein paar wenigen Einträgen in der Konfigurationsdatei fhem.cfg den gerade erzeugen Kalender einbinden. Das funktioniert mit zwei Zeilen Code:

define Kalender_Haussteuerung Calendar ical url link-aus-zwischenspeicher 14400
attr Kalender_Haussteuerung room Kalender

Google Kalender Integration FHEM

In dem Beispiel müssen wir nur noch die https-URL mit der eben kopierten für link-aus-zwischenspeicher ersetzen und den Wert von 14400 stehen lassen. Dieser Wert sorgt dafür, dass der Kalender alle 4 h (= 14400 Sekunden) eingelesen wird.

Testen durch einen Google Kalender Eintrag

Als Erstes probieren wir die Integration unseres Haussteuerungs-Kalenders mit einem Test-Termin aus. Nun sollten wir den neuen Kalender schon in unserem Smartphone sehen.

Wir tragen entweder direkt auf der Google-Kalender-Seite oder am Smartphone einen Testtermin in unserem Haussteuerungskalender ein. Da wir die Prüfung nur alle 4h machen, zwingen wir FHEM zu einem erneuten Laden unseres Kalender. Dazu klicken wir auf der FHEM-Webseite auf unsere neue Rubrik Kalender und dann auf Kalender_Haussteuerung.

FHEM Kalender reload

Dort drücken wir für set Kalender_Haussteuerung reload auf den Set-Button. Anschließend sollte sich in den Readings unterhalb des Kalenders etwas tun:

FHEM Kalender Readings

Infolge des Kalendereintrags und des Neuladens des Kalenders sind vercodete Einträge in den Readings entstanden. Das zeigt uns, dass die Integration funktioniert.

Weiters löschen wir den Testeintrag wieder und erstellen nun einen Eintrag namens „Urlaub„. Wichtig ist, dass der Termin nicht als Ganztageseintrag erstellt wir, sondern ein definiertes Beginn- und Endedatum haben muss. Also z.B. 07:00 Uhr bis 19:00 Uhr.

Dummyvariablen erzeugen

Damit wir hier auf die Kalendereinträge reagieren können, brauchen wir mindestens eine Dummyvariable. In unserem Beispiel wollen wir auf den Kalendertext „Urlaub“ checken. Dementsprechend legen wir eine Variable Urlaub_dummy an:

define Urlaub_dummy dummy
attr Urlaub_dummy alias Urlaubstag
attr Urlaub_dummy devStateIcon ja:rc_dot@green nein:rc_dot@grey
attr Urlaub_dummy icon weather_summer
attr Urlaub_dummy room Kalender
attr Urlaub_dummy setList ja nein
attr Urlaub_dummy webCmd ja:nein

Durch diesen Eintrag können wir später entscheiden, ob ein Urlaubstag ist (=ja) oder nicht (=nein)

Hilfsfunktionen

Damit das Schalten der Dummyvariable nun über den Eintrag in den Online-Kalender funktioniert, brauchen wir zwei Hilfsfunktionen. Zum Einen müssen wir feststellen, ob das Ereignis aufgrund des Kalendertexts für unsere Dummyvariable relevant ist oder nicht. Zum Anderen gibt es prinzipiell drei Events, die in FHEM überwacht werden müssen: Der Start, das Ende und das Löschen eines Termins. Zunächst kümmern wir uns um die benötigten Funktionen.

Hierzu erstellen wir ein neues Include, das wir im Verzeichnis /opt/fhem/FHEM erstellen. Dementsprechend kopieren wir uns den unten aufgelisteten Code in eine leere Datei namens 99_GoogleCalendarUtils.pm. Hierfür können wir den kleinen Editor nano benutzen und die neue Datei mit

cd /opt/fhem/FHEM
nano 99_GoogleCalendarUtils.pm

erstellen. Weiters kopieren wir den unten stehenden Code in den geöffneten Editor und speichern ihn mit STRG+O ab. Schließlich beenden wir den Editor mit STRG+X.
Im Anschluß der Code:

##############################################
# $Id: 99_GoogleCalendarUtils.pm 2691 2016-12-31 martin koch $
package main;

use strict;
use warnings;
use Digest::MD5 "md5_hex";
use HttpUtils;

sub
GoogleCalendarUtils_Initialize($$)
{
  my ($hash) = @_;
}


sub
Kalenderstart ($)
{
  my ($Ereignis) = @_;
        my @Ereignisarray = ();
        my $Ereignisteil1 = "";
        my @uids = ();

        @Ereignisarray = split(/.*:\s/,$Ereignis);
        if($#Ereignisarray > 0)
        {
          $Ereignisteil1 = $Ereignisarray[1];
          @uids=split(/;/,$Ereignisteil1);
          Log 3,"Termin fängt an";
    foreach my $uid (@uids) {
    my $Kalendertext = fhem("get Kalender_Haussteuerung summary $uid");
                Log 3,"uid = $uid, Text = $Kalendertext";
    if ($Kalendertext =~ /Urlaub/) {
      fhem("set Urlaub_dummy ja");
                        Log 3,"Urlaub found";
    }
  }
  }
}
sub Kalenderende ($) {
  my ($Ereignis) = @_;
        my @Ereignisarray = ();
        my $Ereignisteil1 = "";
        my @uids = ();
        
        @Ereignisarray = split(/.*:\s/,$Ereignis);
        if($#Ereignisarray > 0)
        {
          $Ereignisteil1 = $Ereignisarray[1];
          @uids=split(/;/,$Ereignisteil1);
          Log 3,"Termin wurde beendet oder gelöscht";
 	  foreach my $uid (@uids) {
    my $Kalendertext = fhem("get Kalender_Haussteuerung summary $uid");
    if ($Kalendertext =~ /Urlaub/) {
      fhem("set Urlaub_dummy nein");
    }
    }
   }
}

1;

Dummyvariablen schalten

Nun müssen wir nur noch in der Konfigurationsdatei fhem.cfg die Hilfsfunktionen bei Kalenderänderungen antriggern. Das geht ganz einfach mit folgenden drei Notify-Definitionen:

define Kalender_Haussteuerung_Start notify Kalender_Haussteuerung:modeStarted.* {\
   Kalenderstart("$EVENT");;\
}
define Kalender_Haussteuerung_Ende notify Kalender_Haussteuerung:modeEnded.* {\
   Kalenderende("$EVENT");;\
}
define Kalender_Haussteuerung_Loeschen notify Kalender_Haussteuerung:stateDeleted.* {\
   Kalenderende("$EVENT");;\
}

Diese drei Definitionen sorgen nun dafür, dass zu Beginn, Ablauf und Löschen eines Termins in unserem Google-Kalender Haussteuerung die gerade gezeigten Hilfsfunktionen aufgerufen werden. Passt dort der Kalendertext mit „Urlaub“ überein, so wird die Dummyvariable Urlaub_dummy auf „ja“ gesetzt. Sobald der Termin endet, wird die Variable auf „nein“ gesetzt.

Kalenderintegration für Urlaub final testen

Nachdem wir uns nun einen neuen Eintrag in unserem Google-Kalender „Haussteuerung“ unter dem Namen „Urlaub“ erstellt haben, zwingen wir unser FHEM zu einem Neuladen des Kalenders wie oben beschrieben. (set Kalender_Haussteuerung reload). Hierzu sollte der Termin in der Zukunft (für den Test reichen 5 Minuten) sein, da das Schalten sonst nicht ordnungsgemäß funktioniert.

Kalender Urlaub

Sobald nun der Termin beginnt, ruft FHEM die Hilfsmethoden auf und setzt die Variable „Urlaub_dummy“ auf „ja„.

Was sind die Grenzen?

Was nicht funktioniert ist, dass man beispielsweise einen Vorlauf vor einem solchen Termin einstellt. Da eine Heizung in der Regel einige Zeit braucht, um einen Raum aufzuwärmen, würden wir die Heizung gerne um eine Stunde früher einschalten als ein Termineintrag „Arbeit“ im Google Kalender aussagen würde. Leider triggert der Google Kalender exakt zum Beginn eines Termins „Arbeit“, so dass das mit diesem Modul nicht ohne weiteres möglich ist. Deswegen prüfe ich nicht nur nach einem Ereignis, sondern noch nach dem Termineintrag „Heizung“. Man benötigt zwar einen zusätzlichen Eintrag „Heizung“ im Kalender, diesen kann man aber immer wieder verschieben, auch aus der Vergangenheit. Man braucht ja den alten Termineintrag nicht mehr, also verschiebt man ihn dorthin, wo das Ereignis „Heizung“ den Dummy für die Heizung schalten soll.

Zuletzt aktualisiert am 24.09.2017.

6 Gedanken zu „Über Google Kalender Ereignisse schalten“

  1. Hallo,

    das Ganze funktioniert sehr gut.
    Ich möchte aber über einen Kalendereintrag „arbeiten“ die Heizung früher einschalten.
    Der Kalendereintrag „arbeiten“ beginnt um 06:00
    Mit Fahrtzeit usw. muss die Heizung dann z.B. um 4:30 angehen, damit im Bad eine angenehme Wärme herscht.
    –> D.h. der Dummy soll eine Zeit x vorher getriggert werden.
    Ist das irgendwie möglich?
    Ein zusätzlichger Eintrag in einem speziellen FHEM Kalender wäre natürlich eine einfache Lösung, aber wenig praktikabel.

    1. Hallo,

      das hätte ich auch gerne. Ich verstehe die Anforderung nur zu gut!
      Leider schaut das Google Kalender Modul nicht in die Zukunft bzw. liest zukünftige Kalendereinträge. Erst bei Beginn eines Kalendereintrags läuft ja der Trigger aufgrund dessen dann der Kalendereintrag gescannt und nach bestimmten Teilstrings durchsucht wird. Umgekehrt wäre es natürlich denkbar, das Ereignis einfach später zu schalten, indem ich den Dummy nicht sofort beschreibe, sondern über ein dynamisch erstelltes Ereignis, das dann wiederum den Dummy schaltet.
      Das hilft aber nichts in Richtung Vordatierung. Ein Dummy früher zu schalten als der Eintrag im Google Kalender ist, geht so nicht…
      Auch ich habe das über einen eigenen Eintrag im Kalender markiert. Ich scanne nicht nur nach „Arbeit“, sondern auch nach „Heizung“, sodass sowohl bei „Arbeit“ als auch bei „Heizung“ der selbe Dummy gesetzt wird.
      Diesen Dummy-Kalendereintrag verschiebe ich einfach am Smartphone aus der Vergangenheit, so dass ich den Eintrag nicht mehr erstellen muss. Dieser „Heizung“-Eintrag ist dann einfach um 1:30 h früher angesetzt als „Arbeiten“
      Technisch wird das mit dem Google Kalender Modul nicht viel einfacher funktionieren, man müsste stattdessen ein eigenes Modul bauen, und immer vorab über alle Kalendereinträge scannen. Somit könnte ein Ereignis rechtzeitig eingesteuert werden.

      Gruß
      Martin

  2. Hallo Martin,

    ich möchte gerne einen zweiten Dummy über den Kalender schalten.
    Dummy1= Kalendereintrag Urlaub
    Dummy2 = Kalendereintrag Heizung
    Ist dies möglich und welche Erweiterungen muss ich vornehmen?

    Gruß

    Thomas

    1. Hallo Thomas,

      das ist eigentlich ganz einfach. Es müssen nur die beiden sub-Methoden angepasst werden.
      Hier mein Vorschlag:

      ##############################################
      # $Id: 99_GoogleCalendarUtils.pm 2691 2016-12-31 martin koch $
      package main;

      use strict;
      use warnings;
      use Digest::MD5 "md5_hex";
      use HttpUtils;

      sub
      GoogleCalendarUtils_Initialize($$)
      {
      my ($hash) = @_;
      }

      sub
      Kalenderstart ($)
      {
      my ($Ereignis) = @_;
      my @Ereignisarray = ();
      my $Ereignisteil1 = "";
      my @uids = ();

      @Ereignisarray = split(/.*:\s/,$Ereignis);
      if($#Ereignisarray > 0)
      {
      $Ereignisteil1 = $Ereignisarray[1];
      @uids=split(/;/,$Ereignisteil1);
      Log 3,"Termin fängt an";
      foreach my $uid (@uids) {
      my $Kalendertext = fhem("get Kalender_Haussteuerung summary $uid");
      Log 3,"uid = $uid, Text = $Kalendertext";
      if ($Kalendertext =~ /Urlaub/) {
      fhem("set Dummy1 ja");
      Log 3,"Urlaub found";
      }
      if ($Kalendertext =~ /Heizung/) {
      fhem("set Dummy2 ja");
      Log 3,"Heizung found";
      }
      }
      }
      }
      sub Kalenderende ($) {
      my ($Ereignis) = @_;
      my @Ereignisarray = ();
      my $Ereignisteil1 = "";
      my @uids = ();

      @Ereignisarray = split(/.*:\s/,$Ereignis);
      if($#Ereignisarray > 0)
      {
      $Ereignisteil1 = $Ereignisarray[1];
      @uids=split(/;/,$Ereignisteil1);
      Log 3,"Termin wurde beendet oder gelöscht";
      foreach my $uid (@uids) {
      my $Kalendertext = fhem("get Kalender_Haussteuerung summary $uid");
      if ($Kalendertext =~ /Urlaub/) {
      fhem("set Dummy1 nein");
      }
      if ($Kalendertext =~ /Heizung/) {
      fhem("set Dummy2 nein");
      }
      }
      }
      }

      1;

  3. Hallo Martin,

    ich bin gerade dabei mich in die Kalender Funktionen zu informieren und zunächst einmal DANKE für deine sehr gute Erklärung.
    Kann man das Heizungsproblem nicht über die Benachrichtigungs-Funktion des Kalenders lösen? Beim Termin kann ich ja zB eine Benachrichtigung 2h vor dem Termin deklarieren.
    Was mich zu meiner eigentlichen (ähnlichen) Frage bringt:
    Viele erzeugen über den Termin Text eine Wettervorhersage, da bekomme Ich aber das Wetter für mein zu hause und nicht für den Ort des Termins. Im Termin gebe ich ja den Ort an, aber kann ich den auch explizit nutzen? Also fürs Wetter, Staus, Fahrtzeit, ….

    Best Regards
    Thomas

    1. Hallo Thomas,

      sorry, dass ich mich erst jetzt melde. Aber ich habe mich inzwischen eingehend mit dem Thema Benachrichtigung befasst. Die Benachrichtigungsfunktion ist eine Funktion der jeweiligen Applikation, nicht des Termins. Leider gibt das Calendar Plugin das nicht her bzw. gibt es dort kein Reading, über das ich mir Termine aus der Zukunft mit einem gewissen Vorlauf als zuteilungsreif deklarieren kann. Allerdings gibt es einen Zustand modeUpcoming, dieser bezieht sich aber leider nur auf das nächste einzutretende Ereignis des Kalenders, das bringt uns auch nicht viel näher ans Ziel. Mit viel Aufwand könnte man regelmässig dieses Reading checken, dann den Betreff des kommenden Termins auslesen und in Abhängigkeit davon vielleicht etwas auslösen. Das funktioniert aber dann nicht über die Standard-Funktionen des Calendar Plugins, das immer genau dann schaltet, wenn ein Termin startet.

      Den Ort kann man allerdings auslesen. Mit
      get Kalender_Martin summary $uid
      kann man ja den Betreff des Termins auslesen. Mit
      get Kalender_Martin location $uid
      dürfte man dann noch den Ort hinzulesen können. Somit ließe sich dieser für die Wettervorhersage zum Ort des Termins realisieren….

      Gruß
      Martin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert