Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Präzise Regenvorhersage: Arduino-Wetterstation mit Python & Keras selbst bauen

Komponenten und Materialien

Kleines Kunststoffgehäuse mit abnehmbarem Deckel (geschraubt), ca. 11×7×5 cm 1
3× AAA-Batteriehalter 1
3× AAA-NiMH-Akkus (wiederaufladbar) 1
6 V Solarmodul (klein) 1
SparkFun Arduino Pro Mini 328 – 5 V/16 MHz 1
Diode 1N4004 (Rückstromsperre Solarmodul → Akku) 1
NPN-Transistor (Allzweck) + 1 kΩ Widerstand (Leistungsschaltung für Sensoren) 1
Regensensor 1
HC-12 Funkmodul (Seriell, 433 MHz) 1
HC-12 USB-Seriell-Modul (Basisstation) 1
SparkFun BME280 Breakout (Luftfeuchte, Temperatur, Druck) 1
BH1750 Lichtsensor 1
PCB, Kabel, Lötzinn, KF301-2P Schraubklemmen, Steckverbinder, Kleber 1
3,3 V Spannungsregler 1

Benötigte Werkzeuge

Projektüberblick

Ziel: Vorhersage, ob es in den nächsten 6 Stunden regnet (Ja/Nein). Der komplette Weg:

  1. Wetterstation bauen – netzunabhängig (Solar), Extrem-Stromsparmodus (wenige µA).
  2. Firmware programmieren – alle 10 Min. Sensordaten an Basisstation senden.
  3. Daten sammeln – auf Basisstation (Linux-PC/Board) in Datenbank speichern.
  4. Daten aufbereiten & Modell trainieren – Python, Pandas, Keras (Neuronales Netz).
  5. Vorhersage & Benachrichtigung – E-Mail bei Regenwahrscheinlichkeit.
Präzise Regenvorhersage: Arduino-Wetterstation mit Python & Keras selbst bauen
Präzise Regenvorhersage: Arduino-Wetterstation mit Python & Keras selbst bauen

Mit ca. 600 Tagen Daten erreicht das System ~80 % Trefferquote (abhängig von Parametern). Das Tutorial deckt alles ab: Hardwarebau, Arduino-Code, Datenbank, Machine Learning – ohne externe Wetter- oder ML-APIs.

Schritt 1: Teile & Werkzeuge

(Siehe Tabellen oben. Basisstation: dauerhaft laufender Linux-Rechner mit HC-12 USB-Modul.)

Fertigkeiten: Löten, Arduino-Grundlagen, Linux-Dienste/Pakete, Programmiererfahrung.

Schritt 2: Wetterstation bauen

1. Gehäuse & Solarmodul: 4 Bohrungen (Solarkabel, 3 Sensoren). Solarmodul aufkleben, Kabel nach innen führen.

2. PCB-Bestückung:

3. Akku: 3 geladene AAA-NiMH in Halter, in Gehäuse legen, an Klemme anschließen.

4. Sensoren: BME280 & BH1750 außen an Steckverbinder. Regensensor: 3 Drähte (GND, VCC, Signal) anlöten, andere Seite mit Steckpins für PCB.

5. Aufstellung: Geschützter Standort für Hauptbox; Regensensor separat im Freien mit längeren Kabeln. Befestigung per starkem Klebeband o.ä.

Fritzing-Datei: sketch.fzz

Schritt 3: Arduino-Code

Die Station sendet alle 10 Min. codierte Sensordaten per Software-Serial (HC-12). Format:

H1:78|T1:12|PS1:1022|L1:500|R1:0|V1:4010|

(Station 1: Feuchte 78 %, Temp 12 °C, Druck 1022 hPa, Licht 500 lx, Regen 0, Spannung 4010 mV)

Ablauf: Sensoren lesen → Senden → Peripherie abschalten → 10 Min. Deep-Sleep (< 50 µA) → Wiederholung. Bei Spannung > 4,2 V wird normales delay() genutzt (schneller Entlade-Schutz gegen Überladung).

Code: GitHub Repository oder unten kopieren. Zeile transmitSenzorData("V", sensors.voltage); entfernen.

#include "LowPower.h"
#include "SoftwareSerial.h"
#include "Wire.h"
#include "Adafruit_Sensor.h"
#include "Adafruit_BME280.h"
#include "BH1750.h"

SoftwareSerial serialComm(4, 5); // RX, TX
Adafruit_BME280 bme;
BH1750 lightMeter;
const byte rainPin = A0;
byte sensorsCode = 1;
int voltageDeepSleepThreshold = 4200;
const byte peripherialsPowerPin = 6;

struct sensorData { byte humidity; int temperature; byte rain; int pressure; long voltage; int light; };
sensorData sensors;

void setup() {
  Serial.begin(9600); serialComm.begin(9600);
  pinMode(peripherialsPowerPin, OUTPUT);
  digitalWrite(peripherialsPowerPin, HIGH);
  delay(500);
  if (!bme.begin()) { Serial.println("BME280 nicht gefunden!"); while(1) customSleep(100); }
  Serial.println("Initialisierung OK");
  delay(50); digitalWrite(peripherialsPowerPin, HIGH);
}

void loop() { updateSenzors(); transmitData(); customSleep(75); }

void updateSenzors() {
  bme.begin(); lightMeter.begin(); delay(300);
  sensors.temperature = bme.readTemperature();
  sensors.pressure = bme.readPressure() / 100.0F;
  sensors.humidity = bme.readHumidity();
  sensors.light = lightMeter.readLightLevel();
  sensors.voltage = readVcc();
  sensors.rain = readRain();
}

void transmitData() {
  emptyIncommingSerialBuffer();
  Serial.print("Temp:"); Serial.println(sensors.temperature);
  Serial.print("Humid:"); Serial.println(sensors.humidity);
  Serial.print("Pressure:"); Serial.println(sensors.pressure);
  Serial.print("Light:"); Serial.println(sensors.light);
  Serial.print("Voltage:"); Serial.println(sensors.voltage);
  Serial.print("Rain:"); Serial.println(sensors.rain);

  transmitSenzorData("T", sensors.temperature);
  transmitSenzorData("H", sensors.humidity);
  transmitSenzorData("PS", sensors.pressure);
  transmitSenzorData("L", sensors.light);
  transmitSenzorData("V", sensors.voltage); // <-- ENTFERNEN
  transmitSenzorData("R", sensors.rain);
}

void emptyIncommingSerialBuffer() { while (serialComm.available() > 0) { serialComm.read(); delay(5); } }

void transmitSenzorData(String type, int value) {
  serialComm.print(type); serialComm.print(sensorsCode);
  serialComm.print(":"); serialComm.print(value); serialComm.print("|");
  delay(50);
}

void customSleep(long eightSecondCycles) {
  if (sensors.voltage > voltageDeepSleepThreshold) { delay(eightSecondCycles * 8000); return; }
  digitalWrite(peripherialsPowerPin, LOW);
  for (int i = 0; i < eightSecondCycles; i++) LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  digitalWrite(peripherialsPowerPin, HIGH); delay(500);
}

byte readRain() { return map(analogRead(rainPin), 0, 1023, 0, 100); }

long readVcc() {
  // Interne 1,1 V Referenz gegen AVcc messen
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(MUX3) | _BV(MUX2);
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif
  delay(2); ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA, ADSC));
  uint8_t low = ADCL; uint8_t high = ADCH;
  long result = (high << 8) | low;
  result = 1125300L / result; // 1,1*1023*1000
  return result; // mV
}

Benötigte Bibliotheken (Arduino IDE → Sketch → Bibliothek einbinden → .ZIP oder Bibliotheksverwalter):

Schritt 4: Basisstation vorbereiten (Linux)

HC-12 USB-Modul an Linux-Rechner (z. B. Ubuntu). Dauerhaft online.

  1. Anaconda installieren (Python-Paketmanager, Versionen kontrollierbar). Anleitung (Schritte 1–8).
  2. MongoDB installieren (schemalos, ideal für Zeitreihen). MongoDB 3.4.6 (neuere Versionen funktionieren auch). Optional Index: db.weather_station.createIndex({"date": 1}).
  3. Projekt klonen: git clone https://github.com/danionescu0/home-automation.git → Ordner weather-predict.
  4. Conda-Umgebung:
    cd weather-predict
    conda create --name weather python=3.6.2
    conda activate weather
    pip install -r requirements.txt
    
    Pakete: Keras, Pandas, PyMongo, scikit-learn.

Schritt 5: Konfiguration & Betrieb

config.py anpassen: MongoDB Host/Port, Serial-Port (ls -l /dev/tty* vor/nach HC-12 Einstecken → meist /dev/ttyUSB0, 9600 Baud).

Daten importieren (meine Testdaten)

mongoimport -d weather -c weather_station --file sample_data/weather_station.json

Warnung: Kombinieren mit eigenen Daten kann Genauigkeit senken (Hardware-/Standortunterschiede).

Eigene Daten sammeln

conda activate weather
python serial_listener.py
# Alle 10 Min. erscheinen Daten: [Sensor: type(temperature), value(14.3)] ...

Modell trainieren

python train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 8 --hour-granularity 6

Diagramme anzeigen

python graphs.py --days-behind 10

Vorhersage & E-Mail

python predict.py --datapoints-behind 8 --hour-granularity 6 \
  --from-addr ihre@gmail.com --from-password gmail_pw --to-addr ziel@email.de

Gmail: „Weniger sichere Apps zulassen“ aktivieren. Für stündliche Vorhersage per Cronjob eintragen.

Schritt 6: Wie es funktioniert (Technischer Deep-Dive)

1. Architektur

Trennung: Wetterstation (nur Messen/Senden, extrem sparsam) ↔ Basisstation (Datenbank, Training, Vorhersage). Vorteile: Strombedarf, Portabilität, Skalierbarkeit (mehrere Stationen), niedrige Kosten.

Datenbank: MongoDB (BSON/JSON-ähnlich). Eintrag pro Minute (10-Min-Intervall aggregiert).

ML-Stack: Python, Pandas (Datenverarbeitung), Keras (High-Level NN über TensorFlow).

2. Machine-Learning-Grundlagen

Künstliche neuronale Netze ahmen biologische Neuronen nach: Eingänge → Gewichte → Bias → Aktivierungsfunktion → Ausgabe. Lernen = Gewichte anpassen per Backpropagation (Optimierer: RMSprop, Loss: MAE, Metrik: Accuracy). Überwachtes Lernen: Inputs + gewünschte Outputs bekannt.

3. Datenaufbereitung (Kernschritt)

4. Keras-Modell

from keras.models import Sequential
from keras.layers import Dense, Dropout

input_dim = X.shape[1]
model = Sequential()
inner = int(input_dim / 2)
model.add(Dense(inner, activation='relu', input_dim=input_dim, kernel_initializer='uniform'))
model.add(Dropout(0.05))
model.add(Dense(inner, activation='relu', kernel_initializer='uniform'))
model.add(Dropout(0.05))
model.add(Dense(1, activation='sigmoid', kernel_initializer='uniform'))

model.compile(optimizer='rmsprop', loss='mean_absolute_error', metrics=['accuracy'])
model.fit(X, y, batch_size=1, epochs=50)
model.save('model_file_name')

Dropout verhindert Overfitting. Parameter (Layer, Neuronen, Dropout, Optimizer, Loss, Batch, Epochs) stark tunen!

5. Zukunftsverbesserungen

Schritt 7: Bonus – Offizielles Wetterdatenset (Dark Sky API)

Test mit Dark Sky API (historische Daten, mehr Parameter: Wind, UV, Sichtweite). Ergebnis: Genauigkeit steigt von ~80 % auf ~90 %, besonders bei Regentagen.

  1. Daten herunterladen (API-Key, Koordinaten in download_import/config.py) → python download_import/darksky.py -d 1000 (Free-Tier: 1000 Requests/Tag). Oder meine Bukarest-Daten importieren: mongoimport -d weather -c darksky --file sample_data/darksky.json.
  2. Training auf Dark-Sky-Datensatz: python train.py -d 2000 -p 20 -dp 4 -hg 6 --data-source darksky.
  3. Batch-Prediction: python predict_batch.py -f sample_data/test_data.csv.

Fazit: Datenqualität & -umfang sind entscheidend.

Code-Schnipsel (Referenz)

Im Originalprojekt sind zahlreiche Code-Schnipsel für Datenverarbeitung, Training, Evaluation, Vorhersage hinterlegt. Die wichtigsten sind im GitHub-Repo (danionescu0/home-automation) im Ordner weather-predict zu finden.

Schaltplan

Präzise Regenvorhersage: Arduino-Wetterstation mit Python & Keras selbst bauen

Arduino-Sketch: GitHub

Herstellungsprozess

  1. Fern-Temperatursensor mit Raspberry Pi & Python bauen – Schritt-für-Schritt-Anleitung
  2. DIY Photoshop-Steuerkonsole mit Arduino Nano RP2040 bauen
  3. Dateien und Verzeichnisse in Python mit os.rename() umbenennen – Schritt-für-Schritt-Anleitung
  4. RFID-Anwesenheitssystem mit Arduino & Python – Daten direkt in phpMyAdmin (XAMPP) speichern
  5. Universelle Android-Fernbedienung mit Arduino, 1Sheeld & IR-Steuerung
  6. Intelligentes Voltmeter mit Arduino & Smartphone bauen – Einfaches DIY-Projekt
  7. DIY Infrarot-Herzschlag-Sensor mit Arduino: Schritt-für-Schritt-Anleitung
  8. Frequenz & Tastverhältnis präzise messen mit Arduino UNO
  9. DIY-Voltmeter mit Arduino und Nokia 5110 Display – Schritt-für-Schritt-Anleitung
  10. Echtzeit-Entfernungsmessung mit Arduino Sonar & Processing-Visualisierung