logo elektroda
logo elektroda
X
logo elektroda

Wemos D1 „Arduino“ und DHT11 - einfache Wetterstation mit Diagrammen auf einer Webseite

p.kaczmarek2 
Diagramm für Temperatur und Luftfeuchtigkeit auf der ESP8266-Wetterstations-Webseite
Ich mache ein Projekt über die Erstellung von Diagrammen mit Arduino R4 auf dem ESP8266 in PlatformIO. Standardmäßig wird das Ganze aus vorgefertigten Bibliotheken zusammengebaut und ich werde den Prozess als Tutorial beschreiben. Zuerst werde ich hier den DHT11 Temperatur- und Luftfeuchtigkeitssensor betreiben, dann werde ich zeigen, wie die aktuelle Uhrzeit aus dem Internet heruntergeladen werden kann. Dann werde ich demonstrieren, wie die Messwerte im Speicher in einem Ringpuffer gesammelt werden können, und schließlich werde ich sie auf einer einfachen Webseite mit einem Diagramm anzeigen, das über unser Wi-Fi zugänglich ist.

Erste Schritte
Hier gehe ich davon aus, dass wir ein OTA laufen haben und ich werde das verwenden, was ich zuvor entwickelt habe. Zur Erinnerung - hier ist mein "hello world":
Code: C / C++
Melde dich an, um den Code zu sehen

In diesem Thema versuchen wir, alles aus vorgefertigten Komponenten zusammenzubauen, also werden wir auch eine vorgefertigte Bibliothek für den DHT11-Sensor verwenden. Wir brauchen sie nur zu installieren.
Wir öffnen die Registerkarte Libraries:
PlatformIO-Oberfläche mit geöffnetem Bibliotheken-Tab in Visual Studio Code

Wir suchen nach DHT. Die DHT-Bibliothek erfordert auch den Zusatz von Adafruit Unified Sensor Library, wir fügen also beide Bibliotheken hinzu. Erstens, Unified Sensor:
Screenshot zeigt die Suche nach DHT-Bibliotheken in PlatformIO.

Wir ergänzen das Projekt:
PlatformIO-Oberfläche mit ausgewählter Adafruit Unified Sensor-Bibliothek

Man muss angeben, zu welchem unserer Projekte diese Bibliothek hinzugefügt werden soll:
Dialogfeld zum Hinzufügen von Projektabhängigkeiten in PlatformIO

Hinzugefügt:
Installation von Adafruit Unified Sensor in PlatformIO

Auf diese Weise fügen wir beide Bibliotheken hinzu. Ein aufmerksames Auge wird feststellen, dass sie auch zu unserer platformio.ini hinzugefügt wurden:
PlatformIO-Bibliothekskonfiguration mit hinzugefügten Adafruit-Bibliotheken

Außerdem gibt es auf der Website der Bibliothek ein Beispiel für ihre Verwendung:
Screenshot eines Beispiels zur Verwendung der DHT_Unified_Sensor-Bibliothek in PlatformIO.

Integrieren wir sie in unseren Code. Ich nehme die Messung vor, wenn der Zustand der Diode umgeschaltet wird:
Code: C / C++
Melde dich an, um den Code zu sehen

Im Moment sende ich die Ergebnisse nur über UART. Wir werden später eine Webseite einrichten. Prüfen wir zunächst, ob der DHT überhaupt funktioniert:
Terminalanzeige mit WiFi-Verbindungsdaten sowie Temperatur- und Feuchtigkeitsmessungen.

Website hinzufügen
Unsere Messungen in die Welt hinauszutragen ist wirklich recht einfach. Die ESP8266WebServer-Klasse wird verwendet, um den Server zu erstellen. Zuerst fügen wir ihren Header ein:
Code: C / C++
Melde dich an, um den Code zu sehen

Wir erstellen dann ihre Instanz, wobei das Argument der Port ist, an dem der Server erstellt wird (HTTP ist im Allgemeinen Port 80):
Code: C / C++
Melde dich an, um den Code zu sehen

Wir erstellen dann die Funktionen, die die betreffenden Seiten unterstützen:
Code: C / C++
Melde dich an, um den Code zu sehen

In der Hauptschleife bedienen wir Clients
Code: C / C++
Melde dich an, um den Code zu sehen

Und schließlich die Funktion, die die Hauptseite unterstützt:
Code: C / C++
Melde dich an, um den Code zu sehen

Ergebnis:
Webseite, die den Text Hello Elektroda! in einem Browser anzeigt.
Es ist wirklich sehr einfach. Wir werden nun die Temperatur anzeigen.

Anzeige der Temperatur
Um die Temperatur auf der Seite anzuzeigen, müssen wir zwei Dinge tun:
- die Messwerte müssen gespeichert werden, der Einfachheit halber geben wir sie in globale Variablen ein
- wir müssen sie dann in den Text der Seite einfügen. Für die Formatierung der Überschrift verwende ich meine Lieblingsmethode, nämlich einen Puffer im C-Stil und die Funktion sprintf.
Die globalen Variablen selbst:
Code: C / C++
Melde dich an, um den Code zu sehen

Schreiben in globale Variablen:
Code: C / C++
Melde dich an, um den Code zu sehen

Modifizierte Funktion zur Erstellung der Seite:
Code: C / C++
Melde dich an, um den Code zu sehen

Auf diese Weise erscheint die Temperatur- und Luftfeuchtigkeitsanzeige, abgelesen von DHT, auf unserem Bildschirm.

Uhrzeit aus dem Netz (NTP)
NTP ist das Network Time Protocol, ein Verfahren zum Abrufen der Uhrzeit aus dem Netz. Auch hier haben wir eine fertige Lösung, wir verwenden die Klasse NTPClient. Wir fügen die entsprechende Bibliothek wie zuvor hinzu:
Screenshot, der die Bibliothekssuchoberfläche für NTPClient in PlatformIO zeigt.

PlatformIO-Oberfläche mit geöffnetem NTPClient-Bibliothek im Code-Editor.

Auch für diese Bibliothek gibt es natürlich ein fertiges Anwendungsbeispiel:
Code: C / C++
Melde dich an, um den Code zu sehen

Man muss die Uhrzeit noch irgendwie in Form einer Beschriftung erhalten. Hierfür gibt es eine fertige Funktion - getFormattedTime. Einmal in unsere Website integriert, erhalten wir:
Code: C / C++
Melde dich an, um den Code zu sehen

Ergebnis:
Screenshot mit Wetterdaten auf einer Webseite

Wenn wir ehrgeizig sind, können wir die Uhrzeit selbst formatieren, wie wir wollen. Dafür gibt es die Funktion strftime, die ähnlich wie spritnf funktioniert. Darin formatieren wir die Uhrzeit ebenfalls mit speziellen Tags. Unten ist ein leicht entwickeltes Beispiel:
Code: C / C++
Melde dich an, um den Code zu sehen


Bessere Organisation
Unser Ziel ist es jedoch, Messungen zu sammeln. Bevor wir das realisieren, schlage ich vor, dass wir unser Messprotokoll besser organisieren. Führen wir eine Struktur ein, um die Messung darzustellen. Was genau sollte eine solche Struktur enthalten? Sie wird Folgendes umfassen:
- Temperatur (float)
- Luftfeuchtigkeit (ebenfalls float)
- Uhrzeit (hier ist es am besten, den Typ time_t zu verwenden, der in der Tat auch eine Zahl ist. Ich rate davon ab, die Uhrzeit als String zu schreiben, das wäre ineffizient und unbequem bei der weiteren Verarbeitung)
Code: C / C++
Melde dich an, um den Code zu sehen

Dann kann eine Instanz dieser Struktur global erstellt werden:
Code: C / C++
Melde dich an, um den Code zu sehen

und unser Programm läuft wie bisher. Wichtig ist nur, dass die Uhrzeit zum Zeitpunkt der Messung gespeichert wird und nicht erst beim Lesen der Seite.

Geschichte der Messung - Ringpuffer - Teil 1
Nun muss man überlegen, wie man die Messungen speichern will. Man würde gerne ein einfaches Array verwenden, aber was ist mit dem Überschreiben alter Messungen? Der Arbeitsspeicher ist nicht unendlich.
Es gibt eine einfache Möglichkeit, dies zu tun - ein Ringpuffer bietet sich hier an.
Ein Ringpuffer ist eine auf dem Array basierende Datenstruktur, die es ermöglicht, eine Reihe von Datenelementen zu speichern. Wenn der Puffer voll ist, ersetzen neue Daten die ältesten Daten. Wie der Name schon sagt - der Index des Elements, in das wir hier schreiben, zieht einen Kreis. Durch geeignete Manipulation des Array-Indexes (zusammen mit der richtigen Art des Lesens und Schreibens) wird es zu einem Ringpuffer.
Entscheiden wir uns zunächst für die Größe des Arrays - wenn wir einen Tag mit Messungen alle 10 Minuten haben wollen, dann reichen 24 * 6 aus.
Code: C / C++
Melde dich an, um den Code zu sehen

Außerdem benötigen wir den Index der letzten Messung (dieser Index wird im Array "kreisen", also in einer Schleife):
Code: C / C++
Melde dich an, um den Code zu sehen

Eine Funktion, die eine Messung hinzufügt (und den Index mit Hilfe des Modulo-Operators in einer Schleife wiederholt):
Code: C / C++
Melde dich an, um den Code zu sehen

Und eine Funktion zum Überschreiben von Arrays:
Code: C / C++
Melde dich an, um den Code zu sehen

Natürlich muss es noch mit dem Erfassen der DHT-Messungen verbunden werden
Code: C / C++
Melde dich an, um den Code zu sehen

und in ihrer Anzeige (vorerst ohne Diagramm):
Code: C / C++
Melde dich an, um den Code zu sehen


Schließlich ein Diagramm
Nun ist es an der Zeit, das Diagramm zu erstellen. Ich habe mich dafür entschieden, die Bibliothek chart.js zu verwenden.
Beispiele für die Verwendung findet man auf der Website W3schools:
https://www.w3schools.com/js/js_graphics_chartjs.asp
Um ein Beispiel von der oben genannten Seite zu zitieren - es geht darum, unsere gesammelten Werte in die Arrays einzufügen:
Beispielquellcode für ein Liniendiagramm in Chart.js

Der obige Code erzeugt ein solches Diagramm:
Liniendiagramm mit drei Linien in verschiedenen Farben.

Arrays zeichnen sich dadurch aus, dass allen Elementen außer dem ersten ein Komma vorangestellt wird, das wir ebenfalls behandeln müssen, wahrscheinlich mit irgendwelchem if.
Wir erstellen drei Arrays:
- Beschriftungen (Zeichen, hier Datum/Uhrzeit)
- Temperaturwerte
- Luftfeuchtigkeitswerte
Ein Beispiel für die Lösung:
Code: C / C++
Melde dich an, um den Code zu sehen

Die obige Lösung ignoriert bisher den Ringpuffer!
Darüber hinaus breche ich die Schleifen frühzeitig ab, um die „leeren“ Messungen zu überspringen.
Dann bleibt nur noch, die so erzeugten Arrays in den restlichen Code für die Diagrammerzeugung einzufügen, was wir zumindest aus den Beispielen der Verwendung dieser Bibliothek entnehmen können:
Code: C / C++
Melde dich an, um den Code zu sehen

Hier ist das Ergebnis, für den Effekt habe ich den Sensor mit einer starken Taschenlampe erhitzt:
Diagramm zeigt Temperatur- und Feuchtigkeitsänderungen.
Webseite mit Temperatur- und Feuchtigkeitsdiagramm.

Verbesserungen und Erweiterungen
Der Code im vorherigen Absatz ist nicht korrekt. Wir müssen den Ringpuffer beachten und leere Messungen überspringen. Eine Messung ist leer, wenn die Zeit 0 ist, und wir beginnen die Iteration des Puffers mit dem ältesten Eintrag, den wir identifizieren als:

(lastSample+1)%SAMPLES_COUNT

Der %-Operator ist modulo, der Rest der Division durch eine ganze Zahl. Wir beginnen also mit dem ältesten Eintrag und enden mit lastSample.
Code: C / C++
Melde dich an, um den Code zu sehen

Hier kann man noch das Ergebnis zeigen, aber vom Standpunkt des Aussehens wird sich wahrscheinlich nichts ändern (es sei denn, wir würden länger warten, in diesem Fall könnte das Diagramm ohne die Korrektur für den Ringpuffer zusammenbrechen):
Temperatur- und Feuchtigkeitsdiagramm auf einer Webseite

Häufigkeit der Messung, Verbesserung
Jetzt ist es immer noch sinnvoll, diese 1000 ms Temperaturabtastzeit in eine separate Variable aufzuteilen. Sagen wir:
Code: C / C++
Melde dich an, um den Code zu sehen

Eigentlich sollte dieser ganze Code umgeschrieben werden, vielleicht könnte man z. B. die Klasse Ticker verwenden, aber das vielleicht im nächsten Abschnitt.

Einblick in den vollständigen Code:
Code: C / C++
Melde dich an, um den Code zu sehen

Screenshot der Sammlung von Proben über einen längeren Zeitraum in einer leicht modifizierten Version des Programms:
Temperatur- und Luftfeuchtigkeitsdiagramm über die Zeit

Zusammenfassung
Ein sehr einfaches und nettes Projekt, genau richtig für den Anfang mit ESP. Wenn man die Anzahl der Abtastungen (man ist durch den Arbeitsspeicher begrenzt) und die Abtastrate richtig eingestellt hat, kann man schöne Diagramme mit Temperatur und Luftfeuchtigkeit der letzten Tage erstellen.
Natürlich ist dies nur ein kleines Beispiel und es können noch viele Verbesserungen vorgenommen werden, z. B:
- Ästhetik (Unterteilung des Diagramms in zwei, Einheiten usw.)
- Code (der bereits erwähnte Ticker wäre nützlich)
- Konfigurierbarkeit (es wäre möglich, Wi-Fi-Manager einzubinden, um zu vermeiden, dass wir unsere SSID und unser Passwort starr im Code eingeben müssen)
- es wäre auch nützlich, vor der ersten Messung zu prüfen, ob die Uhrzeit vom NTP bereits erfasst wurde, wenn nicht, die Messung überspringen.
Vielleicht werde ich das im nächsten Teil ansprechen, aber jetzt lade ich zum Kommentieren ein. Habt Ihr so ein oder ein ähnliches Projekt mit ESP durchgeführt? Oder ist vielleicht jemand versucht, den hier gezeigten Keim weiterzuentwickeln und in ein vollwertiges System zu verwandeln?

Über den Autor
p.kaczmarek2
p.kaczmarek2 hat 11793 Beiträge geschrieben mit der Bewertung 9913 , und dabei 563 Mal geholfen. Er ist seit 2014 bei uns.