Teil 3
This commit is contained in:
parent
b3a40a8c5a
commit
5c319a26a1
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 93 KiB |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,73 @@
|
|||
# ESP8266 MQTT Wetterstation
|
||||
|
||||
Wie man eine Wetterstation basierend auf einem ESP8266 baut...
|
||||
|
||||
Der ESP verbindet sich per WLAN mit einem MQTT-Server und sendet die Messwerte als JSON (alle 10 Minuten), welche dann in Node-Red empfangen und verarbeitet werden. Zusätzlich werden die Daten in eine Influx-DB Datenbank geschrieben und können in Grafana visualisiert werden.
|
||||
|
||||
Diese Wetterstation kann als Erweiterung der Bresser-Wetterstation gesehen werden. Es werden Funktionen hinzugefügt, welche über die Bresser-Wetterstation nicht gemessen und empfangen werden können.
|
||||
|
||||
|
||||
# Die Sensoren
|
||||
| Sensor | Protocol | Values |
|
||||
| --------- |---------- | ------ |
|
||||
| BME 280 | I2C | Temperatur (nicht genutzt da nicht exakt), Luftfeuchtigkeit (nicht genutzt da von Bresser-Station gemesssen), Luftdruck |
|
||||
| 2x DS18B20 | OneWire Bus | Temperatur (2m und 0m Höhe) |
|
||||
| BH1750 | I2C | Helligkeit |
|
||||
| Rain sensor | Analog in | Regen ja/nein |
|
||||
| VEML6070 | I2C | UV-Intensität (daraus kann der UV-Index berechnet werden) |
|
||||
|
||||
<br>
|
||||
|
||||
# Hardware
|
||||
Es wird ein WeMos D1 Mini Board verwendet. Das PCB-Layout passt (nur) für dieses Board.
|
||||
## Schaltplan
|
||||
[<img src="Wetterstation_Schaltplan.png" width="80%">](Wetterstation_Schaltplan.png)
|
||||
|
||||
## Hauptplatine
|
||||
[<img src="Wetterstation_Leiterplatte.png" width="40%">](Wetterstation_Leiterplatte.png)
|
||||
|
||||
## 3D gedruckte Teile
|
||||
Im Internet habe ich einen sog. Stevenson-Screen gefunden, welcher als Sonnenschutz-Gehäuse für den BME280 und die DS18B20 Sensoren dient.
|
||||
|
||||
Für die beiden Lichtsensoren habe ich jeweils ein Gehäuse erstellt, welche z.B. mit einem Stück Plexiglas geschlossen oder für noch besseren Feuchtigkeitsschutz mit transparenten Epoxidharz ausgegossen werden können.
|
||||
Die Modelle können aus der GitHub repository heruntergeladen werden. Das Lichtsensor Gehäuse ist auch auf Tinkercad verfügbar: https://www.tinkercad.com/things/6c97AcGgvdE
|
||||
|
||||
<br>
|
||||
|
||||
# Software
|
||||
## ESP8266
|
||||
- Es wird bei jeder Messung ein Mittelwert aus 3 Messungen gebildet
|
||||
- Der Luftdruck auf NN-Niveau wird berechnet. (Im Programmcode muss die Aufstellhöhe der Station angepast werden, damit dieser Wert korrekt berechnet werden kann)
|
||||
- Es sind einige Debugging-Funktionen implementiert: ESP Reset, Ping/Pong, WIFI Signalstärke
|
||||
- Debug LED
|
||||
bootup: ein
|
||||
nach Initialisierung: blinkt 2x
|
||||
error, MQTT nicht verbunden: dauer ein
|
||||
- Damit die DS18B20 Sensoren funktionieren müssen die Sensoradressen im Code angepasst werden. Diese Adressen können mit Beispielcode `oneWireSearch.ino` der DallasTemperature Bibiliothek in Erfahrung gebracht werden.
|
||||
- Alle benötigten Bibiliotheken sind im Code verlinkt und können von dort heruntergeladen werden.
|
||||
|
||||
Achtung: Damit die Datenübertragung mit JSON funktioniert muss die zulässige Paketgröße `MQTT_MAX_PACKET_SIZE` in der `PubSubClient.h` Datei auf `1024` erhöht werden. Diese Datei ist unter Windows zu finden unter: `C:\Users\*YOUR_USERNAME*\Documents\Arduino\libraries\pubsubclient-master\src\PubSubClient.h`
|
||||
|
||||
## Datenverarbeitung: Node-Red
|
||||
Die Auswertung der Messwerte erfolgt in Node-Red.
|
||||
Ich habe einen Flow erstellt, welcher die Werte im Node-Red Dashboard grafisch darstellt sowie in eine Influx-DB Datenbank schreibt. Somit ist eine weitere Auswertung mit Grafana möglich. In Node-Red wird ebenfalls die Berechnung des UV-Risikofaktors (UV-Index) durchgeführt. Die Messwerte werden in globale Variablen geschieben, sodass sie innerhalb von Node-Red weiterverwendet werden können (z.B. für das [MQTT Weather Display](https://github.com/dustinbrun/MQTT-Weather-display))
|
||||
|
||||
[Screenshot des Node-Red Flows](Node-Red/node-red-flow.PNG)
|
||||
|
||||
Der Flow kann aus der Github Repository heruntergeladen werden.
|
||||
|
||||
# Quellen
|
||||
- https://github.com/jp112sdl/HB-UNI-Sen-WEA
|
||||
- Rain sensor: https://www.heise.de/developer/artikel/Darf-es-etwas-mehr-sein-Anschluss-von-Umweltsensoren-3339616.html
|
||||
- MQTT: https://randomnerdtutorials.com/esp8266-and-node-red-with-mqtt/
|
||||
- BME280, debug functions: https://github.com/adlerweb/ESP8266-BME280-Multi/blob/master/src/main.cpp
|
||||
- Stevenson Screen: https://www.thingiverse.com/thing:2755149
|
||||
- Weitere Quellen (Bibiliotheken etc.) sind im Code verlinkt
|
||||
|
||||
|
||||
<br><br>
|
||||
<p xmlns:dct="http://purl.org/dc/terms/" xmlns:cc="http://creativecommons.org/ns#" class="license-text">This work by <span property="cc:attributionName">Dustin Brunner</span> is licensed under <a rel="license" href="https://creativecommons.org/licenses/by/4.0">CC BY 4.0<img style="height:15px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" /><img style="height:15px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" /></a></p>
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons Lizenzvertrag" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />Dieses Werk von <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">Dustin Brunner</span> ist lizenziert unter einer <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Namensnennung 4.0 International Lizenz</a>.
|
||||
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
WARNING:
|
||||
If you are not receiving the Json Messages you probably have to increase the
|
||||
MQTT_MAX_PACKET_SIZE in the PubSubClient.h file to at least 1024
|
||||
(Located on Windows at C:\Users\*YOUR_USERNAME*\Documents\Arduino\libraries\pubsubclient-master\src\PubSubClient.h)
|
||||
*/
|
||||
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BME280.h> //https://github.com/adafruit/Adafruit_BME280_Library
|
||||
#include <BH1750.h> //https://github.com/claws/BH1750
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <PubSubClient.h> //https://github.com/knolleary/pubsubclient
|
||||
#include <OneWire.h>
|
||||
#include <DallasTemperature.h> //https://github.com/milesburton/Arduino-Temperature-Control-Library
|
||||
#include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson
|
||||
#include "Adafruit_VEML6070.h" // https://github.com/adafruit/Adafruit_VEML6070
|
||||
|
||||
|
||||
|
||||
const char *ssid = "----WIFI_SSID_HERE----";
|
||||
const char *password = "----WIFI_PASSWORD_HERE----";
|
||||
|
||||
//MQTT Server
|
||||
const char *mqtt_server = "----MQTT_SERVER_IP_HERE----";
|
||||
const char *mqtt_user = "----MQTT_USERNAME_HERE----";
|
||||
const char *mqtt_pass = "----MQTT_PASSWORD_HERE----";
|
||||
|
||||
|
||||
|
||||
uint8_t ds18b20_2m[8] = {0x28, 0xB4, 0x2A, 0xA7, 0x4D, 0x20, 0x01, 0x11}; //You need to adapt these addresses
|
||||
uint8_t ds18b20_0m[8] = {0x28, 0xA9, 0x2F, 0x1C, 0x0B, 0x00, 0x00, 0xA8};
|
||||
|
||||
const int hoehe = 437; //Aufstellhoehe in m
|
||||
|
||||
//Pins
|
||||
const int dataled = D8;
|
||||
const int onewire = D3; //DS18B20
|
||||
const int regensensorpin = A0;
|
||||
const int regensensorpower = D5;
|
||||
|
||||
#define TEMPERATURE_PRECISION 11 //9-12 Bit for DS18B20
|
||||
/* 9-12 Bit
|
||||
9 - 0.5 Steps
|
||||
10 - 0.25 Steps
|
||||
11 - 0.125 Steps <- Best for this Case
|
||||
12 - 0.0625 Steps
|
||||
*/
|
||||
|
||||
Adafruit_BME280 bme;
|
||||
Adafruit_VEML6070 uvMeter = Adafruit_VEML6070();
|
||||
BH1750 lightMeter;
|
||||
WiFiClient espClient;
|
||||
PubSubClient client(espClient);
|
||||
OneWire oneWire(onewire);
|
||||
DallasTemperature ds18b20(&oneWire);
|
||||
StaticJsonBuffer<1024> jsonBuffer;
|
||||
|
||||
|
||||
//Variablen
|
||||
float temp = 0;
|
||||
float bodentemp = 0;
|
||||
float druck_sensorwert = 0;
|
||||
float druck = 0;
|
||||
float feuchte = 0;
|
||||
float lux = 0;
|
||||
int uv = 0;
|
||||
float regensensorwert = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("MQTT Wetterstation");
|
||||
|
||||
pinMode(dataled, OUTPUT);
|
||||
pinMode(regensensorpin, INPUT_PULLUP);
|
||||
pinMode(regensensorpower, OUTPUT);
|
||||
digitalWrite(regensensorpower, LOW);
|
||||
|
||||
ledon();
|
||||
delay(500);
|
||||
|
||||
ds18b20.begin();
|
||||
ds18b20.setResolution(ds18b20_2m, TEMPERATURE_PRECISION);
|
||||
ds18b20.setResolution(ds18b20_0m, TEMPERATURE_PRECISION);
|
||||
|
||||
// SDA, SCL
|
||||
Wire.begin(D2, D1);
|
||||
|
||||
if (! bme.begin(0x76))
|
||||
{
|
||||
Serial.println("Could not find BME280 sensor");
|
||||
//while (1) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("BME280 initialized.");
|
||||
}
|
||||
|
||||
|
||||
if (! lightMeter.begin())
|
||||
{
|
||||
Serial.println("Could not find BH1750 sensor");
|
||||
//while (1) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("BH1750 initialized.");
|
||||
}
|
||||
|
||||
|
||||
uvMeter.begin(VEML6070_4_T);
|
||||
/*
|
||||
possible integration times: -> adapt the convert_to_risk_level-function accordingly!
|
||||
VEML6070_HALF_T ~62.5ms
|
||||
VEML6070_1_T ~125ms
|
||||
VEML6070_2_T ~250ms
|
||||
VEML6070_4_T ~500ms
|
||||
|
||||
*/
|
||||
uv = uvMeter.readUV();
|
||||
if (uv == -1 || uv == 65535)
|
||||
{
|
||||
Serial.println("Could not find VEML6070 sensor");
|
||||
//while (1) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("VEML6070 initialized.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("WiFi connected.");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
client.setServer(mqtt_server, 1883);
|
||||
client.setCallback(callback);
|
||||
|
||||
ledblink();
|
||||
Serial.println("-----Initialisierung beendet-----");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (!client.connected())
|
||||
reconnect();
|
||||
client.loop();
|
||||
|
||||
delay(100);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
void ledon() {
|
||||
for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
|
||||
analogWrite(dataled, fadeValue);
|
||||
delay(7);
|
||||
}
|
||||
}
|
||||
|
||||
void ledoff() {
|
||||
for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
|
||||
analogWrite(dataled, fadeValue);
|
||||
delay(7);
|
||||
}
|
||||
}
|
||||
|
||||
void ledblink() {
|
||||
ledon();
|
||||
delay(200);
|
||||
ledoff();
|
||||
delay(200);
|
||||
ledon();
|
||||
delay(200);
|
||||
ledoff();
|
||||
delay(200);
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Json format:
|
||||
{
|
||||
"temp_2m": 22.45,
|
||||
"temp_0m": 12.45,
|
||||
"druck": 1234.56,
|
||||
"feuchte": 45.4,
|
||||
"helligkeit": 12345.56,
|
||||
"regensensor": "256",
|
||||
"uvsensor" : "1234"
|
||||
}
|
||||
*/
|
||||
|
||||
void sendmqtt() {
|
||||
|
||||
JsonObject& json = jsonBuffer.createObject();
|
||||
json["temp_2m"] = temp;
|
||||
json["temp_0m"] = bodentemp;
|
||||
json["druck"] = druck;
|
||||
json["feuchte"] = feuchte;
|
||||
json["helligkeit"] = lux;
|
||||
json["regensensor"] = regensensorwert;
|
||||
json["uvsensor"] = uv;
|
||||
|
||||
char output[1025];
|
||||
json.printTo(output, sizeof(output));
|
||||
|
||||
client.publish("wetter_außen/get", output);
|
||||
client.publish("wetter_außen/update", "1");
|
||||
|
||||
jsonBuffer.clear();
|
||||
}
|
||||
|
||||
|
||||
void reconnect() {
|
||||
while (!client.connected()) {
|
||||
Serial.print("MQTT Verbindungsversuch...");
|
||||
if (client.connect("ESP8266_Wetterstation_außen", mqtt_user, mqtt_pass)) {
|
||||
Serial.println("connected");
|
||||
ledoff();
|
||||
client.subscribe("wetter_außen/debug/#");
|
||||
client.subscribe("wetter_außen/set/#");
|
||||
}
|
||||
else {
|
||||
Serial.print("fehlgeschlagen, rc=");
|
||||
Serial.print(client.state());
|
||||
Serial.println("Erneuter Versuch in 5 Sekunden");
|
||||
ledon();
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void callback(char* topic, byte* payload, unsigned int length) {
|
||||
Serial.print(F("Message arrived ["));
|
||||
Serial.print(topic);
|
||||
Serial.print(F("] "));
|
||||
|
||||
char message[length + 1];
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
message[i] = (char)payload[i];
|
||||
}
|
||||
message[length] = '\0';
|
||||
Serial.println(message);
|
||||
|
||||
String topicStr = topic;
|
||||
|
||||
if (topicStr.startsWith("wetter_außen/set"))
|
||||
{
|
||||
readsensors();
|
||||
sendmqtt();
|
||||
return;
|
||||
}
|
||||
|
||||
if (topicStr.startsWith("wetter_außen/debug/reset")) {
|
||||
Serial.println("MQTT RESET!");
|
||||
Serial.flush();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
if (topicStr.startsWith("wetter_außen/debug/ping")) {
|
||||
Serial.println("PING");
|
||||
client.publish("wetter_außen/debug/pong", message, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (topicStr.startsWith("wetter_außen/debug/wifi/ping")) {
|
||||
//@author Marvin Roger - https://github.com/marvinroger/homie-esp8266/blob/ad876b2cd0aaddc7bc30f1c76bfc22cd815730d9/src/Homie/Utils/Helpers.cpp#L12
|
||||
int32_t rssi;
|
||||
rssi = WiFi.RSSI();
|
||||
uint8_t quality;
|
||||
if (rssi <= -100) {
|
||||
quality = 0;
|
||||
} else if (rssi >= -50) {
|
||||
quality = 100;
|
||||
} else {
|
||||
quality = 2 * (rssi + 100);
|
||||
}
|
||||
char qualityString[8];
|
||||
dtostrf(quality, 1, 1, qualityString);
|
||||
client.publish("wetter_außen/debug/wifi/pong", qualityString);
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
void readsensors() {
|
||||
ledon();
|
||||
digitalWrite(regensensorpower, HIGH);
|
||||
delay(50);
|
||||
|
||||
temp = 0;
|
||||
bodentemp = 0;
|
||||
druck_sensorwert = 0;
|
||||
feuchte = 0;
|
||||
lux = 0;
|
||||
regensensorwert = 0;
|
||||
uv = 0;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
//BME280
|
||||
//temp += bme.readTemperature();
|
||||
druck_sensorwert += bme.readPressure();
|
||||
feuchte += bme.readHumidity();
|
||||
|
||||
//BH1750
|
||||
lux += lightMeter.readLightLevel();
|
||||
|
||||
//DS18B20
|
||||
ds18b20.requestTemperatures();
|
||||
bodentemp += ds18b20.getTempC(ds18b20_0m);
|
||||
temp += ds18b20.getTempC(ds18b20_2m);
|
||||
|
||||
//VEML6070
|
||||
uv += uvMeter.readUV(); //measurement takes as long as the integration time is set
|
||||
|
||||
//Regensensor
|
||||
regensensorwert += analogRead(regensensorpin);
|
||||
|
||||
delay(100);
|
||||
}
|
||||
temp = temp / 3;
|
||||
druck_sensorwert = druck_sensorwert / 3;
|
||||
feuchte = feuchte / 3;
|
||||
lux = lux / 3;
|
||||
bodentemp = bodentemp / 3;
|
||||
uv = uv / 3;
|
||||
regensensorwert = regensensorwert / 3;
|
||||
digitalWrite(regensensorpower, LOW);
|
||||
|
||||
//Rechnen
|
||||
//druck = (druck_sensorwert / 100) + (hoehe / 8.5);
|
||||
druck = druck_sensorwert / 100;
|
||||
druck = bme.seaLevelForAltitude(hoehe, druck);
|
||||
|
||||
ledoff();
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
Binary file not shown.
After Width: | Height: | Size: 137 KiB |
|
@ -5,7 +5,8 @@ Dieses Projekt besteht aus mehreren Teilen:
|
|||
|
||||
## 1. [Grundlagen: VEML 6070 Sensor, UV-Index Berechnung](VEML_6070/README.md)
|
||||
## 2. [Bresser Wetterstation MQTT-Anbindung mit RTL-433](rtl_433_Bresser/README.md)
|
||||
## [Zusatzinfos: verwendete Berechnungsformeln](Berechnungsfunktionen.md)
|
||||
## 3. [Erweiterung der Bresser Wetterstation: ESP8266-Wettersensoren](ESP8266/README.md)
|
||||
## 4. [Zusatzinfos: verwendete Berechnungsformeln](Berechnungsfunktionen.md)
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue