TensorFlow-gestützte IoT-Wetterstation sagt Niederschlagsintensität präzise voraus
Komponenten und Materialien
| DFRobot Wetterstationen-Set (Anemometer, Windfahne, Regenmesser) | 1 |
| NodeMCU ESP8266 Breakout (ESP-12E) | 1 |
| DFRobot SIM808 GPS/GPRS/GSM Shield für Arduino | 1 |
| Arduino UNO | 1 |
| Raspberry Pi 3 Model B+ (oder 4) | 1 |
| Lötbares Mini-Breadboard | 2 |
Benötigte Werkzeuge
- Heißklebepistole
Apps und Online-Dienste
- Arduino IDE
- TensorFlow
- Microsoft Visual Studio 2017 (für PHP-Webanwendung)
Projektmotivation
Starkregenereignisse nehmen durch den Klimawandel zu und verursachen massive Schäden in der Landwirtschaft (Ernteverluste bis 34 % bei Mais, vergleichbar mit Dürre). Bestehende Warnsysteme reichen ohne lokale, hochaufgelöste Daten nicht aus. Dieses Projekt liefert eine kostengünstige, remote Wetterstation, die lokale Wetterdaten sammelt und per neuronalem Netz (ANN) die Niederschlagsintensität klassifiziert.
Gefahren durch Starkregen: Überschwemmungen, Gebäudeschäden, Ernte-/Viehverluste, Erdrutsche.
Studien belegen: Neuronale Netze eignen sich hervorragend für kurzfristige Niederschlagsvorhersagen (1–3 h) und sogar Tornado-/Nebelvorhersage.
Systemarchitektur
Wetterstation (DFRobot Kit) sendet Daten an zwei Entwicklungsboards:
- NodeMCU ESP-12E (WiFi) – für Balkon/nahe Router.
- Arduino Uno + SIM808 Shield (GPRS) – für entfernte Standorte (Garten).
Daten werden via PHP-Webanwendung (auf Raspberry Pi) in Google Sheets gespeichert. Nach >3 Monaten Datensammlung (alle 5 Min.) wird ein ANN mit TensorFlow/Keras trainiert.
Schritt 1: Wetterstation zusammenbauen
Das DFRobot-Set (Anemometer, Windfahne, Regenmesser, Sensorboard) ist einfach zu montieren:
- Anemometer & Windfahne mit Schrauben an Brücke befestigen.
- Windfahne per RJ11-Kabel mit Anemometer verbinden.
- Edelstahlstange an Brücke schrauben.
- Regenmesser-Unterteil montieren.
- Regenmesser auf Stange setzen.
Sensorboard ist nicht wetterfest → Kunststoffbox als Schutzgehäuse für Board + SIM808-Shield.
Datenformat (37 Bytes/s, CR/LF Ende):
c000s000g000t086r000p000h53b10020
c000: Windrichtung (Grad)s000: mittlere Windgeschwindigkeit (0,1 mph)g000: max. Windgeschwindigkeit (0,1 mph)t086: Temperatur (°F)r000: Regen 1 h (0,01 Zoll)p000: Regen 24 h (0,01 Zoll)h53: Luftfeuchte % (00 = 100 %)b10020: Luftdruck (0,1 hPa)
Schritt 2: Daten in Google Sheets sammeln
2.1 Google Sheets API einrichten
- Google Developer Console → Neues Projekt „Remote Weather Station“.
- APIs & Services → Google Sheets API aktivieren.
- Credentials → Service Account + Key erstellen.
- OAuth Consent Screen konfigurieren → OAuth Client ID (Desktop App) erstellen →
credentials.jsonherunterladen.
2.2 Spreadsheet anlegen
- Google Sheets → Blanko-Tabelle „Remote Weather Station“.
- Spaltenköpfe (Zeile 1):
WD, Av_WS, Mx_WS, 1h_RF, 24h_RF, Tem, Hum, b_PR. - Optional: Diagramm für Live-Ansicht erstellen.
Schritt 3: PHP-Webanwendung (Daten → Google Sheets)
Läuft auf Raspberry Pi (LAMP) oder beliebigem PHP-Server. Benötigt Google Client Library for PHP.
Ordner remote_weather_station mit vier Dateien:
index.php– Hauptlogik (HTTP GET empfangen, an Sheets anhängen).account_verification_token.php– Verifizierungscode für OAuth.credentials.json(aus Schritt 2.1).token.json(wird nach erster Autorisierung automatisch erzeugt).
index.php (Kernlogik)
<?php
require_once $_SERVER['DOCUMENT_ROOT']."google-api-php-client-2.4.1/vendor/autoload.php";
require_once "account_verification_token.php";
// 1. Wetterdaten per GET empfangen
$variables_from_module;
if (isset($_GET['wd']) && isset($_GET['a_ws']) && isset($_GET['m_ws']) &&
isset($_GET['1_rf']) && isset($_GET['24_rf']) && isset($_GET['tem']) &&
isset($_GET['hum']) && isset($_GET['b_pr'])) {
$variables_from_module = [
"wd" => (int)$_GET['wd'], "a_ws" => (float)$_GET['a_ws'],
"m_ws" => (float)$_GET['m_ws'], "1_rf" => (float)$_GET['1_rf'],
"24_rf" => (float)$_GET['24_rf'], "tem" => (float)$_GET['tem'],
"hum" => (int)$_GET['hum'], "b_pr" => (float)$_GET['b_pr']
];
} else {
$variables_from_module = array_fill_keys(["wd","a_ws","m_ws","1_rf","24_rf","tem","hum","b_pr"], "err");
}
// 2. Google Client konfigurieren
$client = new Google_Client();
$client->setApplicationName('Remote Weather Station');
$client->setScopes('https://www.googleapis.com/auth/spreadsheets');
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
// 3. Token laden / erneuern
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
print("Token Found!");
}
if ($client->isAccessTokenExpired()) {
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
$authUrl = $client->createAuthUrl();
print("Open: <br><br>$authUrl<br><br>");
$authCode = trim($GLOBALS['account_verification_token']);
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
if (array_key_exists('error', $accessToken)) throw new Exception(join(', ', $accessToken));
else print("Successful! Refresh the page.");
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
// 4. An Spreadsheet anhängen
$service = new Google_Service_Sheets($client);
$spreadsheetId = '<spreadsheet_ID>'; // Aus Sheet-URL entnehmen
$range = 'A1:H1';
$values = [[
$variables_from_module["wd"], $variables_from_module["a_ws"],
$variables_from_module["m_ws"], $variables_from_module["1_rf"],
$variables_from_module["24_rf"], $variables_from_module["tem"],
$variables_from_module["hum"], $variables_from_module["b_pr"]
]];
$body = new Google_Service_Sheets_ValueRange(['values' => $values]);
$params = ['valueInputOption' => "RAW"];
if ($variables_from_module["wd"] !== "err") {
$result = $service->spreadsheets_values->append($spreadsheetId, $range, $body, $params);
printf("<br><br>%d cells appended.", $result->getUpdates()->getUpdatedCells());
} else { print("<br>Missing Data!"); }
account_verification_token.php
<?php $account_verification_token = "<Enter Token>"; ?>
3.1 Auf Raspberry Pi deployen
- Ordner nach
/var/www/html/verschieben (sudo mv ...). - Erster Aufruf im Browser → Fehler (fehlender Token).
- Generierten Auth-Link öffnen → „Go to Remote Weather Station (unsafe)“ → Berechtigungen gewähren.
- Verifizierungscode kopieren → in
account_verification_token.phpeintragen. - Seite neu laden → „Successful! Refresh the page.“ →
token.jsonwird gespeichert. - Test:
https://localhost/remote_weather_station/?wd=12&a_ws=8&m_ws=11&1_rf=14&24_rf=84&tem=24&hum=32&b_pr=57→ 8 Zellen angehängt.
Schritt 4: Wetterdaten senden – ESP8266 (WiFi)
NodeMCU ESP-12E sendet alle 5 Min. an PHP-Endpunkt.
Code-Highlights
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266HTTPClient.h> #include <SoftwareSerial.h>
const char *ssid = "<SSID>"; const char *password = "<PASSWORD>";
SoftwareSerial Serial_1(D6, D5); // RX, TX zum Sensorboard
char databuffer[35]; double temp; int transferring = 0;
void getBuffer() { /* 35 Bytes einlesen, Start 'c' prüfen */ }
String weather_data = "wd=" + String(WindDirection()) + "&a_ws=" + String(WindSpeedAverage()) +
"&m_ws=" + String(WindSpeedMax()) + "&1_rf=" + String(RainfallOneHour()) +
"&24_rf=" + String(RainfallOneDay()) + "&tem=" + String(Temperature()) +
"&hum=" + String(Humidity()) + "&b_pr=" + String(BarPressure());
String server = "https://192.168.1.24/remote_weather_station/?";
// Im Loop: alle 300 s HTTP GET
if (++transferring == 300) {
HTTPClient http; http.begin(server + weather_data);
int httpCode = http.GET(); String payload = http.getString();
Serial.println("HTTP Code => " + String(httpCode) + " Response => " + payload);
http.end(); transferring = 0;
}
delay(1000);
Parser-Funktionen (Auszug):
int transCharToInt(char* buf, int start, int stop) { /* ASCII-Ziffern → int */ }
int WindDirection() { return transCharToInt(databuffer,1,3); }
float WindSpeedAverage() { return 0.44704 * transCharToInt(databuffer,5,7); } // m/s
float WindSpeedMax() { return 0.44704 * transCharToInt(databuffer,9,11); }
float Temperature() { return (transCharToInt(databuffer,13,15) - 32.0) * 5.0/9.0; } // °C
float RainfallOneHour() { return transCharToInt(databuffer,17,19) * 25.4 * 0.01; } // mm
float RainfallOneDay() { return transCharToInt(databuffer,21,23) * 25.4 * 0.01; }
int Humidity() { return transCharToInt(databuffer,25,26); }
float BarPressure() { return transCharToInt(databuffer,28,32) / 10.0; } // hPa
Schritt 4.1: Wetterdaten senden – SIM808 (GPRS)
Arduino Uno + SIM808 Shield für entfernten Standort. Code weitgehend identisch, Unterschiede:
- Bibliothek
DFRobot_sim808.h. - TCP-Verbindung zu Server (Port 80), HTTP/1.0 GET Request per
sim808.send(). - DHCP-Join (
cmnet), TCP-Connect, Senden, Empfangen, Close, Disconnect. - Externe 7–23 V Batterie für SIM808 nötig. GPS/GSM-Antennen, SIM-Karte, Function-Switch (None→Arduino), Boot-Button drücken bis Net-LED 1 Hz blinkt, dann 3 Hz (Netz registriert).
Schritt 4.2: Datensatz über >3 Monate
Gesammelte Parameter (32219 Zeilen): Windrichtung, ø/max Windgeschwindigkeit, Regen 1 h/24 h, Temperatur, Feuchte, Luftdruck. CSV-Export: Remote Weather Station.csv.
Schritt 5: ANN mit TensorFlow/Keras trainieren
Python-Skript IoT_weather_station_neural_network.py (vollständig unten). Schritte:
- Datenvisualisierung (Matplotlib): Histogramme jedes Sensors vs. 1-h-Regen.
- Skalierung/Normalisierung:
- Windrichtung + Geschwindigkeit → Windvektor (X/Y-Komponenten via cos/sin), da 360°/0° zyklisch.
- Temperatur / 25, Feuchte / 70, Druck / 1013, 24-h-Regen / 24.
- Label-Erzeugung aus approx. Regenrate = (1h_RF + scaled_24h_RF) × 100:
- 0: Kein Regen
- 1: Leichter Regen (< 2,5 mm/h)
- 2: Mäßiger Regen (2,5–7,6 mm/h)
- 3: Starker Regen (7,6–50 mm/h)
- 4: Heftiger Regen (> 50 mm/h)
- Features: 7 skalierte Werte
[scaled_WX, scaled_WY, scaled_max_WX, scaled_max_WY, scaled_Tem, scaled_Hum, scaled_bPR]. - Split: 60 % Training, 40 % Test.
- Modellarchitektur: Input(7) → Dense(16, ReLU) → Dense(32, ReLU) → Dense(64, ReLU) → Dense(128, ReLU) → Dense(5, Softmax).
- Training: Optimizer Adam, Loss sparse_categorical_crossentropy, 19 Epochen. Train-Accuracy 0,83–0,85.
- Evaluation: Test-Accuracy 0,72–0,73 (Overfitting durch noch kleinen Datensatz). Weitere Datensammlung läuft.
- Vorhersage:
model.predict()→argmax()für Klassenindex.
Beispiel-Vorhersagen
| Eingabe (7 Features) | Klasse | Bedeutung |
|---|---|---|
| [0, 0, 0.318, 0.318, 0.699, 0.815, 0.993] | 0 | Kein Regen |
| [0, -0, 0, -0, 0.844, 1.0, 0.968] | 3 | Starker Regen |
| [0, 0, 0.45, 0, 0.876, 0.959, 1.001] | 4 | Heftiger Regen |
| [-0, -0, -0, -0, 0.822, 1.057, 0.993] | 4 | Heftiger Regen |
Verkabelung
ESP8266
NodeMCU ESP-12E : Weather Station
VV (5V) --------- 5V
D5 -------------- RX
D6 -------------- TX
G --------------- GND
SIM808 + Arduino Uno
Arduino Uno: SIM808 Shield
D0 ------------ RX
D1 ------------ TX
D12 ----------- POWER
Weather Station:
5V ------------ 5V
D5 ------------ RX
D6 ------------ TX
GND ----------- GND
Hinweise: D0/D1/D12 durch Shield belegt. Externe 7–23 V für SIM808. Antennen, SIM, Function-Switch (1→3), Boot-Button.
Fazit & Ausblick
Nach >3 Monaten Datensammlung funktioniert das Modell als Ausgangsbasis. Weitere Datensammlung läuft. Potenzial:
- Schwarm von Stationen auf Farmen/Gewächshäusern für lokale Frühwarnung.
- Datenaustausch zwischen Stationen (Schwarm-Intelligenz).
- Anwendung: Wasserressourcen, Ertragssicherung, Ökosysteme, Hydrologie.
Referenzen
- NIWA: Extreme weather – heavy rainfall.
- Univ. Illinois: Excessive rainfall as damaging to corn yield as extreme heat, drought (ScienceDaily, 2019).
- Andrew Culclasure: Using Neural Networks to Provide Local Weather Forecasts, Georgia Southern Univ., 2013.
Code-Dateien (GitHub / Projektseite)
IoT_weather_station_neural_network.py(Python/TensorFlow)ESP12E_remote_weather_station.ino(Arduino/ESP8266)SIM808_remote_weather_station.ino(Arduino/SIM808)index.php&account_verification_token.php(Web-App)
Alle Dateien im Repository: Projektseite / GitHub.
Schaltpläne
Custom Parts
CSV-Datensatz: remote_weather_station_OobOCQNPSW.csv
Herstellungsprozess
- DIY Solar-betriebene Wetterstation mit Raspberry Pi
- Outdoor-Wetterstation mit Raspberry Pi 2 & ADS-WS1 bauen
- Raspberry Pi Wetterstation bauen, die tägliche Wetterdaten per E-Mail sendet
- Einsteiger IoT Tutorial: Temperaturdaten vom Raspberry Pi streamen
- Remote-Wetterüberwachung mit Raspberry Pi 3 & PubNub
- Wetterstation mit CWOP integrieren: Praktischer Leitfaden
- IoT mit Java ME 8 auf Raspberry Pi: Teil 1 – GPIO Sensor-Integration
- Raspberry Pi 3 mit DHT11 verbinden und Daten an ThingsIo.ai Cloud hochladen
- Adafruit 10DOF IMU Daten von Raspberry Pi 2 an Azure Event Hubs senden (Windows 10 IoT Core)
- Fortgeschrittene Wetterstation v2.0: Echtzeit Temperatur, Druck, Feuchte & Höhe Monitoring