Wettersensor mit ESP32 und BME280

Ich habe mein Projekt eines kleines Wettersensors nach den neuen Erfahrungen mit dem DeepSleep-Modus nochmal aufgegriffen. Ziel ist die Erfassung von Temperatur, Luftdruck und Feuchtigkeit über einen längeren Zeitraum.

Update vom 11.06.2024: Die kleinen S2mini sind bezüglich WLAN einfach zu unzuverlässig. Mal funktioniert es, – mal wieder nicht. Zwei Geräte hatte ich aufgebaut und selbst die verhielten sich noch unterschiedlich, aber leider nicht reproduzierbar. Ich habe die Sensoren jetzt stillgelegt und werde es in nächster Zeit mal mit anderen Boards ausprobieren. Bestellt sind sie schon.

Da der gesamte Sensor aufgrund des DeepSleeps des ESP32 keine Webseite mit den Daten bieten kann, muss eine neue Lösung her. Man könnte die Daten in eine Datei schreiben, die auf einem erreichbaren Computer liegt. Das könnte beispielsweise auch ein RaspberryPi sein. Wesentlich eleganter ist allerdings, die Daten in eine Datenbank zu schreiben. Damit kann man dann auch später wesentlich mehr anfangen und spart sich zudem den Aufwand eines Dateimangements. Datenbank hört sich erstmal komplex an, ist es aber eigentlich nicht. Es gibt diverse Pakete für den Raspi, die gleich eine SQL-Datenbank enthalten. In der Regel ist das die MariaDB. Da ich ständig ein NAS von QNAP laufen lasse, auf dem auch ein Webserver, unter anderem für diesen Blog, läuft, habe ich die Datenbank dort platziert. Ich nutze eine MariaDB in der Version 10. Gleich an dieser Stelle sei ein Tool erwähnt, das die Arbeit mit Datenbanken sehr erleichtert: HeidiSQL.

Die grundsätzliche Arbeit mit einer Datenbank kann ich hier nicht erklären, da es den Rahmen des Beitrages sprengen würde. Es gibt aber im Netz sehr viele Informationen dazu, – nicht zuletzt die Seite von HeidiSQL.

Erzeuge eine Datenbank (z.Bsp. sensorwetter)

Erstelle einen User nur für diese Datenbank mit allen Rechten

Erzeuge in der Datenbank eine Tabelle (z.Bsp. meldungen)

Erzeuge in der Tabelle folgende Spalten:

Ich habe mich dabei an diesem Beitrag orientiert, aber einige Erweiterungen und auch Änderungen vorgenommen. Beispielsweise habe ich die Datenfelder nicht als „float“ formatiert sondern als „varchar“, was darin begründet liegt, dass meine Übertragung nur Texte überträgt. Neben den eigentlichen Datenfeldern sollte unbedingt der „TimeStamp“ und ein „Sensorname“ benutzt werden. Damit hat man dann den zeitlichen Ablauf der Sensormeldungen im Griff und kann auch mehrere Sensoren in die Datenbank schreiben lassen.

Es wird Zeit sich darum zu kümmern, dass die Datenbank gefüllt wird. Rein prinzipiell wäre es möglich mit einem ESP32 direkt über WLAN in die Datenbank zu schreiben. Nach diversen Versuchen habe ich das aber aufgegeben und diverse Artikel und Anfragen im Netz haben meine Probleme bestätigt. Zumindest mein ESP32, nämlich ein LOLIN S2mini, scheint wohl Probleme mit der entstehenden Datenmenge zu haben. Irgendwie mag das in den Griff zu kriegen sein, – aber wie? … und ist es den Aufwand wert? Die Lösung ist recht einfach, auch wenn sie einen aktiven Webserver verlangt, der aber auch mit einem Raspi leicht umsetzbar ist. Auf dem Webserver benötigt man eine php-Datei, die die Daten vom ESP32 annimmt und den in die Datenbank schreibt:

<?php

if(isset($_GET["Temperature"])) { //mindestens die Temperatur muss übergeben werden
$temperature = $_GET["Temperature"]; // get temperature value from HTTP GET
$humidity = $_GET["Humidity"];
$pressure = $_GET["Pressure"];
$sensorname = $_GET["Sensorname"]; // Hinweis: Sobald Buchstaben im Übergabestring vorkommen müssen ' ' gesetzt werden: http://IP des Servers/PHP/Sensorwetter.php?temperature=32&humidity=54&pressure=76&sensorname='BME280'

$servername = "IP der Datenbank"; // Beispiel: $servername = "192.168.8.46";
$username = "UserID für Datenbank";
$password = "Password für Datenbank";
$database_name = "sensorwetter";

// Create MySQL connection fom PHP to MySQL server
$connection = new mysqli($servername, $username, $password, $database_name);
// Check connection
if ($connection->connect_error) {
die("MySQL connection failed: " . $connection->connect_error);
}

$sql = "INSERT INTO meldungen (Temperature, Humidity, Pressure, Sensorname) VALUES ($temperature, $humidity, $pressure, $sensorname)";

if ($connection->query($sql) === TRUE) {
echo "New record created successfully";
}
else {
echo "Error: " . $sql . " => " . $connection->error;
}

$connection->close();
}
else {
echo "temperature is not set in the HTTP request";
}
?>

Ich arbeite mit der GET-Methode. Denkbar wäre auch die POST-Methode. Da ich aber schon aus Testzwecken die Übergabe als Internetlink ermöglichen wollte, ist nur die GET-Methode sinnvoll. Erläuterungen gibt es beispielsweise hier. Ist dieses File mit der Endung „.php“ erzeugt, kann es dann auch gleich in Verbindung mit der Datenbank getestet werden. Bei mir liegt die Datei in einem Verzeichnis „PHP“. Sollte das bei Dir anders sein, musst Du das anpassen:

http://IP des Servers/PHP/Sensorwetter.php?temperature=32&humidity=54&pressure=76&sensorname='BME280'

Die ganze Zeile (natürlich mit eingesetzter eigener IP) wird so in einem Internetbrowser eingegeben und sollte die Erfolgsmeldung „New record created successfully“ als Antwort ausgeben. Außerdem kann man den erzeugten Datensatz in der Datenbank sehen:

Wenn das nicht absolut sicher funktioniert, lohnt es sich nicht weiterzumachen !!!

Nachdem der Nachweis erbracht ist, dass unsere PHP-Datei die Datenbank in richtiger Weise befüllen kann, geht es weiter mit dem Sketch für den ESP32. Da wir aber bisher noch gar keinen BME280 an unseren LOLIN S2mini angebracht haben, sei auch dies noch kurz angerissen. 

Den BME280 gibt es in zwei Ausführungen, die sich in der verwendeten Versorgungsspannung unterscheiden. Der eine nimmt 3,3V, was auch der Versorgungsspannung des eigentlich verbauten Sensors entspricht. Eine weitere Variante wird mit einer Versorgungsspannung von 5V angeboten, bei der dann über einen Spannungswandler die überschüssigen 1,7V verheizt werden. Ich empfehle die 3,3V-Version:

Da der Lolin (WEMOS) S2mini einen 3,3V-Anschluss hat, funktioniert das problemlos. Die Verdrahtung zwischen dem S2mini und dem Sensor ist einfach. Neben der Versorgungsspannung, die deutlich auf dem BME mit VCC und auf dem S2mini mit 3V3 und dem ebenfalls auf beiden Platinen mit GND bezeichneten Anschluss sind noch zwei Datenleitungen SDA  zu PIN 33 und SCL zu PIN 35 zu legen. Folgendes Bild sollte alle Unklarheiten beseitigen.

Für den ersten Versuchsaufbau reicht das auch schon an Verdrahtung.

Jetzt kommen wir zum Sketch, der Software, für den S2mini, den ich hier zunächst in Abschnitten beschreiben will.

#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_BME280.h> //Einbinden der Bibliothek des Sensors

#define sleeptime 600 //Schlafzeit in Sekunden = 10 Minuten

#define led 15 //BUILD_IN LED am Pin 15
#define sensor_address 0x76 // Adafruit devices use 0x77 all others use 0x76

Adafruit_BME280 bme; // Für die Kommunikation mittels I2C
WiFiClient client;
String textfeld;

String serverName = "http://eigene IP/PHP/Sensorwetter.php";
// Webserver mit PHP-Datei

String Sensorname = "BME280-02"; // Sensorkennzeichen, freie Bezeichnung

float temperature = 0;
float humidity = 0;
float pressure = 0;

Es geht los mit den Headerdateien, die die benutzen Funktionen und Definitionen bereitstellen. Sie müsse in der Arduino IDE über die Bibliotheksfunktion eingebunden werden, bevor der Sketch kompiliert wird.

Ein paar Defines werden dafür gebraucht, dass man bestimmte Parameter auch später noch leicht identifizieren und anpassen kann. Ähnlich sind die beiden Stringvariablen zu erklären. Ersterer zum Servernamen bezeichnet den Weg zur PHP-Datei. Der Sensorname hingegen ermöglich die Individualisierung einzelner Sensoren. Die Deklarationen bme und client stellen Strukturen für den Datenverkehr bereit.

void setup() {
Serial.begin(115200); // serielle Kommunikation starten

pinMode(led, OUTPUT); //definieren das der Pin der LED als Ausgang dient

digitalWrite(led, HIGH); //aktivieren der LED

delay(1000); // 1 Sekunde Warten

if (!bme.begin(sensor_address)) { // Überprüfung ob der Sensor angeschlossen ist, alternative Adresse ist 0x75
Serial.println("BME280 nicht gefunden!");
while (1);
}
}

void setup() ist ein Standardabschnitt in einem Sketch. Hier werden grundlegende Arbeiten erledigt, die üblicherweise nur einmalig laufen. Da wir den ESP32 aber nach jedem Durchlauf schlafenlegen, wird beim Neustart auch die setup-Routine erneut durchlaufen. Es beginnt mit der Baudrate der seriellen Kommunikation, die für das Debugging recht hilfreich ist. Auch die blaue OnBoardLED wird genutzt um die Aktivität des Sensors anzuzeigen. Die if-Schleife testet, ob ein BME280 angeschlossen ist. Bestimmte Sensoren verlangen eine andere Adresse als die oben gewählte 0x76.

void loop(){
temperature = bme.readTemperature();
humidity = bme.readHumidity();
pressure = bme.readPressure() / 100.0F;

Serial.println("Verbindung zum Netzwerk wird aufgebaut"); // Einbinden ins Heimnetzwerk
WiFi.begin("eigene SSID", "dazugehöriges Password"); // Name und Password des Netzwerks
while (WiFi.status() != WL_CONNECTED) { // Einfache Statusanzeige
delay(500);
Serial.print(".");
}

Serial.println("Erfolgreich verbunden - IP Addresse:"); // IP Adresse zum Verbinden anzeigen
Serial.println(WiFi.localIP());

HTTPClient http;

Die loop()-Routine wird eigentlich immer wieder ausgeführt. Wie oben erwähnt, funktioniert das aber aufgrund der Schlafperioden unsere ESP32 etwas anders. Trotzdem wird der Abschnitt standardmäßig vom Kompiler erwartet.

Es beginnt mit dem Einlesen der Wetterdaten in eigene Variablen. Die dazu verwendeten Funktionen stammen aus der includierten Headerdatei <Adafruit_BME280.h>. Unter Anwendung der eigenen Zugangsdaten für das eigene WLAN wird eine Verbindung aufgebaut. Das wird auch entsprechend über die serielle Schnittstelle kommentiert. Solange die Verbindung noch nicht steht, geht es nicht weiter. Die IP-Adresse des ESP32 wird ausgegeben. Zum Schluss wird noch eine weitere notwendige Struktur „http“ erzeugt.

String httpRequestData = serverName + "?"
+ "Temperature=" + temperature
+ "&Humidity=" + humidity
+ "&Pressure=" + pressure
+ "&Sensorname=" + "'" + Sensorname + "'";


http.begin(httpRequestData.c_str()); //HTTP


Serial.print("httpRequestData: ");
Serial.println(httpRequestData);

int httpResponseCode = http.GET();

if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
String payload = http.getString();
Serial.println(payload);
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();

WiFi.disconnect();

Genau wie auf die Internetbrowserzeile weiter oben beschrieben, wird ein Übergabestring „zusammengebastelt“. Ganz wichtig: Der Sensorname muss in einfachen Anführungszeichen stehen!! Mit http.begin wird die Zeile an die php-Datei gesendet.

Ausschließlich zu Debuggingzwecken wird die übergebende Zeile über Seriell ausgegeben. Es gibt natürlich von der php-Datei eine Antwort, – das hatten wir ja schon beim Test über die Browserzeile gesehen. Dieser Rückgabecode wird ausgewertet und auch per serieller Schnittstelle angezeigt.

Nachdem die Kommunikation erledigt ist, werden die Verbindungen getrennt.

  Serial.println("Going to sleep...");
Serial.flush();

BME280_Sleep(sensor_address); // BME280 into sleep mode

esp_sleep_enable_timer_wakeup(sleeptime * 1000000); //ESP-Board soll schlafen und nach 5s aufwachen
esp_deep_sleep_start(); //Aktivierung Schlafzyklus
}

Die Initialisierung des Schlafmodus hatte ich ja schon im vorherigen Beitrag beschrieben. Aber eine Zeile ist hier neu: BME280_Sleep. Der BME280 kann nämlich auch Schlafen und dadurch Strom sparen. Die dazu notwendige Steuerung fand ich hier.

void BME280_Sleep(int device_address) {
const uint8_t CTRL_MEAS_REG = 0xF4;

/* Quelle: https://github.com/G6EJD/BME280-Sleep-and-Address-change/blob/master/BME280_Sleep_v2.ino */

// BME280 Register 0xF4 (control measurement register) sets the device mode, specifically bits 1,0
// The bit positions are called 'mode[1:0]'. See datasheet Table 25 and Paragraph 3.3 for more detail.
// Mode[1:0] Mode
// 00 'Sleep' mode
// 01 / 10 'Forced' mode, use either '01' or '10'
// 11 'Normal' mode
Serial.println("BME280 to Sleep mode...");
Wire.beginTransmission(device_address);
Wire.requestFrom(device_address, 1);
uint8_t value = Wire.read();
value = (value & 0xFC) + 0x00; // Clear bits 1 and 0
Wire.write((uint8_t)CTRL_MEAS_REG); // Select Control Measurement Register
Wire.write((uint8_t)value); // Send 'XXXXXX00' for Sleep mode
Wire.endTransmission();
}

Diese gesamte Funktion habe ich direkt unverändert übernommen.

Die oben gezeigten Abschnitte müssen in gleicher Reihenfolge in einen neuen Sketch in der Arduino IDE übernommen werden. Die persönlichen Daten sind anzupassen und dann kann der S2mini per USB angeschlossen werden und mit dem kompilierten Sketch versorgt werden. Dazu siehe auch den vorherigen Beitrag an. Wenn alles richtig läuft, sollte es im seriellen Monitor der ArduinoIDE so aussehen:

Jetzt ist es natürlich nicht so schön, dass unser neuer Sensor immer an USB hängen muss. Mit einer Batterieversorgung wäre das schon besser. … und noch besser wäre es, wenn man die Batterie bequem laden könnte. Geht alles! Als Batterie nimmt man am besten eine 18650 mit Lötfahnen. Ohne Lötfahnen muss man sich ggfls. eine Batterieschale dazunehmen, was die ganze Sache noch vergrößert.

Einen passenden Ladecontroller findet man hier. Vorsicht, da gibt es diverse Typen. Es sollte schon genau dieser sein!

Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Für den Käufer ändert sich der Preis dadurch nicht.

Akku und Ladecontroller können über nur 4 Drähte mit dem ESP32 verbunden werden. Zwischen 5V und ESP32 VBUS habe ich einen Schiebeschalter gesetzt um den Sensor auch mal abschalten zu können:

Der Akku wird über den MikroUSB-Anschluss des Ladecontrollers geladen und zeigt dabei eine rote LED. Ist der Akku voll, wechselt die LED auf grün.

Niemals darf die USB-Buchse des ESP32 und gleichzeitig die Stromversorgung über den Akku aktiv sein! Also immer den Schalter öffnen, wenn man dem ESP32 einen neuen Sketch verpasst.

Der ganze Aufbau lässt sich wunderbar in ein kleines Gehäuse einbauen, das ich für diesen Zweck konstruiert habe.

Links vorn ist der Zugang zur Ladebuchse. Rechts vorn sieht man das Fenster für den Sensor. Auf der Rückseite ist der Schalter verbaut. Die Verschraubungen für den Deckel und für die ESP-Platine sind mit Einpressgewinden bestückt. Der Sensor BME280 ist nur eingeklemmt. Batterie und Ladecontroller sind mit etwas Heißkleber fixiert.

Wer die Druckdateien für das Gehäuse haben will, darf sich gern bei mir melden. Über 5€ Beitrag würde ich mich freuen. Wer das Gehäuse fertig mit Einpressgewinden, Schrauben und Schalter haben möchte, kann es für 15€ inkl. Versand erwerben (ohne Elektronikkomponenten!).

Ich lasse jetzt schon seit Stunden zwei Sensoren alle 10 Minuten Daten an die Datenbank schicken, was bei guter WLAN-Abdeckung hervorragend funktioniert. Wie lange der Akku durchhält, vermag ich noch nich zu sagen. Ich werde es mal bei Gelegenheit nachtragen.

Ein kleines PHP-Skript (showDataSensorwetter.php) ist nützlich um die Daten aufzulisten:

<!DOCTYPE html>
<html><body>
<?php
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-mysql-database-php/

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
/* einige Anpassungen wurden durch Thomas Sturm vorgenommen */

$servername = "IP der Datenbank";
$username = "UserID";
$password = "PW";
$database_name = "sensorwetter";
$table_name = "meldungen";


$conn = new mysqli($servername, $username, $password, $database_name); // Create connection
if ($conn->connect_error) { // Check connection
die("Connection failed: " . $conn->connect_error);
}

$sql = "SELECT ID, TimeStamp, Temperature,Humidity,Pressure,Sensorname FROM meldungen ORDER BY ID DESC";
echo '<table cellspacing="5" cellpadding="5">
<tr>
<td>ID</td>
<td>TimeStamp</td>
<td>Temperature</td>
<td>Humidity</td>
<td>Pressure</td>
<td>Sensorname</td>
</tr>';

if ($result = $conn->query($sql)) {
while ($row = $result->fetch_assoc()) {
$row_ID = $row["ID"];
$row_TimeStamp = $row["TimeStamp"];
$row_Temperature = $row["Temperature"];
$row_Humidity = $row["Humidity"];
$row_Pressure = $row["Pressure"];
$row_Sensorname = $row["Sensorname"];
// Uncomment to set timezone to - 1 hour (you can change 1 to any number)
//$row_reading_time = date("Y-m-d H:i:s", strtotime("$row_reading_time - 1 hours"));

// Uncomment to set timezone to + 4 hours (you can change 4 to any number)
//$row_reading_time = date("Y-m-d H:i:s", strtotime("$row_reading_time + 4 hours"));

echo '<tr>
<td>' . $row_ID . '</td>
<td>' . $row_TimeStamp . '</td>
<td>' . $row_Temperature . '</td>
<td>' . $row_Humidity . '</td>
<td>' . $row_Pressure . '</td>
<td>' . $row_Sensorname . '</td>
</tr>';
}
$result->free();
}

$conn->close();
?>
</table>
</body>
</html>

Noch ein kleiner Nachtrag:

Die ESP32 LOLIN S2mini haben eine grottenschlechte Qualität. Sehr oft funktiniert das WLAN gar nicht oder nur sporadisch. Ob das Original von WEMOS besser ist? Ich weiß es nicht.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments