DERZEIT IN ÜBERARBEITUNG
Was kann das alles ?
Generell mal zuerst. Das Ding hat hier nicht den Anspruch die beste Wetterstation aller Zeiten zu werden und auch nicht alles perfekt zu messen oder irgendwie eine Referenz zu sein. Das Ding ist halt Hobby. Bei vielen Dingen die hier niedergeschrieben sind, wusste ich vorher nicht ob das so geht und habe vieles einfach mal ausprobiert und angelesen.Somit kann ich nur sagen, was bei mir funktioniert hat. Ob es da noch einen besseren und effizienteren Weg gibt: GARANTIERT! Und gerade bei der Programmierung kann man ganz bestimmt noch vieles verbessern und anders, eleganter lösen, nur bin ich halt leider kein Programmierer.
Ich möchte bei uns im Garten gerne folgendes Messen:
- Lufttemperatur in 2m höhe
- Luftdruck
- Bodentemperatur
- Lufteuchtigkeit
- Feinstaubkonzentration von PM 1,0 / 2,5 / 10,0
- Windgeschwindigkeit
- Windrichtung
- UV Strahlung (A & B)
- Himmelstemperatur
- Bedeckungsgrad, abgeleitet aus Himmelstemperatur
- Niederschlagsmenge (Regen) und ein Signal ob Regen fällt
- Ozon
- Blitzsensor
Bei den Messwerten ist es mir wichtig, dass diese halbwegs in Anlehnung an die "offiziellen" Vorgaben gemessen werden. Bei der Lufttemperatur wäre dies 2m über kurzer Wiese. Das geht bei mir schon nicht wirklich, es sind dann aber 2m über Gemüsebeet geworden. Aber nochmal, dass hat hier ja auch keinen Anspruch in Wettbewerb mit einer Wetterstation für mehrere Tausend Euro zu treten. Die Messwerte sollen natürlich nicht nur gemessen werden, sondern die sollen ja auch irgendwo gespeichert und nach möglichkeit hübsch aufbereitet anguckbar sein. Der Plan ist also, die Messwerte irgendwie an eine Datenbank zu schicken und dort zu speichern. Mein Weg wird dabei so sein, dass die Messwerte durch einen Microcontroller ausgelesen werden, dieser sich bei WiFi bei mir im Netzwerk anmeldet und dann die Daten per MQTT-Telegramm an eine Datenbank schickt.
Was braucht man ?
- ESP32 (mehrere)
DHT22 (Lufttemperatur u Feuchtigkeit)SHT31-D (19€)
- DSB18B20 mit langen Kabel (z.B.3m) (Bodentemperatur) (4-5€)
- DPS310 (Luftdruck) (10€)
- SPS30 von Sensirion (Feinstaub) (50€)
- MLX90614 (IR Temperatur) (15€)
- UV (fehlt noch)
- Gravity Electrochemical Ozone Sensor (SEN0321) (45€)
- Gravity Lighting Distance Sensor (SEN0290) (25€) (AS-3935)
- Intelligent Rain Detection Module (SEN0545) (22€)
- Adafruit LTC4311 I2C Extender / Active Terminator (Oder ähnlicher I²C extender) (7,50€)
- Diverse Kabel und Kleinzeugs
- LiPo Akkus
- Spannungsversorgung (TP4056, MCP1725)
Bei der Windrichtung und Windgeschwindigkeit ist der Plan, dies mit einem Messgerät ohne Bewegliche Teile zu messen. Das Ding heißt dann Ultraschall-Anemometer. Da ich das selbst nicht entwickeln kann, habe ich mich an diese Anleitung gehalten:
Generelle vorgehensweise
Der Plan ist also, dass ganze Gedöns irgendwie zusammen zu bauen und dann die Daten kabellos per MQTT-Telegramm an einen anderen Ort zu schicken.
Jetzt ist es aber so, dass sich manche Werte ja relativ schnell ändern können (u.a. Windgeschwindigkeit, Blitzaktivität) und manche sich relativ langsam ändern (z.B. Luftfeuchtigkeit). Ich habe also überlegt, dass ich mehrere Mikrokontroller benötige und die Aufgaben etwas verteile.
Im ersten Anflug von Wahnsinn habe ich überlegt es wäre schön wenn die Wetterstation dass als Energie nutzen kann, was die Umwelt zur Verfügung stellt. D.h. Stromversorgung über Solarzellen und Batterien. Wir werden gemeinsam rausfinden ob das klappt.
ESP 32 - 1
- Misst alle 5 Minuten und geht dann schlafen
- Temperatur, Luftfeuchtigkeit, Feinstaub, Luftdruck, Ozone
ESP 32 -2
- Misst alle 10 Sekunden Windgeschwindigkeit und Richtung sowie Niederschlag
- Misst alle 5 min IR-Temperur (Bedeckungsgrad) und UV-Strahlung
ESP 32-3
- Betätigt sich als einfacher Blitzsensor
- Misst die Temperatur und Luftfeuchtigkeit
Warum misst das Ding jetzt noch die Temperatur und Luftfeuchtigkeit? Weils das kann! Erstmal nur mit einem DH22 der hier rumlag (siehe Fails ganz unten), aber für den nicht ausgebauten Dachboden sollte das reichen, ich will einfach nur der neugierde halber wissen was da Temperaturtechnisch so passiert.
Es wird also so sein, dass man erst die Hardware zusammenbaut, diese dann programmiert und anschließend werden die Daten von den ESP´s per MQTT verschickt. Leider wird das nicht ohne zu löten ablaufen. Vor Bits & Bites sollte man auch keine Angst haben. Aber, wir schaffen das! Was ich hier nicht erklären will ist, wie man den notwendingen MQTT Broker einrichtet. D.h. die Software die die MQTT Telegramme empfängt. Wer hier jedoch fragen hat, kann sich gerne melden. Ansonsten gibt es wunderbare Erklärungen im Netz. Vielleicht als Hintegrund, bei mir läuft Mosquitto auf einem Raspberry Pi. Hat auch den Hintergrund, dass es da viele Möglichkeiten gibt, MQTT zum laufen zu bringen und sich auch jede Möglichkeit noch ändert. Und ich bin ehrlich gesagt zu Faul um alle paar Wochen mal zu gucken ob das alles noch geht.
Von viel Kram zu einer fertigen Station
Auf gehts!
Ich gehe nochmal zurück auf Anfang und erwähne nochmal, dass viele Dinge nicht beim ersten mal geklappt haben bzw. sich nach einiger Zeit rausstellte, dass etwas so dann doch nicht ging. Diese Anleitung hier wird kontinuierlich aktualisiert und das was nicht ging, findet ihr ganz unten auf dieser Seite unter dem Punkt "FAIL": So here we go.
Im ersten Schritt werden wir den ersten ESP verkabeln, programmieren und dann in eine Gehäuse einbauen. Im zweiten Schritt kommt dann der zweite ESP mit Kabeln, Programm....
Aber warum eigentlich drei ESP ? Wenn man die UV-Strahlung, den Wind mit Geschwindigkeit und Richtung messen möchte und einen dazu noch die Himmelstemperatur interessiert, dann muss man auf eine andere Höhe als bei der Lufttemperatur. Die Lufttemperatur misst man idealerweise 2m über eine kurz gemähten Wiese. Bei uns sind es 2m über dem Gemüsebeet geworden. Dort hängt ebenfalls der Feinstaubsensor und auch das Barometer und der Ozon Sensor. Und der Blitzsensor hat es gerne sehr ruhig und mag keine elektrischen Felder. Sonst fühlt er sich gestört (disturber) oder es rauscht (noise) ihm zu sehr das er nicht arbeiten kann. Daher kommt er irgendwo hin - Dachboden - wo ihn keiner stört.
Auf einem Fahnenmast hängt dann ganz oben der Windmesser, der UV-Sensor und das IR-Thermometer. Das IR Thermometer kann man genau wie das Bauteil zur UV Messung auch tiefer hängen, aber bei mir ist da immer der Mast im weg.
ESP32 an LiPo Akku mit Solarzellen laden
HINWEIS:
ES GIBT HIERZU EIN FAIL MIT EINEM MCP-1700, bitte lesen wenn einer meint er wüste das besser.
Was brauchen wir dazu:
- ESP32 (NodeMCU)
- TP4056
- MCP-1725
- Kondensator (2,2µF / 16V)
- Kabel
- LiPo Akkus
Angefangen habe ich mal ganz einfach. Und zwar habe ich den ESP auf einem Board mit ein paar Kabeln am MCP1725 verdrahtet und den TP4056 und den Akku verbunden. Als Test war erst mal nur der IR-Sensor dran. Verwendet habe ich einen 3700mA LiOn Akku dessen Spannung gemessen und als Batterystand ebenfalls per MQTT übertragen wird. Da der ESP misst und dann für 5 Minuten schlafen geht, scheint der Akku bis zur undendlichkeit und noch viel weiter zu reichen. Meine anfänglichen Bedenken das man beim Laden des Akku dann die 4,2V Ladespannung angezeigt bekommt, hat sich auch nicht bewarheitet.
Der ESP32 hat ein Logik-Level von 3,3 V, man könnte auch sagen, die Spannung mit der das Gerät INTERN arbeitet. Es gibt zwar Boards die einen 5V Anschluss (an der Platine + USB) haben, aber da ist zwischen dem ESP und dem Pin noch ein Baustein der die Spannung reduziert. Wer also mit dem Eingang etwas messe möchte, darf die 3,3V nicht überschreiten. Also sollte. Kann man natürlich machen, aber nur einmal und braucht dann einen neuen ESP.
Jetzt stehen auf dem Akku dummerweise "3,7V". Das ist aber nun die Nennspannung. Voll wäre der Akku bei 4,2V. Die sogenannte Ladeschlussspannung. Da wir aber den vollen Akku (100%) messen wollen, müssen wir die Spannung reduzieren. Das machen wir mit einem Widerstand. Also genauer gesagt mit 2 Widerständen (27k und 100k). In der Software "mappen" wir dann die dann per Widerstand von 4,2V auf 3,3V reduzierte Spannung auf 100%.
So. Nächstes Problem bei Akkus. Wenn die zu tief entladen werden, sterben die. Im Raum stehen da 3,0V. Macht uns aber nix. Unter 3,3V geht nämlich der ESP aus. Die braucht er nämlich. Mehr findet er doof, weniger aber auch. Wir mappen daher in der Software eine Akkuspannung von 3,5V auf 0%.
Dieses Mapping macht also, dass der Analoge Eingangswert von 4095 (4,2V aka 3,3V nach Widerständen) zu 100% wird, und der Analoge Einganswert von 3412 zu 0%. Also die 3,5V im Akku. Eigentlich ganz einfach.
Den kompletten Code gibts übrigens unten!
void Batterie() {
analogRead(33);
int batteryLevel = map(analogRead(33), 3412, 4095, 0, 100); //Mapping from 4,2V/3,5V auf 100/0
delay(200);
client.publish("Wetterstation/Status/ESP32-2-Batteriestand", String(batteryLevel).c_str(), true);
}
Hinweis dazu:
Der Kondensator wird an den 3,3V Ausgang und Masse angeschlossen. Je nach dem welche Bauform und Hersteller man wählt, kann die Belegung der Beinchen anders sein! Bitte unbedingt das Datenblatt beachten!
ESP 32 - 1
Kommt noch.....
ESP 32 - 2
ESP32-2 soll also in 6m Höhe die Himmelstemperatur, die UV-Strahlung und Windrichtung und Stärke messen. Das ganze soll per Akku mit Strom versorgt und mit Solarzellen geladen werden. Das ist der Plan!
ESP 32 - 3
ACHTUNG! Auf den Fotos sieht man ein DF Robot BEETLE ESP 32 Microcontroller. Der ist halt schön klein, hat aber nicht alle GPIO Pins zur Verfügung. Aber ich brauche ja nur den I²C Port und 2 Digitale Pins und er lag halt noch rum. Der Sketch ist aber für einen normalen ESP geschrieben, beim BEETLE müsste man die Bezeichnung der Pin´s ändern.
Wir brauchen also:
- Einen ESP32, ich hatte noch ein BEETLE Board
- DHT22
- Breackout Board mit AS-3935, in meinem Fall eins von DFRobot, da gibts aber auch zig andere
- Kabel
- Netzteil das ausreichend Strom liefert
- Gehäuse, Halterung
An sicht ist das alles einfach. Vom DHT 22 und dem Blitzsensor werden jeweils GND an GND und V an 3,3V angeschlossen. Wenn einer vom DHT22 kein Breackout Board hat, kann er sich an das Fritzing hier halten, dass stimmt überein. Und da der ESP32 interne PULL-Up und Down Widerstände hat, die die Lib von Adafruit auch ansteuert, sucht man sich einfach einen freien GPIO Pin für die Datenleitung vom DHT22. Zum Beispiel Nummer 32. Die Nummer muss dann auch im Sketch angepasst werden!
So, bleiben noch 3 Käbelchen am Blitzsensor AS-3935. Da gibts dann noch eine Leitung für SCL, SDA und wir müssen ein Kabel am Pad anlöten das mit IRQ gekennzeichnet ist. Die SCL und SDA Käbelchen werden am ESP ebenfalls an SCL und SDA angeschlossen. GPIO 21 ist SDA, also die Datenleitung für den I²C Bus, GPIO 22 ist SCL, als die "Clock" Leitung für den I²C Bus. Das IRQ Kabel - hier Grün - wird benötigt um den ESP mitzuteilen, dass etwas passiert ist (hat geblitzt) und jetzt Daten zur Verfügung stehen. Das kann auch wieder an einen beliebigen GPIO Pin, ich habe die 7 genommen. Auch hier gilt: Im Sketch anpassen nicht vergessen.
Das wars schon. Sketch aufspielen, fertig ist die Laube. Zum Sketch noch einen Hinweis. Es gibt mehrere Bibliotheken für den AS-3935, mit der von DFRobot bin ich nicht so ganz warm geworden, die von Sparkfun funktioniert aber auch. Vermutlich wird das aber auch noch mal umgebaut.
Bleibt nur noch die Frage, wo baut man das alles ein. Ich habe mir einen kleinen Fuss gedruckt und alles dran festgeschraubt.
Der Code (der ja bei Arduino Sketch heißt)
Damit das ganz funktioniert, benötigt man einen "Sketch", also die Programmierung für den ESP32.
Ich habe dazu die Arudino IDE benutzt, da auch hier die Installation bzw. vorgehensweise immer etwas variiert, erspare ich mir hier etwas aufzuschreiben das dann in 2 Wochen wieder nicht funktioniert - Updates sei dank.
Generelle Vorgehensweise:
- Arduino IDE Installieren
- Im Boardmanager das Expressif ESP32 hinzufügen (bitte hier die Anleitung der Expressif Seite beachten!)
- Unter "Werkzeuge" --> "Bibliotheken verwalten" alle Bibliotheken installieren die notwendig sind. Sollte da eine fehlen ist das erstmal nicht tragisch, die IDE meckert dann beim kompilieren und man installiert einfach nach
- In Windows muss noch ein COM Port eingerichtet werden damit die IDE z.B. an COM3 dann auch den ESP findet, hier darauf achten das auch das richtige Board ausgewählt ist. Vom ESP gibts nämlich mehrere Versionen
Wenn man das alles hat, kann man den Sketch dann einfach kompilieren und übertragen.
WICHTIG:
Im Sketch müssen noch ein paar Dinge ergänzt werden:
- WiFi SSID
- WiFi Passwort
- MQTT Zugangsdaten usw.
ESP 32 -1 CODE
#include <Wire.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <sps30.h> //Feinstaubsensor
#include <Adafruit_DPS310.h> //Luftdruck
#include <OneWire.h>
#include <DallasTemperature.h>
#include "Adafruit_SHT31.h"
#include <Arduino.h>
#include "DHT.h"
#define wifi_ssid "WIFISSID" //wifi ssid
#define wifi_password "WIFIPASSWORD" //wifi password
#define mqtt_server "MQTT-IP-ADRESS" // server name or IP
#define mqtt_user "MQTT-USER" // username
#define mqtt_password "MQTT-PASSWORD" // password
#define debug_topic "Wetterstation/Status" //Topic for debugging
#define SP30_COMMS I2C_COMMS
#define DPS310_CS 10
#define ONE_WIRE_BUS 2
/* definitions for deepsleep */
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 300 /* Time ESP32 will go to sleep for 5 minutes (in seconds) */
#define TIME_TO_SLEEP_ERROR 3600 /* Time to sleep in case of error (1 hour) */
bool debug = true; //Display log message if True
Adafruit_DPS310 dps;
Adafruit_Sensor *dps_temp = dps.getTemperatureSensor();
Adafruit_Sensor *dps_pressure = dps.getPressureSensor();
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
RTC_DATA_ATTR int bootCount = 0;
Adafruit_SHT31 sht31 = Adafruit_SHT31();
WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(25, DHT22);
void setup() {
++bootCount;
Serial.begin(115200);
sht31.begin(0x44);
Wire.begin();
delay(200);
setup_wifi();
client.setServer(mqtt_server, 1883); // Configure MQTT connection, change port if needed.
if (!client.connected()) {
reconnect();
}
sensors.begin(); // Start up the library
Temperatursensor();
Luftdruck();
Bodentemperatur();
Feinstaubsensor();
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); //go to sleep
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
Serial.println("Boot number: " + String(bootCount));
Serial.println("Going to sleep as normal now."+ String(bootCount));
client.publish("Wetterstation/Status", "Wetterstation1 is Sleeping");
client.publish("Wetterstation/Boots", String(bootCount).c_str());
if (bootCount == 264)
{
client.publish("Wetterstation/Status", "Wetterstation1 FAN CLEANING");
sps30_start_manual_fan_cleaning();
delay(10000);
bootCount = 0;
}
delay(200);
esp_deep_sleep_start();
}
//Setup connection to wifi
void setup_wifi() {
Serial.println();
Serial.print("Connecting to ");
Serial.println(wifi_ssid);
WiFi.begin(wifi_ssid, wifi_password);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi is UP ");
Serial.print("=> ESP32 new IP address is: ");
Serial.print(WiFi.localIP());
Serial.println("");
}
//Reconnect to wifi if connection is lost
void reconnect() {
while (!client.connected()) {
Serial.print("Connecting to MQTT broker ...");
if (client.connect("ESP32Client", mqtt_user, mqtt_password)) {
Serial.println("OK");
client.publish("Wetterstation/Status", "Wetterstation1 is ONLINE");
} else {
Serial.print("[Error] Not connected: ");
Serial.print(client.state());
Serial.println("Wait 5 seconds before retry.");
delay(5000);
}
}
}
void Temperatursensor(){
delay(500);
dht.begin();
client.publish("Wetterstation/Status", "Wetterstation1: Temperaturmessung");
float t = sht31.readTemperature();
float h = sht31.readHumidity();
Serial.print("Temperature : ");
Serial.print(t);
Serial.print("Humidity: ");
Serial.println(h);
delay(750);
float heatindex = dht.computeHeatIndex(t, h);
double VaporPressureValue = h * 0.01 * 6.112 * exp((17.62 * t) / (t + 243.12));
double Numerator = 243.12 * log(VaporPressureValue) - 440.1;
double Denominator = 19.43 - (log(VaporPressureValue));
double DewPoint = (Numerator / Denominator);
client.publish("Wetterstation/Sensoren/Lufttemperatur", String(t).c_str(), true);
delay(100);
client.publish("Wetterstation/Sensoren/Luftfeuchtigkeit", String(h).c_str(), true);
delay(100);
client.publish("Wetterstation/Sensoren/Hitzeindex", String(heatindex).c_str(), true );
delay(100);
client.publish("Wetterstation/Sensoren/Taupunkt", String(DewPoint).c_str(), true );
sht31.heater(true);
delay(500);
}
void Feinstaubsensor(){
//SPS30 Feinstaubsensor Starten
client.publish("Wetterstation/Status", "Wetterstation1: Feinstaubmessung");
struct sps30_measurement m;
char serial[SPS30_MAX_SERIAL_LEN];
uint16_t data_ready;
int16_t ret;
uint8_t auto_clean_days = 1;
uint32_t auto_clean;
Serial.print("Feinstaubsensor starten\n");
sensirion_i2c_init();
delay(500);
while (sps30_probe() != 0) {
Serial.print("SPS sensor probing failed\n");
delay(500);
}
#ifndef PLOTTER_FORMAT
Serial.print("SPS sensor probing successful\n");
delay(500);
#endif /* PLOTTER_FORMAT */
ret = sps30_set_fan_auto_cleaning_interval_days(auto_clean_days);
if (ret) {
Serial.print("error setting the auto-clean interval: ");
Serial.println(ret);
}
ret = sps30_start_measurement();
if (ret < 0) {
Serial.print("error starting measurement\n");
}
#ifndef PLOTTER_FORMAT
Serial.print("measurements started\n");
delay(20000);
#endif /* PLOTTER_FORMAT */
do {
ret = sps30_read_data_ready(&data_ready);
if (ret < 0) {
Serial.print("error reading data-ready flag: ");
Serial.println(ret);
} else if (!data_ready)
Serial.print("data not ready, no new measurement available\n");
else
break;
delay(100); /* retry in 100ms */
} while (1);
ret = sps30_read_measurement(&m);
if (ret < 0) {
Serial.print("error reading measurement\n");
} else {
#ifndef PLOTTER_FORMAT
Serial.print("PM 1.0: ");
Serial.println(m.mc_1p0);
client.publish("Wetterstation/Sensoren/PM10", String(m.mc_1p0).c_str()); //MQTT PM10
delay(100);
Serial.print("PM 2.5: ");
Serial.println(m.mc_2p5 - m.mc_1p0);
client.publish("Wetterstation/Sensoren/PM25", String(m.mc_2p5 - m.mc_1p0).c_str()); //MQTTPM25
delay(100);
Serial.print("PM 4.0: ");
Serial.println(m.mc_4p0- m.mc_2p5);
client.publish("Wetterstation/Sensoren/PM40", String(m.mc_4p0- m.mc_2p5).c_str()); //MQTTPM40
delay(100);
Serial.print("PM 10.0: ");
Serial.println(m.mc_10p0 - m.mc_4p0);
client.publish("Wetterstation/Sensoren/PM100", String(m.mc_10p0 - m.mc_4p0).c_str()); //MQTTPM100
delay(100);
Serial.print("Typical partical size: ");
Serial.println(m.typical_particle_size);
client.publish("Wetterstation/Sensoren/TPS", String(m.typical_particle_size).c_str()); //MQTTtypicalpart
delay(1000);
#endif
Serial.println();
}
}
void Luftdruck(){
client.publish("Wetterstation/Status", "Wetterstation1: Luftdruckmessung");
float airpressure = 0;
char charpressure[] ="0.0";
Serial.println("DPS310");
if (! dps.begin_I2C()) {
Serial.println("Failed to find DPS");
while (1) yield();
}
Serial.println("DPS OK!");
dps.configurePressure(DPS310_64HZ, DPS310_64SAMPLES);
//dps_pressure->printSensorDetails();
delay(2000);
sensors_event_t pressure_event;
dps_pressure->getEvent(&pressure_event);
Serial.print(F("Luftdruck = "));
Serial.print(pressure_event.pressure);
Serial.println(" hPa");
client.publish("Wetterstation/Sensoren/Luftdruck", String(pressure_event.pressure).c_str());
delay(500);
}
void Bodentemperatur(){
client.publish("Wetterstation/Status", "Wetterstation1: Bodentemperaturmessung");
sensors.requestTemperatures();
Serial.println("Bodentemperature is: " + String(sensors.getTempCByIndex(0)) + "°C");
client.publish("Wetterstation/Sensoren/Bodentemperatur",String(sensors.getTempCByIndex(0)).c_str() );
delay(500);
}
void loop() {
}
ESP 32 -2 CODE
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_MLX90614.h> //IR Temp
#include <wire.h>
#define wifi_ssid "WIFI SSID" //wifi ssid
#define wifi_password "WIFI PASSWORD" //wifi password
#define mqtt_server "MQTT SERVER IP" // server name or IP
#define mqtt_user "MQTT USER" // username
#define mqtt_password "MQTT PASSWORD" // password
/* definitions for deepsleep */
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 300 /* Time ESP32 will go to sleep for 5 minutes (in seconds) */
#define TIME_TO_SLEEP_ERROR 3600 /* Time to sleep in case of error (1 hour) */
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
WiFiClient espClient;
PubSubClient client2(espClient);
float tempir = 0;
char chartempir[] ="0,00";
float tempambient =0;
char chartempambient[] = "0,00";
float bedeckungsgrad = 0;
char charbedeckungsgrad[] ="0,00";
//Setup
void setup() {
Serial.begin(115200);
Serial.println("ESP wacht auf\n");
Serial.print("IR Temperatur starten\n");
if (!mlx.begin()) {
Serial.println("Error connecting to MLX sensor. Check wiring.");
while (1);
};
delay(180000);
setup_wifi();
client2.setServer(mqtt_server, 1883); // Configure MQTT connection, change port if needed.
if (!client2.connected()) {
reconnect();
}
Serial.print("Emissivity = "); Serial.println(mlx.readEmissivity());
delay(500);
tempir = mlx.readObjectTempC();
dtostrf(tempir, 4, 1, chartempir);
tempambient = mlx.readAmbientTempC();
dtostrf(tempambient, 4, 1, chartempambient);
bedeckungsgrad = ((1 - (tempambient- tempir)/30)*100);
dtostrf( bedeckungsgrad, 4, 1, charbedeckungsgrad);
client2.publish("Wetterstation/Sensoren/Himmelstemperatur", chartempir);
Serial.print("Himmelstemperatur = "); Serial.println(tempir);
client2.publish("Wetterstation/Sensoren/IR_Umgebung", chartempambient);
Serial.print("IR Umgebung = "); Serial.println(tempambient);
client2.publish("Wetterstation/Sensoren/Bedeckungsgrad",charbedeckungsgrad);
Serial.print("Bedeckungsgrad = "); Serial.println(bedeckungsgrad);
delay(500);
analogRead(33);
int batteryLevel = map(analogRead(33), 3412, 4095, 0, 100); //Mapping from 4,2V/3,5V auf 100/0
Serial.print("Akkustand = "); Serial.println(batteryLevel);
client2.publish("Wetterstation/Status/Battery/WS2_Batterylevel", String(batteryLevel).c_str(), true);
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); //go to sleep
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
Serial.println("Going to sleep as normal now.");
client2.publish("Wetterstation/Status", "Wetterstation 2 SLEEPING");
esp_deep_sleep_start();
}
//Setup connection to wifi
void setup_wifi() {
Serial.println();
Serial.print("Connecting to ");
Serial.println(wifi_ssid);
WiFi.begin(wifi_ssid, wifi_password);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi is UP ");
}
//Reconnect to wifi if connection is lost
void reconnect() {
while (!client2.connected()) {
Serial.print("Connecting to MQTT broker ...");
if (client2.connect("ESP32-2-Client", mqtt_user, mqtt_password)) {
Serial.println("OK");
client2.publish("Wetterstation/Status", "Wetterstation 2 ONLINE");
} else {
Serial.print("[Error] Not connected: ");
Serial.print(client2.state());
Serial.println("Wait 5 seconds before retry.");
delay(5000);
}
}
}
void loop() {
}
ESP 32 -3 CODE
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <SparkFun_AS3935.h>
#include <DHT.h> //Temperatur & Luftteuchtigkeit
String WiFi_SSID = "WIFISSID";
String WiFi_PW = "WIFIPASSWORD";
const char* mqttServer = "IPADRESSEMQTTSERVER";
const int mqttPort = 1883;
const char* mqttUser = "MQTTBENUTZER";
const char* mqttPassword = "MQTTPASSWORD";
unsigned long waitCount = 0;
uint8_t conn_stat = 0;
unsigned long lastStatus = 0;
unsigned long lastTask = 0;
long lastMsg = 0;
char msg[50];
int value_1 = 0;
long time_1 = 0;
#define AS3935_ADDR 0x03
#define INDOOR 0x12
#define OUTDOOR 0xE
const int lightningInt = 7; //Define Interrupt Pin (AS3935) here
#define LIGHTNING_INT 0x08
#define DISTURBER_INT 0x04
#define NOISE_INT 0x01
int noiseFloor = 2;
int intVal = 0;
int periode = 1000;
float tempair = 0;
char chartempair[] = "0.00";
float humid = 0;
char charhumid[] = "0.00";
WiFiClientSecure TCP;
WiFiClient espClient;
PubSubClient client(espClient);
SparkFun_AS3935 lightning(AS3935_ADDR);
DHT dht(2,DHT22); //Define DHT PIN here
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
pinMode(lightningInt, INPUT);
delay(500);
Wire.begin();
lightning.begin();
lightning.setIndoorOutdoor(OUTDOOR);
dht.begin();
}
void loop() {
// start of non-blocking connection setup section
if ((WiFi.status() != WL_CONNECTED) && (conn_stat != 1)) { conn_stat = 0; }
if ((WiFi.status() == WL_CONNECTED) && !client.connected() && (conn_stat != 3)) { conn_stat = 2; }
if ((WiFi.status() == WL_CONNECTED) && client.connected() && (conn_stat != 5)) { conn_stat = 4;}
switch (conn_stat) {
case 0: // MQTT and WiFi down: start WiFi
Serial.println("MQTT and WiFi down: start WiFi");
WiFi.begin(WiFi_SSID.c_str(), WiFi_PW.c_str());
conn_stat = 1;
break;
case 1: // WiFi starting, do nothing here
Serial.println("WiFi starting, wait : "+ String(waitCount));
waitCount++;
break;
case 2: // WiFi up, MQTT down: start MQTT
Serial.println("WiFi up, MQTT down: start MQTT");
client.setServer(mqttServer, mqttPort);
client.connect("ESP32Client3", mqttUser, mqttPassword );
conn_stat = 3;
waitCount = 0;
break;
case 3: // WiFi up, MQTT starting, do nothing here
Serial.println("WiFi up, MQTT starting, wait since: "+ String(waitCount));
waitCount++;
break;
case 4: // WiFi up, MQTT up: finish MQTT configuration
Serial.println("WiFi up, MQTT up: finish MQTT configuration");
client.publish("Wetterstation/Status", "Wetterstation 3 gestartet");
conn_stat = 5;
break;
}
// end of non-blocking connection setup section
// start section with tasks where WiFi/MQTT is required
if (conn_stat == 5) {
if (millis() - lastStatus > 300000) {
Serial.println("Gerät läuft noch");
client.publish("Wetterstation/Status", "Blitzsensor lebt noch");
client.publish("Wetterstation/Blitzsensor/Disturber", "-");
client.publish("Wetterstation/Blitzsensor/Noise", "-");
client.publish("Wetterstation/Blitzsensor/Blitzerkennung", "-");
client.publish("Wetterstation/Blitzsensor/Blitzentfernung", "-");
tempair = dht.readTemperature();
dtostrf(tempair, 2, 2, chartempair);
humid = dht.readHumidity();
dtostrf(humid, 4, 1, charhumid);
Serial.print("Lufttemperatur: ");
Serial.println(tempair);
client.publish("Wetterstation/Blitzsensor/Lufttemperatur", chartempair);
Serial.print("Luftfeuchtigkeit: ");
Serial.println(humid);
client.publish("Wetterstation/Blitzsensor/Luftfeuchtigkeit", charhumid);
lastStatus = millis();
}
if(digitalRead(lightningInt) == HIGH){
intVal = lightning.readInterruptReg();
if(intVal == NOISE_INT){
client.publish("Wetterstation/Blitzsensor/Noise", "Rauschen empfangen");
Serial.println("Rauschen!");
//lastStatus = millis();
}
else if(intVal == DISTURBER_INT){
client.publish("Wetterstation/Blitzsensor/Disturber", "Störung empfangen");
Serial.println("Störung!");
//lastStatus = millis();
}
else if(intVal == LIGHTNING_INT){
client.publish("Wetterstation/Blitzsensor/Blitzerkennung", "Blitz erkannt");
Serial.println("Blitz erkannt");
byte distance = lightning.distanceToStorm();
char s [20];
sprintf (s, "%d", lightning.distanceToStorm());
client.publish("Wetterstation/Blitzsensor/Blitzentfernung", (const char*) s);
lastStatus = millis();
}
}
//Ende Programm
}
client.loop();
}
Gehäuse + 3D-Druckdaten

Die Fails!
SHT-31D zeigt falsche Werte an
Ich hatte beim SHT eine Zeit lang die Vermutung, dass er sehr konsequent und gleichmäßig eine zu hohe Temperatur anzeigt. Und zwar immer um die 3-5 Grad zu viel.
Das war auch wieder so ein Punkt auf den man erst kommt, wenn man weiß wonach man suchen muss:
ALLE Sensoren mit Temperatur und Feuchtemessung in einem Sensor, haben eine Integrierte Heizung um Kondesatbildung zu vermeiden. Die heizt aber den Sensor auf.
IN ARBEIT
ESP32 bleibt bei Beginn der Feinstaubmessung hängen
Ich hatte lange Zeit ein ganz spannendes Problem. Nachdem der ESP aufgewacht ist, lief der Sketch bis zum Beginn der Feinstaubmessung durch
und blieb nach der Initialisierung hängen. Im Serial.Monitor konnte man dann lesen:
SPS sensor probing failed
Das ist dei Fehlermeldung die auch im Sketch steht, wenn keine Daten mehr vom Sensor kommen. Kurzer Neustart und das ganze ging wieder.
Es war für mich nur nicht nachvollziehbar, wo das Problem herkam. Damit es nicht ganz so einfach war, passierte das mal nach 2h, mal nach 3 Tagen,
mal nach einer Woche. Nachdem ich mir dann nicht mehr zu helfen wusste, habe ich dann auf www.mikrokontroller.net mal einen Beitrag geschrieben
und siehe da, ein paar Leute die in der Materie richtig tief drinstecken, hatten ein paar Ideen. Des Rätzels Lösung war der Frequenz vom I²C Bus.
Standardwert sind hier bei Arduino 100kHz, ich habe es einfach auf 20kHz reduziert und seit dem ist der Fehler weg. DANKE INS FORUM!
und dann kommt zwischen die Klammern noch ein Wert, dass wars schon. Einfach.
ESP32 WiFi MQTT Verbindungsprobleme
Ein ganz spannendes Thema, steht auch wieder viel geschrieben im Netz. Gerne auch mal wieder sehr viel falsch kopiert und und.....
Fangen wir mal im Code (Sketch an). Der muss/soll "non Blocking" sein. Was ist das jetzt wieder. Son Programm auf dem ESP soll ja in bestimmten Abständen etwas tun. Zum Beispiel alle 5min etwas messen. Einfach quick und dirty könnte man jetzt dem Controller sagen:
Messe
Warte 5min
Messe
.....
Das warte, im ESP heißt es delay(ZEIT), blockt aber das script, weil in der Zeit der Controller steht und wartet, also nichts tut. Und da geht halt gerne schon mal die Verbindung, ja wohin eigentlich? Also sie ist weg. Einkaufen, Urlaub, Kino...ich weiß es nicht.
Alternativ kann ma auch gucken wie lange die Programmschleife (loop) läuft und setzt am Ende einfach eine Zahl ein, die man bei jedem Durchlauf um 1 erhöht und dann nach X Durchgängen etwas macht.
Das ist also der erste, wichtige Punkt. Non-blocking script. Gibt es auch ganz viele GUTE Anleitungen zu.
Das zweite ist der Router und das WiFi Netzwerk. Statische IP-Adresse ist immer gut. Manchmal macht auch ein MESH-Netzwerk Probleme wenn der kleine dann zwischen zwei Antennen hin und herspringt, dann ist die Verbindung zum MQTT Server auch schon mal gerne da, wo ich nicht weiß wo da ist. Auf jeden Fall weg. Also wenn man den ESP an einen Access-Point festtackern kann: machen.
Und wenn man mehrere ESP im Einsatz hat, muss man beim kopieren von Sketchen und Beispiel aufpassen. Die ESP32 Beispiele im Netz schreiben für das Verbinden mit dem MQTT Server gerne "ESP32Client" als Namen / Identifikation für das einzelnen Gerät. Bei mir seht ihr, dass in zwei Codes noch was dahinter steht. Hier mal als Beispiel der Auszug aus dem Code vom "ESP-3":
Wenn man das nicht macht, passiert folgendes: Da meldet sich am MQTT Server der Günther an und schickt Daten. Alles gut. Und dann kommt noch ein Günter. Und weil ein Computer immer nur einen Günther kennt, schmeißt der Server den ersten Günther raus. Warum ? Das ist halt unwahrscheinlich nervig für den Router und wenn sich da alle paar Sekunden wieder son ESP verbindet, leidet das ganze Netzwerk. Also aufpassen.
DHT 22 - Messung von Luftfeuchte und Lufttemperatur
Wenn man im Netz nach Temperaturmessung und Luftfeuchtigkeit sucht, landet man sehr schnell beim DHT22. Den gibts für wenige Euro mehr oder weniger an jeder Ecke zu kaufen. Beispiel sind ohne Ende vorhanden, also an sich erst mal nicht so schlecht. Anzusteuern ist das Ding über den One-Wire Bus, also braucht man nur drei Kabel (Stromversorgung + Datenleitung). Robust soll er auch sein. Wie sagt man im Ruhrgebiet so schön: Eigentlich und Scheiße sind immer nah beieinander. Eigentlich ist das Ding gut, Scheiße wirds von alleine wenn man längere Zeit Luftfeuchtigkeit messen will. Dann sättigt der Sensor nämlich auf und ein grafischer Verlauf der Luftfeuchtigkeit wird zu einier Linie:
Also die Linie ist die 100% bei der der Sensor dann hängen bleibt. Er kann zwar zwischen 0-100% Rh messen, aber er ist dafür nicht geeignet. Das erfährt man allerdings erst, wenn man gezielt danach sucht und kommt dann zu dem Punkt, dass der Sensor nur für Luffeuchtigkeiten unter 80% zu verwenden ist. Ist dann halt Blöd wenn man das Ding im Winter bei Nebel draußen hat. Um es kurz zu machen, der Sensor war nach dem ersten Nebel (Wir wohnen am Feld), hinüber. Es gibt zwar noch eine angebliche Rettungsmethode mit Backofen usw. aber ich habe mich nach einem neuen Sensor umgesehen. Der SHT31-D hat eine Teflon Membrane über dem Sensor und ist von Hause aus schon mal bis 100% Rh vom Hersteller freigegeben. Aber mit dem Hinweis, dass auch dieser aufsättigen kann, sich aber dann alleine wieder erholt. Wir werden sehen ob das klappt. Ansonsten gibts den nächsten FAIL eintrag.
MCP1700-3302E als Lineare Spannungsquelle für den EPS32
Ich habe im Netz eine Anleitung gefunden die eigentlich für einen Laien wie mich beschreibt, wie man einen ESP32 an einen Akku (z.B. LiPO) hängt und mittels eines TP4056 auflädt. Eigentlich. Wenn man jetzt das Glück hat, dass noch mal zu hinterfragen, kommt man auf eine Foren-Seite bei der recht weit unten jemand der offensichtlich Ahnung hat erläutert, warum das eine Bastellösung ist und Fachlich Falsch und äußerst Dumm. Kurz zusammengefasst hat da jemand geschrieben, dass da Leute die keine Ahnung haben, dass nicht kundtun, dafür aber von Websiten Dinge einfach so kopieren, die sie nie ausprobiert haben und es dann wieder Leute gibt das das nochmal kopieren und nicht ausprobieren...
Ich habe mich entschlossen das einfach mal so zu glauben was er geschrieben hat und anstatt des MCP1700 einen MCP1725 zu kaufen. So, dass Problem ist, der ESP zieht bis zu 400mA Strom in Spitzen. Der 1700er kann aber nur 100mA. Das puffern dann einige mit doch sehr viel Kapazität in Kondensatoren nach, was dann recht instabil läuft und wir wieder bei dem Punkt wären, dass da Leute etwas kopiert haben das sie kopiert haben aber nie ausprobiert haben....... Der 1725er kann bis zu 500mA und wird nur mit sehr wenig Kondensator-Kapazität gepuffert. Kosten tun die Dinger die so aussehen wie Transistoren gleich viel, also kann man auch direkt den größeren nehmen. Läuft bisher mit dem 1725 einwandfrei.