Die Kommunikation zwischen Mega und ESP geschieht über Seriellports. Die Kommunikation mit dem Heimserver/Internet geschieht über eine Rest-Api (PHP GET requests) und wird in eine MySQL Datenbank eingetragen. Daten aus der Sql-Tabelle "toESP" werden genutzt um die Heizung zu Steuern. Die Tabelle "fromESP" nutzen wir als Langzeitspeicher für alles was vom Mega kommt. Da diese nur alle paar Minuten geupdatet wird um den Server nicht zu bombardieren, nutzen wir noch "fromESPrt" zum späteren anzeigen der Daten auf der Webseite. Die PHP´s für die API und die Erstellung der Datenbank werden in einem anderen Kapitel behandelt.
Als Erstes erstellen wir eine zusätzliche Datei mit der Endung ".h" im gleichen Verzeichnis wie die ".ino" Datei, welche wir gleich schreiben. Diese Datei enthält alle sensiblen Daten, die zur Verbindungsherstellung notwendig sind.
#define SECRET_SSID "MySSID"
#define SECRET_PASS "MyPassword"
#define API_KEY "MyApiKey"
#define SERVER_URL "MyIpAdress"
Standard Script zur Verbindung eines ESP8266 mit dem heimischen Wlan. Wir fügen die ESP8266Wifi Bibliothek und unsere secrets.h ein und kontrollieren die Verbindung anhand der integrierten LED auf dem Board.
#include ESP8266WiFi.h
#include "secrets.h"
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
char host[] = SERVER_URL; // URL PHP Api
char ApiK[] = API_KEY;
void setup() {
WiFi.mode(WIFI_STA);
Serial.begin(9600);
pinMode(2, OUTPUT);
digitalWrite(2, HIGH); //LED aus
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
digitalWrite(2, HIGH); // LED aus = Verbindung mit WIFI unterbrochen
Serial.print("Attempting to connect to SSID: ");
Serial.println(SECRET_SSID);
while (WiFi.status() != WL_CONNECTED) {
WiFi.begin(ssid, pass);
Serial.print(".");
delay(5000);
}
Serial.println("\nConnected");
digitalWrite(2, LOW); //LED an = Verbunden mit WIFI
}
}
Da der ESP nur einen Seriellport hat nutzen wir Softseriell und machen zwei frei IO-Ports (14 und 12) zu einer serielle Schnittstelle. Die Daten der Steuerung kommen als Komma getrennter String in den ESP. Dafür werden erstmal Platzhaltervariablen erstellt. Den String teilen wir jetzt an jedem Komma, wandel die Ergebnisse in Integer und füllen damit die Platzhalter. Danach haben wir die Temperaturen, Zustände und Einstellungen der Heizungssteuerung auf dem ESP verfügbar.
SoftwareSerial swSer(14, 12);
String Data, rest;
int tk, ts, br, sp, hp, zp, ks, sm, hk, ta;
void setup() {
WiFi.mode(WIFI_STA);
Serial.begin(9600);
swSer.begin(9600);
}
// read Data from Mega
if (swSer.available()) {
Data = swSer.readString();
ta = Data.substring(0, Data.indexOf(',')).toInt();
rest = Data.substring(Data.indexOf(',') + 1);
tk = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
ts = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
br = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
sp = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
hp = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
zp = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
ks = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
sm = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
hk = rest.substring(0, rest.indexOf(',')).toInt();
}
Damit wir das Lesen und Schreiben unterschiedlich timen können, nutzen wir "millis()" und erstellen uns die "Timing" Variablen als long Integer. Nach Ablauf der werden die entsprechenden Funktionen aufgerufen.
long writeTimingSeconds = 180;
long readTimingSeconds = 10;
long startReadTiming = 0;
long elapsedReadTime = 0;
long startWriteTiming = 0;
long elapsedWriteTime = 0;
// insert Data to sql "fromESP"
elapsedWriteTime = millis() - startWriteTiming;
if (elapsedWriteTime > (writeTimingSeconds * 1000)) {
WriteDB();
startWriteTiming = millis();
delay(500);
}
// read_all data from sql "toESP"
// update data to sql "fromESPrt"
elapsedReadTime = millis() - startReadTiming;
if (elapsedReadTime > (readTimingSeconds * 1000)) {
ReadDB();
RealtimeDB();
startReadTiming = millis();
delay(500);
}
}
Um GET request´s mit dem ESP auszuführen brauchen wir die ESP8266HTTPClient Bibliothek. Dann muss nur der URL-String zusammengebaut werden und definiert werden, wohin (ip) und als was (GET) der request gesendet wird.
#include ESP8266HTTPClient.h
WiFiClient client;
void WriteDB() {
HTTPClient http;
String url = host;
url += "/fromESP/insert.php?";
url += "API_KEY=";
url += ApiK;
url += "&ta=";
url += int(ta);
url += "&tk=";
url += int(tk);
url += "&ts=";
url += int(ts);
url += "&br=";
url += int(br);
url += "&sp=";
url += int(sp);
url += "&hp=";
url += int(hp);
url += "&zp=";
url += int(zp);
url += "&ks=";
url += int(ks);
url += "&sm=";
url += int(sm);
url += "&hk=";
url += int(hk);
http.begin(client, url);
int httpCode = http.GET();
Serial.print("fromESP=");
Serial.println(url);
String result = http.getString();
Serial.print("database=");
Serial.println(result);
Serial.println(">>>");
http.end();
}
void RealtimeDB() {
HTTPClient http;
String url = host;
url += "/fromESPrt/update.php?";
url += "API_KEY=";
url += ApiK;
url += "&ta=";
url += int(ta);
url += "&tk=";
url += int(tk);
url += "&ts=";
url += int(ts);
url += "&br=";
url += int(br);
url += "&sp=";
url += int(sp);
url += "&hp=";
url += int(hp);
url += "&zp=";
url += int(zp);
url += "&ks=";
url += int(ks);
url += "&sm=";
url += int(sm);
url += "&hk=";
url += int(hk);
http.begin(client, url);
int httpCode = http.GET();
Serial.print("fromESPrt=");
Serial.println(url);
String result = http.getString();
Serial.print("database=");
Serial.println(result);
Serial.println(">>>");
http.end();
}
Der Aufbau ist analog zum Schreiben in die Datenbank. Nur, dass wir jetzt Daten im JSON-Format bekommen. Deshalb brauchen wir nun noch die Bibliothek "ArduinoJson". Wenn der Responsecode eine "200" ist, heißt das die Anfrage war erfolgreich und wir bekommen eine Json-String las Daten. Diesen nehmen wir auseinander und verpacken alles wieder in einen kommagetrennten String, welcher über Seriell an den Mega gesendet wird.
#include ArduinoJson.h
void ReadDB() {
HTTPClient http;
String url = host;
url += "/toESP/read_all.php?";
url += "API_KEY=";
url += ApiK;
http.begin(client, url);
int httpCode = http.GET();
Serial.print("toESP=");
Serial.println(url);
if (httpCode == 200) {
String result = http.getString();
Serial.print("database=");
Serial.println(result);
Serial.println(">>>");
StaticJsonDocument<700> doc;
DeserializationError err = deserializeJson(doc, result);
if (err) {
Serial.print(F("deserialize failed: "));
Serial.println(err.c_str());
}
String wwT = doc["toESP"][0]["Status"];
String smT = doc["toESP"][1]["Status"];
String sfT = doc["toESP"][2]["Status"];
String hkT = doc["toESP"][3]["Status"];
String tks = doc["toESP"][4]["Status"];
String bta = doc["toESP"][5]["Status"];
RESET = doc["toESP"][6]["Status"];
String data2send = wwT;
data2send += ",";
data2send += smT;
data2send += ",";
data2send += sfT;
data2send += ",";
data2send += hkT;
data2send += ",";
data2send += tks;
data2send += ",";
data2send += bta;
data2send += "}";
swSer.println(data2send);
}
http.end();
}
Da es Serverseitig (gerade wenn er im Internet und nicht nur im heimischen Netzwerk ist) immer zu Problem wie Verbindungsabbrüche kommen kann, ist es notwendig Rückfallwerte auf der eigentlichen Steuerung zu haben. Aus diesem grund wurde auch eine Trennung von Steuerung und Kommunikation gewählt.
#include ESP8266WiFi.h
#include "secrets.h"
#include SoftwareSerial.h
#include ArduinoJson.h
#include ESP8266HTTPClient.h
SoftwareSerial swSer(14, 12);//, false, 128);
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password
char host[] = SERVER_URL; // URL PHP Api
char ApiK[] = API_KEY;
WiFiClient client;
String Data, data2send, rest;
int RESET = 0;
int tkLast;
int tk, ts, br, sp, hp, zp, ks, sm, hk, ta;
long writeTimingSeconds = 180;
long readTimingSeconds = 10;
long startReadTiming = 0;
long elapsedReadTime = 0;
long startWriteTiming = 0;
long elapsedWriteTime = 0;
void setup() {
//WiFi.persistent(false);
WiFi.mode(WIFI_STA);
Serial.begin(9600);
swSer.begin(9600);
startReadTiming = millis();
startWriteTiming = millis();
pinMode(2, OUTPUT);
digitalWrite(2, HIGH);
}
void loop() {
// Connect or reconnect to WiFi
//WiFi.softAPdisconnect (true);
if (WiFi.status() != WL_CONNECTED) {
digitalWrite(2, HIGH);
Serial.print("Attempting to connect to SSID: ");
Serial.println(SECRET_SSID);
while (WiFi.status() != WL_CONNECTED) {
WiFi.begin(ssid, pass); // Connect to WPA/WPA2 network. Change this line if using open or WEP network
Serial.print(".");
delay(5000);
}
Serial.println("\nConnected");
digitalWrite(2, LOW);
}
// read Data from Mega
if (swSer.available()) {
Data = swSer.readString();
ta = Data.substring(0, Data.indexOf(',')).toInt();
rest = Data.substring(Data.indexOf(',') + 1);
tk = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
ts = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
br = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
sp = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
hp = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
zp = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
ks = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
sm = rest.substring(0, rest.indexOf(',')).toInt();
rest = rest.substring(rest.indexOf(',') + 1);
hk = rest.substring(0, rest.indexOf(',')).toInt();
}
// insert Data to sql "fromESP"
elapsedWriteTime = millis() - startWriteTiming;
if (elapsedWriteTime > (writeTimingSeconds * 1000)) {
WriteDB();
startWriteTiming = millis();
delay(500);
}
// read_all data from sql "toESP"
// update data to sql "fromESPrt"
elapsedReadTime = millis() - startReadTiming;
if (elapsedReadTime > (readTimingSeconds * 1000)) {
ReadDB();
RealtimeDB();
startReadTiming = millis();
delay(500);
}
}
void RealtimeDB() {
HTTPClient http;
String url = host;
url += "/fromESPrt/update.php?";
url += "API_KEY=";
url += ApiK;
url += "&ta=";
url += int(ta);
url += "&tk=";
url += int(tk);
url += "&ts=";
url += int(ts);
url += "&br=";
url += int(br);
url += "&sp=";
url += int(sp);
url += "&hp=";
url += int(hp);
url += "&zp=";
url += int(zp);
url += "&ks=";
url += int(ks);
url += "&sm=";
url += int(sm);
url += "&hk=";
url += int(hk);
http.begin(client, url);
int httpCode = http.GET();
Serial.print("fromESPrt=");
Serial.println(url);
String result = http.getString();
Serial.print("database=");
Serial.println(result);
Serial.println(">>>");
http.end();
}
void ReadDB() {
HTTPClient http;
String url = host;
url += "/toESP/read_all.php?";
url += "API_KEY=";
url += ApiK;
http.begin(client, url);
int httpCode = http.GET();
Serial.print("toESP=");
Serial.println(url);
if (httpCode == 200) {
String result = http.getString();
Serial.print("database=");
Serial.println(result);
Serial.println(">>>");
StaticJsonDocument<700> doc;
DeserializationError err = deserializeJson(doc, result);
if (err) {
Serial.print(F("deserialize failed: "));
Serial.println(err.c_str());
}
String wwT = doc["toESP"][0]["Status"];
String smT = doc["toESP"][1]["Status"];
String sfT = doc["toESP"][2]["Status"];
String hkT = doc["toESP"][3]["Status"];
String tks = doc["toESP"][4]["Status"];
String bta = doc["toESP"][5]["Status"];
RESET = doc["toESP"][6]["Status"];
String data2send = wwT;
data2send += ",";
data2send += smT;
data2send += ",";
data2send += sfT;
data2send += ",";
data2send += hkT;
data2send += ",";
data2send += tks;
data2send += ",";
data2send += bta;
data2send += "}";
swSer.println(data2send);
}
http.end();
}
void WriteDB() {
HTTPClient http;
String url = host;
url += "/fromESP/insert.php?";
url += "API_KEY=";
url += ApiK;
url += "&ta=";
url += int(ta);
url += "&tk=";
url += int(tk);
url += "&ts=";
url += int(ts);
url += "&br=";
url += int(br);
url += "&sp=";
url += int(sp);
url += "&hp=";
url += int(hp);
url += "&zp=";
url += int(zp);
url += "&ks=";
url += int(ks);
url += "&sm=";
url += int(sm);
url += "&hk=";
url += int(hk);
http.begin(client, url);
int httpCode = http.GET();
Serial.print("fromESP=");
Serial.println(url);
String result = http.getString();
Serial.print("database=");
Serial.println(result);
Serial.println(">>>");
http.end();
}