Bauanleitung für eine Raspberry Pi Wetterstation mit Wettervorhersage und ESP32 Funksensoren

Schon seit Jahren steht eine dieser typischen Wetterstationen in meinem Wohnzimmer. Sie funktioniert zwar, aber es fehlt ein zweiter oder gar dritter Funksensor, und eine Wettervorhersage wäre überhaupt der Hit. Deshalb habe ich vor ein paar Wochen damit begonnen, mir meine eigene Wetterstation zu bauen, die möglichst alle meine Wünsche abdecken kann. Inzwischen läuft die Wetterstation stabil, daher möchte ich euch hier eine Beschreibung geben, wie mein Projekt aufgebaut ist. Alle Komponenten sind auf GitHub verfügbar und an den entsprechenden Stellen verlinkt. 

Wetterstation

Was soll die Wetterstation können? Nach etwas Brainstorming ist diese Liste herausgekommen:

  • Raspberry Pi mit Display als Basisstation.
  • Akkubetriebene Sensoren, die über Solarzellen aufgeladen werden.
  • Die Anzahl der Funksensoren kann beliebig den eigenen Wünschen angepasst werden.
  • Die Sensoren sollen Temperatur, Luftfeuchtigkeit und Luftdruck messen.
  • Die Wettervorhersage soll über ein freies API geladen und automatisch regelmäßig aktualisiert werden.
  • Übersichtliche Darstellung der Daten (wobei "übersichtlich" natürlich sehr subjektiv ist).
  • Nur Standardkomponenten, damit der Aufbau reproduzierbar ist.
  • Weltweit verwendbar, also in meinem Fall keine speziellen Wetterdaten aus Österreich, obwohl die deutlich genauer wären.
  • Professioneller Look. Die ganze Wetterstation soll wie ein richtiges Produkt aussehen.

Ich denke, die Liste birgt keine besonderen Überraschungen. Vor allem der letzte Punkt ist mir sehr wichtig. Es wäre nicht das erste Projekt, das nie über den Prototypstatus hinauskommt.

Für die Wetterstation habe ich folgende Komponenten verwendet: (Amazon Affiliate-Links)

Die Bauanleitung gliedert sich in die folgenden Punkte:

  1. Der grundlegende Aufbau der Wetterstation
  2. Raspberry Pi einrichten
  3. OpenWeather API Account einrichten
  4. MQTT-Broker Installation
  5. Wetterstation Applikation
  6. ESP32 Sensormodul
  7. Mögliche Erweiterungen

 

Der grundlegende Aufbau der Wetterstation

Das folgende Diagramm zeigt die wesentlichen Komponenten der Wetterstation:

OpenWeatherMap
OpenWeatherMap
Raspberry Pi
Raspberry Pi
MQTT
MQTT
Sensor 1
ESP32
Sensor 1...
Sensor 2
ESP32
Sensor 2...
Sensor 3
ESP32
Sensor 3...
Weatherstation Application
Weatherstation Applica...
Display
Display


Die eigentliche Basisstation besteht aus einem Raspberry Pi mit einem 7 Zoll Display und ist für das Laden der Wetterdaten und die Anzeige der Wetter- und Sensordaten verantwortlich. Glücklicherweise hatte ich noch einen Raspberry Pi 3 A+ herumliegen, der für diese Aufgabe völlig ausreicht. Im Handel ist er leider kaum mehr zu bekommen und ein teurer Raspberry Pi 4 wäre hier völlig überdimensioniert. Die Sensormodule messen Temperatur, Luftfeuchtigkeit und Luftdruck. Dafür verwende ich den ESP32, da ich diesen Mikrocontroller inzwischen ganz gut kenne und er durch seinen hervorragenden Deep-Sleep-Modus optimal für diese Aufgabe geeignet ist. Die Kommunikation der Sensoren mit der Basisstation erfolgt nicht direkt, sondern über einen MQTT-Broker, der auch auf dem Raspberry Pi läuft. Die Wetterdaten werden über eine REST-Schnittstelle abgerufen, die Daten im JSON-Format liefert, welche dann von der Applikation verarbeitet werden. Nach etwas Recherche habe ich mich für das API von OpenWeather entschieden, da es alles abdeckt, was ich brauche und bis zu einem gewissen Nutzungsgrad auch gratis ist.

Raspberry Pi einrichten

Wie oben schon erwähnt, verwende ich hier einen Raspberry Pi 3 A+. Er ist nach wie vor mein Favorit unter allen Raspberry Pi Modellen. Grundsätzlich sollte das alles aber auch mit einem neueren Raspberry Pi 4 funktionieren. Beim Display handelt es sich um das offizielle Raspberry Pi Touch Display. Den Zusammenbau erkläre ich hier nicht, ich denke da gibt es genügend Anleitungen im Netz. Zusätzlich wird noch eine microSD Karte (8GB oder größer) und natürlich ein Netzteil benötigt.

Installation Raspberry Pi OS

Im ersten Schritt wird das Betriebssystem des Raspberry Pi installiert. Da die Wetterstation in Python und Kivy implementiert ist, reicht das Raspberry Pi OS Lite in der 32-Bit Variante aus. Die derzeitig aktuelle Version ist Debian „Bullseye“. Die Installation erfolgt am einfachsten mit dem Raspberry Pi Imager. Inzwischen kann man damit auch den WLAN-Zugang und den User konfigurieren. Der SSH-Zugang muss auch aktiviert sein. Die folgenden Screenshots zeigen den Vorgang:

Danach kann die SD-Karte in den Raspberry Pi gesteckt und der Rechner gebootet werden. Nach dem Bootvorgang kann man am Router kontrollieren, ob der Raspberry korrekt gestartet hat und welche IP-Adresse er hat. Er erscheint in der Liste der Verbindungen unter dem Namen, der im Setup angegeben wurde. Ich empfehle, dem Raspberry Pi eine feste IP-Adresse zuzuordnen, da diese Adresse von den Sensormodulen benötigt wird.

Jetzt kann man sich (am einfachsten mit PuTTY) per SSH auf dem Raspberry mit dem konfigurierten User einloggen. Es empfiehlt sich, zunächst das System mit den Kommandos

sudo apt-get update
sudo apt-get upgrade
sudo reboot

auf den neuesten Stand zu bringen. Das kann einige Minuten dauern. Nach dem Neustart hat man nun eine aktuelle Raspberry Pi OS Installation.

Kivy Framework installieren

Wie schon bei den Wassertropfen verwende ich auch für diese Applikation das Kivy Framework. Das kommt zwar ohne den Linux Desktop aus, aber einige zusätzliche Bibliotheken braucht man trotzdem. Diese werden mit den folgenden Kommandos installiert:

sudo apt-get install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev
sudo apt-get install libmtdev1 
sudo apt install python3-pip
pip3 install kivy[base]

Damit auch das Touch-Display unterstützt wird, muss die Kivy Konfiguration angepasst werden. Dazu editiert man die Datei ~/.kivy/config.ini mit dem Kommando:

nano  ~/.kivy/config.ini 

und ändert den Bereich [input] folgendermaßen:

mouse = mouse
mtdev_%(name)s = probesysfs,provider=mtdev
hid_%(name)s = probesysfs,provider=hidinput

Um die Auflösung an das Display anzupassen, wird im Bereich [graphics] die Höhe angepasst:

height = 480

Außerdem wird der Mauszeiger nicht benötigt. Dazu wird diese Zeile angepasst:

show_cursor = 0

Abschließend wird noch das Logging abgedreht, um die SD-Karte zu schonen. Diese Einstellung befindet sich im Bereich [kivy]

log_enable = 0


Optimierungen

Es folgen einige Änderungen, um die Lebensdauer der SD-Karte zu verlängern, indem die Schreibzugriffe verringert werden. Zunächst wird das Swapping deaktiviert:

sudo service dphys-swapfile stop
sudo systemctl disable dphys-swapfile
sudo apt-get purge dphys-swapfile

Anschließend erfolgt noch ein Eintrag in /boot/cmdline.txt. Der Editor wird mit

sudo nano /boot/cmdline.txt

gestartet. Am Ende der Zeile wird die Option noswap angefügt. Die ganze Zeile schaut dann so aus:

console=serial0,115200 console=tty1 root=PARTUUID=dbc0c677-02 rootfstype=ext4 fsck.repair=yes rootwait noswap

Um zu verhindern, dass permanent Logfiles auf die SD-Karte geschrieben werden, können temporäre Verzeichnisse in den Arbeitsspeicher verlagert werden. Dazu wird die Datei /etc/fstab mit

sudo nano /etc/fstab

bearbeitet und sollte danach folgendermaßen aussehen:

proc            /proc           proc    defaults          0       0
PARTUUID=dbc0c677-01  /boot           vfat    defaults,noatime  0       2
PARTUUID=dbc0c677-02  /               ext4    defaults,noatime  0       1

# Log to RAM
tmpfs   /tmp            tmpfs   defaults,noatime,nosuid,mode=1777,size=256m 0 0
tmpfs   /var/log        tmpfs   defaults,noatime,nosuid,mode=0755,size=128m 0 0
tmpfs   /var/tmp        tmpfs   defaults,noatime,nosuid,mode=0755,size=128m 0 0

# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that

Nach einem Reboot können die Anpassungen mit dem Kommando

df -h

überprüft werden. Das Ergebnis sollte etwa wie folgt aussehen:

pi@WeatherStation:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        15G  1.9G   12G  14% /
devtmpfs         85M     0   85M   0% /dev
tmpfs           214M     0  214M   0% /dev/shm
tmpfs            86M  3.2M   83M   4% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           256M     0  256M   0% /tmp
tmpfs           128M  164K  128M   1% /var/log
tmpfs           128M     0  128M   0% /var/tmp
/dev/mmcblk0p1  255M   50M  206M  20% /boot
tmpfs            43M     0   43M   0% /run/user/1000


Das Gehäuse für das Display

Was noch fehlt, ist ein wohnzimmertaugliches Gehäuse für das Display und den Raspberry Pi. Im Internet gibt es zwar sehr viele 3D Modelle zum Selberdrucken, aber so richtig gefallen hat mir nichts. Also habe ich mir mein eigenes Gehäuse entworfen. Ich gebe zu, die Konstruktion ist wegen der vielen Überhänge etwas gewagt, aber mein Ender 3 hat es ganz ohne Stützstrukturen recht gut ausgedruckt. Die STEP-Dateien des Gehäuses sind auf GitHub verfügbar

Damit ist die Einrichtung des Raspberry Pi abgeschlossen. Jetzt beginnen die eigentlichen Schritte für die Installation der Wetterstation.

OpenWeather API Account einrichten

Die Voraussetzung für eine Wettervorhersage ist natürlich die entsprechenden Daten. Es gibt inzwischen einige Firmen, die Schnittstellen für Wetterdaten anbieten, und bei einigen Firmen sind diese Daten bis zu einem gewissen Grad sogar gratis. Dazu gehört auch OpenWeather, wobei das "Open" im Namen nichts mit Open Source zu hat. Um das OpenWeather API verwenden zu können, muss man sich zunächst auf der Website registrieren. Nach der Registrierung erhält man eine E-Mail mit einem Link zur Bestätigung. Mit dieser Bestätigung bekommt man Zugriff auf das alte API in der Version 2.5, das 60 Aufrufe pro Minute bzw. 1.000.000 Aufrufe pro Monat erlaubt. Die Vorhersage geht über 3 Stunden bzw. 5 Tage. 

Für meine Wetterstation verwende ich das neue API 3.0. Es handelt sich dabei um ein sogenanntes "Pay as you call" API, man bezahlt also für jeden einzelnen Aufruf. Allerdings sind die ersten 1000 Aufrufe pro Tag kostenlos, was für die Wetterstation mehr als genug ist. Immerhin kann man so alle (24 * 60 * 60) / 1000 = 86,4 Sekunden die neueste Wettervorhersage abrufen. Mit einem einzigen Aufruf erhält man damit folgende Daten:

  • Minutenvorhersage für 1 Stunde
  • Stündliche Vorhersage für 48 Stunden
  • Tägliche Vorhersage für 8 Tage
  • Nationale Wetterwarnungen

Um dieses API verwenden zu können, sind aber noch einige weitere Schritte nötig. Dazu geht man zunächst auf den Reiter Billing plans. Hier wird der Base plan zum Abonnieren angeboten, wobei man sich nicht von den angegebenen Kosten abschrecken lassen darf. Wie gesagt, die ersten 1000 Aufrufe sind gratis. Um sicher zu sein, dass man nicht mehr Aufrufe pro Tag absetzt, kann im Feld Call per day eine maximale Anzahl eingetragen werden. Überschreitet man diese Anzahl, wird das API automatisch blockiert. Ich habe hier einfach 999 eingetragen, damit ich auf der sicheren Seite bin. Die Dauer der Blockierung wird von OpenWeather übrigens sehr seltsam gehandhabt. Ich zitiere aus den FAQ: Our blocking system suspends your account for a couple of hours to several days randomly. If you want to be unlocked immediately, please subscribe to our paid subscriptions.

Jetzt klickt man auf Subscribe. Nun beginnt der unangenehme Teil. Da es sich um ein Abonnement handelt, für das man gegebenenfalls automatisch eine Rechnung bekommt, muss eine Rechnungsadresse und eine gültige Kreditkarte angegeben werden. Es sollte zwar nie eine Rechnung kommen, aber ich kann verstehen, wenn jemanden dieser Schritt abschreckt. Das Abonnement kann aber jederzeit wieder gekündigt werden. Am Ende erscheint eine Seite mit dem aktivierten Base plan.

Zusätzlich wird eine E-Mail verschickt, in der auch ein Test-Link vorhanden ist, mit dem man das API gleich ausprobieren kann. Allerdings dauert es einige Minuten, bis der Link funktioniert. Klickt man auf den Link, sollte das Ergebnis circa so aussehen:

OpeanWeatherMap

Damit hat man jetzt Zugriff auf das aktuelle Wetter und die Wettervorhersage für jeden Ort der Erde.

MQTT-Broker Installation 

MQTT, was ursprünglich ein Akronym für Message Queue Telemetry Transport war, ist ein Netzwerkprotokoll, das wegen seiner Einfachheit sehr gut für IoT Anwendungen geeignet ist. Die Idee dahinter ist, dass Sender und Empfänger nicht direkt miteinander kommunizieren. Sie müssen nicht einmal voneinander wissen. Dazu schickt der Sender, auch Publisher genannt, die Daten mit einem Betreff an den sogenannten Broker. Ein Empfänger, auch Subscriber genannt, teilt dem Broker mit, dass er sich für einen bestimmten Betreff interessiert. Sobald nun Nachrichten beim Broker mit diesem Betreff ankommen, werden sie an diesen Empfänger geschickt. Das folgende Diagramm veranschaulicht den Ablauf:

Sensor Module 0
Sensor Module 0
Sensor Module 1
Sensor Module 1
Sensor Module 2
Sensor Module 2
Broker
Broker
Publish 23,4°C
to Sensor00
Publish 23,4°C...
Publish 15,1°C
to Sensor01
Publish 15,1°C...
Publish 21,7°C
to Sensor10
Publish 21,7°C...
TopicsSensor00Sensor01Sensor10
15,1°C
15,1°C
23,4°C
23,4°C
21,7°C
21,7°C
Subscribe Sensor01
Subscribe Sensor01
Subscribe Sensor10
Subscribe Sensor10
Subscribe Sensor00
Subscribe Sensor00
Publish 23,4°C
Publish 23,4°C
Publish 15,1°C
Publish 15,1°C
Publish 21,7°C
Publish 21,7°C
Widget
Widget
Widget
Widget
Widget
Widget

Mosquitto ist ein MQTT Broker, der in nur wenigen Schritten auf dem Raspberry Pi installiert werden kann. Zunächst werden der Server und ein Client mit diesem Befehl installiert:

sudo apt-get install mosquitto mosquitto-clients

Anschließend wird die Konfiguration mit

sudo nano /etc/mosquitto/conf.d/local.conf

angepasst. Der Inhalt muss folgendermaßen aussehen:

listener 1883
allow_anonymous true
persistence false

Nach dieser Änderung muss der Service noch neu gestartet werden:

sudo systemctl restart mosquitto

Der Status des Service kann mit diesem Befehl überprüft werden:

sudo systemctl status mosquitto

Die Ausgabe sollte folgendermaßen aussehen:

 mosquitto.service - Mosquitto MQTT Broker
     Loaded: loaded (/lib/systemd/system/mosquitto.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2022-12-05 11:47:51 CET; 12min ago
       Docs: man:mosquitto.conf(5)
             man:mosquitto(8)
    Process: 1094 ExecStartPre=/bin/mkdir -m 740 -p /var/log/mosquitto (code=exited, status=0/SUCCESS)
    Process: 1095 ExecStartPre=/bin/chown mosquitto /var/log/mosquitto (code=exited, status=0/SUCCESS)
    Process: 1096 ExecStartPre=/bin/mkdir -m 740 -p /run/mosquitto (code=exited, status=0/SUCCESS)
    Process: 1097 ExecStartPre=/bin/chown mosquitto /run/mosquitto (code=exited, status=0/SUCCESS)
   Main PID: 1098 (mosquitto)
      Tasks: 1 (limit: 407)
        CPU: 395ms
     CGroup: /system.slice/mosquitto.service
             └─1098 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf

Dec 05 11:47:51 WeatherStation systemd[1]: Starting Mosquitto MQTT Broker...
Dec 05 11:47:51 WeatherStation mosquitto[1098]: 1670237271: Loading config file /etc/mosquitto/conf.d/local.conf
Dec 05 11:47:51 WeatherStation systemd[1]: Started Mosquitto MQTT Broker.


Mit dem oben installierten Client kann der Broker auf dem Raspberry Pi getestet werden. Dazu müssen zwei Konsolen geöffnet werden. In der ersten Konsole wird ein Subscriber gestartet:

mosquitto_sub -h localhost -t /test/topic

In der zweiten Konsole wird eine Nachricht geschickt:

mosquitto_pub -h localhost -t /test/topic -m "Just a test"

Diese Nachricht sollte nun in der ersten Konsole ausgegeben werden.

Damit ist der Message Broker am Raspberry Pi installiert und empfangsbereit für die Nachrichten der Sensoren.

Wetterstation Applikation

Die Basisstation ist in Python implementiert und verwendet das Kivy Framework für das Userinterface. Mein Ziel war es, sie viele Daten wie möglich auf dem 7 Zoll Display anzuzeigen. 

Installation der Applikation

Die Applikation benötigt zunächst noch einige Bibliotheken, bevor sie gestartet werden kann. Dazu verbindet man sich per ssh mit dem Raspberry Pi und führt die folgenden Befehle aus:

sudo apt-get install python3-yaml
sudo apt-get install python3-paho-mqtt
sudo apt-get install python3-scipy

In der Konfiguration wird die Locale de_DE.utf8 verwendet werden. Diese Locale muss am Raspberry Pi installiert sein. Das kann mit dem Befehl

sudo dpkg-reconfigure locales

überprüft und gegebenenfalls installiert werden.

Danach muss noch der Autostart eingerichtet werden, damit die Wetterstation nach dem Einschalten des Raspberry Pi automatisch gestartet wird.

Dazu wird eine Unit Datei mit diesem Befehl angelegt:

sudo nano /lib/systemd/system/weatherstation.service

und dieser Inhalt eingefügt:

[Unit]
 Description=WeatherStation
 After=multi-user.target

 [Service]
 Type=idle
 User=pi
 Group=pi
 ExecStart=/usr/bin/python /home/pi/WeatherStation/weather_station_app.py

 [Install]
 WantedBy=multi-user.target

Die Berechtigungen für diese Datei müssen noch angepasst werden:

sudo chmod 644 /lib/systemd/system/weatherstation.service

Abschließend wird der Service aktiviert:

sudo systemctl daemon-reload
sudo systemctl enable weatherstation.service

Damit ist die Applikation eingerichtet. Nach einem Neustart sollte die Applikation jetzt automatisch starten.

Der Code für die Applikation befindet sich auf GitHub.

Konfiguration der Applikation

In der Datei config.yaml werden alle Parameter definiert, die für den Betrieb notwendig sind. Ganz besonders wichtig sind der API Key von OpenWeather, die GPS-Koordinaten, für die das Wetter abgerufen werden soll und die IP Adresse des MQTT Brokers. Die Konfiguration sieht folgendermaßen aus:

openweather:
  url: https://api.openweathermap.org/data/3.0/onecall
  lat: 48.2149546
  lon: 16.302153494876826
  units: metric
  lang: de
  appid: xxxxxxxxxxxxxx    # your api key
  interval: 300  # Call every 5 Minutes (300 seconds), so we have 288 calls per day

kivy:
  kv_directory: templates
  locale: de_DE.utf8
  mqtt_host: 192.168.0.200
  temperature_unit: °C
  pressure_unit: hPa
  humidity_unit: '%'
  battery_unit: V
  wifi_unit: dBm
  wind_unit: m/s
  clouds_unit: '%'

Das Layout wird, wie in Kivy üblich, durch eine KV-Datei definiert. Unter anderem wird dort festgelegt, welche Klasse das jeweilige Widget verwendet wird und welcher Sensor die Werte liefert. Dieser Bereich schaut folgendermaßen aus:

CurrentWidget:
    id: current_widget
    size_hint: 0.46, 1
SensorBme280Widget:
    name: "Balkon"
    topic: '/weatherstation/sensor/00'
    size_hint: 0.18, 1
SensorBme280Widget:
    name: "Wohnzimmer"
    topic: '/weatherstation/sensor/01'
    size_hint: 0.18, 1
SensorBme280Widget:
    name: "Schlafzimmer"
    topic: '/weatherstation/sensor/02'
    size_hint: 0.18, 1

Bisher gibt es nur die Klasse SensorBme280Widget, da alle Sensormodule mit diesem Sensor laufen. Bei einem Sensormodul mit einem anderen oder zusätzlichen Sensor würde man hier eine zusätzliche Klasse definieren, die diese Werte anzeigt.

Das Layout der Applikation

Das Layout besteht grundsätzlich aus zwei Bereichen. Oben rechts werden die Werte von bis zu drei Sensoren angezeigt. Dazu gehören die eigentlichen Werte des Sensors als auch Daten über den Status des Sensors wie Akkuspannung, Signalstärke der WLAN-Verbindung und Uhrzeit der letzten Aktualisierung. Der restliche Bereich dient der Darstellung der Wettervorhersage und zeigt die aktuellen Messwerte, eine stündliche Vorhersage für 48 Stunden und eine tägliche Vorhersage für 8 Tage an. Die blauen und violetten Balken stellen die Niederschlagsmenge für Regen und Schnee dar, wobei Blau für Regen und Violett für Schnee steht. Die Intensität der Farbe zeigt die Wahrscheinlichkeit für Niederschlag an. Der gelbe Hintergrund symbolisiert den Bewölkungsgrad, je gelber desto weniger Wolken.

Wetterstation Applikation

In Zukunft möchte ich noch mehr Daten auf dem Display anzeigen. Die Herausforderung dabei ist, wie die Anzeige trotzdem noch übersichtlich bleibt. Hier wäre ich für Ideen sehr dankbar.

Sensormodul

Die Aufgabe des Sensormoduls ist es, auf eine möglichst energiesparende Weise die Daten des Sensors an die Basisstation zu schicken. Die Wahl des ESP32 war naheliegend, da ich mit diesem Mikrocontroller in den letzten Monaten schon viel Erfahrung sammeln konnte. Es gibt inzwischen sehr viele ESP32 Boards, die sich beim Stromverbrauch deutlich unterscheiden. Hier hat mir ein Video von Andreas Spiess sehr geholfen, wo einige Boards verglichen werden. Meine Wahl fiel auf das FireBeetle 2 Board, da es laut Datenblatt im Deep Sleep Modus lediglich 13 µA verbraucht. Andere Boards, auch das ESP32-DevKitC von Espressif, verbrauchen hier ein Vielfaches. Dieser niedrige Stromverbrauch wird durch den RT9080 Spannungsregler erreicht, der einen Ruhestrom von nur 2 μA hat. Das ganze Sensormodul hat dadurch im Deep Sleep Modus einen Stromverbrauch von nur 20 µA. Allerdings muss man dazu den dünnen Draht in der Mitte des Boards durchtrennen, damit die RGB LED nicht mehr mit Strom versorgt wird. Warum man hier nicht einfach einen Jumper verwendet hat, kann ich nicht wirklich verstehen.

Zum Vergleich habe ich noch ein ESP32 D1 Mini Board ausprobiert, das aber mit über 100 µA das Fünffache im Deep Sleep Modus verbraucht. Und dass, obwohl ich die LED zur Anzeige der Stromversorgung ausgelötet habe.

Zur Messung der Temperatur gibt es eine große Auswahl an Sensoren. Ich habe mich auf solche beschränkt, die über die I2C Schnittstelle angesteuert werden können. Im Internet gibt es zahlreiche Vergleiche solcher Sensoren und ich habe mich schließlich für den BME280 von Bosch entschieden. Dieser Sensor kann Temperatur, Luftfeuchtigkeit und Luftdruck messen. Der BME280 hat zwar das Problem, dass er sich im Betrieb leicht erwärmt und dadurch die Temperatur verfälscht, aber da ich nur alle 10 Minuten eine Messung durchführe, sollte das keine Rolle spielen. 

Da das Board über Solarzellen geladen werden muss, wird auch ein Laderegler benötigt. Der Firebeetle hätte zwar schon einen Laderegler an Bord, aber der ist nur für 5 Volt ausgelegt. Da der USB-Controller auf dem Board direkt mit dieser Stromversorgung verbunden ist, könnte er bei einer höheren Spannung der Solarzelle beschädigt werden und außerdem ist er permanent in Betrieb, was den Stromverbrauch unnötig erhöhen würde. Daher habe ich mich für ein Board entschieden, das auf einen TP4056 Laderegler basiert und den Akku gegen Überladung sowie Tiefentladung schützt.

Elektronik

Die Schaltung für das Sensormodul ist denkbar einfach. Sie besteht im Grunde nur aus den Verbindungen der einzelnen Module. Zusätzlich ist ein Spannungsteiler integriert, mit dem der ESP32 die aktuelle Spannung messen kann. Über einen DIP-Schalter wird dem Sensor eine Nummer zugeordnet, die wiederum die Anzeige auf der Basisstation steuert.

ESP32 Sensormodul Schaltplan

Die ganze Elektronik benötigt im aktiven Mode etwas 200 mA, im Deep Sleep Modus wie oben schon beschrieben etwa 20 µA. Ein Zyklus zwischen Aufwachen, Daten senden und wieder in den Deep Sleep Modus gehen, dauert etwa 10 Sekunden. In dieser Zeit werden also 10s x 200mA + 600s x 0,02mA = 2012mAs verbraucht. Eine voller Lithium-Ionen-Akku hat durchschnittlich eine Kapazität von 2000 mAh oder 7200000 mAs. Dividiert man die beiden Werte, erreicht man 7200000 / 2012 = 3578 Zyklen. Mit einer Zykluslänge von 610s sind das 3578 x 610s = 2182580s, was wiederum ca. 25 Tagen entspricht. Es wird sich im Laufe des Winters noch zeigen, ob das genug Reserven sind, um auch über die dunklen Wintertage zu kommen.

Ein KiCad Projekt mit der Schaltung und dem Platinen Layout sind auf GitHub vorhanden. 

Leider übersteigt der Entwurf eines eigenen ESP32 Boards meine Fähigkeiten. Im Grunde wäre das Board dem Firebeetle sehr ähnlich, nur dass die Stromversorgung über eine Solarzelle anders gelöst sein müsste. Hier würde ich mich sehr über Unterstützung freuen, da der Sensor so noch deutlich kompakter werden könnte.

Software

Der Code für den Sensor ist mit dem ESP-IDF Framework von Espressif in C geschrieben. Das folgende Diagramm zeigt den Ablauf zwischen Aufwachen und Rückkehr in den Deep Sleep Modus:

Blink LED
Blink LED
Read sensor number
Read sensor number
Read battery voltage
Read battery voltage
Read I2C sensor 1
Read I2C sensor 1
Connect to Wi-Fi
Connect to Wi-Fi
Read signal strength
Read signal strength
Connect to MQTT
Connect to MQTT
Send data
Send data
Start deep-sleep
Start deep-sleep
Wake up
Wake up
Init I2C
Init I2C
Disconnect Wi-Fi
Disconnect Wi-Fi
Read I2C sensor 2
Read I2C sensor 2
Read I2C sensor n
Read I2C sensor n

Der Treiben für den Bosch BME280 ist recht leicht zu implementieren, da es bereits eine generische Bibliothek von Bosch auf GitHub gibt. Man muss sich nur um das konkrete I2C Interface kümmern. Neben dem BME280 habe ich auch einen Treiber für den HDC1080 von Texas Instruments implementiert. Allerdings sind die Werte für die Luftfeuchtigkeit deutlich zu hoch, daher werde ich diesen Sensor nicht verwenden. Möglicherweise ist der Sensor defekt oder mein Code einfach noch nicht richtig.

Der Treiber muss folgende Funktionen implementieren:

esp_err_t sensor_driver_init_sensor(sensor_driver_t *handle){
    return handle->init_sensor(handle);
}
esp_err_t sensor_driver_read_values(sensor_driver_t *handle, sensor_data_t *values){
    return handle->read_values(handle, values);
}
void sensor_driver_get_json(sensor_driver_t *handle, sensor_data_t values, char* message){
    return handle->get_json(handle, values, message);
}


Jeder Treiber liefert jeweils die Werte, die er messen kann. Diese Werte werden gesammelt im JSON-Format an den MQTT Broker geschickt. Bei zwei Sensoren sieht das folgendermaßen aus:

{
   "battery":3920,
   "wifi":-65,
   "sensors":{
      "hdc1080":{
         "temperature":22.388611,
         "humidity":56.036377
      },
      "bme280":{
         "temperature":22.365077,
         "humidity":47.958395,
         "pressure":979.601209
      }
   }
}

An diesem realen Beispiel kann man sehr gut den großen Unterschied der Luftfeuchtigkeit zwischen den beiden Sensoren erkennen.

Damit der Sensor einfach ins WLAN gebracht werden kann, ist auch meine SmartConfig Bibliothek integriert. Mit Hilfe eines Smartphones sind dadurch alle Sensoren in wenigen Sekunden konfiguriert und können sich mit dem WLAN verbinden.

Der Code für das Sensormodul liegt auf GitHub.

Gehäuse für das Sensormodul

Natürlich braucht auch das Sensormodul ein Gehäuse. Ich habe versucht, das Gehäuse so kompakt wie möglich bei Verwendung einer 6 Volt/1 Watt Solarzelle zu gestalten. Das Gehäuse ist auf GitHub als STEP-Datei verfügbar.

Es werden noch weitere Bauformen mit mehr Solarzellen folgen, damit der Sensor auch in dunkleren Räumen mit ausreichend Energie versorgt. Sobald sie fertig sind, werde ich den Beitrag entsprechend aktualisieren.

Mögliche Erweiterungen

Die Wetterstation funktioniert und erfüllt auch alle meine Erwartungen. Aber das heißt noch lange nicht, dass die Entwicklung fertig ist. Ganz spontan fallen mir diese Themen ein, die man noch umsetzen könnte:

  • Sensormodul durch eigenes Design ersetzen. Dafür benötige ich aber Hilfe, speziell bei der Stromversorgung.
  • Zusätzliches Wetter API implementieren, zum Beispiel von Tomorrow.io
  • OTA-Update der Sensoren.
  • Einfaches Template System zur Konfiguration des Layouts der Wetterstation.
  • Weitere Temperatursensoren wie DHT20, HTU21D usw. einbinden, aber auch andere Sensoren für Kohlenmonoxid, Luftqualität, Ozon etc.
  • MQTT absichern.
  • Setup-Assistent zum Einstellen des Orts und Auswahl des WLAN-Netzwerks.
  • Automatische Helligkeitssteuerung des Displays.
  • Größeres Display, um mehr Daten anzeigen zu können.
  • Kleines sparsames E-Paper Display in den Sensormodulen

Ich weiß nicht, ob und wann ich die ganzen Punkte umsetzen werde. Aber vielleicht finden sich ja ein paar Menschen da draußen, die das Thema auch interessiert und mitarbeiten wollen. Ich würde mich jedenfalls sehr freuen!

Konversation wird geladen