So, weiter geht es mit dem nächsten Klassiker, dem Temperatur-/Luftfeuchtesensor. Aufbau: Das DHT-Shield (2,27 €) auf den WeMos D1 mini (3,63 €) und fertig.
- WeMos D1 mini mit Sensor Shield
Der folgende Sketch ist für das WeMos „DHT Shield“ und „DHT Pro Shield“ gedacht, sollte aber mit allen Sensoren der Baureihen DHT11, DHT21 und DHT22 funktionieren. (Nicht wundern: Je nach verwendetem Sensortyp werden unterschiedlich viele Nachkommaziffern gemeldet, liegt nicht am Sketch, sondern an der Genauigkeit des Sensortyps.)
Grundfunktionen:
- Alle x Sekunden wird eine Messung durchgeführt.
- Spätestens nach y Sekunden werden die Messwerte in entsprechende CCU-Systemvariablen geschrieben ( 0 = nie).
- Falls sich der zuletzt gemessene Wert vom zuletzt gemeldeten Wert um mindestens den Differenzwert z (Schwellwert, 0 = nie) unterscheidet, wird das sofort der CCU gemeldet.
- Alle Auslöser für eine CCU-Meldung (Zeitintervall, Temperatur- oder Feuchtigkeitsänderung) lassen sich beliebig kombinieren.
- Kontrollmeldungen im seriellen Monitor:
- Abfrage der Werte bzw. Steuerung über HTTP-Befehle:
"<IP-Adresse>" gibt eine Status- und Befehlsübersicht aus
"<IP-Adresse>/temp" gibt die zuletzt gemessene Temperatur aus (Grad Celsius)
"<IP-Adresse>/feucht" gibt die zuletzt gemessene Luftfeuchtigkeit aus (in Prozent)
"<IP-Adresse>/zeit" gibt den CCU-Zeitstempel aus, an dem die letzte Meldung an die CCU erfolgte
"<IP-Adresse>/temp?delta=<wert>" setzt den Temperatur-Differenzwert, der eine CCU-Meldung auslöst
"<IP-Adresse>/temp?korr=<wert>" setzt den Korrekturwert für die Temperaturmessung
"<IP-Adresse>/feucht?delta=<wert>" setzt den Feuchtigkeits-Differenzwert, der eine CCU-Meldung auslöst
"<IP-Adresse>/feucht?korr=<wert>" setzt den Korrekturwert für die Feuchtigkeitsmessung
"<IP-Adresse>/zeit?delta=<wert>" setzt die Zeitspanne, nach der spätestens eine CCU-Meldung erfolgt
"<IP-Adresse>/zeit?mess=<wert>" definiert das Messintervall
Darüber hinaus können die Messwerte um einen festzulegenden Korrekturwert verändert werden, z.B. wenn der Sensor dicht am Chip des WeMos liegt und dadurch aufgeheizt wird. Diese Funktion ist allerdings mit Vorsicht zu genießen, da sie stumpf den Korrekturwert zum Messwert addiert; exponentielle Fehler lassen sich so nicht wirklich sinnvoll korrigieren.
Code: Alles auswählen
/*
* WeMos Temperatur-/Luftfeuchtesensor (Prototyp)
*
* verbindet sich mit dem vorhandenen WLAN als Server
* und bei Bedarf mit der CCU als Client
*
* Steuerung über HTTP-Befehle:
* "<IP-Adresse>" gibt eine Status- und Befehlsübersicht aus
* "<IP-Adresse>/temp" gibt die zuletzt gemessene Temperatur aus (Grad Celsius)
* "<IP-Adresse>/feucht" gibt die zuletzt gemessene Luftfeuchtigkeit aus (in Prozent)
* "<IP-Adresse>/zeit" gibt den CCU-Zeitstempel aus, an dem die letzte Meldung an die CCU erfolgte
* "<IP-Adresse>/temp?delta=<wert>" setzt den Temperatur-Differenzwert, der eine CCU-Meldung ausloest
* "<IP-Adresse>/temp?korr=<wert>" setzt den Korrekturwert fuer die Temperaturmessung
* "<IP-Adresse>/feucht?delta=<wert>" setzt den Feuchtigkeits-Differenzwert, der eine CCU-Meldung ausloest
* "<IP-Adresse>/feucht?korr=<wert>" setzt den Korrekturwert fuer die Feuchtigkeitsmessung
* "<IP-Adresse>/zeit?delta=<wert>" setzt die Zeitspanne (in Sekunden), nach der spaetestens eine CCU-Meldung erfolgt
* "<IP-Adresse>/zeit?mess=<wert>" definiert das Messintervall (in Sekunden)
*
* Getesteter Aufbau:
* WeMos D1 mini
* DHT Shield mini
* Pin-Belegung:
* D4: Datenleitung DHT-Sensor
*
* DHT sensor library by Adafruit v.1.2.3
*
* 9.Februar 2016 —m.yoda
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include "DHT.h"
// ******* Netzwerkeinstellungen, bitte anpassen! *******
const char* ssid = "abc123"; // SSID des vorhandenen WLANs
const char* password = "geheim"; // Passwort für das vorhandene WLAN
IPAddress gateway(xxx,xxx,xxx,xxx); // IP-Adresse des WLAN-Gateways
IPAddress subnet(255,255,255,0); // Subnetzmaske
IPAddress ip(xxx,xxx,xxx,xxx); // feste IP-Adresse für den WeMos
const char* host = "xxx.xxx.xxx.xxx"; // IP-Adresse der CCU (mit Punkten!)
ESP8266WebServer server(80); // Webserver initialisieren auf Port 80
// ******* Sensoreinstellungen, bitte anpassen! *******
DHT dht(D4, DHT11); // verwendeter Datenpin des Sensors, bei WeMos mini Shields = D4
// verwendeter Sensortyp, unterstützt werden DHT11 DHT21 DHT22
// WeMos mini DHT Shield = DHT11
// WeMos mini DHT Pro Shield = DHT22
unsigned long deltaMessungSekunden = 10; //Zeitintervall (Sekunden) nach dem eine Messung erfolgt
float korrTemp = 0; // Korrekturwert fuer die Temperaturmessung
float korrFeucht = 0; // Korrekturwert fuer die Feuchtigkeitsmessung
// ******* Einstellungen fuer Meldungen an die CCU, bitte anpassen! *******
String tempCCUname = "temp"; // Bezeichnung der CCU-Systemvariable für die gemessene Temperatur
String feuchtCCUname = "feucht"; // Bezeichnung der CCU-Systemvariable für die gemessene Luftfeuchtigkeit
unsigned long deltaMeldungSekunden = 3600; // Zeitintervall (Sekunden) nach dem eine CCU-Meldung erfolgt (0 bedeutet nie)
float deltaTemp = 1; // Temperaturaenderung (*C) bei der eine CCU-Meldung erfolgt (0 bedeutet nie)
float deltaFeucht = 0; // Luftfeuchteaenderung (%) bei der eine CCU-Meldung erfolgt (0 bedeutet nie)
float feucht = 0, feuchtCCU = 0, temp = 0, tempCCU = 0;
unsigned long jetztMillis = 0;
unsigned long deltaMessungMillis = deltaMessungSekunden * 1000, letzteMessungMillis = 0;
unsigned long deltaMeldungMillis = deltaMeldungSekunden * 1000, letzteMeldungMillis = 0;
String antwort = "", meldung = "",letzteMeldungCCUzeit = "";
String zeitstempel() { // Betriebszeit als Stunde:Minute:Sekunde
char stempel[10];
int lfdStunden = millis()/3600000;
int lfdMinuten = millis()/60000-lfdStunden*60;
int lfdSekunden = millis()/1000-lfdStunden*3600-lfdMinuten*60;
sprintf (stempel,"%03d:%02d:%02d", lfdStunden, lfdMinuten, lfdSekunden);
return stempel;
}
void messung() { // Sensor abfragen
feucht = dht.readHumidity() + korrFeucht;
temp = dht.readTemperature() + korrTemp;
if (isnan(feucht) || isnan(temp)) {
Serial.println(zeitstempel() + " Fehler: Sensor konnte nicht abgefragt werden");
delay(100);
return;
}
letzteMessungMillis = jetztMillis;
Serial.println(zeitstempel() + " Messung Luftfeuchtigkeit: " + feucht + " % Temperatur: " + temp + " * C");
}
void melde_CCU() { // Werte an die CCU melden
WiFiClient client; // Webclient initialisieren
if (!client.connect(host, 8181)) { // mit dem CCU-Port 8181 verbinden
Serial.println(zeitstempel() + " Fehler: Verbindung zur CCU konnte nicht aufgebaut werden");
delay(100);
return;
}
meldung = "GET /eriwan.exe?antwort1=dom.GetObject('" + feuchtCCUname + "').State('" + feucht + "')";
meldung = meldung + "&antwort2=dom.GetObject('" + tempCCUname + "').State('" + temp + "')";
client.println(meldung); // Daten an CCU melden
delay(100);
int i = 0;
String zeile = "";
while(client.available()){ // Antwort der CCU zeilenweise auslesen
i ++;
zeile = client.readStringUntil('\n'); // Zeitstempel der CCU ausfiltern und merken
if (i == 7) {
letzteMeldungCCUzeit = zeile;
}
}
Serial.println("Werte an CCU gemeldet, " + letzteMeldungCCUzeit);
letzteMeldungMillis = jetztMillis; // gemeldete Daten merken
feuchtCCU = feucht;
tempCCU = temp;
}
void wurzel_behandlung() { // bei Aufruf des Root-Verzeichnisses
String betriebszeit = zeitstempel();
antwort = "WeMos Temperatur-/Luftfeuchtesensor\n";
antwort = antwort + "\tBetriebszeit: " + betriebszeit + " (Std:Min:Sek)\n";
antwort = antwort + "\tVerbunden mit: " + ssid + "\n";
int rssi = WiFi.RSSI();
antwort = antwort + "\tSignalstaerke: " + String(rssi) + " dBm\n\n";
antwort = antwort + "Letzte Messwerte\n\tTemperatur: " + String(temp) + " * C\n";
antwort = antwort + "\tLuftfeuchtigkeit: " + String(feucht) + " %\n\n";
antwort = antwort + "Korrekturwerte\n\tTemperatur: " + String(korrTemp) + " * C\n";
antwort = antwort + "\tLuftfeuchtigkeit: " + String(korrFeucht) + " %\n\n";
antwort = antwort + "Letzte Datenuebertragung CCU\n\t" + letzteMeldungCCUzeit;
antwort = antwort + "\tGemeldete Temperatur: " + String(tempCCU) + " * C\n";
antwort = antwort + "\tGemeldete Luftfeuchtigkeit: " + String(feuchtCCU) + " %\n\n";
antwort = antwort + "Ausloeser fuer Datenuebertragung CCU\n";
antwort = antwort + "\tZeitintervall: " + String(deltaMeldungSekunden) + " Sekunden\n";
antwort = antwort + "\tTemperaturdifferenzwert: " + String(deltaTemp) + " * C\n";
antwort = antwort + "\tFeuchtigkeitsdifferenzwert: " + String(deltaFeucht) + " %\n\n";
antwort = antwort + "HTTP-Befehlsuebersicht:\n";
antwort = antwort + "\"<IP-Adresse>/temp\"\n\tgibt die zuletzt gemessene Temperatur aus (Grad Celsius)\n";
antwort = antwort + "\"<IP-Adresse>/feucht\"\n\tgibt die zuletzt gemessene Luftfeuchtigkeit aus (in Prozent)\n";
antwort = antwort + "\"<IP-Adresse>/zeit\"\n\tgibt den CCU-Zeitstempel aus, an dem die letzte Meldung an die CCU erfolgte\n";
antwort = antwort + "\"<IP-Adresse>/temp?delta=<wert>\"\n\tsetzt den Temperatur-Differenzwert, der eine CCU-Meldung ausloest\n";
antwort = antwort + "\"<IP-Adresse>/temp?korr=<wert>\"\n\tsetzt den Korrekturwert fuer die Temperaturmessung\n";
antwort = antwort + "\"<IP-Adresse>/feucht?delta=<wert>\"\n\tsetzt den Feuchtigkeits-Differenzwert, der eine CCU-Meldung ausloest\n";
antwort = antwort + "\"<IP-Adresse>/feucht?korr=<wert>\"\n\tsetzt den Korrekturwert fuer die Feuchtigkeitsmessung\n";
antwort = antwort + "\"<IP-Adresse>/zeit?delta=<wert \"\n\tsetzt die Zeitspanne (in Sekunden), nach der spaetestens eine CCU-Meldung erfolgt\n";
antwort = antwort + "\"<IP-Adresse>/zeit?mess=<wert>\"\n\tdefiniert das Messintervall (in Sekunden)\n";
server.send(300, "text/plain", antwort);
delay(150);
Serial.println(zeitstempel() + " unspezifische HTTP-Anfrage");
}
void melde_feucht() { // bei Aufruf von ".../feucht"
String delta = server.arg("delta");
String korr = server.arg("korr");
if (delta != "") {
deltaFeucht = delta.toFloat();
server.send(200, "text/plain", "Feuchtigkeitsdifferenzwert fuer CCU-Meldungen auf " + delta + " % gesetzt.");
delay(100);
Serial.println(zeitstempel() + " Feuchtigkeitsdifferenzwert ueber HTTP geaendert: " + delta + " %");
}
else if (korr != "") {
korrFeucht = korr.toFloat() * 1000;
server.send(200, "text/plain", "Korrekturwert fuer Feuchtigkeitsmessung auf " + korr + " % gesetzt.");
delay(100);
Serial.println(zeitstempel() + " Feuchtigkeitskorrekturwert ueber HTTP geaendert: " + korr + " %");
}
else {
server.send(200, "text/plain", String(feucht));
delay(100);
Serial.println(zeitstempel() + " Luftfeuchtigkeit ueber HTTP gemeldet");
}
}
void melde_temp() { // bei Aufruf von ".../temp"
String delta = server.arg("delta");
String korr = server.arg("korr");
if (delta != "") {
deltaTemp = delta.toFloat();
server.send(200, "text/plain", "Temperaturdifferenzwert fuer CCU-Meldungen auf " + delta + " * C gesetzt.");
delay(100);
Serial.println(zeitstempel() + " Temperaturdifferenzwert ueber HTTP geaendert: " + delta + " * C");
}
else if (korr != "") {
korrTemp = korr.toFloat() * 1000;
server.send(200, "text/plain", "Korrekturwert fuer Temperaturmessung auf " + korr + " * C gesetzt.");
delay(100);
Serial.println(zeitstempel() + " Temperaturkorrekturwert ueber HTTP geaendert: " + korr + " Sekunden");
}
else {
server.send(200, "text/plain", String(temp));
delay(100);
Serial.println(zeitstempel() + " Temperatur ueber HTTP gemeldet");
}
}
void melde_zeit() { // bei Aufruf von ".../zeit"
String delta = server.arg("delta");
String mess = server.arg("mess");
if (delta != "") {
deltaMeldungSekunden = delta.toInt();
deltaMeldungMillis = deltaMeldungSekunden * 1000;
server.send(200, "text/plain", "Zeitintervall fuer CCU-Meldungen auf " + delta + " Sekunden gesetzt.");
delay(100);
Serial.println(zeitstempel() + " Zeitintervall fuer CCU-Meldungen ueber HTTP geaendert: " + delta + " Sekunden");
}
else if (mess != "") {
deltaMessungMillis = mess.toInt() * 1000;
server.send(200, "text/plain", "Zeitintervall fuer Sensorabfrage auf " + mess + " Sekunden gesetzt.");
delay(100);
Serial.println(zeitstempel() + " Zeitintervall fuer Sensorabfrage ueber HTTP geaendert: " + mess + " Sekunden");
}
else {
server.send(200, "text/plain", "Letzte Aktualisierung der CCU\n" + letzteMeldungCCUzeit);
delay(100);
Serial.println(zeitstempel() + " Letzte Aktualisierung der CCU ueber HTTP Status gemeldet");
}
}
void setup() {
dht.begin(); // Sensor initialisieren
// Seriellen Monitor für Kontrollausgaben öffnen
Serial.begin(115200);
Serial.println("");
Serial.println("WeMos Temperatur-/Luftfeuchtesensor");
// WLAN-Verbindung herstellen
WiFi.config(ip, gateway, subnet); // auskommentieren, falls eine dynamische IP bezogen werden soll
WiFi.begin(ssid, password);
Serial.print("Verbindungsaufbau");
// Verbindungsaufbau abwarten
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" erfolgreich!");
Serial.println("");
Serial.print("Verbunden mit: ");
Serial.println(ssid);
Serial.print("Signalstaerke: ");
int rssi = WiFi.RSSI();
Serial.print(rssi);
Serial.println(" dBm");
Serial.print("IP-Adresse: ");
Serial.println(WiFi.localIP());
Serial.println("");
// HTTP-Anfragen bearbeiten
server.on("/", wurzel_behandlung);
server.on("/temp", melde_temp);
server.on("/feucht", melde_feucht);
server.on("/zeit", melde_zeit);
// HTTP-Server starten
server.begin();
Serial.println(zeitstempel() + " HTTP-Server gestartet");
// Startwerte fuer Zeittrigger
letzteMessungMillis = millis();
letzteMeldungMillis = millis();
}
void loop() {
// auf HTTP-Anfragen warten
server.handleClient();
jetztMillis = millis();
// neue Messung falls Zeitintervall erreicht
if(jetztMillis - letzteMessungMillis > deltaMessungMillis) {
messung();
}
// neue Meldung an die CCU falls Zeitintervall erreicht
if(!deltaMeldungMillis == 0 && jetztMillis - letzteMeldungMillis > deltaMeldungMillis) {
Serial.print(zeitstempel() + " Zeitintervall erreicht: ");
melde_CCU();
}
// neue Meldung an die CCU falls Luftfeuchtigkeitsaenderung den Schwellwert erreicht
if(!deltaFeucht == 0 && abs(feucht - feuchtCCU) >= deltaFeucht) {
Serial.print(zeitstempel() + " Luftfeuchtigkeitsaenderung: ");
melde_CCU();
}
// neue Meldung an die CCU falls Temperaturaenderung den Schwellwert erreicht
if(!deltaTemp == 0 && abs(temp - tempCCU) >= deltaTemp) { // Neue Meldung wg. Temperaturaenderung?
Serial.print(zeitstempel() + " Temperatursaenderung: ");
melde_CCU();
}
}
Ein paar Anpassungen (im oberen Teil) des Sketches wie z.B. IP-Adressen, Namen der CCU-Systemvariablen etc. sind natürlich noch nötig.
Ich freue mich auf eure Kommentare und Feedback, ob es in eurem Setting auch funktioniert - bei mir tut es soweit.
Frohes Basteln und gutes Gelingen!
—m.yoda
*** Nachträgliche Änderung ***
"Onkel Fritz" hat mich darauf aufmerksam gemacht, dass bei den Netzwerkeinstellungen im Beispielsketch immer noch der Fehlerteufel steckt.
Deshalb habe ich am 17.8.2016 die Zeile
const char* host = "xxx,xxx,xxx,xxx"; // IP-Adresse der CCU
ersetzt durch
const char* host = "xxx.xxx.xxx.xxx"; // IP-Adresse der CCU (mit Punkten!)
Ich hoffe, dass jetzt niemand mehr auf's Glatteis geführt wird...
—m.yoda
EDIT: Laut Hinweis von TomT funktioniert der oben angeführte Code nicht mehr, da die Art der Datenübertragung an die CCU geändert wurde.
Der richtige Codeschnipsel findet sich hier :
viewtopic.php?f=31&t=29321&p=411995#p411995
Roland M. - Mod