IOT Daten am Webserver empfangen (3/4)

Im dritten Teil dieser Serie siehst du, wie man Daten von einem IOT Client (ein ESP8266/ESP32 aber auch ein Arduino UNO) auf einem Webserver empfangen und speichern kann.

Allgemeines

Wir gehen hier vom Beispiel aus, dass ein Weblient auf Basis eines ESP8266 periodisch Daten an einen Webserver sendet. Konkret werden wir folgende Daten erhalten:

  • board ... eine eindeutige ID vom IOT Device
  • uptime ... die aktuelle Laufzeit in Sekunden
  • adc ... den Messwert an einem Analogeingang
  • pin1 ... den Status an einem Pin
  • pin2 ... und den Status von einem weiteren Pin.

Ein Beispiel Sketch für den ESP8266 findest du im ersten Teil dieses Tutorials.

Im ersten Schritt soll der Webserver lediglich die Daten übernehmen und an ein CSV File anfügen. In zwei Exkursen stellen wir eine HTML Seite und einen Download-Bereich für das geschrieben CSV File zur Verfügung.

Vorraussetzung ist ein Webserver mit PHP. Dieser kann bei einem Webhoster im Internet stehen - oder du richtest dir in deinem lokalen Netz einen Webserver mit PHP ein. Eine Kurzanleitung für eine Synology NAS gibt es im vierten Teil des Tutorials.

Exkurs: Unterschied GET vs POST

Technisch kann ein Webclient Daten als Parameter an den URI anhängen oder im Message Body übermitteln. Kurz zum Unterschied:

Bei GET werden Parameter nach einem ? direkt nach dem aufzurufenden URI angehängt (und das sieht auch der Anwender in seinem Browser-Adressfeld)

Der HTTP Request beginnt beispielsweise mit

GET /form.php?variable=1&nochein=Text HTTP/1.1
HOST: 172.18.67.80
Content-Length: 42

<!doctype html>
<html>

Bei POST werden die übermittelten Daten im HTTP Body übertragen. Der HTTP Header ist vom HTTP Body durch eine Leerzeile getrennt.

POST /form.php HTTP/1.1
HOST: 172.18.67.80
Content-Type: application/x-www-form-urlencoded
Content-Length: 24

variable=1&nochein=Text

Der Aufbau der Variablen/Werte Paare ist gleich

Variable = Wert

Als Trenner zwischen den Variablen-Wert Päarchen wird in beiden Fällen ein & verwendet.

Aufbau der PHP Dateien

Ich kann hier keinen "PHP in 5 Minuten Kurs geben", aber im Internet findet man zahlreiche Tutorials. selfphp.de wäre deutschsprachig und meine Empfehlung für den Ersteinstieg. Jetzt wäre es an der Zeit, dass du in den Links am Ende dieser Seite das ZIP mit den Webserver-Dateien runterlädst und auf deinem Webserver in ein Verzeichnis "iot" entpackst.

Meine PHP Scripte sind in der Regel aufgeteilt in mehrere Dateien

  • Model
  • View
  • Controller

Für den Einstieg in das Konzept von "Model View Controller" liest du am besten in der Wikipedia nach (Link am Ende der Seite). Kurz zusammengefasst: Im Model steckt die ganze Logik was mit den Daten passieren soll, der View kümmert sich um eventuelle Ausgaben und der Controller kümmert sich um den Ablauf und bildet die Klammer um alle notwendigen Komponenten. 

Um einen Eintrag zu übernehmen benötigst du zunächst folgende Dateien:

  • entry.php   (der Controller)
  • entry_m.php (das Model)
  • entry_v.php (der View)
  • config.inc.php (globale Variablen und diverse zentrale Parameter)

Die Datei config.inc.php ist hinzugekommen, um Variablen und Parameter zentral für alle Scripte zur Verfügung zu stellen.

Der Eingangspunkt entry.php (Controller)

Die entry.php stellt den Einstieg für deine IOT Devices dar. Ein IOT Device sendet somit an das Script entry.php die Daten. Der Controller entry.php liest die übermittelten Parameter aus.

Grundsätzlich empfiehlt sich für die Datenübermittlung die POST Methode und daher solltest du den Client mittels POST senden lassen. Zu Testzwecke erlauben wir im PHP Script auch die Datenübermittlung mittels GET (also dem anhängen der Daten an den URI). Damit kannst du durch die einfache Eingabe im Adressfeld deines Browsers eine Datenübermittlung anstoßen. Daher lesen wir die GEFILTERTEN Parameter zusammen:

if(filter_input_array(INPUT_POST)) 
  $parameters = filter_input_array(INPUT_POST);
if(filter_input_array(INPUT_GET)) 
  $parameters = array_merge($parameters, filter_input_array(INPUT_GET));

In den nächsten Zeilen übernimmst du dann die einzelnen Parameter in separate Variablen:

if(isset($parameters['board']))  {$board = $parameters['board']; $valid++;}
if(isset($parameters['adc']))    {$adc1 = $parameters['adc']; $valid++;}
if(isset($parameters['pin1']))   {$pin1 = $parameters['pin1']; $valid++;}
if(isset($parameters['pin2']))   {$pin2 = $parameters['pin2']; $valid++;}
if(isset($parameters['uptime'])) {$uptime = $parameters['uptime']; $valid++;}

Mit

require_once("entry_m.php"); // include the model / business logic

übergibt der Controller an das Business Modell und am Ende ruft der Controller noch den View auf

require_once("entry_v.php"); // include the view

Die Business Logik entry_m.php (Model)

Das Model entry_m.php kümmert sich um das Speichern der Daten. Anfänglich speichern wir die Daten in einem flachen CSV File. Jeder neue Eintrag wird am Ende der Datei hinzugefügt. Dazu wird die Datei mit "a+" Parameter geöffnet. a für append, + damit die Datei erstellt wird, sollte sie noch nicht existieren:

$handle = fopen($filepath."/".$filename[$board],"a+"); // open file for appending. If not exists - create new file

Sollte das öffnen der Datei fehlschlagen befüllt das Script die Variable $result die du später ausgeben kannst.

Wenn du nicht an den historischen Werten interessiert bist sondern nur den letzten aktuellen Wert speichern möchtest, dann öffne die Datei im Schreibemodus:

$handle = fopen($filepath."/".$filename[$board],"w+"); // open file for write. If not exists - create new file

Die Ausgabe entry_v.php (View)

Das entry_v.php kümmert sich nur um die Ausgabe des Ergebnisses. Du kannst dieses Ergebnis auf deinem IOT Device auswerten und beispielsweise weitere Aktion abhängig vom Rückgabewert des Webservers auslösen.

Die Include Datei config.inc.php

In der config.inc.php gibt es drei zentrale Variablen:

Zunächst definierst du den Pfad zu den CSV Dateien:

$filepath = "data"; // where are your datafiles stored

Bitte beachte: das Script benötigt Schreibeberechtigungen für das angegebene Unterverzeichnis!

Anschließend die Definition, welches Board in welche CSV Datei schreiben soll

$filename[0] = "board0.csv"; // filename for 

Du kannst auch mehrere Filenamen für weitere IOT Boads anlegen.

Und schließlich benötigst du auch noch ein Trennzeichen mit dem die Werte in der CSV Datei getrennt werden sollen:

$delimiter = ","; // delimiter for the csv file

Diese Variablen werden in eine separate Datei ausgelagert, weil wir diese später auch in anderen Scripte benötigen werden und mit dieser Include Datei haben wir alle zentralen Parameter an einer zentralen Stelle.

Testen der PHP Scripte

Da du im entry.php auch die Übernahme von GET Parametern zugelassen hast, kannst du den Eintrag direkt im Browser testen. Rufe dazu im Browser das PHP Script mit Angabe der Parameter auf:

http://{ip deines Servers}/iot/entry.php?board=0&uptime=42&adc=1&pin1=1&pin2=2

Wenn das alles klappt wird der Eintrag in die Datei board0.csv eingetragen und du erhältst als Rückmeldung ein

OK; valid=5

Bei falschen Filenamen erhältst du vermutlich eine entsprechende Fehlermeldung. Auch fehlende Schreibeberechtigungen werden zu Fehlern führen.

Die Daten werden nun in die Datei data/board0.csv geschrieben - genauer: sie werden an das Ende der Datei angehängt.

Wenn im Browser alles geklappt hat, kannst du einen Microcontroller programmieren und diesen die Daten an den Webserver senden lassen. Auch hier erleichtert die Rückmeldung vom Webserver eventuelle Programmierfehler schneller zu finden.

Exkurs: Ausgabe der Daten  auf einer HTML Seite

Da die Daten nun in einer CSV datei vorliegen, kannst du diese auch mit einem PHP Script auslesen. Als Beispiel dient eine einfache Seite (display.php) die die letzt gültigen Werte ausgibt.

Der Controller display.php

Der Controller (display.php) bindet die zentralen Parameter aus der config.inc.php ein und erwartet einen Parameter board damit du festlegen kannst, welches Board ausgegeben werden soll. Wird kein Parameter übergeben, defaultet das Board auf 0.

if(filter_input_array(INPUT_GET)) 
$parameters = filter_input_array(INPUT_GET);

if(isset($parameters['board'])) $board = $parameters['board']; else $board = 0; 

anschließend wird das Model und der View eingebunden.

Das Model display_m.php

Das Model liest zeilenweise die Datei bis ans Ende der Datei. Somit steht in der Variable $last_line die letzte Zeile - was somit der aktuellste Eintrag ist. Mit explode wird die Zeile in ein Array data zerlegt.

Der View display_v.php

Die eigentliche HTML Ausgabe wird durch den View display_v.php erledigt. Im HTML Header wird ein Stylesheet eingebunden und anschließend erfolgt die Ausgabe der Daten bzw. eine eventuell weitergereichte Fehlermeldung.

echo " <h2>Last Data from Board $board </h2>\n";
echo " <ul>\n";
echo " <li>Last entry: <span class='value'>".$data[0]."</span></li>\n";
echo " <li>uptime: <span class='value'>".$data[1]."</span></li>\n";
echo " <li>adc1: <span class='value'>".$data[2]."</span></li>\n";
echo " <li>pin1: <span class='value'>".$data[3]."</span></li>\n";
echo " <li>pin2: <span class='value'>".$data[4]."</span></li>\n";
echo " <li>stored entries: <span class='value'>".$entries."</span></li>\n";
echo " </ul>\n";

Das Stylesheet format.css

Das Stylesheet format.css ist nicht zwingend notwendig, aber es frischt die HTML Ausgabe optisch etwas auf.

 

Exkurs: Ein Frontend für den Dateidownload list.php

Wenn du einen gehosteten Webserver verwendest hast du möglicherweise nur mit FTP Zugriff auf deine Datenfiles. Für den Dateidownload mittels Browser kannst du auch eine einfache Seite erstellen.

Die list.php liest die globalen Variablen aus der config.inc.php aus und ruft Model und View auf.

Das Model list_m.php liest den Inhalt des Datenverzeichnisses in ein Array ein (und wirft dabei die Verzeichnisse . und .. weg).

Der View list_v.php erstellt das eigentliche HTML Dokument mit der Auflistung aller Files aus dem Datenverzeichnis und stellt Hyperlinks zu den Dateien zum Download zur Verfügung.

Zusammenfassung

Das Übernehmen von Daten und Speichern mit einem Webserver gelingt mit einiger Übung ganz leicht. Natürlich kannst du statt dem Speichern in eine CSV Datei auch in eine Datenbank schreiben lassen. Dazu musst du nur das Modell entry_m.php austauschen und die Dateizugriffe durch Datenbank-Zugriffe ersetzen. Ebenso verändern musst du das display_m.php und das list_m.php. Es gibt ja nach dem Umbau keine CSV Dateien mehr, sondern die Daten müssen aus der Datenbank gelesen werden.

Da du nun die Daten auf einem Webserver hast, kannst du die Daten auch in ansehnlicher Form in deinem eigenen "Dashboard" anzeigen lassen. Es stehen dir nun alle Möglichkeiten der zentralen Ansicht deiner IOT Daten zur Verfügung.

Das übersteigt nun aber den Umfang eines Einsteiger Tutorials.

Links

Protokoll

First upload: 2020-09-26 | Version: 2021-12-05