ESP Weekendprojekt #1: DIY WiFi Wetterstation

In diesem Beitrag möchte ich dir zeigen wie du dir mit wenigen Bauteilen, relativ günstig und vor allem an einem Wochenende eine kleine DIY WiFi Wetterstation aufbaust.

DIY Wetterstation mit Wemos D1 Mini & DHT11 Sensor
DIY Wetterstation mit Wemos D1 Mini & DHT11 Sensor

Ziel

Das Ziel soll es zunächst sein die Wetterstation aufzubauen und eine kleine Webseite zu erstellen auf welcher die Messdaten eines DHT11 (Temperatur & relative Luftfeuchtigkeit) anzeigt.

Wemos D1 mini DHT11 Shield
Wemos D1 mini DHT11 Shield

Die Webseite kann von einem Smartphone, Tablet oder ähnlichem Gerät aufgerufen werden. Dabei spielt die Zielplattform (Android, iPhone, Windows Phone) keine Rolle.

benötigte Bauteile

BeschreibungPreis
Wemos D1 Mini2 €
Wemos D1 Mini, DC Power Supply Modul2 €
Wemos D1 Mini, DHT113,5 €
Wemos D1 Mini, Dual Base Shield1 €
Batterieclip mit Anschlußkabel und Hohlbuchse1 €
9V Blockbatterie**1 €
Frischebox (als Gehäuse)*1,5 €
Micro USB Kabel (min. 1m)3 €
4x M3 Schraube inkl. Mutter3 €
1x kleinen Kabelbinder (für die Batterie) 

* Die Frischebox habe ich aus dem örtlichen Woolworth für knapp 1,5€ erhalten , natürlich findet man diese auch im T€di, 1€ Shop, Thomas Phillips oder andere günstige Märkte.
** Die 9V Block Batterie erhält man in jedem gut sortierten Supermarkt (zbsp. Aldi, Lidl).

Die Gesamtkosten des Projektes betragen ca. 18€.

Werkzeuge

  • Bohrmaschine,
    • 10er Holzbohrer
  • Lötkolben, 15 Watt
    • Lötzinn,
    • hitzebeständige Unterlage
  • evtl. dritte Hand,
  • Seitenschneider,
  • Entlötpumpe,

Aufbau

Der Vorteil am Wemos D1 Mini ist das, die Module nachdem Löten einfach zusammengesteckt werden können. Jedoch muss man darauf achten das die Module korrekt zusammengesteckt werden, d.h. man muss auf die Beschriftung der Platine achten!

Pinbelegung auf den Shields
Pinbelegung auf den Shields

Die Module werden fast komplett zerlegt geliefert d.h. wir müssen zunächst die Pins anlöten.

Wemos D1 mini Shield - DC Power Shield
Wemos D1 mini Shield – DC Power Shield

Es empfiehlt sich für das zusammenlöten ein kleines, 170 Pin, Breadboard zu verwenden, auf dieses Breadboard lassen sich die Pins im geradezu 90 Grad Winkel stecken und somit ist die Platine zum löten bestens ausgerichtet.

Breadboards
Breadboards

das Gehäuse

Es gibt einige Gehäuse welche man mit einem 3D Drucker drucken kann, die entsprechenden Vorlagen findet man zbsp. unter Thingiverse.com. In diesem kleinen Weekend Projekt möchte ich jedoch auf eine einfache Frischebox zurückgreifen denn das drucken eines solches Gehäuses würde selber ein Wochenende dauern. (natürlich ist das abhängig vom 3D Drucker)

Frischebox als Gehäuse für die DIY Wetterstation
Frischebox als Gehäuse für die DIY Wetterstation

Ich verwende eine Frischebox mit den Abmaßen 

  • nutzbare Fläche 70mm x 70mm
  • Höhe 40mm

In dieses Gehäuse wird nun mit einem 10er Holzbohrer in jede Seite ein Loch gebohrt. Das Loch wird anschließend mit einem scharfen Taschenmesser (zbsp. Opinel Nr.9) oder einem Cuttermesser entgratet.

Bodenplatte

Damit die Dual Base Plate des Wemos und die 9v Batterie sicher im Gehäuse verstaut und untergebracht ist, benötigen wir eine kleine Bodenplatte im Maß von 70mm x 70mm. Hier bietet sich einfaches 3mm Sperrholz an, dieses bekommst du in jedem Baumarkt (und wenn man lieb fragt sägen diese einem das auf genau richtige Maß zurecht).

Ich verwende hier mir meinen 3D Drucker mit transparentem, 1,75mm Filament.

Bodenplatte - DIY Wetterstation
Bodenplatte – DIY Wetterstation

Zum selber nachdrucken, findest du hier das STL File:

 

Auf die Bodenplatte kann man nun mit den M3 Schrauben die Dual Base Plate des Wemos D1 mini festschrauben. Oder aber man verwendet kleine Plastikschrauben inkl. Abstandshalter und Muttern. Diese gibt es im Sortiment auf zbsp. ebay.de für 10 Euro in Schwarz oder Weiß.

Abstandhalter & Schraubensortiment
Abstandhalter & Schraubensortiment

Wer etwas mehr investieren möchte, kann sich diese auch in Messing oder sogar Edelstahl kaufen, diese sind jedoch deutlich teuer.

zusammenstecken der Shields

Die Shields des Wemos D1 mini kann man ineinander stecken. Ein Problem gibt es nur bei recht großen Modulen auf den Shields oder aber wo es keinen Sinn ergibt zbsp. OLED Display, 8×8 LED Matrix, Button Shield. 

Jedoch kann man die hier verwendeten Shields in fast unendlichen Möglichkeiten zusammenstecken.

Dadurch das ich am Powwer Shield die Stiftleisten ohne Buchsenleiste angelötet habe, bin ich hier etwas eingeschränkt. Aber das ist kein Problem.

Anschluß der Batterie

Die 9V Block Batterie wird mit einem Batterieclip angeschlossen. Am einfachsten ist der Batterieclip mit einem Hohlstecker denn dieser kann in das Power Shield gesteckt werden ohne das man auf die korrekte Polung achten. Ich verwende einen Batterieclip ohne Hohlstecker jedoch gibt es da keine großen Unterschiede.

Programmierung

Die Programmierung des Sketches möchte ich in 6 Stufen machen.
Mit jeder Ausbaustufe wächst das kleine Projekt und wir haben nach jeder dieser Stufe ein fertiges „Produkt“.

Wichtig: Die ersten beiden Ausbaustufen werden in der dritten Ausbaustufe zusammengeführt und für alle anderen benötigt, d.h. du kannst ab der Ausbaustufe 3 jeweils zu der Stufe wechseln welche du für dein Projekt benötigst.

 

Ausbaustufe 1 – Daten auf der seriellen Schnittstelle ausgeben

In der erstes Ausbaustufe werden die Daten (Temperatur und relative Luftfeuchtigkeit) des DHT11 Sensors auf der seriellen Schnittstelle ausgegeben. Dieses habe ich bereits in dem Beitrag Wemos D1 mini Shield: DHT11 Sensor behandelt.

#include "DHT.h" //DHT Bibliothek

//Pin an welchem der DHT11 Sensor angeschlossen ist.
//Beim DHT11 Shield ist es der digitale Pin D4.
#define DHTPIN D4 
 
//Festlegen welcher Typ von DHT Sensor verwendet wird.
#define DHTTYPE DHT11

//Initialisieren des Sensors mit dem Anschluss und dem Typ
DHT dht(DHTPIN, DHTTYPE);
 
void setup() {
  Serial.begin(9600); //Begin der seriellen Kommunikation mit 9600 Baud.
  //Ausgabe eines Textes auf dem seriellen Ausgang.
  Serial.println("Wemos D1 mini DHT11 Shield"); 
 
  dht.begin(); //DHT Kommunikation beginnen.
}
 
void loop() {
  //Der DHT11 Sensor liefert alle 2 Sekunden einen neuen
  //Wert daher lohnt es sich nicht die loop konstant durchlaufen 
  //zu lassen.
  delay(2000);
 
  //lesen der Luftfeuchtigkeit
  double luftfeuchtigkeit = dht.readHumidity();
  //lesen der Temperatur in Grad Celsius
  double temperaturC = dht.readTemperature();
  //lesen der Temperatur in Grad Fahrenheit
  //mit dem Boolean Parameter wird "gesteuert" ob
  //die Temperatur in Fahrenheit oder Celsius ausgegeben wird.
  double temperaturF = dht.readTemperature(true);
 
  //Prüfen ob die Werte erfolgreich gelesen wurden.
  if (isnan(luftfeuchtigkeit) || isnan(temperaturC) || isnan(temperaturF)) {
    Serial.println("Fehler beim lesen von Daten.");
    return;
  }
  
  Serial.print("Luftfeuchtigkeit: ");
  Serial.print(luftfeuchtigkeit);
  Serial.println(" %\t");
  Serial.print("Temperatur: ");
  Serial.print(temperaturC);
  Serial.print(" °C ");
  Serial.print(temperaturF);
  Serial.println(" °F\t");
}

Ausbaustufe 2 – Webserver einrichten

Im zweiten Abschnitt werden wir nun zum bestehenden Sketch die Eigenschaften für einen Webserver hinzufügen. Diese Eigenschaften benötigen wir damit wir später mit einem Browser oder einer Anwendung auf den Webserver zugreifen und so die Daten empfangen können.

#include <ESP8266WiFi.h>

const char* ssid = ""; //SSID aus dem Router
const char* password = ""; //Passwort für den Zugang zum WLAN

WiFiServer server(80);

void setup() {
  Serial.begin(115200); //Baudrate für die Serielle Geschwindigkeit.
  delay(10); //10ms. Warten damit die Seriele Kommunikation aufgebaut wurde.

  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!");

  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("/");
}

void loop() {
  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);
  }
  client.flush();
  delay(1500);
}

Es muss nun noch die SSID und das Passwort in die entsprechende Variablen eingegeben werden.

Wenn man nun den Sketch auf den Microcontroller hochläd dann sollte nach einer kleinen Wartezeit der Server sich mit dem Router verbinden.

Ausgabe des Sketches auf dem seriellen Monitor der Arduino IDE
Ausgabe des Sketches auf dem seriellen Monitor der Arduino IDE

Ausbaustufe 3 – zusammenfügen der Sketche

Als nächstes wollen wir nun die beiden ersten geschriebenen Sketche zu einem zusammenfügen und die Daten in zwei Funktionen auslesen (einmal die Temperatur, einmal die relative Luftfeuchtigkeit). Diese Funktionen werden wir im späteren verlauf weiter verwenden. 

#include <ESP8266WiFi.h>
#include "DHT.h"

const char* ssid = ""; //SSID aus dem Router
const char* password = ""; //Passwort für den Zugang zum WLAN

WiFiServer server(80);

#define DHT11PIN D4
#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.

  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(".");
  }

  Serial.println("");

  //Bei erfolgreicher Verbindung wird der folgende Text ausgeben.
  Serial.print("Mit ");
  Serial.print(ssid);
  Serial.print(" erfolgreich verbunden!");

  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("/");

  dht11.begin();
}

void loop() {
  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);
  }

  Serial.println(getTempCelsius());
  Serial.println(getTempFahrenheit());
  Serial.println(getHumidity());
  
  client.flush();
  delay(1500);
}

//Temperatur in Celsius vom Sensor DHT11 lesen
float getTempCelsius() {
  return getTemp(false);
}

//Temperatur in Fahrenheit vom Sensor DHT11 lesen
float getTempFahrenheit() {
  return getTemp(true);
}

//Liefert die Temperatur vom DHT11 Sensor
//der Parameter inFahrenheit steuert ob
//die Temperatur in Fahrenheit (true) oder in Celsius (false)
//geliefert wird.
float getTemp(bool inFahrenheit) {
  float tempValue = dht11.readTemperature(inFahrenheit);
  if (isnan(tempValue)) {
    Serial.println("DHT11 konnte nicht ausgelesen werden");
    tempValue = -1;
  }
  return tempValue;
}

//Lesen der relativen Luftfeuchtigkeit vom DHT11 Sensor
float getHumidity() {
  float humidity = dht11.readHumidity();
  if (isnan(humidity)) {
    Serial.println("DHT11 konnte nicht ausgelesen werden");
    humidity = -1;
  }
  return humidity;
}

Wenn wir also nun in einem Browser die IP Adresse eingeben welche auf dem seriellen Monitor der Arduino IDE angezeigt wird, eingeben dann sehen wir zwar keine Ausgabe im Browser aber wir erhalten auf dem seriellen Monitor der Arduino IDE folgende Ausgabe:

.......Mit FRITZBox7590GI24 erfolgreich verbunden!Server gestartet
Adresse : http://192.168.178.41/
Neuer Client verbunden.
24.00
75.20
45.00
Neuer Client verbunden.
24.00
75.20
45.00
Neuer Client verbunden.
24.00
75.20
43.00
Neuer Client verbunden.
24.00
75.20
43.00

In diesem Fall habe ich 3x die Seite mit der Taste „F5“ aktualisiert.

Mit diesem Sketch können wir nun die weiteren Ausbaustufen des Projektes durchführen.

Ausbaustufe 4 – Daten als JSON Bereitstellen

Wenn wir die Daten des DHT11 Sensors mit einem anderen System (zbsp. Raspberry PI oder ähnliches) benötigen wir ein einfaches, lesbares Format. Hier bieten sich XML und JSON an. Für dieses Projekt möchte das JSON Format benutzen. 

{
	"temperatur": {
		"celsius": 21.00,
		"fahrenheit": 69.80
	},
	"humidity": 39.00
}

Zunächst schreiben wir uns eine Funktion in welcher wir eine Rückgabe / Respond an den Client senden. Dieser Respond kann von einem Browser (wie Mozilla FireFox, Google Chrome) oder aber auch einem Tool wie Postman empfangen und angezeigt werden.

Als Parameter übergeben wir dieser Funktion den bereits verbundenen WiFiClient.

In der ersten Zeile wird der HTTP Header sowie der Content-Type gesetzt. Über diese Daten kann dann das Tool bzw. der Browser ermitteln um welche Daten es sich handelt und vorallem ob alles richtig abgelaufen ist. Bei einem Fehler könnte man zbsp. einen anderen HTTP Fehlercode senden.

Der Content-Type wird in einigen Browsern auch verwendet um die Daten Formatiert anzeigen zu lassen.

void sendRespond(WiFiClient client){
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: application/json");
  client.println("");
  client.print("{");
  client.print("\"temperatur\":");
  client.print("{");
  client.print("\"celsius\":");
  client.print(getTempCelsius());
  client.print(",");
  client.print("\"fahrenheit\":");
  client.print(getTempFahrenheit());
  client.print("},");
  client.print("\"humidity\":");
  client.print(getHumidity());
  client.println("}");  
}

Die Funktion „sendRespond“ wird nun in der Loop eingebunden. Da wir dafür einen verbundenen Client benötigen (wo sollen wir sonst die Daten hinsenden?) muss dieses nach der Schleife “ while (!client.available())“ geschehen. Jedoch muss dieses auch vor dem Absenden der gesamten Daten an den Client passieren („client.flush();“).

Serial.println("Neuer Client verbunden.");
while (!client.available()) {
  delay(1);
}

sendRespond(client);

client.flush();

Wenn die neue Funktion implementiert wurde, kann nun der Sketch erneut auf den Wemos D1 mini geladen werden und wir können einen Test durchführen.

Ich nutze zunächst das Tool Postman. (Dieses habe ich auch bereits in anderen Beiträgen auf diesem Blog eingesetzt.)

DIY Wetterstation - JSON Respond
DIY Wetterstation – JSON Respond

Wir haben also nun unsere Daten im JSON Format vorliegen und könnten nun damit weiterarbeiten.

 

ein kleines Oracle Java Programm

Hier nun ein kleines Oracle Java Programm welches die Daten vom Wemos D1 Mini empfängt und in einem Diagramm anzeigt. Es muss nur die Zieladresse und der Intervall ein 100 Millisekunden Schritten eingegeben werden.

Einfache Java Anwendung - DHT11 Sensordaten

Wenn du möchtest kannst du dir die Anwendung nachfolgend herunterladen.

Wenn du das Projekt gerne fortführen möchtest dann findest du hier das gesamte Eclipse Projekt.

 

Python3 Script

Natürlich kann man das auch mit Python lösen, hier also nun ein Script welches 5 Datenpakete sammelt und diese dann in einem Liniendiagramm anzeigt.

import http.client
import json
import time
import matplotlib.pyplot as plt

dataList = []
index = 0
while index < 5:
    conn = http.client.HTTPConnection("192.168.178.41")
    conn.request("GET","/")

    response = conn.getresponse()
    ##print("Status ",response.status, response.reason)
    jsonValue = response.read()

    dht11Value_dict = json.loads(jsonValue)

    dataList.append(dht11Value_dict)
    time.sleep(2)
    index += 1

tempClist = []
tempFlist = []
humidityList = []

for d in dataList:
    tempClist.append(d['temperatur']['celsius'])
    tempFlist.append(d['temperatur']['fahrenheit'])
    humidityList.append(d['humidity'])

#Plot a line graph
plt.plot(tempClist, label='Temp. Celsius')
plt.plot(tempFlist, label='Temp. Fahrenheit')
plt.plot(humidityList, label='rel. Luftfeuchtigkeit')
 
# Add labels and title
plt.title("DHT11 Sensordaten")
plt.xlabel("Zeit")
plt.ylabel("Wert")
 
plt.legend()
plt.show()
DHT11 Sensordaten in einem Liniendiagramm
DHT11 Sensordaten in einem Liniendiagramm

Da die Temperatur in Celsius den gleichen Wert wie die relative Luftfeuchtigkeit hatte, sind diese beiden Linien übereinander und man sieht nur die zuletzt gezeichnete Linie!

Ausbaustufe 5 – Daten in einer Webseite darstellen

Die Daten eines DHT11 Sensors habe ich bereits im Beitrag WEMOS D1 – WLAN Thermometer mit DHT11 Sensor ausführlich behandelt jedoch möchte ich dieses hier zusätzlich aufzählen da dieses zum Thema gehört.

Daten als Text darstellen

Im einfachsten Fall werden die Daten als Text auf einer Webseite angezeigt.

void sendRespond(WiFiClient client) {
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println("");
  client.print("<html>");
  client.print("<body>");
  client.print("<ul>");
  client.print("<li>Temperatur");
  client.print("<ul>");
  client.print("<li>Celsius: ");
  client.print(getTempCelsius());
  client.print("&deg;C</li>");
  client.print("<li>Fahrenheit: ");
  client.print(getTempFahrenheit());
  client.print("&deg;F</li>");
  client.print("</ul>");
  client.print("</li>");
  client.print("<li>relative Luftfeuchtigkeit: ");
  client.print(getHumidity());
  client.print("%</li>");
  client.print("</ul>");
  client.print("</body>");
  client.println("</html>");
}

Wenn man nun im Browser die IP-Adresse des Wemos D1 Mini eingibt erhält man folgende Ausgabe:

Ausgabe der Daten in Textform
Ausgabe der Daten in Textform

Um die Daten zu aktualisieren muss man nun jeweils im Browser die F5 Taste betätigen. 

automatische Aktualisierung nach x Sekunden

Man kann auch die Seite nach x Sekunden aktualisieren, dazu können wir entweder ein Redirect auf die selbe Seite machen oder die Daten per Ajax nachladen. Im einfachsten Fall (dem Redirect) brauchen wir nur folgendes hinzufügen.

client.println("<head>");
String ipAddress = WiFi.localIP().toString();
client.println("<meta http-equiv=\"refresh\" content=\"10; URL=http://"+ ipAddress +"/\"/>");
client.println("</head>");

Im dem META Tag wird definiert das ein redirect auf die IP-Adresse des Wemos D1 Mini nach 10 sek. durchgeführt wird.

 

Ausbaustufe 6 – Daten in einem Diagramm darstellen

Wie man Daten von einem DHT11 Sensor in einer kleinen Webseite anzeigt, habe ich bereits im Beitrag WEMOS D1 – WLAN Thermometer mit DHT11 Sensor ausführlich behandelt. In diesem Abschnitt möchte ich jedoch trotzdem dieses behandeln.

void sendRespond(WiFiClient client) {
  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'/>");   
  String ipAddress = WiFi.localIP().toString();
  client.println("<meta http-equiv=\"refresh\" content=\"10; URL=http://"+ ipAddress +"/\"/>");
  client.println("<title>DIY - Wetterstation - DHT11 Sensordaten</title>");
  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(getTempCelsius()); 
  client.print(");");
  client.print("drawPressChart(");
  client.print(getHumidity()); 
  client.print(");");
  client.println("}"); 
  client.println("</script>"); 
  client.println("</body>"); 
  client.println("</html>"); 
}

Ich verwende hier zusätzlich 2 Resourcen welche auf „meinem“ Server unter „http://progrs.draeger-it.blog/wemosd1/dht11“ liegen.

Wenn man nun die IP-Adresse des Wemos D1 Mini in den Browser eingibt, erhält man folgende Ausgabe.

DHT11 Sensordaten auf Google Gauges
DHT11 Sensordaten auf Google Gauges

Die Seite wird nach 10 Sekunden automatisch aktualisiert.

 

Liniendiagramm 

Möchte man die Daten in einem Verlauf betrachten so sollten diese Daten in einem Liniendiagramm dargestellt werden. Für dieses Liniendiagramm verwende ich die ebenfalls kostenfreie Bibliothek von Google welche du unter https://developers.google.com/chart/interactive/docs/gallery/linechart findest.

Wir wollen zunächst die Temperatur in Celsius sowie die relative Luftfeuchtigkeit anzeigen. (Ich lasse in diesem Beispiel die Temperatur in Fahrenheit mal außen vor.) 
Diese Sensordaten müssen wir zwischenspeichern ich nutze dazu ein Mehrdimensionales Array.

float chartData[255][2] = {};

Beginnen wollen wir jedoch zunächst mit einem leeren Array. Zusätzlich benötigen wir jedoch noch eine Variable wo wir die Einträge hochzählen wollen. 

int counter = -1;

Da Arrays mit dem Index 0 beginnen, beginnt unser Zähler bei -1.

In der Methode zum schreiben der HTML Seite, zählen wir zunächst unsere Variable „counter“ um eins hoch. Danach prüfen wir ober der Wert der Variable in dem maximalen Gültigkeitsbereich des Arrays liegt. Wenn dieser erreicht wurde, beginnen wir wieder bei 0.

Danach wird die Seite aufgebaut. 

void sendRespond(WiFiClient client) {
 counter++;
 if(counter > (MAX_DATA-1)){
   counter = 0;
 }
  
 chartData[counter][0] = getTempCelsius();
 chartData[counter][1] = getHumidity();
  
  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/linechart.js'></script>"); 
  client.println("<link rel='stylesheet' href='http://progs.draeger-it.blog/wemosd1/dht11/styles.css'/>");   
  String ipAddress = WiFi.localIP().toString();
  client.println("<meta http-equiv=\"refresh\" content=\"1; URL=http://"+ ipAddress +"/\"/>");
  client.println("<title>DIY - Wetterstation - DHT11 Sensordaten</title>");
  client.println("</head>"); 
  client.println("<body>"); 
  client.println("<div id='chart' class='chartContainer' style='width: 900px; height: 500px'></div>"); 
  client.println("<script>"); 
  client.println("google.charts.load('current', {'packages':['line']});"); 
  client.println("google.charts.setOnLoadCallback(drawCharts);"); 
  client.println("function drawCharts() {"); 

  client.println("var data = new google.visualization.DataTable();");
  client.println("data.addColumn('number', 'Zaehler');");
  client.println("data.addColumn('number', 'Temperatur in Celsius');");
  client.println("data.addColumn('number', 'rel. Luftfeuchtigkeit');");
  
  client.println(" data.addRows([");
  for(int i=0;i<=counter;i++){
    client.print("["); 
    //client.print("'"); 
    client.print(i+1); 
    //client.print("'"); 
    client.print(","); 
    client.print(chartData[i][0]); 
    client.print(","); 
    client.print(chartData[i][1]); 
    client.print("]"); 
    if(i != counter){
      client.print(",");
    }
  }
  client.println("]);");
  
  client.println("drawLineChart(data);");
  client.println("}"); 
  client.println("</script>"); 
  client.println("</body>"); 
  client.println("</html>"); 
}

Wie bereits erwähnt verwenden wir die Google Bibliothek zum zeichnen des Linien Diagramms diese Bibliothek ist eine JavaScript Bibliothek und wird mit den Daten aus unserem Array befüllt.
Dieses JavaScript Objekt übergeben wird nun unserer JavaScript Funktion auf dem Server.

Daten vom DHT11 Sensor in einem Google LineChart
eine Tabelle mit Daten implementieren

Die Daten werden im Liniendiagramm angezeigt jedoch wäre es noch besser wenn die Daten zusätzlich in einer Tabelle angezeigt würden.
Hier können wir uns zusätzlich in der Schleife unsere Tabelle aufbauen und später positionieren.

 String tableData = "";

 for(int i=0;i<=counter;i++){
    client.print("["); 
    //client.print("'"); 
    client.print(i+1); 
    //client.print("'"); 
    client.print(","); 
    client.print(chartData[i][0]); 
    client.print(","); 
    client.print(chartData[i][1]); 
    client.print("]"); 
    if(i != counter){
      client.print(",");
    }

    tableData +="<tr>";
    tableData +="<td>";
    tableData +=String(i);
    tableData +="</td>";
    tableData +="<td>";
    tableData +=String(tempC);
    tableData +="&deg;C</td>";
    tableData +="<td>";
    tableData +=String(humidity);
    tableData +="%</td>";
    tableData +="</tr>";
    
  }

...

client.println("<table border='1' style='float:left;margin-left:25px;'>"); 
client.println("<thead>"); 
client.println("<tr>"); 
client.println("<th>Zaehler</th>"); 
client.println("<th>Temperatur</th>"); 
client.println("<th>rel. Luftfeuchtigkeit</th>"); 
client.println("</tr>"); 
client.println("</thead>"); 
client.println("<tbody>"); 
client.println(tableData);  
client.println("</tbody>"); 
client.println("</table>");

Es wird nun zusätzlich eine Tabelle neben dem Liniendiagramm aufgebaut.

DHT11 Sensordaten im Google LineChart inkl. Tabelle
DHT11 Sensordaten im Google LineChart inkl. Tabelle

 

 

2 Gedanken zu „ESP Weekendprojekt #1: DIY WiFi Wetterstation

  • 20. März 2020 um 10:43
    Permalink

    Der 9v Block ist ungeeignet, zu schnell leer. 3x AA in selbstgedrucktem Batteriehalter..‘

    Antwort
    • 20. März 2020 um 10:48
      Permalink

      Hi,

      da gebe ich dir recht. Jedoch ist die Dose etwas zu klein geraten so das ich darauf nicht zurück greifen konnte. Wobei man aber auch bei 3x AA Batterien nicht gerade von einer langen Lebensdauer reden kann.
      Hast du damit gute Erfahrungen gemacht? Welche Batterien (Marke) verwendest du?

      Gruß,

      Stefan

      Antwort

Schreibe einen Kommentar

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