Wie du deine eigene kleine DIY Wetterstation mit einem Wemos D1 Mini aufbaust, erfährst du in diesem Beitrag.
Ich habe dir bereits einige Projekte mit diversen Sensoren auf meinem Blog vorgestellt und auch einige kleine Projekte um die aktuelle Temperatur, den Luftdruck oder ähnliches anzeigen zu lassen. Dieses Mal soll es aber ganz anders werden.
Was soll diese Wetterstation alles können?
Die kleine Wetterstation soll dir folgende Werte anzeigen:
- die Temperatur,
- die rel. Luftfeuchtigkeit,
- den Luftdruck,
- die UV Intensität,
Und all das soll auf einem Dashboard im lokalen Netzwerk verfügbar sein.
Was wird für den Aufbau der DIY Wetterstation benötigt?
Für den Aufbau der DIY Wetterstation benötigst du einen Mikrocontroller mit WiFi Schnittstelle, einige Sensoren, einen Widerstand sowie diverse Breadboardkabel und ein großes Breadboard.
- einen Wemos D1 Mini*,
- ein Micro USB Datenkabel*,
- einen DHT11 Sensor*,
- einen BMP180 Sensor*,
- einen UV Sensor ML8511*,
Zunächst bauen wir die Schaltung auf einem Breadboard auf, damit können wir flexibel auf Änderungen eingehen. Daher benötigen wir noch zusätzlich:
- ein paar Breadboardkabel, 20cm, männlich – männlich*,
- ein 830 Pin Breadboard*
Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!
Aufbau der Schaltung
Nachfolgend zeige ich dir nun die Schaltung mit den oben aufgeführten Sensoren am Wemos D1 Mini.
Zuordnung der Pins
Sensor | Wemos D1 Mini |
---|---|
DHT11 | |
VCC | 5V |
GND | G – GND |
DATA | GPIO12 – D6 |
BMP180 | |
VCC | 3v3 |
GND | G – GND |
SCL | GPIO5 – SCL – D1 |
SDA | GPIO4 – SDA – D2 |
UV Sensor – ML8511 | |
VCC | 3v3 |
GND | G – GND |
OUT | A0 |
Programmieren des Sketches
Das Programm bzw. Sketch wird in der Arduino IDE programmiert. Jedoch benötigst du zunächst zwei zusätzliche Bibliotheken, welche du zunächst einbinden musst.
einbinden der benötigten Bibliotheken
Wie erwähnt benötigst du zwei Bibliotheken:
- DHT11 – RobTillaart DhtLib
- BMP180 – Adafruit BMP085 Unified
Wie du eine Bibliothek in die Arduino IDE einbindest habe ich dir im Beitrag Arduino IDE, Einbinden einer Bibliothek ausführlich erläutert.
erstellen des Programmes, Schritt für Schritt
Wenn die beiden Bibliotheken eingebunden wurden, so müssen diese im Sketch eingebunden werden. Für den UV Sensor wird keine zusätzliche Bibliothek benötigt da dieser „nur“ über einen analogen Pin ausgelesen wird. (Wertebereich von 0 bis 1023)
//Bibliothek zur Kommunikation mit dem DHT11 Sensor #include "DHT.h" //OneWire Bibliothek für den BMP180 Sensor #include <Wire.h> //Bibliothek zur Kommunikation mit dem BMP180 Sensor #include <BMP180.h>
Danach werden wir nun die 3 Sensoren definieren und die Objekte instanziieren.
Zunächst den DHT11 Sensor, da die eingebundene Bibliothek auch für den DHT22 sowie dem AM2320 funktioniert, müssen wir definieren, dass wir einen DHT11 Sensor angeschlossen haben und auslesen möchten.
//DHT11 Sensor am digitalen Pin D6 angeschlossen #define DHTPIN 12 //Festlegen welcher Typ von DHT Sensor verwendet wird. #define DHTTYPE DHT11 //Initialisieren des Sensors mit dem Anschluss und dem Typ DHT dht(DHTPIN, DHTTYPE);
Den UV Sensor haben wir am einzigen analogen Pin A0 des Wemos D1 Mini angeschlossen.
//UV Sensor am analogen Pin A0 angeschlossen #define UV_SENSOR A0
Der BMP180 wird per I²C angeschlossen, diese Pins sind im System bekannt und somit müssen diese nicht benannt werden. Jedoch muss das Objekt aus der Bibliothek instanziiert werden damit wir die Daten lesen können.
//Die Instanzvariable eines BMP180 Sensors. BMP180 barometer;
Am Schluss werden noch die Konstanten für den UV-Sensor definiert.
const float inMin = 0.99; const float inMax = 2.9; const float outMin = 0.0; const float outMax = 15.0; const byte numberOfReadings = 8;
In der Funktion „setup“ wird die serielle Kommunikation gestartet sowie die benötigten Pins der Sensoren auf INPUT gesetzt.
Zusätzlich starten wir auch die Kommunikation mit dem DHT11 Sensor und prüfen ob ein BMP180 Sensor verbunden ist. Wenn kein BMP180 Sensor verbunden ist, so wird eine Fehlermeldung auf der seriellen Schnittstelle ausgegeben.
void setup() { //beginn der seriellen Kommunikation mit 9600 Baud Serial.begin(9600); pinMode(DHTPIN, INPUT); pinMode(UV_SENSOR, INPUT); //DHT Kommunikation beginnen. dht.begin(); Wire.begin(); //Adafruit Wire Bibliothek für die I2C Kommunikation mit dem BMP180 Sensor. barometer = BMP180(); //setzen einer Instanz des BMP180 Sensors. //Prüfen ob ein BMP180 Sensor gefunden wurde. if (!barometer.EnsureConnected()) { Serial.println("Es wurde kein BMP180 Sensor gefunden."); } }
Die Daten der Sensoren werden in der Funktion „loop“ alle 2 Sekunden gelesen.
void loop() { delay(2000);
Zunächst lesen wir die Daten des DHT11 Sensors.
//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);
Als Nächstes prüfen wir nun ob korrekte Daten empfangen wurden und ob der BMP180 Sensor verfügbar ist. Sollte dieses nicht so sein, so wird die Funktion „loop“ an dieser Stelle durch ein „return“ verlassen.
//Prüfen ob die Werte erfolgreich gelesen wurden und der BMP180 Sensor verfügbar ist. if (isnan(luftfeuchtigkeit) || isnan(temperaturC) || isnan(temperaturF) || !barometer.IsConnected) { Serial.println("Fehler beim lesen von Daten."); return; }
Da die Daten des DHT11 Sensors vorliegen, geben wir diese auf der seriellen Schnittstelle aus.
Serial.print("Temperatur: "); Serial.print(temperaturC); Serial.print(" °C | "); Serial.print(temperaturF); Serial.println(" °F\t"); Serial.print("Luftfeuchtigkeit: "); Serial.print(luftfeuchtigkeit); Serial.println(" %\t");
Danach werden die Daten des verbundenen BMP180 Sensors gelesen und ebenfalls ausgegeben.
//Lesen des Wertes für den Luftdruck aus dem Sensor. long currentPressure = barometer.GetPressure(); Serial.print("Luftdruck: "); Serial.print(currentPressure / 100); Serial.println(" hPa");
Zum Schluss wird nun noch der UV-Sensor ausgelesen.
Als Erstes wird der analoge Wert ausgelesen (Wertebereich 0 bis 1023) dazu werden X Werte gelesen und durch die Anzahl geteilt.
Aus diesem gelesenen Wert berechnen wir nun Spannung. Dazu wird die 3v3 Spannung benötig, ein Problem ist hier meist das nicht genau 3,3V anliegen, sondern meistens deutlich darunter daher ist dieser Wert ziemlich ungenau.
Mit der Funktion „mapfloat“ setzen wir den Wert der Spannung in relation zum Wertebereich des Sensors.
int uvLevel = averageAnalogRead(UV_SENSOR); float outputVoltage = 3.3 * uvLevel / 1024; float uvIntensity = mapfloat(outputVoltage, inMin, inMax, outMin, outMax);
Funktion zum berechnen des Durchschnittswertes des Sensors.
int averageAnalogRead(int pinToRead) { unsigned int runningValue = 0; for (int x = 0 ; x < numberOfReadings ; x++) { runningValue += analogRead(pinToRead); } return (runningValue / numberOfReadings); }
Funktion „mapfloat“ aus dem Arduino Forum.
//Arduino map Funktion unterstützt kein Float daher wurde diese neu implementiert //(eine Kopie aus dem Arduino Forum) float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
das fertige Sketch für die Wemos D1 Mini – Wetterstation
//Bibliothek zur Kommunikation mit dem DHT11 Sensor #include "DHT.h" //OneWire Bibliothek für den BMP180 Sensor #include <Wire.h> //Bibliothek zur Kommunikation mit dem BMP180 Sensor #include <BMP180.h> //DHT11 Sensor am digitalen Pin D6 angeschlossen #define DHTPIN 12 //Festlegen welcher Typ von DHT Sensor verwendet wird. #define DHTTYPE DHT11 //Initialisieren des Sensors mit dem Anschluss und dem Typ DHT dht(DHTPIN, DHTTYPE); //UV Sensor am analogen Pin A0 angeschlossen #define UV_SENSOR A0 //Die Instanzvariable eines BMP180 Sensors. BMP180 barometer; const float inMin = 0.99; const float inMax = 2.9; const float outMin = 0.0; const float outMax = 15.0; const byte numberOfReadings = 8; void setup() { //beginn der seriellen Kommunikation mit 9600 Baud Serial.begin(9600); pinMode(DHTPIN, INPUT); pinMode(UV_SENSOR, INPUT); //DHT Kommunikation beginnen. dht.begin(); Wire.begin(); //Adafruit Wire Bibliothek für die I2C Kommunikation mit dem BMP180 Sensor. barometer = BMP180(); //setzen einer Instanz des BMP180 Sensors. //Prüfen ob ein BMP180 Sensor gefunden wurde. if (!barometer.EnsureConnected()) { Serial.println("Es wurde kein BMP180 Sensor gefunden."); } } void loop() { 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 und der BMP180 Sensor verfügbar ist. if (isnan(luftfeuchtigkeit) || isnan(temperaturC) || isnan(temperaturF) || !barometer.IsConnected) { Serial.println("Fehler beim lesen von Daten."); return; } Serial.print("Temperatur: "); Serial.print(temperaturC); Serial.print(" °C | "); Serial.print(temperaturF); Serial.println(" °F\t"); Serial.print("Luftfeuchtigkeit: "); Serial.print(luftfeuchtigkeit); Serial.println(" %\t"); //Lesen des Wertes für den Luftdruck aus dem Sensor. long currentPressure = barometer.GetPressure(); Serial.print("Luftdruck: "); Serial.print(currentPressure / 100); Serial.println(" hPa"); int uvLevel = averageAnalogRead(UV_SENSOR); float outputVoltage = 3.3 * uvLevel / 1024; float uvIntensity = mapfloat(outputVoltage, inMin, inMax, outMin, outMax); Serial.print("UV Intensität: "); Serial.print(uvIntensity); Serial.println(" mW/cm²"); Serial.println(); } //Funktion zum lesen des Durchschnittswertes eines Sensors am analogen Pin int averageAnalogRead(int pinToRead) { unsigned int runningValue = 0; for (int x = 0 ; x < numberOfReadings ; x++) { runningValue += analogRead(pinToRead); } return (runningValue / numberOfReadings); } //Arduino map Funktion unterstützt kein Float daher wurde diese neu implementiert //(eine Kopie aus dem Arduino Forum) float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
Ausgabe des Sketches auf der seriellen Schnittstelle:
Aufteilen des Sketches in Dateien
Damit das Programm in einem weiteren Beitrag wiederverwendet werden kann, möchte ich dieses in separate Dateien aufteilen. Dieses hat den Vorteil dass, das Programm deutlich lesbarer und Wartbarer wird. Des Weiteren können Änderungen leichter verfolgt werden.
Du kannst dir das fertige Programm auch als ZIP Datei herunterladen und somit diesen Schritt einfach überspringen.
erstellen einer zusätzlichen Datei in der Arduino IDE
Erstellen wir zunächst einen neuen Tab indem wir die Schaltfläche rechts in der IDE mit dem kleinen Pfeil nach unten betätigen.
In diesem neuen Kontextmenü wählen wir den Eintrag „Neuer Tab“ (siehe Grafik) aus.
Es wird dann ein gelber Bereich unterhalb des Editors für den Quellcode angezeigt. In diesem geben wir nun den Dateinamen ein, zbsp. „dht11.h“.
Dieses wiederholen wir für die Sensoren und dem Wifi Modul und zusätzlich für unsere Konfigurationsdatei.
- dht11.h
- bmp180.h
- uvSensor.h
- wifi.h
- config.h
DHT11 Sensor
Den Code für den DHT11 Sensor legen wir im Tab „dht11.h“ ab.
//Bibliothek zur Kommunikation mit dem DHT11 Sensor #include "DHT.h" //DHT11 Sensor am digitalen Pin D6 angeschlossen #define DHTPIN 12 //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 initDHTSensor() { pinMode(DHTPIN, INPUT); //DHT Kommunikation beginnen. dht.begin(); } double getDHTSensor_Humidity() { double hum = dht.readHumidity(); if (isDebug) { Serial.println("Luftfeuchtigkeit: " + String(hum, DEC) + " %"); } return hum; } double getDHTSensor_Temperature_Celsius() { double celsius = dht.readTemperature(); if (isDebug) { Serial.println("Temperatur: " + String(celsius, DEC) + " °C"); } return celsius; } double getDHTSensor_Temperature_Fahrenheit() { double fahrenheit = dht.readTemperature(true); if (isDebug) { Serial.println("Temperatur: " + String(fahrenheit, DEC) + " °F"); } return fahrenheit; }
BMP180
Der Code für den BMP180 Sensor legen wir im gleichnamigen Tab „bmp180.h“ ab.
//OneWire Bibliothek für den BMP180 Sensor #include <Wire.h> //Bibliothek zur Kommunikation mit dem BMP180 Sensor #include <BMP180.h> //Die Instanzvariable eines BMP180 Sensors. BMP180 barometer; void initBMP180() { Wire.begin(); //Adafruit Wire Bibliothek für die I2C Kommunikation mit dem BMP180 Sensor. barometer = BMP180(); //setzen einer Instanz des BMP180 Sensors. //Prüfen ob ein BMP180 Sensor gefunden wurde. if (!barometer.EnsureConnected()) { Serial.println("Es wurde kein BMP180 Sensor gefunden."); } } long getBMP180Value() { long currentPressure = barometer.GetPressure(); if (isDebug) { Serial.println("Luftdruck: " + String(currentPressure / 100, DEC) + " hPa"); } return currentPressure; }
UV-Sensor
Der Code und die Funktionen zum errechnen des UV – Wertes legen wir ebenfalls im Tab „uvSensor.h“ ab.
//UV Sensor am analogen Pin A0 angeschlossen #define UV_SENSOR A0 const float inMin = 0.99; const float inMax = 2.9; const float outMin = 0.0; const float outMax = 15.0; const byte numberOfReadings = 8; //Funktion zum lesen des Durchschnittswertes eines Sensors am analogen Pin int averageAnalogRead(int pinToRead) { unsigned int runningValue = 0; for (int x = 0 ; x < numberOfReadings ; x++) { runningValue += analogRead(pinToRead); } return (runningValue / numberOfReadings); } //Arduino map Funktion unterstützt kein Float daher wurde diese neu implementiert //(eine Kopie aus dem Arduino Forum) float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } void initUvSensor() { pinMode(UV_SENSOR, INPUT); } int getUVSensorValue() { int uvLevel = averageAnalogRead(UV_SENSOR); float outputVoltage = 3.3 * uvLevel / 1024; float uvIntensity = mapfloat(outputVoltage, inMin, inMax, outMin, outMax); Serial.print("UV Intensität: "); Serial.print(uvIntensity); Serial.println(" mW/cm²"); Serial.println(); return uvIntensity; }
WiFi Modul
Die WiFi Funktionen legen wir im Tab „wifi.h“ ab. Hier wird auch später die Funktion implementiert, um das Dashboard aufzubauen. Aber dazu später mehr.
#include <ESP8266WiFi.h> WiFiServer server(80); void initWifiModul() { Serial.println("Aufbau der Verbindung zu: " + String(ssid)); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("Mit " + String(ssid) + " erfolgreich verbunden!"); server.begin(); Serial.println("Server gestartet"); Serial.print("Adresse : http://"); Serial.println(WiFi.localIP()); }
Konfigurationsdatei
Für die spätere WiFi Verbindung benötigen wir noch zusätzlich eine Datei wo wir die Verbindungsdaten zum lokalen WLAN speichern wollen.
bool isDebug = true; const char* ssid = "FRITZBox7590GI24"; const char* password = "xzy";
Projekt zum Download
Hier nun das vorbereitete Projekt zum einfachen Download.
Hallo, vielen Dank! Ich musste zwar einiges anpassen da die Bibliotheken nicht 100% gepasst haben, habe es aber (seriell) geschafft.
Per ping ist der Wemos schon erreichbar.
Gibt es schon den nächsten Teil? Danke!
Gruß
Hi,
vielen Dank für dein Kommentar.
Der „Teil 2“ zu diesem Beitrag ist geplant, jedoch habe ich die Wetterstation neu designd und daher lässt dieser leider noch etwas auf sich warten.
Das neue Design findest du unter:
https://draeger-it.blog/diy-wetterstation-v2-0/
Zu dieser werde ich dann auch das Dashboard entwerfen, das ist natürlich auch kompatibel mit dem „alten“ Model.
Gruß
Stefan Draeger