Überraschungsei für Wetterfrösche dank BME680, ESP8266, Arduino & ThingSpeak

In der heutigen Folge soll eine von einem Arduino-Board betriebene Wetterstation periodisch Umweltdaten erfassen, und diese Daten mittels WiFi über HTTP in eine Cloud-Plattform übertragen.

In Pocket speichern vorlesen Druckansicht 17 Kommentare lesen
Lesezeit: 23 Min.
Von
  • Dr. Michael Stal
Inhaltsverzeichnis

In der heutigen Folge soll eine von einem Arduino-Board betriebene Wetterstation periodisch Umweltdaten erfassen, und diese Daten mittels WiFi über HTTP in eine Cloud-Plattform übertragen. Interessierte Zeitgenossen können dann live am mobilen oder stationären Gerät die Entwicklung der Messdaten in der Cloud verfolgen. Um dieses Ziele zu erreichen, müssen wir uns mehreren Herausforderungen stellen. Welche das sind und wie sie sich lösen lassen, zeigt der vorliegende Artikel. Seien Sie aber unbesorgt - es gibt ein Happy End!

Wenn wir Sensor-Daten der Wetterstation in der Cloud speichern wollen, können wir PasS/IaaS-Plattformen wie Amazon AWS oder Microsoft Azure nutzen. Einfacher und preisgünstiger gestaltet sich die Aufgabe mit einer speziell für Datenanalytik konzipierten Lösung. ThingSpeak ist eine solche IoT-Plattform und ermöglicht das Ablegen von Sensordaten. Sie integriert darüber hinaus MATLAB-Werkzeuge von MathWorks für komplexere Datenvisualisierungen. Ein freier Account stellt eine kostenlose Möglichkeit dar, um Daten-Kanäle einzurichten, die der Nutzer allerdings höchstens alle 16 Sekunden aktualisieren darf. Kanäle können dabei privat oder öffentlich zugänglich sein. Der Charme von ThingSpeak liegt in seiner einfachen Nutzbarkeit dank schlichtem HTTP, das es für das Lesen oder Schreiben von Daten verwendet. Die Kanäle lassen sich über Webbrowser oder Apps beobachten.

Zum Registrieren eines neuen Kontos gehen Interessierte auf die ThingSpeak-Webseite.

Anmeldung als neuer Nutzer auf der ThingSpeak

Nach der erfolgreichen Erstellung eines neuen Kontos kann die neue Nutzerin sich in das eigene anmelden.

(Bild: Erstellen eines neuen Benutzerkontos auf ThingSpeak)

Ist das Konto fertig eingerichtet, kann der Nutzer durch einfachen Knopfdruck einen neuen Kanal erstellen: siehe hier. Der Kanal braucht zumindest einen Namen, und zwischen eins und acht Daten-Feldern. Nur wer will, kann zusätzlich weitere Information wie geographische Position, eine externe Webseite oder Metadaten angeben.

Teilnehmer können ihre eigenen Kanäle anmelden

Der neue Kanal taucht jetzt in der Hauptseite des Nutzers auf. Über die Registerkarte API Keys lassen sich die vertraulichen Zugriffsschlüssel zum Lesen und Schreiben abrufen.

Auf der Registerkarte erfährt der IoT-Maker seine API-Schlüssel, die er später in seinen Programmen benötigt

In der Registerkarte Sharing ist das eingeschränkte Freigabe des Kanals für bestimmte Personen oder sogar die öffentliche Freigabe des Kanals möglich. In letzterem Fall kann jeder Nutzer weltweit den Kanal beobachten, etwa durch Eingabe der öffentlichen Channel ID. Der von mir für dieses Postings benutzte Kanal besitzt übrigens die Kennung 438188 und lässt sich über die Seite lesen. Das ist auch programmatisch möglich, wie der Artikel noch später illustriert. Die ersten fünf Diagramme zeigen den zeitlichen Verlauf der Sensordaten-Felder, das sechste eine MATLAB-Analyse über die Häufigkeiten bestimmter Temperaturwerte.

ThingSpeak erlaubt die Erstellung privater Kanäle.

Einen privaten Datenkanal kann nur dessen Ersteller nutzen

Alternativ ist auch die Kreierung eines öffentlich zugänglichen Kanals möglich. Öffentliche Kanäle haben eine eindeutige Kennung. Sie lassen sich über Web-Browser beobachten, oder auch von mobilen Geräten aus. Etwa von einem Tablet

Kanalbeobachtung für die Wetterstation auf einem iPad

Oder auch über Apps:

Eine der Apps zum Beobachten von öffentlichen ThingSpeak-Kanälen

Die Datenablage wäre also jetzt geklärt. Nur woher kriegen wir eigentlich unsere physikalischen Messwerte?
Der Sensor BME680 von Bosch Sensortec misst Umweltgrößen und adressiert speziell kleinere und mobile Geräte. Er erweitert den bekannten Sensor BME280 aus gleichem Hause. Zu seinen Messgrößen gehören Temperatur (-45...85°) , Luftfeuchtigkeit (0...100%), Luftdruck (300...1100hPa), Höhe, und Luftqualität im Raum (Indoor Air Quality). Dabei liegt sein Stromverbrauch bei wenigen Micro-Ampere. Mit Ausmaßen von 3.0mm x 3.0mm x 0.93mm zeigt sich der Sensor gut gewappnet, um eine kleinere Wetterstation oder ein Wearable zu betreiben. Die Luftbelastung ermittelt der BME680 in Form eines Widerstandswerts in der Einheit KOhm. Je niedriger dieser Widerstand ausfällt, desto mehr Teilchen sind in der Luft. Bosch berechnet daraus den Indoor Air Quality Index. Das funktioniert aber nur mit einer speziellen Bibliothek des Herstellers (https://github.com/BoschSensortec/BME680_driver), da dazu auch einige Betriebswerte des Sensors ins Spiel kommen. Wollen Sie den Index berechnen, müssen Sie folglich diese Bibliothek in Ihren Sketch integrieren. Weitere Details über den Sensor können sie dessen Datasheet entnehmen.

Der Sensor BME680 misst verschiedene Umweltgrößen

(Bild: Bosch Sensortec)

Natürlich erwerben Maker den Sensor üblicherweise nicht “nackt”, sondern in Form eines Breakout-Boards. Die Produkte stammen von Herstellern wie BlueDot, Adafruit, Watterott, MikroElektronika, Octopus oder Pimeroni. Die meisten Breakout-Boards stellen eine I2C- und als Alternative eine SPI-Schnittstelle zur Verfügung, und haben einen Logic Level Konverter onboard, sodass der Nutzer den Sensor mit Spannungen von 3V-5V betreiben kann.

Für den vorliegenden Beitrag findet ein entsprechendes Board von Watterott zu preisgünstigen 15,95 Euronen Verwendung (siehe Abbildung).

BME680-Breakout-Board von Watterott

(Bild: Watterott)

Beim Anschluss habe ich mich für I2C (auch bezeichnet mit IIC, I2C, TWI) entschieden, um mit zwei Leitungen für die Kommunikation zwischen Arduino und BME680 auszukommen. Nähere Details zu I2C hat dieser Blog bereits früher vorgestellt.
Unter I2C/TWI besitzt der Sensor entweder die eindeutige I2C-Kennung 0x76 oder 0x77, je nachdem ob der Pin SDO auf 0 liegt oder auf 1. Letzteres sofern gleichzeitig Pin CS auf 1 liegt. Jedenfalls verbinden Maker IIC-Takt und Datenleitungspins von Arduino und Breakout-Board abhängig vom gewählten Arduino-Board.

Auf der Arduino IDE ist für die Ansteuerung des BME680 eine Bibliothek von Adafruit verfügbar. Da die BME680-Boards direkten Zugriff auf den Sensor implementieren, ist die Adafruit-Bibliothek wie auch zum Beispiel die Bibliothek von BlueDot für das Watterott-Breakout-Board ebenfalls nutzbar. Suchen Sie also im Bibliotheksmanagement der Arduino IDE nach dem Begriff BME680 und installieren Sie die entsprechende Bibliothek von Adafruit. Zwecks manueller Installation lässt sich die Bibliothek auch über GitHub beziehen: hier geht es zur Bibliothek.

Die Programmierung ist selbsterklärend. bme.setup() startet den Sensor, bme.performReading() führt die Messung durch. Danach lassen sich über die Variable bme die Messwerte auslesen. Die Initialisierung am Anfang von setup() habe ich der Dokumentation von Bosch Sensortec entnommen.

// Adafruit-Bibliothek für BME680
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"

// Luftdruck auf Meereshoehe:
#define SEALEVELPRESSURE_HPA 1013.25

Adafruit_BME680 bme; // Zugriff ueber I2C


double humidity = 0.0; // Feuchtigkeit
double temperature = 0.0; // Temperatur
double pressure = 0.0; // Druck
double gas = 0.0; // Gas/Luftqualitaet
double est_altitude= 0.0; // Ungefaehre Hoehe


void setup()
{
Serial.begin(9600); // seriellen Monitor starten

if (!bme.begin()) {
Serial.println("Keinen BME680 Sensor gefunden!");
while (1);
}

// Initialisierung von Oversampling und Filter
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}


void loop()
{
measurement(); // Messwerte erfassen
}

void measurement(void)
{
// Erst den bme680 auslesen
if (! bme.performReading()) {
Serial.println("Fehler beim Messen ");
return;
}

// Werte ermitteln:
temperature = bme.temperature;
pressure = bme.pressure / 100.0;
humidity = bme.humidity;
gas = bme.gas_resistance / 1000.0;
est_altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);

// und am seriellen Monitor ausgeben
Serial.print("Temperatur = ");
Serial.print(temperature);
Serial.println(" *C");

Serial.print("Luftdruck = ");
Serial.print(pressure);
Serial.println(" hPa");

Serial.print("Feuchtigkeit = ");
Serial.print(humidity);
Serial.println(" %");

Serial.print("Gas = ");
Serial.print(gas);
Serial.println(" KOhms");

Serial.print("Ungefaehre Hoehe = ");
Serial.print(est_altitude);
Serial.println(" m");

Serial.println();
delay(2000);
}

Die Ausgabe schaut bei einem Testlauf meiner Schaltung wie folgt aus:

Temperatur = 24.13 *C
Luftdruck = 939.03 hPa
Feuchtigkeit = 31.02 %
Gas = 60.68 KOhms
Ungefaehre Hoehe = 636.94 m

Temperatur = 24.13 *C
Luftdruck = 939.05 hPa
Feuchtigkeit = 31.00 %
Gas = 61.08 KOhms
Ungefaehre Hoehe = 636.94 m

Bosch empfiehlt, den Sensor längere Zeit einzubrennen, damit er stabile Messwerte liefert. Speziell am Anfang ist sonst zum Beispiel der gemessene Luftwiderstand zu ungenau. Lassen Sie Ihre Schaltung daher ruhig initial für 24-48 Stunden laufen.

Für die Messwerterfassung und die Integration aller Komponenten kommt, wie nicht anders zu erwarten, ein Original-Arduino zum Einsatz.

Ein Arduino Nano ist kompakt und preisgünstig, aber trotzdem elistungsfähig

(Bild: Reichelt)


Als Board verwendet der Beitrag den Arduino Nano mit 5V-Logik, der unter seiner Motorhaube einen ATmega328 beherbergt. Mit 2 KB SRAM und 32 KB Flashspeicher sowie 16 Mhz Frequenz ist das kompakte Board ideal für eine kleine Wetterstation geeignet. Pin Layout auf der Seite verfügbar.

Das Pin-Layout eines Arduino Nano. Rechts im Bild sind die I2C-Pins A4 und A5 zu sehen

Für die Kommunikation über I2C mit dem BME680-Breakout-Board dienen beim Nano die Pins A4 und A5 (Daten über SDA, Takt über SCL).
Selbstverständlich können Sie statt des Nano auch ein anderes Arduino-Board einsetzen, das I2C oder SPI implementiert, etwa einen Leonardo, Uno oder Mega. Dann müssen Sie statt A4 und A5 die jeweils dort zuständigen Pins für I2C verwenden.

Wir haben inzwischen die Cloudplattform, den Sensor und als zentrale Steuerung einen Arduino Nano. Das letzte Puzzlestück besteht aus der Kommunikation des Arduino-Boards mit der Cloud. Wer kein Arduino-Board mit integriertem (W)LAN-Anschluss sein eigen nennt (Arduino MKR1000, Yun, Arduino plus Ethernet-Shield oder WiFi-Shield …), muss sich anderweitig behelfen. Den dafür prädestinierten Chip von Espressif namens ESP8266 hatte dieser Blog schon ausführlich adressiert: siehe hier. Ihn gibt es in verschiedenen Varianten für eine Handvoll Euro. Allgemein steht ESP8266 für einen Microcontroller mit zusätzlicher WiFi-Komponente. Soll ein Arduino Board günstig ins Internet, bietet sich daher der ESP8266 geradezu an. Größere ESP8266-Varianten wie nodemcu (ESP-12e oder ESP-12f) kann der Entwickler auch standalone einsetzen, also ganz ohne Arduino.

Für die Kommunikation der Wetterstation kommt ein ESP-01 aus der Produktfamile ESP8266 zum Einsatz

Wir nutzen trotzdem die einfachste Bauform, den ESP-01, um unsere Arduino-basierte Schaltung für lau mit WiFi-Kommunikation auszustatten.

Die Pinbelegung eines ESP-01 (ESP8266)

Da der ESP-01 nur 3,3V verträgt, braucht die Wetterstation allerdings einen Logik Level Konverter zwischen den 3,3V des ESP-01 und der 5V Logik des Arduino Nano. Für unseren Zweck sollte der Konverter-Baustein neben den Stromanschlüssen Vcc und GND auf jeder Seite über 4 Kanäle verfügen. Beispielsweise tut es folgendes Produkt von SparkFun: Logic-Level-Konverter.

Ein Logic Level Converter vermittelt zwischen 3,3V und 5V Bausteinen

(Bild: SparkFun)


Seinen “Saft” kann der ESP-01 von verschiedenen Seiten erhalten. In der vorliegenden Schaltung habe ich mich für ein FTDI-TTL-to-USB-Modul entschieden, da sich der ESP-01 damit auch direkt am Computer, beispielsweise über die Arduino IDE betreiben lässt.

Exemplarisch ein FTDI-Board von SparkFun. Damit können Entwickler den ESP-01 mit einem PC verbinden

(Bild: SparkFun)

Das ist beispielsweise nötig, um ihn zu konfigurieren oder mit neuer Firmware zu flashen.
Es ergibt sich somit folgende Schaltung:

Um den ESP-01 standalone zu programmieren, erfolgt eine Verbindung mit dem Computer über ein FTDI-USB-to-TTL Board

Der ESP-01 hat standardmäßig einen AT-Kommandointerpreter als Firmware an Bord, und ist auf hohe Baudraten eingestellt. Da viele Arduino-Boards leider nur einen einzigen UART-Eingang besitzen, den sie per USB zum Laden von Firmware, Bootloadern und Sketches nutzen, müssen wir jeden weiteren seriellen Kanal per Software simulieren. Dazu gibt es die Bibliothek SoftwareSerial, dank der sich zwei beliebige Pins des Arduino als RX (Eingang) und TX (Ausgang) nutzen lassen, was aber nur bei niedrigeren Baudraten funktioniert. Daher besteht die erste Aufgabe darin, den ESP-01 entsprechend zu konfigurieren. Beispielsweise benötigen wir eine Rekonfiguration des ESP-01 auf eine Baudrate von 9600.
Zu diesem Zweck schließen wir den ESP-01 über einen FTDI-USB-to-TTL-Adapter direkt an den Desktop oder Notebook an, und rufen die Arduino IDE auf. Unter dem Menü Tools stellen wir den richtigen COM-Port des FTDI-Adapters ein. Wir wechseln in den seriellen Monitor (ebenfalls im Tools-Menü). Als Baudrate funktioniert zunächst dank Werkseinstellung meistens 112500 oder 57600 Baud (rechts unten im Fenster). Als Modus sollte Both NL and CR selektiert sein (links neben der Baudrate).

Die Verwendung der Arduino IDE ist nicht alternativlos. Anstelle der IDE erlauben Terminal-Werkzeuge wie putty, ssh einen Dialog mit dem ESP-01.

Sitzung mit dem AT-Kommandointerpreter des ESP-01. Für die Wetterstation sind Baudrate und ZUgang/Verbindung mit einem WLAN einzurichten

Um die Funktionstüchtigkeit des ESP-01 zu prüfen, gibt der Nutzer im Textfeld AT, gefolgt von der Eingabetaste ein, worauf die Rückmeldung Ok erscheinen müsste. Der Befehl AT+UART_DEF=9600,8,1,0,0 konfiguriert die Baudrate dauerhaft auf 9600 Baud.
Mit AT+CWMODE=1 lässt sich der ESP-01 als WLAN-Client einstellen.
Der AT-Befehl für die Verbindung zu einem existierenden WLAN lautet: AT+CWJAP=“SSID”,”PASSWORD”
Anschließend müsste der ESP-01 die erfolgreiche Verbindung zum WLAN bestätigen. Es sollte sich hierbei um das WLAN handeln, in die sich die Wetterstation später einloggt. Alternativ können Sie diese Verbindung aber auch aus dem Arduino-Sketch heraus bewerkstelligen.
Mittels Eingabe von AT+CIFSR erfährt der Entwickler dann unter anderem die IP, die der Access Point dem ESP-01 zugewiesen hat. Nun kennen Sie die Adresse der Wetterstation im eigenen Netz.
Nach dieser Konfiguration ist der ESP-01 für den Zugriff über den Arduino Nano gerüstet. Ein Arduino-Sketch sendet AT-Befehle über einen SoftwareSerial-Anschluss an den ESP-01, und kann diesen durch Ansteuerung des RESET-Eingangs sogar neustarten.

Der ESP8266 lässt sich übrigens auch wie ein Arduino Board innerhalb der Arduino IDE nutzen.
Dazu geben Sie im Sub-Menü Voreinstellungen (beziehungsweise Preferences) zusätzliche die URL folgenden Boardsmanagers ein:

 http://arduino.esp8266.com/stable/package_esp8266com_index.json 

Steht dort schon ein Eintrag, geben Sie an dessen Ende ein Komma ein, gefolgt von der genannten URL.
Anschließend können Sie im Tools > Board Menü die esp8266-Plattform installieren. Danach ist noch im Tools-Menü die Auswahl des richtigen COM-Ports und im Boards-Menü das Selektieren des Generic ESP8266 Module notwendig. Jetzt lassen sich Arduino-Sketches auf dem ESP-Modul hochladen und ausführen. Achtung: Dadurch wird auch eine neue Firmware (Arduino Core) auf den ESP-01 übertragen. Die AT-Firmware, die wir für die Wetterstation benötigen, geht damit verloren, und Sie müssen diese Firmware demzufolge bei Bedarf neu auf den ESP-01 flashen.

An dieser Stelle ist noch der Hinweis wichtig, dass ein ESP8266 zwei Laufzeitmodi kennt. Das eine ist der Programmausführungsmodus, also der Normalbetrieb, bei dem der ESP-01 ein Programm ausführt. Das andere ist der Flash-Modus bzw. Bootloader-Modus, der dem Entwickler gestattet, eine neue Firmware aufzuspielen. Wie bereits erwähnt, ist das Hochladen eines neuen Sketches über die Arduino IDE auf ein ESP8266-Board gleichbedeutend mit einem Flashen. Kurz und prägnant: Kein Flashmodus => Kein Sketchupload.
In welchem Modus der ESP läuft, entscheidet sich beim Boot/RESET des Chips. Ist während des Resets der Pin GPIO0 mit LOW belegt, startet der ESP8266 im Flashmodus, ansonsten im Ausführungsmodus.

Es führen mehrere Wege nach Rom. Zum einen erlaubt das ESP8266 Flasher Werkzeug unter Windows ein relativ bequemes interaktives Flashen.
Dieses Tool erhalten Sie kostenlos unter der URL.
Die AT-Firmware ist über eine Webseite downloadbar.
Mit dem kommandozeilenorientierten Python-Werkzeug esptool.py auf GitHub (siehe hier) ist das Firmware-Flashen auch unter Windows, MacOS oder Linux möglich.

Nun liegen alle Teile der Wetterstation unserer Stückliste vor:

  • Breadboard
  • ESP-01 (ESP8266)
  • Arduino Nano
  • FTDI USB-to-TTL Adapter
  • BME680 Sensor
  • Logic Level Converter (3,3V und 5V) mit 4 Datenkanälen
  • Mehrere Steckverbindungsdrähte (male-male und female-male)
  • Zwei USB-Kabel, eines für Arduino Nano und eines für das FTDI-Board

Der Aufbau der Schaltung kann beginnen. Insgesamt ergibt sich folgendes Bild:

Auf dem Bild ist die komplette Schaltung mit allen beteiligten Komponenten zu sehen

Fehlt nur noch die Software. Beachten Sie auch die Variable esp01, hinter der sich die serielle Verbindung vom Arduino Nano zum ESP-01 verbirgt:

  • Pin D6 des Nano fungiert als virtueller RX-Kanal und ist mit dem TX-Pin des ESP-01 verbunden
  • Pin D7 des Nano fungiert als virtueller TX-Kanal und ist mit dem RX-Pin des ESP-01 verbunden
  • Pin D8 des Nano ist mit dem RESET-Eingang des ESP-01 verbunden
SoftwareSerial

SoftwareSerial esp01(6,7)

Über diese serielle Verbindung sendet der Arduino-Sketch AT-Befehle zum ESP-01 beziehungsweise erhält von dort Rückmeldungen.

Der Sketch verbindet sich bei setup() mit ESP-01, seriellen Monitor und BME280-Sensor. In der Ereignisschleife loop() fragt der Arduino Nano nach mindestens 16 Sekunden die Messwerte des BME680 ab (measurement()) und versendet diese über den ESP-01 an ThingSpeak (sendMeasurement()). sendMeasurement() verbindet sich mit der HTTP-basierten ThingSpeak-API (connectToThingSpeak()) und liefert dann über HTTP GET einen Update der Messwerte ab (writeToThingSpeakChannel()).

resetESP01() dient - nomen est omen - zum programmatischen RESET des ESP-01.

In der Vereinbarung für CHANNEL_WRITE_KEY hinterlegen Sie ihren Schlüssel zum Updaten des Kanals (im Listing rot markiert).

/************************************************** 
*
* Mini-Wetterstation
* mit Sensor BME380
* Arduino Nano und
* ESP8266
* (c) Michael Stal, 2018
* Creative Commons License
*
**************************************************/


/****** Nur wenn nicht Hardware-Serial ******/

#include <SoftwareSerial.h>
#define ESP_RX 6 // Nutzung der Pins D6
#define ESP_TX 7 // ... und D7
// Anschluss des ESP01 ueber ESP_RX und ESP_TX

SoftwareSerial esp01(ESP_RX, ESP_TX);
/********************************************/

/******** Adafruit BME680 Bibliothek ********/


// Adafruit-Bibliothek für BME680

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"

// Luftdruck auf Meereshoehe:
#define SEALEVELPRESSURE_HPA 1013.25

Adafruit_BME680 bme; // Zugriff ueber I2C


double humidity = 0.0; // Feuchtigkeit
double temperature = 0.0; // Temperatur
double pressure = 0.0; // Luftdruck
double gas = 0.0; // Gas/Luftqualitaet
double est_altitude= 0.0; // Ungefaehre Hoehe

/********************* THINGSPEAK ********************/
#define CHANNEL_WRITE_KEY "<Tragen Sie Ihren Key hier ein>"
#define THINGSPEAK_IP "184.106.153.149"
#define THINGSPEAK_PORT 80
/******************* ESP spezifisch ******************/
#define ESP_SPEED 9600 // ESP-01 auf 9600 Baud eingestellt!
#define ESP_RESET 8 // Arduino D8 pin <-> RESET pin ESP-01

#define ESP_AT_COMMAND_CIPSTART "AT+CIPSTART=\"TCP\",\""
#define ESP_AT_COMMAND_CIPSEND "AT+CIPSEND="
#define ESP_AT_COMMAND_CIPCLOSE "AT+CIPCLOSE"
/********************** Timing ************************/
// Alles was mit Zeitintervallen zu tun hat
long sampleTime = 16; // Mindestzeit zwischen Datenversand
// ist 16 Sekunden
long startInterval = 0; // Start des Intervals
long delta = 0; // Zeit seit Start des Intervals


/****************** Fehlerbedingung *******************/
boolean errorCondition;

/**************************************************
*
* setup()
* initialisiert BME680 Sensor
* resetted ESP-01
* und stellt Verbindung zu ESP-01 her
*
**************************************************/

void setup()
{
Serial.begin(9600); // seriellen Monitor starten

if (!bme.begin()) {
Serial.println("Keinen BME680 Sensor gefunden!");
while (1);
}

// Initialisierung von Oversampling und Filter
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320°C für 150 msec

pinMode(ESP_RESET,OUTPUT);

esp01.begin(ESP_SPEED); // Mit ESP01 reden
resetESP01(); // Resetten des ESP01
startInterval = millis(); // Aktuelle Zeit erfassen
}


/**************************************************
*
* loop()
* Misst alle 16 Sekunden (sampleTime) die
* Unweltwerte, und sendet diese an ThingSpeak
*
**************************************************/

void loop()
{
errorCondition=false; // erst mal optimistisch sein

delta = millis()-startInterval; // Zeit seit Start

if ((delta / 1000) > sampleTime) // Zeit seit Zugriff > Sampling Zeit?
{
measurement(); // Messwert erfassen
sendMeasurement(); // Daten schreiben

// jetzt wird startInterval mit aktueller Zeit besetzt
startInterval = millis();
}

if (errorCondition)
{
Serial.println("Fehler aufgetreten");
delay (2000); // warten und dann wieder weiter
}
}

/**************************************************
*
* measurement()
* Liest den BME680 aus und speichert die Werte
* in Variablen, gibt diese auch am seriellen
* Monitor aus
*
**************************************************/

void measurement(void)
{
// Erst den bme680 auslesen
if (! bme.performReading()) {
Serial.println("Fehler beim Messen ");
return;
}

// Werte ermitteln und merken:
temperature = bme.temperature;
pressure = bme.pressure / 100.0;
humidity = bme.humidity;
gas = bme.gas_resistance / 1000.0;
est_altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);

// und am seriellen Monitor ausgeben
Serial.print("Temperatur = ");
Serial.print(temperature);
Serial.println(" *C");

Serial.print("Luftdruck = ");
Serial.print(pressure);
Serial.println(" hPa");

Serial.print("Feuchtigkeit = ");
Serial.print(humidity);
Serial.println(" %");

Serial.print("Gas = ");
Serial.print(gas);
Serial.println(" KOhms");

Serial.print("Ungefaehre Hoehe = ");
Serial.print(est_altitude);
Serial.println(" m");

Serial.println();
delay(2000);
}

/**************************************************
*
* sendMeasurement()
* verbindet sich mit ThingSpeak-Kanal
* und sendet eine HTTP GET, um die gemessenen
* Werte im Kanal zu speichern
*
**************************************************/

void sendMeasurement(void)
{

connectToThingSpeak(); // Verbindungsaufbau

if (!errorCondition) { // nur wenn Verbindung geklappt hat
String update = "GET /update?api_key=";
update += CHANNEL_WRITE_KEY;
update +="&field1=";
update += String(temperature);
update +="&field2=";
update += String(humidity);
update +="&field3=";
update += String(gas);
update +="&field4=";
update += String(pressure);
update +="&field5=";
update += String(est_altitude);
update += "\r\n\r\n";

writeToThingSpeakChannel(update); // Messwerte schreiben
}
if (errorCondition)
Serial.println("Verbindung hat nicht geklappt");
}

/**************************************************
*
* resetESP01()
* startet den angeschlossenen ESP-01 neu
*
**************************************************/

void resetESP01(void)
{
Serial.println("Reset des ESP01");
digitalWrite(ESP_RESET, LOW);
delay(1000);
digitalWrite(ESP_RESET, HIGH);
delay(10000);
Serial.println("ESP01 RESET beendet");
}

/**************************************************
*
* connectToThingSpeak()
* verbindet sich mit ThingSpeak-Kanal
*
**************************************************/

void connectToThingSpeak(void)
{
esp01.flush(); // Buffer leeren

String espCommand = ESP_AT_COMMAND_CIPSTART;
espCommand += THINGSPEAK_IP; // IP
espCommand += "\","; // PORT
espCommand += THINGSPEAK_PORT;
Serial.print("Verbindungsaufbau mit thingspeak ueber ");
Serial.println(espCommand);
esp01.println(espCommand);


if(esp01.find("error")) // Fehler aufgetreten?
{
Serial.println("Verbindungsfehler");
errorCondition=true;
}
}

/**************************************************
*
* writeToThingSpeakChannel()
* sendet einen Update-Befehl an den Kanal
* Uebergabe der Parameter mit command
*
**************************************************/

void writeToThingSpeakChannel(String command)
{
int len = command.length();
String specifyLengthCommand = ESP_AT_COMMAND_CIPSEND;
specifyLengthCommand += String(len);
Serial.print("Paketlaenge: ");
Serial.println(len);
// Mitteilen der Paketlaenge an ESP-01:
esp01.println(specifyLengthCommand);

if(esp01.find('>')) // Nach Nutzlast suchen
{
Serial.print("Kommando = ");
Serial.println(command);
esp01.print(command); // Eigentliches Update der Messdaten anfordern

delay(1000); // Warten auf ESP


while (esp01.available()) // Daten liegen Zeile fuer Zeile an
{
String line = esp01.readStringUntil('\n'); // Zeile lesen
if (line.length() == 1) // es war eine Leerzeile
{ // Inhalt nach Leerzeile lesen
line = esp01.readStringUntil('\n');
// ... und ausgeben:
Serial.print("Antwort: ");
Serial.println(line);
}
}
}
else
{
esp01.println(ESP_AT_COMMAND_CIPCLOSE); // Verbindung schliessen
Serial.println("Sendefehler");
errorCondition=true;
}
} // this is the end, my friend

Wir haben in dieser Folge aus Arduino, ESP-01, BME680, Logic-Level-Konverter in Kombination mit der Cloud-Plattform ThingSpeak eine Wetterstation als IoT-Lösung zusammengebaut. Natürlich ließe sich diese Wetterstation relativ problemlos um weitere Sensoren erweitern. Einige andere Arten von Sensoren für dieses Einsatzgebiet (Regensensoren, Helligkeit, UV-Strahlung, Radioaktivität, Gewittererkennung, Bodenfeuchtigkeit, Feinstaub-Belastung) haben wir in früheren Artikeln bereits kennengelernt. Schön wäre des Weiteren ein wasserfestes Gehäuse sowie Batterie- oder LiPo-Betrieb, damit wir die Station auch ausserhalb von Wohnung oder Haus betreiben können. Oder ein GSM/GPRS-Modul, um das System sogar in abgelegeneren Gefilden autonom zum Einsatz zu bringen. Mittels SD-Kartenschreiber könnten wir die Wetterdaten auch temporär lokal speichern, sollte eine Verbindung einmal nicht möglich sein. Nötig ist auch ein ansprechendes Gehäuse. Die Wunschliste wächst bei längerem Nachdenken. Oder aber wir sind bereits mit der einfachen Lösung wunschlos glücklich.

Viel Spaß beim Experimentieren. ()