AdSense

Sonntag, 30. August 2020

Home Automation mit Raspberry PI und ESP8266, Teil 1: Die Grundlagen (Raspberry PI)

(English version) Heute möchte ich anfangen, mein Smart Home System zu präsentieren. Ich habe damit Anfang des Jahres angefangen und inzwischen ist es ziemlich groß gewachsen. Aktuell besteht das System aus:

  • 6 Temperatur- und Luftfeuchte-Sensoren innen
  • 3 Temperatur- und Luftfeuchte-Sensoren außen
  • 2 Temperatur- und Luftfeuchte-Sensoren in unseren zwei Terrarien
  • 1 CO2-Sensor
  • 5 schaltbaren Steckdosen
  • 3 schaltbaren Lampen
  • 1 Umschalter für die Eingänge vom Soundsystem
  • Sensoren an Waschmaschine und Trockner
  • Mikrofon und zwei Kameras am 3D-Drucker
  • Dashboard als Website an einem alten Tablet bzw. auf dem Smartphone
  • Telegram-Bot mit automatischen Benachrichtigungen und Kommandos

Die Grundlage für alles ist ein Raspberry PI 4, welcher als Server im WLAN fungiert. Hier werden alle Daten gespeichert, die Website liegt hier und alle Sensoren kommunizieren mit ihm. Auf dem Raspberry PI muss eigentlich nicht viel eingerichtet werden, ich habe den Apache2 Webserver installiert, hier findet man zahllose Tutorials, im Endeffekt ist es aber nur der folgende Befehl:

sudo apt install apache2

Außerdem habe ich den Apache2 für Php installiert, auch dazu gibt es viele Tutorials, der Befehl hierfür wäre:

sudo apt-get install php libapache2-mod-php

Das sind nun eigentlich schon alle Sachen die auf dem Raspberry PI eingerichtet werden müssen. Es empfiehlt sich aber, den Ordner /var/www/html/ als Share freizugeben, dann kann man auch von einem anderen Computer im Netzwerk auf alle Daten und Skripte zugreifen. Außerdem habe ich noch den Ordner /var/www/html/data/ angelegt, hier werden alle gespeicherten Daten abgelegt.

Damit ist schon alles eingerichtet und es kann mit den ersten Skripten losgehen. Hier möchte ich nur das grundlegende Skript zum Senden von Daten posten, alle weitere Modifikationen und Skripte werde ich dann bei den jeweiligen Posts präsentieren. Zum Senden von Daten nutze ich die Datei "SendValues.php", welche über GET-Parameter die folgenden Daten vom Sensor erwartet:

  • "name", also der Name des Sensors, z.B. "Temperatursensor_1"
  • "split", wie die Daten in verschiedenen Dateien aufgesplittet werden. Die Idee ist hier, wenn Sensoren über Jahre hinweg laufen, dass die hier nicht riesige Dateien entstehen, die man dann gar nicht mehr öffnen kann, sondern man z.B. für jeden Monat oder jedes Jahr eine eigene Datei hat. Split 0 bedeutet kein Aufsplitten, 1 bedeutet eine Datei pro Jahr, 2 eine Datei pro Monat und 3 eine Datei pro Tag
  • "data", die eigentlichen Daten, per Komma getrennt. z.B. für einen Temperatur- und Luftfeuchte-Sensor: 24.1,54.6

Das Skript besteht nun aus folgenden Teilen. Zuerst der Header:

<html>
 <head>
  <title>Send Sensor Values</title>
 </head>
 <body>
  <?php 

Danach beginnt der eigentliche Code. Hier werden die Daten gelesen und das aktuelle Datum bestimmt:

$name = htmlspecialchars($_GET["name"]);
$split = htmlspecialchars($_GET["split"]);
$data = htmlspecialchars($_GET["data"]);

$date = gmdate("Y-m-d") . "T" . gmdate("H:i:s.u") . "Z";

Als nächstes wird eine [name]_last.csv-Datei erstellt, welche den aktuellsten Wert hat:

$file = "data/".$name."_last.csv";
$Saved_File = fopen($file, 'w');
fwrite($Saved_File, $date . "," . $data . "\r\n");
fclose($Saved_File);

Als nächstes wird nun das Splitten gemacht. Dazu wird der Dateiname erstellt, [name]_[Jahr]-[Monat]-[Tag].csv. Da ich einen Überlapp zwischen den verschiedenen Dateien haben will erstellt er auch gleich die nächste Datei, also für nächstes Jahr, nächsten Monat, nächsten Tag, und schreibt hier auch den Wert rein, das sorgt dafür, dass wenn ich mir das letzte Jahr plotten möchte, ich nicht nur Werte bis zum 1.1. habe, sondern auch von dem Jahr davor, sodass der Zeitraum von einem Jahr auf jeden Fall in der Datei enthalten ist. $file1 ist die aktelle Datei, $file2 die für den nächsten Zeitraum.

$file = "data/".$name.".csv";

if ($split == "1")
{
  $file = "data/".$name."_" . gmdate("Y") . ".csv";
  $file2 = "data/".$name."_" . gmdate("Y", strtotime("+1 year")) . ".csv";
}
if ($split == "2")
{
  $file = "data/".$name."_" . gmdate("Y-m") . ".csv";
  $file2 = "data/".$name."_" . gmdate("Y-m", strtotime("+1 month")) . ".csv";
}
if ($split == "3")
{
  $file = "data/".$name."_" . gmdate("Y-m-d") . ".csv";
  $file2 = "data/".$name."_" . gmdate("Y-m-d", strtotime("+1 day")) . ".csv";
}

Anschließend wird das nun in die Dateien gespeichert. Falls "split" 0 ist, wird auf das Speichern in die zweite Datei verzichtet, da es ja für den gesamten Zeitraum nur eine Datei gibt.

$Saved_File = fopen($file, 'a');
fwrite($Saved_File, $date . "," . $data . "\r\n");
fclose($Saved_File);
if ($split == "0")
{
}
else
{
  $Saved_File = fopen($file2, 'a');
  fwrite($Saved_File, $date . "," . $data . "\r\n");
  fclose($Saved_File);
}

Und das war auch schon der Code, man muss jetzt noch die ganzen Tags wieder zu machen, und schon ist SendValues.php fertig:

  ?>
 </body>
</html>

Das ist nun eigentlich schon alles, was man auf der Server-Seite benötigt, als nächstes können die Sensoren ihre Werte senden. Zum Ausprobieren kann man das auch über den Browser im Heimnetz testen, dabei sollten die Dateien Temperatursensor_1_last.csv, und noch zwei weitere Dateien mit dem aktuellen und dem kommenden Jahr als Endung erstellt werden:

http://raspberrypi/SendValues.php?name=Temperatursensor_1&split=1&data=25.3,64.59

Für alle, die sich das nicht einzeln kopieren möchten hier nochmal der gesamte Quellcode:

<html>
 <head>
  <title>Send Sensor Values</title>
 </head>
 <body>
  <?php
 
$name = htmlspecialchars($_GET["name"]);
$split = htmlspecialchars($_GET["split"]);
$data = htmlspecialchars($_GET["data"]);

$date = gmdate("Y-m-d") . "T" . gmdate("H:i:s.u") . "Z";

$file = "data/".$name."_last.csv";
$Saved_File = fopen($file, 'w');
fwrite($Saved_File, $date . "," . $data . "\r\n");
fclose($Saved_File);

$file = "data/".$name.".csv";

if ($split == "1")
{
  $file = "data/".$name."_" . gmdate("Y") . ".csv";
  $file2 = "data/".$name."_" . gmdate("Y", strtotime("+1 year")) . ".csv";
}
if ($split == "2")
{
  $file = "data/".$name."_" . gmdate("Y-m") . ".csv";
  $file2 = "data/".$name."_" . gmdate("Y-m", strtotime("+1 month")) . ".csv";
}
if ($split == "3")
{
  $file = "data/".$name."_" . gmdate("Y-m-d") . ".csv";
  $file2 = "data/".$name."_" . gmdate("Y-m-d", strtotime("+1 day")) . ".csv";
}
$Saved_File = fopen($file, 'a');
fwrite($Saved_File, $date . "," . $data . "\r\n");
fclose($Saved_File);
if ($split == "0")
{
}
else
{
  $Saved_File = fopen($file2, 'a');
  fwrite($Saved_File, $date . "," . $data . "\r\n");
  fclose($Saved_File);
}

  ?>
 </body>
</html>

Keine Kommentare:

Kommentar veröffentlichen