... | @@ -27,9 +27,9 @@ TimeHandle_t wifiReconnectTimer; //Never mind! |
... | @@ -27,9 +27,9 @@ TimeHandle_t wifiReconnectTimer; //Never mind! |
|
|
|
|
|
> :bulb: :exclamation: By convention, CONSTANTS are written in uppercase letters.
|
|
> :bulb: :exclamation: By convention, CONSTANTS are written in uppercase letters.
|
|
|
|
|
|
## Verbinden mit WiFi.begin()
|
|
## Connection with WiFi.begin()
|
|
|
|
|
|
Um den Code übersichtlicher zu gestalten wird eine Funktion ``wifiConnect()`` definiert:
|
|
To keep the code more organized, a function `wifiConnect()` is defined:
|
|
|
|
|
|
```C++
|
|
```C++
|
|
void initWiFi() {
|
|
void initWiFi() {
|
... | @@ -48,7 +48,8 @@ void initWiFi() { |
... | @@ -48,7 +48,8 @@ void initWiFi() { |
|
> :exclamation: :books: Include this function in your code to connect your ESP with the WiFi. This function must be placed outside and above the 'setup()' function
|
|
> :exclamation: :books: Include this function in your code to connect your ESP with the WiFi. This function must be placed outside and above the 'setup()' function
|
|
|
|
|
|
> :books: Rufen Sie diese Funktion ``wifiConnect()`` in der ``setup()`` Ihres Programmcodes auf!
|
|
> :books: Rufen Sie diese Funktion ``wifiConnect()`` in der ``setup()`` Ihres Programmcodes auf!
|
|
> Damit die Ausgabe über den seriellen Monitor funktioniert, müssen Sie in der ``setup()`` außerdem die Funktion ``Serial.begin(115200)`` aufrufen!
|
|
> For the output to work on the serial monitor, you must also call the function `Serial.begin(115200)` in the `setup()`.
|
|
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
... | @@ -115,252 +116,53 @@ You can have a look into the documentation or simply replace one line of code: |
... | @@ -115,252 +116,53 @@ You can have a look into the documentation or simply replace one line of code: |
|
```C++
|
|
```C++
|
|
WiFi.begin("Wokwi-GUEST", "", 6);
|
|
WiFi.begin("Wokwi-GUEST", "", 6);
|
|
```
|
|
```
|
|
|
|
> Now you should have an simulated ESP32 with established Wifi-Connection.
|
|
|
|
|
|
# Communication via MQTT
|
|
# Communication via MQTT
|
|
Im industriellen Kontext wird oftmals das MQTT_Protokoll zur Kommunikattion von entetitäten genutzt.
|
|
In an industrial context, the MQTT protocol is often used for communication between entities. It allows for cleanly structured and efficiently distributed messages. If you are unfamiliar with MQTT, you can review some basics on our fundamentals page. At a minimum, you should understand the basic procedures and differences compared to, for example, REST, to comprehend the advantages of MQTT in practice.
|
|
Es können Nachrrichten sauber strukturiert und effizient destributiert werden.
|
|
|
|
Falls Sie noch nie etwas davon gehört haben können Sie ein paar Basics auf unserer Grundlagen Seite durcharbeiten. Zumindest Grundlegende Verfahren und Unterschiede zu bspw. REST sollten Sie kennen, um Vorteile von MQTT in der Praxis nachvollziehen zu können.
|
|
|
|
// Link zum MQTT-Page
|
|
// Link zum MQTT-Page
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# JSON
|
|
# JSON
|
|
|
|
|
|
Json ist ein Format um Daten lesbar und einfach verständlich darzustellen. Json nutzt dabei einen objektbasierten Aufbau.
|
|
JSON is a format for representing data in a readable and easily understandable way, using an object-based structure.
|
|
|
|
|
|
:pushpin: Beispiel:
|
|
:pushpin: Beispiel:
|
|
|
|
|
|
```JSON
|
|
```JSON
|
|
{"Obstkorb":
|
|
{"fruitBasket": {
|
|
{
|
|
"name": "Victor",
|
|
"name" : "Viktor",
|
|
"material": "PVC",
|
|
"Material" : "PVC",
|
|
"emptyWeight": 200,
|
|
"Leergewicht" : 200,
|
|
"content": {
|
|
"Inhalt" : {
|
|
"apple": {
|
|
"Apfel" : {
|
|
"weight": 100,
|
|
"Gewicht" : 100,
|
|
"color": "light green",
|
|
"Farbe" : "hellgrün",
|
|
"colorCodeRGB": [0, 255, 150],
|
|
"FarbcodeRGB" : [0, 255, 150],
|
|
"isPoisonous": false
|
|
"Giftig?" : false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}}
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
```
|
|
|
|
|
|
> :bulb: Der Obstkorb mit dem Namen Viktor besteht aus dem Material PVC und hat ein Leergewicht von 200 Gramm. Der Obstkorb Viktor hat den Inhalt "Apfel", welcher wiederum die Attribute Gewicht, Farbe und Giftig?, welche mit den jeweiligen Werten belegt werden können.
|
|
> :bulb: The fruit basket named Victor is made of PVC and has an empty weight of 200 grams. The fruit basket Victor contains an apple, which has attributes such as weight, color, and isPoisonous, each with respective values.
|
|
|
|
|
|
Dieses Format erlaubt es dem Nutzer diese eine gewisse Menge an Daten gebündelt und ordentlich Verpackt zu übertragen und übermitteln.
|
|
This format allows users to bundle and transmit a certain amount of data in an organized and packaged manner.
|
|
|
|
|
|
## ArduinoJSON
|
|
## ArduinoJSON
|
|
|
|
|
|
ArduinoJson ist eine Bibliothek, welche das Json Format auf die Arduino Ebene bringt.
|
|
ArduinoJson is a library that brings the JSON format to the Arduino level. With this library, we can easily define JSON objects in our code and prepare them for publishing data packets over MQTT. This enables us to distribute data in the cloud, turning our ESP32 into an IoT data source.
|
|
|
|
|
|
:bookb: Um die Bibliothek in ihr Projekt einzubinden, fügen Sie ``bblanchon/ArduinoJson@^7.0.4`` in die Kategorie ``lib_deps`` in Ihrer ``platformio.ini`` Datei ihrer PlatformIO Projektes hinzu.
|
|
|
|
|
|
|
|
:bulb: die Dokumentation der bibliothek finden Sie [hier](https://registry.platformio.org/libraries/bblanchon/ArduinoJson)
|
|
|
|
|
|
|
|
:books: Damit Sie die Bibliothek verwenden können, müssen Sie diese mit ``#include <ArduinoJson.h>`` in Ihr Projekt einbinden.
|
|
|
|
|
|
|
|
Beispiel zum verwenden der Bibliothek:
|
|
|
|
```C++
|
|
|
|
#include <Arduino.h>
|
|
|
|
#include <ArduinoJson.h>
|
|
|
|
|
|
|
|
JsonDocument jsonDoc; //Erstellen von einem JsonDocument Objekt
|
|
|
|
JsonObject obstKorb = jsonDoc.to<JsonObject>(); //Erstellen eines JsonObject Objektes, welches mit dem JsonDocument verknüpft ist. Oberobjekt der Json Nachricht
|
|
|
|
JsonObject korbInhalt = obstKorb.createNestedObject("Inhalt"); //Unterobjekt des Objektes ObstKorb
|
|
|
|
JsonObject apfel = korbInhalt.createNestedObject("Apfel"); //Unterobjekt des Objektes korbinhalt erstellen
|
|
|
|
|
|
|
|
void setup(){
|
|
|
|
Serial.begin(115200);
|
|
|
|
Serial.println("Entering Setup");
|
|
|
|
|
|
|
|
apfel["Farbe"] = "gruen"; //ObjektAttribut mit Wert befüllen
|
|
|
|
apfel["Gewicht"] = 200;
|
|
|
|
apfel["Gewichtseinheit"] = "g";
|
|
|
|
|
|
|
|
Serial.println("\n\n\nDas JsonObjekt");
|
|
|
|
serializeJson(jsonDoc, Serial); //Aus dem JsonObjekt einen lesbaren String machen
|
|
|
|
delay(500);
|
|
|
|
Serial.println("\n\n\nJetzt noch mal in schön");
|
|
|
|
serializeJsonPretty(jsonDoc, Serial);
|
|
|
|
|
|
|
|
Serial.println("\n\n\nExiting Setup");
|
|
|
|
}
|
|
|
|
|
|
|
|
void loop()
|
|
|
|
{
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
BSP JsonObjekt:
|
|
|
|
|
|
|
|
```
|
|
|
|
obstKorb : {
|
|
|
|
korbInhalt : {
|
|
|
|
apfel : {
|
|
|
|
"Farbe" : "gruen",
|
|
|
|
"Gewicht" : 200,
|
|
|
|
"Gewichtseinheit" : "g"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
````
|
|
|
|
|
|
|
|
:bulb: Erklärung: Das Objekt ObstKorb beinhaltet ein Objekt Korbinhalt. Im Korbinhalt ist ein Objekt Apfel mit den Parametern Farbe, Gewicht und Gewichtseinheit enthalten. Die Parameter haben die jeweiligen Werte.
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
# MQTT
|
|
|
|
|
|
|
|
MQTT ist ein standardisiertes Kommunikationsprotkoll. Dabei arbeitet das Protokoll nach dem *Publisher-Subscriber* Prinzip.
|
|
|
|
|
|
|
|
<img src="images/mqtt-overview.webp" width = "700" alt="Overview MQTT">
|
|
|
|
Quelle: https://www.hivemq.com/blog/how-to-get-started-with-mqtt/
|
|
|
|
|
|
|
|
Die Kommunikation verläuft dabei über Topics. Auf diese Topics werden Nachrichten gesendet.
|
|
|
|
|
|
|
|
Bsp:
|
|
|
|
- Ein smartHome Temperatursensor published jede 10 Sekunden auf das Topic ``/bedroomTemp`` die Temperatur, welcher der Sensor gerade gemessen hat.
|
|
|
|
- Jeder Teilnehmer, welcher im gleichen Netzwerk hängt, kann nun auf dieses Topic ``/bedroomTemp`` subscriben, also sich abbonnieren und somit alle 10 Sekunden die aktuelle Temperatur, welche der Sensor gemessen hat verwerten und benutzen.
|
|
|
|
|
|
|
|
## MQTT und ESP32
|
|
|
|
|
|
|
|
Für den ESP32 gibt es mehrere Bibliotheken um MQTT Topic zu subscriben und zu publishen.
|
|
|
|
|
|
|
|
:exclamation: Damit dies funktioniert muss der ESP32 mit einem WLan Netzwerk verbunden werden, in dem ein MQTT Broker läuft. Befolgen Sie dazu die Schritte in [ESP&WiFi](../WIFI/README.md)
|
|
|
|
|
|
|
|
|
|
|
|
Als MQTT Bibliothek werwenden Sie bitte die AsyncMQTTClient von [marvinroger](https://registry.platformio.org/libraries/marvinroger/AsyncMqttClient/installation)
|
|
|
|
|
|
|
|
> :books: Fügen sie ``marvinroger/AsyncMqttClient@^0.9.0`` in die Kategorie ``lib-deps`` Ihrer ``platformio.ini`` ein.
|
|
|
|
|
|
|
|
Hier ein Beispiel für die Benutzung der Bibliothek:
|
|
|
|
```C++
|
|
|
|
#include <Arduino.h>
|
|
|
|
#include <AsyncMqttClient.h>
|
|
|
|
#include <ArduinoJson.h>
|
|
|
|
#include "WiFi.h"
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
const int PUB_INTERVAL = 1000; // delay until message is published again
|
|
|
|
|
|
|
|
#define WIFI_SSID "iaAM_Manualworkstation_1" //<-- Achten Sie auf die Anweisung der Praktikumsleitung
|
|
## Implementing an Asynchronous MQTT Connection to a Public MQTT Broker
|
|
#define WIFI_PASSWORD "iaAM_Manualworkstation_1_pw"
|
|
|
|
|
|
|
|
|
|
In most cases, we have a bidirectional data connection with our ESP32. It should not only send data to the cloud but also be able to react to incoming message packets. Therefore, we use an asynchronous MQTT library in 99% of cases. This library provides functions that are called whenever a new message appears on the subscribed topic. This structure requires a few minor changes to our existing code and the programmed WiFi structure.
|
|
|
|
|
|
TimerHandle_t wifiReconnectTimer;
|
|
To demonstrate how quickly and easily the ESP32 can connect to WiFi, we previously discussed a simplified WiFi program. Now, we will adapt this and test the communication using dummy data and a public broker. The MQTT broker can also be installed and started on a local PC, provided it is accessible over the network.
|
|
|
|
|
|
|
|
## Adapting the Code
|
|
|
|
|
|
#define MQTT_HOST "test.mosquitto.org" //Dies ist der MQTT Broker - hier von Mosquitto als öffentlicher Broker zur Verfügung gestellt.
|
|
|
|
#define MQTT_PORT 1883
|
|
|
|
const char* ID = "JonnyESPDemo"; //<-- Name des Publishers!
|
|
|
|
TimerHandle_t mqttReconnectTimer;
|
|
|
|
AsyncMqttClient mqttClient; //Objekt welches die MQTT Verbindung regelt
|
|
|
|
|
|
|
|
String setIntMsg(byte rgb_G_val) //this function creates the jsonobject
|
|
|
|
{
|
|
|
|
JsonDocument jsonDoc;
|
|
|
|
JsonObject root = jsonDoc.to<JsonObject>();
|
|
|
|
JsonObject typeObj = root.createNestedObject("ProcessData");
|
|
|
|
typeObj["GreenValue"] = rgb_G_val;
|
|
|
|
|
|
|
|
String jsonString;
|
|
|
|
serializeJsonPretty(root, jsonString);
|
|
|
|
Serial.println(jsonString);
|
|
|
|
|
|
|
|
return jsonString;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void publishGreenValue(byte rgb_G_val) //this function publishes a created json object to a specific topic
|
|
|
|
{
|
|
|
|
String msg;
|
|
|
|
msg = setIntMsg(rgb_G_val);
|
|
|
|
String topic = "MatriklNr/MaschineSimulator/Data/GreenValue";
|
|
|
|
|
|
|
|
mqttClient.publish((char*)topic.c_str(), 0, true, (char*)msg.c_str()); //publish the "msg" Object to the "topic". The msg is retreived by the function ``setIntMsg()``
|
|
|
|
}
|
|
|
|
|
|
|
|
//handle WiFi connection
|
|
|
|
void connectToWifi() {
|
|
|
|
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
|
|
|
Serial.println("");
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for connection
|
|
|
|
while (WiFi.status() != WL_CONNECTED) {
|
|
|
|
delay(500);
|
|
|
|
Serial.print(".");
|
|
|
|
}
|
|
|
|
|
|
|
|
Serial.println("");
|
|
|
|
Serial.print("Connected to ");
|
|
|
|
Serial.println(WIFI_SSID);
|
|
|
|
Serial.print("IP address: ");
|
|
|
|
Serial.println(WiFi.localIP());
|
|
|
|
}
|
|
|
|
|
|
|
|
//handle MQTT Connection
|
|
|
|
void connectToMqtt(){
|
|
|
|
mqttClient.connect();
|
|
|
|
}
|
|
|
|
void onMqttConnect(bool sessionPresent) {
|
|
|
|
Serial.println("Connected to MQTT.");
|
|
|
|
}
|
|
|
|
void onMqttPublish(uint16_t packetId) {
|
|
|
|
Serial.println("Publish acknowledged.");
|
|
|
|
Serial.print(" packetId: ");
|
|
|
|
Serial.println(packetId);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//handle WiFi disruptions and events
|
|
|
|
void WiFiEvent(WiFiEvent_t event) {
|
|
|
|
Serial.printf("[WiFi-event] event: %d\n", event);
|
|
|
|
switch(event) {
|
|
|
|
case SYSTEM_EVENT_STA_GOT_IP:
|
|
|
|
Serial.println("WiFi connected");
|
|
|
|
Serial.println("IP address: ");
|
|
|
|
Serial.println(WiFi.localIP());
|
|
|
|
connectToMqtt();
|
|
|
|
break;
|
|
|
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
|
|
|
Serial.println("WiFi lost connection");
|
|
|
|
xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
|
|
|
|
xTimerStart(wifiReconnectTimer, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void setup() {
|
|
|
|
Serial.begin(115200);
|
|
|
|
Serial.println("Entering Setup");
|
|
|
|
|
|
|
|
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
|
|
|
|
wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));
|
|
|
|
|
|
|
|
WiFi.onEvent(WiFiEvent);
|
|
|
|
|
|
|
|
mqttClient.onConnect(onMqttConnect);
|
|
|
|
mqttClient.onPublish(onMqttPublish);
|
|
|
|
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
|
|
|
|
|
|
|
|
connectToWifi();
|
|
|
|
|
|
|
|
Serial.println("Exiting Setup");
|
|
|
|
}
|
|
|
|
|
|
|
|
void loop(){
|
|
|
|
publishGreenValue(random(255)); //call the function that publishes the jsonobject, the creation of the jsonobject will be handled internally
|
|
|
|
delay(2000);
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
Jetzt sollte der esp32 über euren Router das Datenpaket im Zyklus von 2000ms an den MQTT-Broker senden!
|
|
Jetzt sollte der esp32 über euren Router das Datenpaket im Zyklus von 2000ms an den MQTT-Broker senden!
|
|
Naja das sollten wir schon überprüfen.
|
|
Naja das sollten wir schon überprüfen.
|
|
Es gibt sogenannte SnifferTools mit denen wir das Topic abonnieren können oder auch den gesamten Broker (Sprich alle Topic) abhören können.
|
|
Es gibt sogenannte SnifferTools mit denen wir das Topic abonnieren können oder auch den gesamten Broker (Sprich alle Topic) abhören können.
|
... | | ... | |