Smarthome-Steuerung mit Mails

Smarthome-Steuerung mit Mails

Ein Smarthome bietet eine Menge Möglichkeiten. Heute kann fast alles in diesem Zusammenhang miteinander verbunden werden und dadurch mehr Bequemlichkeit, Wohnqualität, Kosteneinsparungen und Sicherheit ermöglichen. Möchte man von unterwegs über das Internet zugreifen, gibt es aber Gefahren.

Von der Beleuchtung über die Heizung und Kameraüberwachung bis zur Waschmaschine lässt sich heute alles mit einem Smarthome verbinden. Das ist bequem und wenn man sich daran gewöhnt hat, möchte man meistens einige Funktionen auch unterwegs mobil nutzen können.

Dafür es es aber erforderlich, das eigene System über das Internet erreichbar zu machen. Damit sind Sie aber auch von außen viel stärker angreifbar. Sie müssen sich regelmäßig mit Updates versorgen und Ihr System aktuell halten. Ein Restrisiko bleibt aber dennoch bestehen, auch wenn man mit einem Raspberry Pi unter Debian mit einem sehr sicheren System arbeitet.

Ich bin aus diesen Gründen momentan noch nicht bereit, mein System für das Internet zu öffnen. Trotzdem hätte ich gerne eine Möglichkeit, die Vorteile mobil zu nutzen.

Da aber der Smarthome-Rechner meist trotzdem mit dem Internet verbunden ist, warum nicht diese bestehenden Verbindung nutzen? Damit ist vielleicht nicht die schönste Lösung realisierbar, aber vielleicht erst einmal eine sichere.

Eine Mail-Steuerung

Ich möchte hier einen Lösungsvorschlag für so eine mögliche Zwischenstufe vorstellen: eine E-Mail-Steuerung.

Mail-Steuerung
Steuerung über E-Mails

Auf dem Rechner mit der Smarthome-Software läuft eine weitere Software, die in regelmäßigen Abständen ein bestimmtes Mail-Postfach auf Nachrichten überprüft. Wenn eine Nachricht bestimmte Kriterien erfüllt, werden von der Software Aktionen auf dem Smarthome-Rechner ausgeführt.

In meinem Fall ist das ein Raspberry Pi. Über einen Cron-Job wird regelmäßig alle 5 min mein Smarthome-Mail-Postfach auf neue Nachrichten abgefragt. Welches Intervall möglich ist, hängt aber vom jeweiligen Mail-Anbieter ab. Manche Anbieter lassen nicht alle Intervalle zu.

Um auch hier eine hohe Sicherheit zu gewährleisten, müssen mehrere Bedingungen erfüllt sein, bevor eine Aktion vom Programm ausgelöst wird. Welche das sind, ist in der folgenden Abbildung dargestellt.

Ablauf
Prüfungen im Programm “mailchecker”

Ein Beispiel für eine Mail könnte so aussehen:

Von: name@provider.de
An: smarthome@provider.de
Betreff: SH
Nachrichtentext:**STATUS
**LICHT_WZ_AUS

Nur wenn im Betreff SH steht, der Absender name@provider.de eine Berechtigung hat und gültige Befehle (**STATUS, **LICHT..) enthalten sind, nur dann werden Aktionen ausgeführt.

Beispiele für Befehle:

**STATUS  Könnte eine Mail an den Absender zurückschicken und in den Nachrichtentext interessante Zustände liefern, z. B. welche Türen sind offen, welche Lichter sind an usw.

**REBOOT  Führt einen Neustart des Raspberry Pi’s durch. Das ist zwar nicht oft erforderlich, aber machmal doch praktisch.

Es können aber auch Aktoren gesetzt werden, um z. B. ein Licht auszuschalten. Durch den Zeitversatz des Mailabrufs, ist das natürlich nicht für eine direkte Steuerung sinnvoll. Aber so könnte ein vergessenes Licht noch ausgeschaltet werden. In meinem Fall erfolgt das über dieses Kommando.

**LICHT_WZ_AUS  Schaltet z. B. das Licht im Wohnzimmer aus.

**…

Realisierung mit Lazarus und Freepascal

Das Abrufen der Nachrichten von der Mailbox erfolgt über das IMAP-Protokoll. Dafür sind mehrere Einstellungen, abhängig vom Mail-Provider, notwendig. Im Quellcode werden die Werte als Konstanten hinterlegt.

IMAP_HOST = 'imap.1und1.com';
IMAP_PORT = '993';
MAIL_USER = 'smarthome@ihreadresse.de';
MAIL_PASSWORD = 'geheim';

Lazarus stellt von Haus aus keine Funktionen zum Arbeiten mit Mails zur Verfügung. Es gibt aber eine sehr gute Bibliothek von Synapse von Ararat. Den Download-Link dazu finden Sie am Ende des Artikels. Entpacken Sie das Archiv in einen beliebigen Ordner und fügen den Ordner dem Projekt hinzu. Alternativ können Sie auch im Projektinspektor auf HINZUFÜGEN: DATEIEN AUS DEM DATEISYSTEM klicken und die Datei imapsend.pas im Synapse-Ordner auswählen.

Lib einfügen
Ordner der Synapse-Bibliothek in den Projekteinstellungen hinzufügen

Dafür ist die Arbeit mit der Bibliothek sehr einfach. Die Prüfung auf neuen Nachrichten und das Auslösen von Aktionen findet in einer einzigen Prozedur CheckMailbox statt.

procedure CheckMailbox;
var
  s, user : string;
  j, cnt ,spcnt : integer;
  mail : TStringList;
  Imap : TIMAPSend;
  MimeMess : TMimeMess;
  MimePart : TMimePart;
begin
  mail:=TStringList.Create;
  imap:=TIMAPSend.create;
  MimeMess:=TMimeMess.Create;

  //Einstellungen für IMAP
  Imap.TargetHost:=IMAP_HOST;
  Imap.TargetPort:=IMAP_PORT;
  Imap.UserName:=MAIL_USER;
  Imap.Password:=MAIL_PASSWORD;
  Imap.AutoTLS:=false;
  Imap.FullSSL:=false;

  if Imap.Login then
    begin
      //Gibt es neue ungelesene Nachrichten??
      cnt:=Imap.StatusFolder('INBOX','UNSEEN');
      if cnt>0 then
        begin
          Output('Es gibt '+IntToStr(cnt)+' neue Nachricht(en)');
          Imap.SelectFolder('INBOX'); //Ordner Inbox auswählen
          //neue Nachrichten einzeln durchlaufen
          for j:=Imap.SelectedCount-Imap.SelectedRecent+1 to Imap.SelectedCount do
            begin
              Imap.FetchMess(j,MimeMess.Lines); //Nachricht abholen
              MimeMess.DecodeMessage;
              Output('');
              Output('---');
              output('Prüfung: '+MimeMess.Header.Subject+' von '+MimeMess.Header.From);
              //Prüfen, ob eine Aktions-Mail vorliegt
              if (ValidUsers.IsValid(MimeMess.Header.From)=true)
                and (Uppercase(MimeMess.Header.Subject)=ACTION_SUBJECT) then
                begin
                  mail.Clear;
                  user:=MimeMess.Header.From;
                  spcnt:=MimeMess.MessagePart.GetSubPartCount();
                  Output('>>> Gültige Mail');
                  if spcnt>0 then
                    for cnt:=0 to {spcnt-1} 0 do
                      begin
                        MimePart:=MimeMess.MessagePart.GetSubPart(cnt);
                        MimePart.DecodePart;
                        mail.Add(MimePart.Primary);
                        mail.Add(MimePart.Secondary);
                        setlength(s,MimePart.DecodedLines.Size);
                        MimePart.DecodedLines.Read(s[1],length(s));
                        mail.Add(s);
                      end
                  else mail.AddStrings(MimeMess.MessagePart.Lines);
                  //output(mail.Text);
                  //Gibt es Aktionen??
                  //Welche Aktionen sollen ausgeführt werden??
                  if Pos('**STATUS',mail.Text)>0 then ActionStateMail(user);
                  if Pos('**LICHT_WZ_EIN',mail.Text)>0 then ActionRunScript('/home/pi/scripts/licht_wz_ein');
                  if Pos('**LICHT_WZ_AUS',mail.Text)>0 then ActionRunScript('/home/pi/scripts/licht_wz_aus');
                  if Pos('**REBOOT',mail.Text)>0 then ActionRunScript('/home/pi/scripts/reboot_pi');
                  if Pos('**HELP',mail.Text)>0 then ActionHelp(user);
                end;
            end;
        end else Output('Es gibt keine neuen Nachrichten!');
    end else Output('Login fehlgeschlagen!');
  MimeMess.Free;
  Imap.free;
  mail.Free;
end; 

 

Aktionen ausführen

Im letzten Teil der obigen Prozedur werden mögliche Aktionen definiert, die Sie ermöglichen möchten.

Hier gibt es nur Ihren Einfallsreichtum als Grenze. Im Quellcode habe ich zwei Grundfunktionen als Beispiel eingebaut.

a) Mail senden

Um eine Mail zu senden, wird eine weitere Prozedur SendToEx von Synape benutzt.

function SendMail(const MailTo, Subject : string; const MailData: TStrings) : boolean;
begin
  Result:=SendToEx(MAIL_USER, MailTo, Subject, SMTP_HOST, MailData,
  MAIL_USER, MAIL_PASSWORD);
end;

Die Konstanten MAIL_USER, MAIL_PASSWORD sind bereits bei der Mail-Abfrage definiert worden. Für das Senden eines Mails ist noch der SMTP-Host erforderlich.

Für den Anbieter 1und1 wäre das beispielsweise:

SMTP_HOST = 'smtp.1und1.com';

Ein Beispiel für die Anwendung könnte eine Status-Mail über interessante Zustände im Smarthome sein. In meinem Fall stehen die Statuswerte als Textfiles auf dem Raspberry Pi zur Verfügung. Diese Dateien werden eingelesen und in einen Text umgesetzt. Der gesamte Text wird in einer TStringList gespeichert und am Ende als Mail-Text versendet.

procedure ActionStateMail(user : string);
var
  mailtext,datei : TStringList;
  i : integer;
begin
  mailtext:=TStringList.Create;
  datei:=TStringList.Create;

  mailtext.Add('Status im Smarthome:');
  mailtext.Add('');

  datei.LoadFromFile('/var/www/status/garagentor.txt');
  if datei[0]='1' then mailtext.Add('Garagentor: GESCHLOSSEN')
  else mailtext.Add('Garagentor: OFFEN');

  datei.LoadFromFile('/var/www/status/garagentuer.txt');
  if datei[0]='1' then mailtext.Add('Garagentüre: GESCHLOSSEN')
  else mailtext.Add('Garagentüre: OFFEN');

  datei.LoadFromFile('/var/www/status/kaninchen.txt');
  if datei[0]='1' then mailtext.Add('Kaninchen: GEFÜTTERT')
  else mailtext.Add('Kaninchen: HUNGRIG');

  //Codierung anpassen auf Ansi
  for i:=0 to mailtext.Count-1 do
    mailtext[i]:=UTF8ToAnsi(mailtext[i]);

  //Mail verschicken
  SendMail(user,'Smarthome: Status',mailtext);
  Output('Befehl **STATUS ausgeführt.');

  mailtext.Free;
  datei.Free;
end;

b) Skripte/andere Programme ausführen

Unter Lazarus und Freepascal gibt eine Reihe von Möglichkeiten, wie andere Programme oder Skripte gestartet werden können.

Wenn man plattformübergreifend arbeiten möchte, eignet sich das Objekt TProcess recht gut.

procedure ActionRunScript(script : string);
var
  Process : TProcess;
begin
  Process:=TProcess.Create(nil);
  Process.CommandLine:=script;
  Process.Options:=Process.Options+[poWaitOnExit];
  Process.Execute;
  Process.Free;
  Output('Befehl '+script+' ausgeführt.');
end;

 

Beispiel-Projekt und Ausblick

Im Download-Bereich finden Sie ein Beispiel-Projekt für eine Konsolenanwendung. Sie basiert auf den oben beschriebenen Quelltexten. Sie können es sowohl unter Windows, wie auch unter Linux benutzen.

Für einen sinnvollen Einsatz müssen Sie es aber regelmäßig über Cron aufrufen.

Falls keine neue Mail im Postfach ist, sieht die Anwendung aus, wie in folgendem Bild dargestellt:

Beispiel
Beispiel für den Aufruf von MAILCHECKER: keine neue Nachricht im Postfach

Ein Beispiel dafür, dass eine neue Mail mit dem entsprechenden Schlüsselwort da ist, sieht wie in dieser Abbildung aus:

Beispiel
Beispiel für den Aufruf von MAILCHECKER: neue Nachricht im Postfach!

Passen Sie doch die Konstanten in mailcheck.pas auf Ihr Mail-Postfach an und entwickeln Sie das Projekt für Ihren Anwendungsfall weiter. Mit ein wenig HTML könnte eine Antwort-Mail mit einem Smarthome-Status beispielsweise eine schickere Optik bekommen.

Vielleicht finden Sie ja auch eine noch viel bessere Möglichkeit diese Steuerungsart zu nutzen.

Viel Erfolg!

Download

symbol_download


Beispiel-Projekt für Lazarus

Für die Kompilierung benötigen Sie die Library Synapse. Diese können Sie unter http://synapse.ararat.cz/doku.php/download finden. Haben Sie Lazarus noch nicht auf Ihrem Rechner installiert, schauen Sie sich am besten den Artikel Lazarus installieren an.

 

Links

Artikel von Michaël Van Canneyt zum Senden von Mails mit Lazarus
https://www.freepascal.org/~michael/articles/lazmail/lazmail-en.pdf

Wikipedia-Artikel zu IMAP
https://de.wikipedia.org/wiki/Internet_Message_Access_Protocol

Wiki von Lazarus über TProcess
http://wiki.freepascal.org/Executing_External_Programs/de

Wiki über Synapse
http://wiki.freepascal.org/Synapse

Wikipedia-Eintrag zu Cron
https://de.wikipedia.org/wiki/Cron

Installation von Lazarus / Freepascal


Click here to read this article in English.

Dieser Beitrag hat einen Kommentar

Kommentar verfassen

Menü schließen