ESP32 Wetterstation 2.0: Funksensoren, Open-Meteo API, IPS Display, mmWave Radar, Feinstaubsensor und vieles mehr

Die ESP32 Wetterstation ist inzwischen schon über ein Jahr alt. Höchste Zeit also für ein Update. Daher habe ich die letzten Wochen damit verbracht, eine rundum verbesserte Version der Wetterstation zu entwickeln. Die Veränderungen betreffen sowohl die Software, als auch die Hardware und umfassen die folgenden Punkte:

  • Neues Display mit IPS Panel
  • Wechsel vom Arduino Framework zu ESP-IDF
  • Setup Screen zum Einstellen aller variablen Werte
  • Freies Open-Meteo API statt OpenWeather API
  • 24GHz mmWave Radar für die Erkennung menschlicher Präsenz
  • Verbesserter Lichtsensor mit I2C Schnittstelle
  • Stabileres Gehäuse mit Gewindeeinsätzen zum Einschmelzen

Natürlich ist auch diesmal der komplette Aufbau wieder Open-Source und wird an den entsprechenden Stellen verlinkt.

ESP32 Wetterstation

Die Liste der Features ist dadurch noch etwas länger geworden:

  • Basisstation mit ESP32-S3 und 7 Zoll IPS Display.
  • Setup-Screen zur Konfiguration der Wetterstation.
  • Funksensoren auf ESP32 Basis. Es gibt drei mögliche Varianten der Sensoren.
  • Akku der Funksensoren wird über Solarzellen geladen.
  • Sehr niedriger Stromverbrauch der Funksensoren durch Deep-Sleep Modus und ESP-NOW Protokoll.
  • Je nach Funksensor können 4 oder 8 Sensoren per DIP Schalter konfiguriert werden.
  • Funksensoren verbinden sich vollautomatisch mit der Basisstation.
  • Jeder Funksensor misst Temperatur, Luftfeuchtigkeit und Luftdruck.
  • Die Basisstation liefert Temperatur, Luftfeuchtigkeit, VOC-Index, Feinstaub-, NOx- und CO2-Gehalt.
  • Detaillierte Wettervorhersage über das Open-Meteo API für die kommenden 48 Stunden bzw. 7 Tage.
  • Das Display passt sich automatisch an die Helligkeit der Umgebung an.
  • Befindet sich niemand in der Nähe der Wetterstation, wird das Display automatisch abgedunkelt.
  • Gehäuse aus dem 3D-Drucker, damit die Wetterstation auch wohnzimmertauglich ist.

Im weiteren Verlauf dieses Artikels werde ich die einzelnen Hardware- und Softwarekomponenten genauer beleuchten. Bei unveränderten Teilen verweise ich auf die Beschreibung der vorherigen Version.

Aufbau der Wetterstation

Die Funktionsweise der Wetterstation hat sich grundsätzlich kaum verändert. Lediglich der Fotowiderstand, der an einem A/D Wandler des ESP32 angeschlossen war, wurde durch ein BH1750 Lichtsensor ersetzt. Zusätzlich ist noch ein Radar-Sensor zur Erkennung menschlicher Präsenz mit dem I2C Bus verbunden. Somit sind in der Wetterstation fünf Geräte über den I2C Bus mit dem Mikrocontroller verbunden.

Open-Meteo API
Open-Meteo API
On
On
1
1
2
2
3
3
Sensor 0
Sensor 0
Solar
Panel
Solar...
ESP32
ESP32
ESP32 S3
ESP32 S3
SEN55
SEN55
SCD41
SCD41
ESP-NOW
ESP-NOW
ESP-NOW
ESP-NOW
ESP-NOW
ESP-NOW
I2C
I2C
I2C
I2C
BME280
BME280
I2C
I2C
Base Station
Base Station
WIFI
WIFI
On
On
1
1
2
2
3
3
Sensor 1
Sensor 1
Solar
Panel
Solar...
ESP32
ESP32
BME280
BME280
I2C
I2C
On
On
1
1
2
2
3
3
Sensor 2
Sensor 2
Solar
Panel
Solar...
ESP32
ESP32
BME280
BME280
I2C
I2C
Screen
Screen
LDR
LDR
Radar
Radar
I2C
I2C
I2C
I2C
I2C
I2C
RGB
RGB
Touch
Touch

An den Funksensoren hat sich nichts verändert, sie kommunzieren immer noch über das ESP-NOW Protokoll mit der Wetterstation. Diese Lösung hat sich in den letzten Monaten sehr bewährt.

Neues Display mit IPS Panel

Der eigentliche Auslöser für die neue Version der Wetterstation war das Display von Makerfabs. Im Februar habe ich das Display zugeschickt bekommen und nach anfänglicher Enttäuschung über die 800x600 Pixel Version war die Begeisterung für die Version mit 1024x600 Pixel umso größer. Details dazu können in meinem Artikel über die MaTouch Displays von Makerfabs nachgelesen werden. Ich habe bisher noch kein anderes 7 Zoll Display mit ESP32-S3 und IPS Panel gefunden. Natürlich ist auch dieses Display nicht perfekt. Vor allem die wenigen Pins für die Peripherie und die exotischen Stecker stören mich. Das ist auch einer der Gründe, warum ich statt einem Fotowiderstand jetzt einen Lichtsensor mit I2C Schnittstelle verwende. Diesen Bus hat jedes Display, das ich mir bisher angeschaut habe.

Das Problem mit den Steckern und dem fehlenden Anschluss für die 5 Volt Stromversorgung habe ich pragmatisch gelöst und die Kabel einfach direkt auf das Board gelötet:

Verlötete Kabel am MaTouch Display

Die 5 Volt habe ich an der Schottky-Diode angelötet, und zwar auf der Seite, die mit dem USB-Stecker verbunden ist, also der Anode. Hier hat man wirklich 5 Volt zur Verfügung. In dem Schaltplan von Makerfabs sieht man ein Lötpad, das aber mit der Kathode der Schottky-Diode verbunden ist. Sogar die Beschriftung sagt 5 Volt. Aber in Wirklichkeit liegen hier nur 4,4 Volt an, da an der Diode eine gewisse Spannung abfällt. Das kann man auch im Datenblatt der Diode (Typ SS54) nachlesen, wo ein (maximaler) Wert von 0,55 Volt angegeben ist.

Wechsel vom Arduino Framework zu ESP-IDF

In meinem Artikel über das MaTouch Display beschreibe ich auch den Display Treiber, den ich für dieses Display (und andere parallele Displays) geschrieben habe. Für diesen Treiber habe ich aber nicht das Arduino Framework, sondern das ESP-IDF Framework verwendet. Der Grund war, dass ich die neuesten Features zum Ansteuern von parallelen Displays des Espressif APIs verwenden wollte. Aus diesem Grund habe ich auch den ganzen Rest der Software umgeschrieben. Das ist grundsätzlich kein Problem, da ja auch das Arduino Framework letztendlich nur auf Funktionen des ESP-IDF Frameworks zugreift. Allerdings musste ich dadurch auch für das mmWave Radar Modul und den Lichtsensor einen entsprechenden Treiber schreiben, da es dafür nur Arduino Bibliotheken gibt. Das folgende Diagramm zeigt den Aufbau der Software:

Main task
Main task
Brightness task
Brightness task
Sensor task
Sensor task
Weather task
Weather task
Clock task
Clock task
Networking
Networking
Display
Display
Display Driver
Display Driver
LVGL
LVGL
GUI
GUI
ESP-NOW
ESP-NOW
Sensors
Sensors
Sensors
Sensors
Sensors
Sensors
Sensors
Sensors
Callback
Callback
Semaphore
Semaphore
Event loop
Event loop
BH1750
Light sensor
BH1750...
SEN0610
Presence sensor
SEN0610...
SEN55
Environement sensor
SEN55...
SCD41
CO2 sensor
SCD41...
HTTPS
Open-Meteo API
HTTPS...
SNTP
Time information
SNTP...
Setup Screen
Setup Screen

Das Layout der LVGL Screens wurde wieder zum größten Teil mit SquareLine Studio erstellt. Durch einen kleinen Trick ist es möglich, auch mehr als 150 Widgets zu verwenden. Das ist allerdings ein bisschen umständlich und man sollte einen guten XML Editor haben. Der Source Code der Wetterstation liegt wieder auf GitHub.

Setup Screen zum Einstellen aller variablen Werte

Den Setup Screen gibt es genau genommen auch schon in der alten Version. Allerdings ist er erst später dazugekommen, daher beschreibe ich ihn hier kurz. Das folgende Bild gibt einen Überblick über alle Einstellungen:

Setup Screen

Zunächst kann der WLAN-Zugang konfiguriert werden. Der Scan-Button sucht nach den verfügbaren Netzwerken. In der Dropdown List kann dann das eigene Netzwerk ausgewählt werden. Hat man das dazugehörige Passwort eingegeben, kann mit dem Verbinden-Button geprüft werden, ob eine Verbindung aufgebaut werden kann.

AppId wird eigentlich nicht mehr benötigt. Hier wurde der ID von OpenWeatherMap eingegeben. Das neue Wetter-API benötigt das aber nicht mehr. Trotzdem behalte ich die Einstellung vorerst. Vielleicht werde ich OpenWeatherMap noch zusätzlich einbauen, dann kann man dadurch steuern, welches API verwendet werden soll.

Die Zeitzone ist für die Darstellung der Uhrzeit wichtig. Darüber wird auch die Sommerzeit gesteuert.

Die letzten Felder sind die Beschriftungen der jeweiligen Sensoren bzw. der Wetterstation selbst.

Abschließend klickt man auf Starten, dann wird zum Screen mit den Wetter- und Sensordaten gewechselt.

Freies Open-Meteo API statt OpenWeather API

Eine der grundlegendsten Änderungen bei der Wetterstation ist das Wetter-API. Das Erstellen eines API Keys bei OpenWeatherMap ist ziemlich umständlich und das Hinterlegen einer Kreditkarte hat auch mir nicht gefallen. Leider gibt es keine Option ohne Kreditkarte, so dass der Zugang einfach blockiert wird, wenn das tägliche Limit überschritten ist. Man kann zwar in den Einstellungen so ein Limit wählen, aber das ändert nichts am Zwang, eine Kreditkarte angeben zu müssen.

In einem der Kommentare zu einem vorherigen Artikel hat jemand Open-Meteo vorgeschlagen. Das habe ich mir jetzt angeschaut und die Daten sind meiner Meinung recht gut. Open-Meteo ist eine Wetter-API, die eine kostenlose Nutzung für nicht-kommerzielle Projekte mit bis zu 10.000 API-Aufrufen pro Tag bietet. Die API liefert stündliche Wettervorhersagen für 7 Tage und kann auf bis zu 16 Tage erweitert werden. Sie verwendet Daten von verschiedenen nationalen Wetteranbietern, um die bestmögliche Vorhersage für jeden Standort weltweit zu erstellen. Das API ist recht simpel und wird auf der Website von Open-Meteo gut beschrieben.

Der Aufruf des Wetter-APIs per HTTPS für das momentane Wetter sieht beispielsweise so aus:

static const char *WEATHER_URL_BASE = "https://api.open-meteo.com/v1/forecast";

static const char *WEATHER_URL_CURRENT =
        "https://api.open-meteo.com/v1/forecast?"
        "latitude=12.34&longitude=56.78&"
        "current=temperature_2m,relative_humidity_2m,apparent_temperature,"
        "is_day,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m,uv_index&"
        "timeformat=unixtime&timezone=auto";

http_response_t response = {0};

esp_http_client_config_t config = {
	.event_handler = _http_event_handler,
	.url = WEATHER_URL_BASE,
	.crt_bundle_attach = esp_crt_bundle_attach,
	.user_data = &response,
	.disable_auto_redirect = true,
};

esp_http_client_handle_t client = esp_http_client_init(&config);

esp_http_client_set_url(client, WEATHER_URL_CURRENT);

err = esp_http_client_perform(client);
if (err == ESP_OK) {

	cJSON *json = cJSON_Parse(response.buffer);
	if (json == NULL) {
		const char *error_ptr = cJSON_GetErrorPtr();
		if (error_ptr != NULL) {
			ESP_LOGE(TAG, "Error before: %s", error_ptr);
		}
	}
	else {
		cJSON *current = cJSON_GetObjectItem(json, "current");

		current_data.temperature_2m = cJSON_GetObjectItem(current, "temperature_2m")->valuedouble;
		current_data.relative_humidity_2m = cJSON_GetObjectItem(current, "relative_humidity_2m")->valueint;
		current_data.apparent_temperature = cJSON_GetObjectItem(current, "apparent_temperature")->valuedouble;
		current_data.is_day = cJSON_GetObjectItem(current, "is_day")->valueint;
		current_data.weather_code = cJSON_GetObjectItem(current, "weather_code")->valueint;
		current_data.cloud_cover = cJSON_GetObjectItem(current, "cloud_cover")->valueint;
		current_data.wind_speed_10m = cJSON_GetObjectItem(current, "wind_speed_10m")->valuedouble;
		current_data.wind_direction_10m = cJSON_GetObjectItem(current, "wind_direction_10m")->valueint;
		current_data.wind_gusts_10m = cJSON_GetObjectItem(current, "wind_gusts_10m")->valuedouble;
		current_data.uv_index = cJSON_GetObjectItem(current, "uv_index")->valuedouble;
	}
	
	cJSON_Delete(json);
	
	if (response.buffer) {
		heap_caps_free(response.buffer);
		response.buffer = NULL;  
		response.buffer_len = 0; 
	}

} else {
	ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}

esp_http_client_close(client);



Zum Parsen der JSON Daten, die das Wetter-API liefert, verwende ich cJSON. Die Bibliothek ist in C geschrieben und eignet sich für diese Aufgabe sehr gut. Mit ihrer Hilfe kann ich die erhaltenen Wetterinformationen strukturiert extrahieren und für die Anzeige auf dem Display der Wetterstation aufbereiten.

24GHz mmWave Radar Personen Präsenz Sensor

Im Gehäuse der Wetterstation befinden sich neben dem Display auch die Umweltsensoren von Sensirion. Von den beiden Sensoren verwende ich den Feinstaubsensor, um die aktuelle Temperatur zu messen. Allerdings erwärmt sich das Display mit der Zeit ein wenig, was den Messwert natürlich verfälscht. Sensirion hat dazu auch die Option eines Korrekturfaktors vorgesehen, den man an sein jeweliges Gerät anpassen muss. Diesen Wert habe ich experimentell mehr oder weniger genau bestimmt, aber auch das ist nicht ganz genau. Das Display passt seine Helligkeit an die Umgebung an und wird folglich auch mehr oder weniger warm.

Bei dem neuen Display habe ich sogar das Gefühl, dass es sich noch mehr erwärmt. Daher habe ich nach einer anderen Lösung gesucht. Wäre es nicht viel besser, wenn das Display nur dann mit der vollen Helligkeit leuchtet, wenn auch wirklich jemand darauf schaut? Ansonsten könnte das Display entweder ganz aus sein oder zumindest mit der geringsten Helligkeit leuchten. Die Erwährmung in dieser kurzen Zeit wäre völlig vernachlässigbar. Bei meiner Recherche bin ich dann auf den mmWave Radar Sensor von DFROBOT gestoßen. Mit diesem Sensor kann man feststellen, ob sich jemand vor dem Sensor befindet und in welcher Entfernung. Damit ist es möglich, dass das Display erst dann die normale Helligkeit annimmt, wenn jemand beispielsweise in weniger als drei Meter Entfernung vor dem Display steht.

24GHz mmWave Radar Sensor

Ich finde diesen Sensor so spannend, dass ich wohl noch einen eigenen Artikel darüber schreiben werde. Leider ist Dokumentation von DFROBOT sehr spärlich und erst nach mehreren Anfragen habe ich noch einige Dokumente zugeschickt bekommen. Aber selbst jetzt sind mit noch nicht alle Funktionen restlos klar.

Verbesserter Lichtsensor mit I2C Schnittstelle

Bisher wurde die Helligkeit des Displays über einen Fotowiderstand gesteuert. An dieser Lösung haben mich aber zwei Dinge gestört. Erstens ist es schwierig, immer den gleichen Typ zu bekommen. Die Parameter der Helligkeitssteuerung müssen aber an den jeweiligen Typ angepasst werden. Zweitens bin ich mit dem A/D-Wandler des ESP32 nicht sehr zufrieden. Die Werte streuen sehr, was man per Software ausgleichen muss, sonst würde die Helligkeit des Displays ständig schwanken. Daher habe ich nach einem standardisierten Lichtsensor gesucht, der über die I2C Schnittstelle angesteuert werden kann. Der BH1750 erfüllt genau diese Anforderung.

BH1750

Der BH1750 ist ein digitaler Umgebungslichtsensor, der sich ideal für die Erfassung von Umgebungslichtwerten zur Anpassung einer Hintergrundbeleuchtung eignet. Er verfügt über eine I2C-Schnittstelle, einen großen Erfassungsbereich (1 - 65535 Lux) und eine genügend hohe Auflösung. Vor allem aber ist diese kleine Platine breit verfügbar und kostet nur ein paar Euro.

Stabileres Gehäuse mit Gewindeeinsätzen zum Einschmelzen

Das Display von Makerfabs schaut leider völlig anders aus als das Sunton Display. Daher musste ich auch ein neues Gehäuse konstruieren. Erstmals habe ich dafür Gewindeeinsätze zum Einschmelzen verwendet. Bis vor kurzem wusste ich nicht einmal, dass so etwas gibt, entsprechend nervös war ich auch beim Einschmelzen. Nach stundenlangem 3D-Drucken wäre es ja schade, wenn ich jetzt die Teile wieder ruinieren würde. Aber es hat sich dann als kinderleicht herausgestellt, selbst die Bohrlöcher nahe der Wand waren kein Problem. Hier ein paar Fotos vom Gehäuse und dem Zusammenbau. Leider ist mir ein kleiner Fehler passiert. Fällt es wem auf?

Besonders stolz bin ich auf den Fuß. Ist er nicht wahnsinnig elegant? :-)

Die Gewindeeinsätze sind vom Typ M2.5x5x3.5mm. Um den passenden Durchmesser für die Bohrungen zu finden, habe ich mir zunächst einen Testblock mit verschiedenen Durchmessern gedruckt. Als idealer Wert für die Gewindeeinsätze hat sich 3,4 mm ergeben.

Bei der Konstruktion des Gehäuses habe ich meistens ca. 0,5 mm Luft miteinberechnet, aber es hat sich herausgestellt, dass der Prusa Drucker so genau ist, dass die Teile dann wackeln. Besonders beim Fuß war das der Fall. Daher habe ich dann doch wieder die genauen Werte genommen und damit passt der Fuß tatsächlich perfekt in das Gehäuse.

Die STEP und STL Dateien der einzelnen Teile zum selber Drucken liegen auf GitHub.

Zusammenbau der Wetterstation

Die folgenden Bilder zeigen den Aufbau der Wetterstation. Auf einer kleinen Streifenrasterplatine ist der CO2 Sensor und die Kabel zu den anderen Sensoren eingelötet. Leider ist die Reigenfolge der Pins bei jedem Gerät anders angeordnet, daher wirken die Kabel etwas durcheinander...

DSCF4799.jpg

Und so sieht der komplette Aufbau der Wetterstation aus. Das Display wird einfach in die vordere Blende gelegt. Dafür ist keine Verschraubung nötig. In die Aussparung fur den Lichtsensor kommt eine Platte aus transparentem Filament. Ich habe diese Platte einfach angeklebt. Dann wird der Fuß von hinten auf die Rückseite geschraubt.

DSCF4793.jpg

Zuletzt wird die Rückseite vorsichtig auf die Front gelegt und an den 4 Schrauben befestigt. Danach sollte die Wetterstation dann so aussehen:

DSCF4801.jpg

Damit ist die Wetterstation auch schon fertig aufgebaut.

Die Funksensoren

Für die Funksensoren gibt es inzwischen drei Varianten:

Der ursprüngliche Sensor für die Raspberry Wetterstation. Hier sind ESP32, Laderegler und der BME280 auf getrennten Platinen:
Sensor-Firebeetle-ESP32.jpg

Meine selbst entworfene Platine, die alle Komponenten enthält:
Sensor-ESP32.jpg

Die Version mit dem FireBeetle 2 ESP32-C6. Hier ist nur noch der BME280 eine eigene Platine:
Sensor-Firebeetle-ESP32-C6.jpg

Alle drei Versionen sind gleichermaßen als Sensor geeignet. Für den Nachbau ist die letzte Variante wohl die Einfachste. Die Bauteile sind einfach zu bekommen und für den Zusammenbau wird kein spezielles PCB benötigt. Auch der Energieverbrauch ist bei allen Versionen annähernd gleich.

Fazit

Inzwischen würde ich die Wetterstation als sehr ausgereift bezeichnen. In den nächsten Wochen werde ich vor allem die Qualität der Open-Meteo Daten beobachten. Derweil schauen die Werte aber recht gut aus. Ein wenig Feinschliff an der Software wird es aber ganz sicher noch geben.

Für die Zukunft überlege ich, ob ein Funksensor mit einem kleinen Display und den Sensirion Umweltsensoren Sinn machen würde. Dieses Gerät müsste dann aber per USB mit Strom versorgt werden. Und für die etwas fernere Zukunft spiele ich mit dem Gedanken, Sensoren mit der LoRa Funktechnologie zu entwickeln. Mir fehlt nur noch ein guter Anwendungsfall dafür, da in einer Stadtwohnung die Wi-FI Technik völlig ausreicht.

Bei Fragen oder sonstigen Anregungen schreibt mir einfach eine Nachricht. Ich freue mich immer über Feedback!

Konversation wird geladen