Diese Werte werden im Browser auf dem PC oder dem Smartphone angezeigt, wenn man die IP-Adresse des Web Servers (bei mir: http://192.168.178.100) in die Adresszeile eingibt.
Der Webserver ist so programmiert, dass er bei Überschreiten einer Temperatur von 50°C oder einer Gaskonzentration von 100 das Wort „Alarm“ ausgibt. Aber man muss schon aktiv auf der entsprechenden Seite nachsehen, um alles angezeigt zu bekommen. Das hat mir nicht gereicht, ich wollte auch mit einem akustischen und optischen Signal benachrichtigt werden. Also musste ich die Web-Seite mit einem Micro Controller oder Micro Computer auswerten, die Messwerte herausfiltern und ggf. den Alarm mit Buzzer und LED auslösen. Im zweiten Teil habe ich eine Lösung mit einem WLAN-fähigen Raspberry Pi und 1,3 Zoll OLED I2C 128 x 64 Pixel Display vorgestellt.
Nun möchte ich den Aufbau mit einem D1 Board und LCD Keypad Shield zeigen:
Benötigte Hardware für den ersten Teil
1 |
||
optional |
||
optional |
Lithium Batterie 3,7V |
|
1 |
||
1 |
||
Mini Breadboard, Jumperkabel |
Benötigte Hardware für den dritten Teil
1 |
||
1 |
LCD1602 Display Keypad Shield HD44780 1602 Modul mit 2x16 Zeichen |
|
alternativ |
||
Mini Breadboard, Jumperkabel |
||
Buzzer |
||
rote LED mit Vorwiderstand 200 bis 330 Ohm |
Ausgangspunkt für viele Projekte ist die Sammlung von Beispiel-Sketchen, die mit jeder Installation neuer Micro Controller oder einer Programmbibliothek erweitert wird. Schnell habe ich unter Beispiele/ESP8266WiFi die Sketche WiFiClient und WiFiClientBasic gefunden, die grundsätzlich geeignet sind, Verbindung mit Webseiten aus dem Internet aufzunehmen.
Zwei Herausforderungen (habe ich bei der NATO gelernt: „No Problems, only Challenges“):
Erstens möchte ich nicht ins Internet, sondern eine IP-Adresse im heimischen WLAN abfragen. Und zweitens möchte ich den übermittelten HTML-Text in einer String-Variablen für die weitere Bearbeitung speichern.
Also muss der Sketch WiFiClientBasic erweitert und modifiziert werden. Wir benötigen folgende Programmbibliotheken, um das D1 Board zunächst ebenfalls am heimischen Router anzumelden und dann als Web Client die HTML-Seite des Web Servers im Gartenhäuschen auszulesen.
ESP8266WiFiMulti WiFiMulti;
Im Weiteren werden die SSID und das Passwort für den WLAN-Zugang deklariert sowie die IP-Adresse des Web Servers (bei mir http://192.168.178.100) und der Port für HTML (80) eingegeben. Hier müssen Sie Ihre eigenen Eingaben vornehmen.
Dann werden die globalen Variablen für die Messwerte definiert, damit diese in allen Funktionen verfügbar sind.
In der void setup() werden die Verbindungen zum Seriellen Monitor der Arduino IDE sowie zum heimischen WLAN hergestellt.
Die regelmäßige Abfrage des Web Servers erfolgt dann mit http.GET() und http.GetString() in der void loop(), die gesamte Web-Seite wird in der Variablen payload abgespeichert.
Nach vielen Zeilen mit Formatierungen und dem Code für die automatische Aktualisierung der Web-Seite im Browser finden wir ganz am Ende die gesuchten Messwerte für Temperatur, Rel. Luftfeuchtigkeit (engl. Humidity) vom DHT22 und für die Gaskonzentration vom MQ-2. Da hilft zunächst nur „Tabula rasa“ = das Löschen der ersten 721 Zeichen mit der String-Methode StringName.substring(from,to). Bei mir war from=722, to ist optional und kann entfallen.
Mit einer for-Schleife suche ich dann die Indizes für die Buchstaben T (für Temperatur), H (für Humidity= Rel. Luftfeuchtigkeit) und G (für Gaskonzentration) als Bezugsgrößen für die erneute Verwendung der Methode StringName.substring(from,to). Bei den jeweiligen Werten für die Parameter from und to musste ich ein wenig tüfteln, denn die Temperatur kann ein- oder zweistellig sein und ggf. mit einem Minuszeichen versehen sein, und der Wert der Gaskonzentration kann zwei- oder dreistellig sein. Zum Glück ist die Methode String.toFloat() sehr tolerant und ignoriert die Leerzeichen bei der Temperatur und das Zeichen < am Ende eines zweistelligen Wertes für die Gaskonzentration.
Voila, damit werden die Werte für die Temperatur, Luftfeuchtigkeit und Gaskonzentration im Seriellen Monitor angezeigt. Hier der (Teil-) Sketch zum Download
Aber das ist ja nur die halbe Miete. Wir wollen das D1 Board ja ohne Anschluss an den PC benutzen und ggf. einen Alarm bei Überschreiten der Grenzwerte auslösen. Also muss ein kleines Display her und selbstverständlich wieder unser Buzzer und ggf. eine rote LED für den Alarm, wenn die Grenzwerte überschritten werden.
Weil es so schön praktisch ist, benutze ich das LCD Keypad Shield. Besonderheiten zur Benutzung des Keypads (also der Tasten) finden Sie in dem Blog-Beitrag „Der neue D1 mit ESP8266mod-12F im Uno-Format“. Aber die Tasten benötigen wir hier nicht. Wir benutzen nur das LCD, das hier an GPIO-Pins angeschlossen ist. Also die entsprechende Bibliothek (nicht I2C) installieren und inkludieren sowie die Pins gemäß Pinout-Diagramm des D1 Boards definieren:
// Das LCD hat keinen I2C-Adapter, die Daten werden über die Pins D4 bis D7 übertragen
//LCD pin to Arduino
const int pin_BL = 15;
const int pin_EN = 2;
const int pin_RS = 0;
const int pin_D4 = 4;
const int pin_D5 = 14;
const int pin_D6 = 12;
const int pin_D7 = 13;
Den freien Pin D2 = GPIO16 benutzen wir für den Buzzer und die LED.
Hier der erweiterte Sketch: (Download)
/*
This sketch reads the HTML-Text from a TCP server in your local network.
By Gerald Lechner and Bernd Albrecht for AZ-Delivery*/
//*** HTTP-Client
const char* ssid = STASSID;
const char* password = STAPSK;
const char* url = "http://192.168.178.100";
const uint16_t port = 80;
// Das LCD hat keinen I2C-Adapter, die Daten werden über die Pins D4 bis D7 übertragen
//LCD pin to Arduino
const int pin_BL = 15;
const int pin_EN = 2;
const int pin_RS = 0;
const int pin_D4 = 4;
const int pin_D5 = 14;
const int pin_D6 = 12;
const int pin_D7 = 13;
LiquidCrystal lcd( pin_RS, pin_EN, pin_D4, pin_D5, pin_D6, pin_D7);
float t = 0.0;
float h = 0.0;
float g = 0.0;
int indexT;
int indexH;
int indexG;
int buzzer=16;
ESP8266WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// initialize digital pin D2=GPIO16 as an output.
pinMode(buzzer, OUTPUT);
lcd.begin(16, 2); //LCD1602 mit 16 Zeichen und 2 Zeilen
// We start by connecting to a WiFi network
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, password);
Serial.println();
Serial.println();
Serial.print("Wait for WiFi... ");
while (WiFiMulti.run() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
delay(500);
}
void loop() {
Serial.print("connecting to ");
// Serial.print(host);
Serial.print(url); //neu
Serial.print(':');
Serial.println(port);
//**** Neue Hauptschleife
if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClient client;
HTTPClient http;
Serial.print("[HTTP] begin...\n");
if (http.begin(client, url)) { // HTTP "url" ""entfernt
Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
String payload1 = payload.substring(722);
// Serial.println(payload);
// Serial.println();
Serial.println(payload1);
for (int i=0;i<=payload1.length();i++)
{
if (payload1.charAt(i) == 'T') indexT = i;
// Serial.println(indexT);
if (payload1.charAt(i) == 'H') indexH = i;
// Serial.println(indexH);
if (payload1.charAt(i) == 'G') indexG = i;
// Serial.println(indexG);
}
String Tstring = payload1.substring(indexT+12,indexH-10);
String Hstring = payload1.substring(indexH+10,indexH+12);
String Gstring = payload1.substring(indexG+18,indexG+22);
// Serial.println(payload1);
Serial.println(Tstring);
Serial.println(Hstring);
Serial.println(Gstring);
t = Tstring.toFloat();
h = int(Hstring.toFloat());
g = int(Gstring.toFloat());
Serial.println(t,1);
Serial.println(int(h));
Serial.println(int(g));
lcd.clear();
lcd.setCursor(0,0); //Zählung beginnt bei Null, erst Zeichen, dann Zeile
lcd.print("t=");
lcd.print(String(t));
lcd.print(" h=");
lcd.print(String(int(h)));
lcd.setCursor(0,1); // 0=Erstes Zeichen, 1=zweite Zeile
lcd.print("g=");
lcd.print(String(int(g)));
if (t>50.0 || g>100) {
lcd.print(" Alarm!");
digitalWrite(buzzer, HIGH); // turn the Buzzer and LED on
delay(200); // wait
digitalWrite(buzzer, LOW); // turn the Buzzer and LED off
delay(100); // wait
digitalWrite(buzzer, HIGH); // turn the Buzzer and LED on
delay(200); // wait
digitalWrite(buzzer, LOW); // turn the Buzzer and LED off
delay(100); // wait
}
}
}
else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("[HTTP} Unable to connect\n");
}
}
delay(5000);
}
In dem dreiteiligen Blog habe ich gezeigt, wie man Sensordaten über das heimische WLAN senden kann und die Werte am PC, Smartphone, mit Raspberry oder ESP8266 (auch alle gleichzeitig) anzeigen und einen Alarm auslösen kann, wenn Grenzwerte überschritten werden. Wie eingangs erwähnt, könnte man auch Bewegungsmelder und andere Sensoren als Diebstahlsicherung ergänzen. Viel Spaß beim Nachbauen.
2 Reacties
Andreas Wolter
@jürgen: die multi-Variante lässt die Verwaltung mehrere WiFi-Netzwerke zu. Z.B. wenn Sie den Standort verlassen und sich in ein anderes Netzwerk einloggen möchten. Warum die andere Variante mit inkludiert ist, kann ich nicht genau sagen. Entweder werden beide Bibliotheken zusammen verwendet, da eine auf der anderen aufsetzt, oder es ist ein Überbleibsel aus der Entwicklung des Sketches. Probieren Sie es einmal aus, indem Sie die andere Variante auskommentieren.
Grüße,
Andreas Wolter
AZ-Delivery Blog
jürgen
Warum wird hier #include und nicht nur #include benutzt? Warum werden beide Versionen eingeschlossen? Welchen Vorteil bringt in diesem Beispiel die Multi-Varinate??