Basierend auf das Tutorial WEMOS D1 – WLAN Thermometer mit DHT11 Sensor möchte ich nun die Daten in eine Datenbank speichern.
Dazu nutze ich eine MySQL Datenbank von „meinem“ Server.
Ziel
Ziel soll es nun sein den vorhandenen Sketch so umzuschreiben das die Webseite immer noch angezeigt wird, jedoch sollen die Daten in eine Datenbank geschrieben werden.
Schritt 1 – Erstellen der Datenbank
Als Erstes wird die Datenbank erzeugt. Da ich einen Webserver gemietet habe und auf diesem noch einige Datenbanken frei sind, kann ich mit folgendem Script eine Tabelle in einem aktuellen Schemata anlegen.
CREATE TABLE `data` ( `id` int(11) NOT NULL, `temp` double NOT NULL, `press` double NOT NULL, `timestamp` bigint(20) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Schritt 2 – PHP Schnittstelle zum Schreiben in die Datenbank
Wenn die Datenbank erzeugt wurde, muss eine Schnittstelle zur Datenbank geschaffen werden. Dazu benutze ich nun eine einfache PHP Datei welche über die URL als Parameter die Werte der Temperatur und den Luftdruck erhält.
Der Zeitstempel wird vom Server zusätzlich an den Datensatz gehängt.
<?php error_reporting(E_ALL); ini_set('display_errors', 1); if (empty($_GET) || (!isset($_GET['temp']) || !isset($_GET['press']))) { echo "<h1>Es wurden keine oder nicht alle Parameter übergeben!</h1><br/>"; echo "Mögliche Parameter sind:<br/>"; echo "<ul>"; echo "<li>temp - Temperatur</li>"; echo "<li>press - Luftdruck</li>"; echo "</ul><br/><br/>"; $sampleLink = "http://progs.draeger-it.blog/wemosd1/dht11db/upload.php?temp=12.4&press=54.5"; echo "zbsp.: <a href='$sampleLink'>$sampleLink</a>"; } else { echo "<h2>Folgende Parameter wurden empfangen:</h2>"; $tempValue = 0; $pressValue = 0; date_default_timezone_set('Europe/Berlin'); $milliseconds = round(microtime(true)); foreach ($_GET as $key => $value) { echo "Parameter: "; echo $key; echo "<br/>Wert:"; echo $value; echo "<br/><br/>"; if($key === 'temp'){ $tempValue = $value; } else if($key === 'press'){ $pressValue = $value; } } echo "Zeitstempel: "; echo date('d.m.Y H:i:s',$milliseconds); echo " (<i>automatisch</i>)"; echo "<br/>"; storeData($tempValue, $pressValue, $milliseconds); } function storeData($tempValue, $pressValue, $milliseconds){ $stmt = "INSERT INTO `data` "; $stmt .= "(`id`, `temp`, `press`, `timestamp`)"; $stmt .= " VALUES ("; $stmt .= "NULL"; $stmt .= ",'"; $stmt .= $tempValue; $stmt .= "',"; $stmt .= "'"; $stmt .= $pressValue; $stmt .= "',"; $stmt .= "'"; $stmt .= $milliseconds; $stmt .= "'"; $stmt .= ");"; fireSQLStmt($stmt); } function fireSQLStmt($sqlStmt){ $connection = getDBConnection(); $result = mysqli_query($connection,$sqlStmt); return $connection->error; } function getDBConnection(){ //Das bleibt Geheim! $dbname = ""; $dbusername = ""; $dbpassword = ""; $dburl=''; //Erzeugt einen Datenbanklink aus den Parametern (die Verbindungsdaten stehen in der Datei dbconfig.php) $link = mysqli_connect($dburl, $dbusername, $dbpassword,$dbname); if (!$link) { die('Verbindung schlug fehl: ' . mysqli_error()); } /* check connection */ if (mysqli_connect_errno()) { die($fehler1); } return $link; } ?>
Schritt 3 – Erweitern des Arduino Sketches
Der Arduino Sketch muss nun so erweitert werden das der Wemos D1 eine HTTP Verbindung zu einem Server aufnimmt.
In diesem Fall soll der Wemos D1 eine Anfrage (Request) an die Adresse
http://progs.draeger-it.blog/wemosd1/dht11db/upload.php?temp=22.00&press=44.00
aufnehmen.
#include <ESP8266WiFi.h> #include "DHT.h" const char* ssid = ""; //SSID aus dem Router const char* password = ""; //Passwort für den Zugang zum WLAN int ledPin = D5; //digitaler PIN 5 des Wemos D1 an welchem die LED angeschlossen ist. int ledStatus = LOW; //aktueller Status der LED (default / start -> AUS) WiFiServer server(80); //Port auf welchem der Server laufen soll. #define DHT11PIN 2 #define DHT11TYPE DHT11 DHT dht11(DHT11PIN, DHT11TYPE); void setup() { Serial.begin(115200); //Baudrate für die Serielle Geschwindigkeit. delay(10); //10ms. Warten damit die Seriele Kommunikation aufgebaut wurde. pinMode(ledPin, OUTPUT); //Den LEDPin als ausgang setzen. digitalWrite(ledPin, ledStatus); //Die LED initial auf den Status "AUS" setzen. Serial.print("Aufbau der Verbindung zu: "); //Ausgabe der SSID auf der Seriellen Schnittstelle. Serial.println(ssid); WiFi.begin(ssid, password); //Initialisieren der Wifi Verbindung. while (WiFi.status() != WL_CONNECTED) { //Warten bis die Verbindung aufgebaut wurde. delay(500); //Einen Punkt auf der Seriellen Schnittstelle ausgeben so das der Benutzer erkennt dass, das Sketch noch läuft. Serial.print("."); } //Bei erfolgreicher Verbindung wird der folgende Text ausgeben. Serial.print("Mit "); Serial.print(ssid); Serial.print("erfolgreich verbunden!"); dht11.begin(); server.begin(); // Starten des Servers. Serial.println("Server gestartet"); //Ausgabe auf der Seriellen Schnittstelle das der Server gestartet wurde. // Ausgabe der IP Adresse Serial.print("Adresse : http://"); Serial.print(WiFi.localIP()); Serial.println("/"); } /** * Die Funktion gibt den HTML Kopf auf dem Client aus. * Dieses wird für jeden Respond verwendet. **/ void writeResponse(WiFiClient client, float tempValue, float pressValue){ client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(""); client.println("<!DOCTYPE HTML>"); client.println("<html>"); client.println("<head>"); client.println("<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>"); client.println("<script type='text/javascript' src='http://progs.draeger-it.blog/wemosd1/dht11/gauges.js'></script>"); client.println("<link rel='stylesheet' href='http://progs.draeger-it.blog/wemosd1/dht11/styles.css'/>"); client.println("</head>"); client.println("<body>"); client.println("<div id='tempChart' class='chartContainer'></div>"); client.println("<div id='pressChart' class='chartContainer'></div>"); client.println("<script>"); client.println("google.charts.load('current', {'packages':['gauge']});"); client.println("google.charts.setOnLoadCallback(drawCharts);"); client.println("function drawCharts() {"); client.print("drawTempChart("); client.print(tempValue); client.print(");"); client.print("drawPressChart("); client.print(pressValue); client.print(");"); client.println("}"); client.println("</script>"); client.println("</body>"); client.println("</html>"); } void loop() { //Prüfen ob sich ein Client verbunden hat, wenn nicht die Loop "verlassen" WiFiClient client = server.available(); if (!client) { return; } // Wenn sich ein Client verbunden hat solange warten bis Daten gesendet werden. Serial.println("Neuer Client verbunden."); while(!client.available()){ delay(1); } String request = client.readStringUntil('\r'); Serial.println(request); client.flush(); float tempValue = dht11.readTemperature(); //Temperatur vom Sensor DHT22 lesen float pressValue = dht11.readHumidity(); //relative Luftfeuchtigkeit vom Sensor DHT22 lesen if (isnan(tempValue) || isnan(pressValue)) { Serial.println("DHT11 konnte nicht ausgelesen werden"); } writeResponse(client, tempValue, pressValue); delay(1500); storeData(tempValue, pressValue); delay(1); //1ms. Pause } void storeData(float tempValue,float pressValue){ WiFiClient client; const char* host = "progs.draeger-it.blog"; const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return; } String url = "/wemosd1/dht11db/upload.php?"; url = url + "temp="+tempValue; url = url + "&press="+pressValue; client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); delay(10); }
Wenn nun im Browser die Adresse des Wemos D1 eingegeben wird, wird die bekannte Seite aus dem Tutorial WEMOS D1 – WLAN Thermometer mit DHT11 Sensor angezeigt.
Und 1500ms später wird der Request an die Adresse mit den Sensordaten gestellt.
Das WLAN Thermometer (also mit der WebGUI) und dem Volkszähler Projekt wäre meiner Meinung nach sehr interessant.
Hallo Svenja,
soweit ich das überblicken kann ist das Volkszähler Projekt ja eher für den Bereich Photovoltaik ausgelegt.
Aber sicherlich kann man generell jeden Sensor auslesen und die Daten an eine geeignete Schnittstelle senden.
Gruß,
Stefan
Hallo habe folgendes Problem,
es funktioniert soweit alles, bis auf die Speicherung in der Datenbank.
Keine Fehlermeldung aber es kommt nichts an.
Bin mit meinem Latein am Ende.
Hallo,
schauen Sie doch mal in das Access Log vom Webserver ob man zumindest einen Zugriff sieht. Ansonsten einmal die URL nachbauen und manuell über den Browser absenden.
Ggf. sind Sonderzeichen enthalten welche durch Urlencoding Escaped werden müssen.
Gruß,
Stefan Draeger
Hallo,
was ist falsch? Wenn ich „https://localhost/dht/public/upload.php?temp=12.4&press=54.5“ mit Browser abschicke, kommt es in der Datenbank an.
Versuche ich es über die IP, erscheint im seriellen Monitor:
„Adresse : http://192.168.178.48/
Neuer Client verbunden.
GET / HTTP/1.1
connection failed
Neuer Client verbunden.
GET /favicon.ico HTTP/1.1
connection failed“
Die „ino“ sieht so aus(Auszug):
const char* host = „localhost“;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println(„connection failed“);
return;
}
String url = „/dht/public/upload.php?“;
url = url + „temp=“+tempValue;
url = url + „&press=“+pressValue;
und die upload.php(Auszug) :
function getDBConnection(){
//Das bleibt Geheim!
$dbname = „dht“;
$dbusername = „root“;
$dbpassword = „“;
$dburl=’localhost‘;
Komme nicht weiter.
Gruß Bernd
Hi Bernd,
der „Fehler“ liegt daran das bei der connection mit localhost geprüft wird. Gleich am Anfang des Codes. Das klappt mit localhost im eigenen, lokalen Netzwerk ohne Probleme. Wenn du aber über das Internet mit einer entsprechenden Freigabe arbeiten möchtest dann musst du hier die IP Adresse eintragen.
Gruß,
Stefan Draeger
Danke für schnelle Antwort.
Ich arbeite nicht übers internet, sondern mit „xammp“. Deshalb habe ich in der „Upload.php“ und in der „ino“ „localhost“ eingetragen.
function getDBConnection(){
//Das bleibt Geheim!
$dbname = „dht“;
$dbusername = „root“;
$dbpassword = „“;
$dburl=’localhost‘;
void storeData(float tempValue,float pressValue){
WiFiClient client;
const char* host = „localhost“;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println(„connection failed“);
return;
Hi,
okay aber du musst trotzdem die Zeile „const char* host = “localhost”;“ auf deine genannte IP-Adresse anpassen, dann sollte es passen.
Die DB Konfiguration ist so i.O.
Gruß,
Stefan Draeger
Hallo nochmal,
letzte Frage. Die Verbindung mit der Datenbank scheint jetzt klappen. Es werden aber keine Werte eingetragen. Wenn ich
client.print(String(„GET“) + url + “ HTTP/1.1\r\n“ +
„Host: “ + host + „\r\n“ +
„Connection: close\r\n\r\n“);
auch auf dem Monitor ausgeben lasse, erscheint
Neuer Client verbunden.
GET /favicon.ico HTTP/1.1
GET/localhost/uploadlocal.php?temp=32.30&press=1.00 HTTP/1.1
Host: 192.168.178.43
Connection: close
Sollte doch so stimmen, oder?
Gruß Bernd
Hi,
wenn ich richtig sehe fehlt da ein Leerzeichen „GET/localhost/u….“ -> „GET /localhost/u…“.
Gruß,
Stefan
Hallo Stefan
find das Projekt echt spannend
komm leider nicht mehr weiter
hab auf einem anderen PC Apache laufen
hatte auch die Datenbank eingerichtet
laut Access Log von Apache wird das Übergeben
192.168.0.14 – – [13/Dec/2021:12:16:28 +0100] „GET 192.168.0.15/tank/upload.php?temp=22.80&press=34.00 HTTP/1.1“ 400 328 „-“ „-“
hoffe das das so passt
bin kein Programmierer Sorry !
leider werden keine Daten in die Datenbank eingetragen
hier mal die Datenbankverbindung aus dem PHP
function getDBConnection(){
//Das bleibt Geheim!
$dbname = „data“;
$dbusername = „tank“;
$dbpassword = „tank12“;
$dburl=’192.168.0.15′;
und hier die der vom Arduino IDE
void storeData(float tempValue,float pressValue){
WiFiClient client;
const char* host = „192.168.0.15“;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println(„connection failed“);
return;
}
String url = „192.168.0.15/tank/upload.php?“;
url = url + „temp=“+tempValue;
url = url + „&press=“+pressValue;
client.print(String(„GET „) + url + “ HTTP/1.1\r\n“ +
„Host: “ + host + „\r\n“ +
„Connection: close\r\n\r\n“);
weis mittlerweile nicht mehr weiter
können Sie mir weiterhelfen? das ganze soll dann später so geändert werden dass ich die Menge meiner Öltanks anzeigen kann und speichern ohne dass ich immer in die Garage muss 🙂
schonmal vielen dank !!!
Hallo Thomas,
das & in der URL ist nicht korrekt. Ersetze dieses escapte Zeichen gegen ein einfaches UND Symbol „&“.
Gruß,
Stefan