ich möchte für diverse Projekte einen “Standardaufbau” schaffen, den ich immer wieder nutzen kann.
Ein ESP8266-NodeMCU (genutzt mit Arduino IDE) soll von diversen Sensoren (RFID, Temperatur und Luftfeuchte (DHT22) etc.) Daten an einen MySQL-Server senden.
Das Senden der Daten an den Server funktioniert bereits tadellos durch Nutzung eines PHP-Scripts auf einem RaspberryPi. Die gemessenen Daten werden vie URL an das PHP-Script übergeben.
(Beispiel: 192.168.178.55/myphp.php/?temp=24.5)
Jetzt möchte ich aber auch Daten vom Server an den ESP8266 senden um beispielsweise die Durchschnitttemperatur der letzten Stunde abzubilden oder den Nutzer-Namen zu einem RFID-Tag im Display anzuzeigen.
Die Durchschnittstemperaturen kann ich ja einfach durch einen SQL-SELECT in der PHP ermitteln.
Das gleiche funktioniert auch zur Ermittlung des Namens zu einem RFID-Tag. (RFID-Nummern und dazugehörige Namen sind in einer MySQL Tabelle abgelegt.)
Ich habe aber noch keinen Weg gefunden, um diese Daten an den ESP8266 zu übergeben.
Am liebsten wäre mir eine Methode, bei der ein vom Server übermittelter Wert (String oder Integer oder Float oder whatever) vom ESP8266 in einer Variable abgelegt wird um damit innerhalb des Arduino-Codes weiterzuarbeiten.
Vielleicht hat hier jemand schon Erfahrung mit einem ähnlichen Projekt und kann mit weiterhelfen.
Hallo Jonas, muss diese Kommunikation denn wirklich vom Server ausgehen? Erfahrungsgemäß ist es meist einfacher, vom Client (z. B. per GET Request) auf die Daten zuzugreifen sobald sie gebraucht werden (sonst brauchst du auf dem Server auch cronjobs o. ä.). Wie sich das konkret auf dem ESP schreiben lässt kann ich dir auf die schnelle nicht sagen, das kann ich machen wenn ich wieder daheim bin
Ok, um Daten vom Server an den Client zu schicken gibt es unterschiedliche Möglichkeiten.
Die eine ist, auf dem Client einen Webserver laufen zu lassen. Dieser Webserver wird dann vom PHP-Skript (oder auch direkt von dir im Browser) angesprochen um deine Aktion auszuführen. Mithilfe von Anfrageparametern kannst du dieser Anfrage dann zusätzliche Daten mitgeben auf die der ESP reagiert. Eine Anleitung für einen Webserver mit ESP8266 findest du hier:
Um das ganze dann in einem PHP-Skript ansprechen zu können solltest du dir das Programm cUrl anschauen, dafür gibt es auch eine PHP-Erweiterung.
Alternativ kann auch eine einfache TCP-Verbindung genutzt werden um Daten direkt zu übertragen. Der Vorteil hierbei ist, dass es weniger Overhead auf dem MC erzeugt (weil nur das gesendet wird was gebraucht wird). Ein Beispiel kannst du dir hier anschauen: https://www.esp8266.com/viewtopic.php?f=32&t=7005
Alternativ kann natürlich auch der Client Anfragen senden und die Antwort verarbeiten. Dafür würde ich am ehesten eine Library verwenden um das Parsen nicht selbst übernehmen zu müssen. Hierfür eignet sich zum Beispiel diese:
Da du vermutlich relativ bald an den Punkt kommen wirst, an dem einfache Zahlenreihen oder Texte nicht mehr ausreichen, solltest du dir zusätzlich das JSON-Format anschauen. In PHP kann ein Array einfach zu einem JSON-Text formatiert werden, der Arduino kann diesen z.B. mit dieser Library verarbeiten:
Falls du dazu Fragen hast oder Hilfe brauchst kannst du auch gerne Freitags von 18 - 22 Uhr bei uns am OpenLab vorbei kommen, diese Woche bin ich zwar nicht da aber es findet sich bestimmt jemand der dir hilft. Ab nächster Woche bin ich dann auch wieder anzutreffen
bei meinem Temperatursensor setze ich für die Kommunikation MQTT ein. Auf dem Raspberry läuft der MQTT Server mosquitto. Jeder Client, der dort den Topic mit der Temperatur abonniert hat, empfängt die Daten und kann sie weiterverarbeiten (Anzeigen, in eine Datenbank schreiben, verändert wieder beim Server publizieren). So kannst du dann auch auf dem ESP8266 einen Client laufen lassen, der einem Topic auf dem Server lauscht und bei Veränderung eine Aktion ausführt (-> Befehle an den ESP8266 senden). Für die Arduino IDE gibt es die Bibliothek PubSubClient. Die kenne ich aber nicht, da ich Lua bzw. microPython nutze.
Also: Mit JSON und nem PHP-Script läuft es nun genau so wie ich es mir vorgestellt habe.
Zunächst ein Blick in die MySQL-Tabelle der bekannten Nutzer mit RFID-Tags. Aktuell sind zwei Nutzer angelegt.
Der Arduino empfängt per 433 MHz (der Aufbau stand bei mir noch so rum, deshalb) das RFID-Tag.
Das Arduino-Script sendet eine Anfrage an den Server. In der URL wird die RFID übermittelt.
Das PHP-Script startet eine SQL-Abfrage und gibt den zur RFID gehörigen Nutzer per JSON zurück.
Die Verarbeitung und Ausgabe kann dann beliebig erfolgen. Zur Demonstration ist die Ausgabe im seriellen Monitor abgebildet.
Arduino Code
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include <RCSwitch.h> //433 MHz
RCSwitch mySwitch = RCSwitch(); //433 MHz
// WiFi Parameters
const char* ssid = "SSID eintragen";
const char* password = "Passwort eintragen";
void setup() {
Serial.begin(115200);
// WiFi-Initialisierung##############################
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED){
delay(1000);
Serial.println("Connecting to WiFi...");}
if (WiFi.status() == WL_CONNECTED){
Serial.println("WiFi Connected");
Serial.println();}
//433 MHz Receiver PIN Belegung##########
mySwitch.enableReceive(D4); // Empfänger ist an Interrupt-Pin "0" - Das ist am UNO der Pin2
//##########################
} //void Setup end
void loop() {
// Check WiFi Status
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http; //Object of class HTTPClient
if (mySwitch.available()) // Wenn ein Code Empfangen wird...
{
Serial.println("RFID-Tag empfangen");
int value = mySwitch.getReceivedValue(); // Empfangene Daten werden unter der Variable "value" gespeichert.
if (value == 0) // Wenn die Empfangenen Daten "0" sind, wird "Unbekannter Code" angezeigt.
{
Serial.println("Unbekannter Code");
}
else // Wenn der Empfangene Code brauchbar ist, wird er hier an den Serial Monitor gesendet.
{
Serial.print("Via 433 MHz Empfangener RFID-Tag: ");
Serial.println( mySwitch.getReceivedValue() );
Serial.println();
}
int inrfid = mySwitch.getReceivedValue(); //Variable inrfid wird beschrieben
mySwitch.resetAvailable(); // Hier wird der 433 MHz-Empfänger "resettet"
String url = "http://192.168.178.46/jsonRFIDcheck.php?RFID=";
url += inrfid;
Serial.println("Serverabfrage....");
http.begin(url);
int httpCode = http.GET();
//Check the returning code
if (httpCode > 0) {
// Parsing
const size_t bufferSize = JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(8) + 370;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& root = jsonBuffer.parseObject(http.getString());
// Parameters
int id = root["id"]; // 1
const char* name = root["NAME"];
const char* rfid = root["RFID"];
// Output to serial monitor
Serial.print("RFID: ");
Serial.println(rfid);
Serial.print("Name: ");
Serial.println(name);
Serial.println();
}
http.end(); //Close connection
}
}
// Delay
delay(1000);
}
PHP-Script
<?php
$host="192.168.178.46";
$username="arduino";
$password="codearduino";
$db_name="db_arduino";
$tbl_name="tbl_user";
//Get Values from URL
$RFID = $_GET['RFID'];
//open connection to mysql db
$connection = mysqli_connect("$host","$username","$password","$db_name") or die("Error " . mysqli_error($conne$
//fetch table rows from mysql db
//SQL Select wird nach input RFID gefiltert
$sql = "select * from $tbl_name WHERE RFID=$RFID";
$result = mysqli_query($connection, $sql) or die("Error in Selecting " . mysqli_error($connection));
//create an array
$emparray = array();
while($row =mysqli_fetch_assoc($result))
{
// $emparray[] = $row;
$emparray = $row;
}
echo json_encode($emparray);
//close the db connection
mysqli_close($connection);
?>
einbinden. (Den Punkt vor den schließenden Anführungszeichen musst du entfernen, den musste ich da schreiben damit die Anzeige passt).
Die Sprache gibt das Syntax-Highlighting vor. Dein PHP-Code enthält komischer weise keine Zeilenumbrüche, da musst du nochmal schauen woran das liegt
Sehr gut.
Zu deinem PHP-Code:
Für Datenbankanfragen verwendet man üblicherweise Prepared-Statements, wenn Nutzerdaten in eine Abfrage eingebaut werden sollen. Die haben den Vorteil dass Angriffe wie SQL-Injection nicht möglich sind. In deinem Fall ist das vermutlich nicht notwendig, weil es bei dir im Netzwerk passiert, aber falls es dich interessiert kannst du das hier nachlesen: http://php.net/manual/de/mysqli.quickstart.prepared-statements.php