-
Notifications
You must be signed in to change notification settings - Fork 0
/
E07_MQTT.qmd
424 lines (328 loc) · 31.4 KB
/
E07_MQTT.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
---
title: "IoT Monitoring"
author: "Pia Bereuter"
date: today
other-links:
- text: Kapitel PDF
icon: file-pdf
href: chapters/E07_MQTT.pdf
code-links:
- text: Ausgangsdaten
icon: file-zip
href: data/E07_MQTT.zip
resources:
- data/E07_MQTT.zip
abstract: "IoT Monitoring ermöglicht die Erfassung von Sensordaten, die Kommunikation und Visualisierung von Daten in Echtzeit. Dies erfordert eine Architektur, die die Daten erfasst, Echtzeitkommunikation, asynchroner Kommunikation, Datenspeicherung und Visualisierung ermöglicht. Diese Übung baut einen typischen IoT Stack auf mit MQTT, Node-Red, InfluxDB und Grafana und zeigt wie Sensordaten über MQTT publiziert und abonniert werden können."
---
## Einführung
Ein IoT Datenfluss erstreckt sich über verschiedene Instanzen, die für die einzelnen Prozesse zuständig sind, von der Erfassung von Sensormesswerten im IoT Gerät über die Kommunikation der Messwerte bis zur Datenverarbeitung, Speicherung und Visualisierung (@fig-iotpipeline). Hierbei können alle Schritte auf einem Gerät durchgeführt werden oder jeder einzelne über ein anderes Gerät oder Server.
In der Abbildung aufgezeigt sind typische Softwarekomponenten, die in IoT eingesetzt werden, wie Node-Red für die Datenverarbeitung, die InfluxDB Datenbank, welche für das Speichern von Zeitreihendaten entwickelt wurde und Grafana eine Visualisierungsplattform, die für Messdaten optimiert ist. Es sind Werkzeuge die über ihre graphische Oberfläche einen guten Einstieg ermöglichen, sogenannte *low-code* Tools, die sich gut eignen für die Entwicklung von Prototypen mit geringem zeitlichen Aufwand. Je nach Anwendung können die einzelnen Prozessschritte auch gut in einer Scriptsprache wie Python durchgeführt oder eine andere Datenbank verwendet werden.
![Typischer IoT Datenfluss und Verarbeitung über diverse Instanzen, von dem IoT Gerät mit Sensorik, Datenkommunikation mit MQTT und dem MQTT Broker, zur Datenprozessierung mit Node-Red, Datenspeicherung und und Visalisierung.](images/mqtt-node-red-inffluxdb-grafana.jpg){#fig-iotpipeline}
Ziel dieser Übung ist es MQTT näher kennenzulernen und die MQTT Kommunikation mit dem Raspberry Pi zu testen. MQTT ist ein leichtgewichtiges Kommunikationsprotokoll, welches das *Publish-Subscribe* Muster verwendet und sich gut für die Anwendung in IoT Projekten geeignet.
**Unterlagen:** *<i class="bi-file-zip"></i> E07_MQTT.zip*
## Übungsaufbau
- Schliesse den Raspberry Pi an Monitor, Keyboard und Maus an oder verbinde Dich mit diesem über SSH (und SFTP).
- Erstelle auf dem Raspberry Pi im `Documents` Ordner einen neuen Ordner `mqtt`, in welchem Du Änderungen und neue Dateien für diese Übung speichern kannst.
- Schliesse den Sensor **BME688** an den Raspberry Pi über die Breakout Garden **I2C** Schnittstelle korrekt an (siehe [E01 Luftqualität](E01_Luftqualitaet.qmd)), so dass die Beschriftung der Anschlüsse am Sensor und bei der Schnittstelle übereinstimmen.
- Kontrolliere mit dem Befehl `i2cdetect -y 1` ob der Raspberry Pi mit dem Sensor verbunden ist. Der Sensor sollte auf der Adresse `0x76` erkannt werden.
- Kontrolliere, ob die Library `bme680` installiert ist mit `python -c "import bme680"`. Installiere die Library mit in der aktivierten virtuellen Environment `source ~/.env/bin/activate` mit `pip install bme680`, falls sie nicht installiert ist.
- Wechsle in den Ordner *Documents* und erstelle einen Ordner *mqtt* für diese Übung.
## Aufgabe 1: MQTT kennenlernen
[Mosquitto](https://mosquitto.org) ist eine kompakter open-source Message Broker der Eclipse Foundation, welcher das MQTT Protokoll implementiert und auf Produktionsserver, wie auch auf stromsparenden Geräten wie dem Raspberry Pi eingesetzt werden kann. Wir testen die Kommunikation mit dem MQTT Broker und den Clients auf dem Raspberry Pi. Der Mosquitto Broker ist auf dem Raspberry Pi Image vorkonfiguriert und läuft als Service im Hintegrund. Die Clients `mosquitto_pub` und `mosquitto_sub` sind ebenfalls installiert und können für das Testen der Kommunikation MQTT verwendet werden.
Mosquitto Dokumentation: [https://mosquitto.org/documentation](https://mosquitto.org/documentation)
![MQTT Device publiziert an den MQTT Broker über ein definiertes Topic Messdaten. Der Broker publiziert die Daten über die definierten Topics. Diese werden vom Subscriber abonniert und empfangen mit dem Vorteil, dass keines der Geräte zur gleichen Zeit synchron senden und empfangen muss.](images/mqtt-publish-subscribe.jpg)
Erstelle einen Subscriber der für das Topic `iot/temperature` eine Subscription erstellt.
```bash
mosquitto_sub -h 127.0.0.1 -v -t 'iot/temperature'
```
Öffne ein zweite Shell und erstelle einen Publisher für dasselbe Topic
```bash
mosquitto_pub -h 127.0.0.1 -t 'iot/temperature' -m 'Aussentemperatur: 22° Celsius'
```
MQTT Message
: Die MQTT Nachrichten (Messages) bestehen aus einem *Topic* (Thema) und einer *Payload* dem Nachrichteninhalt.
MQTT Topics
: MQTT verwendet Themen (Topic) und hierarchische Themenebenden getrennt über einem Schrägstrich `/` ähnlich einem Ordnersystem auf einem Computer. Dies ermöglicht eine Strukturierung und auch Filterung der Messages. Topics sind case-sensitive, sollten nicht mit einem `/`, `$` beginnen und keine Leerzeichen enthalten, sowie kurz und aussagekräftig sein. Filtern von Topics ist mit dem Wildcard `+` für ein einzelnes Thema und `#` für alle Themen möglich^[Topics, die mit `$` beginnen sind reserviert für interne Informationen des Brokers und Clientstatistiken, oft in der Form `$SYS/`. Beispielsweise zeigt `$SYS/broker/clients/connected` die Anzahl der verbundenen Clients. Mit dem Wildcard `#` Filter könnt Ihr mit `$SYS/#` alle Systeminformationen der Brokers anzeigen lassen.].
MQTT Payload
: Die Nachrichten (Messages) die über MQTT übertragen werden, werden als Payload bezeichnet. Diese Payload ist nicht an eine bestimmte Struktur gebunden und kann ein Text- oder Binärformat sein. Eine festgelegte Struktur für die Payload ist jedoch sinnvoll für eine reibungslose Datenverarbeitung beispielsweise im JSON Format. Übliche Fromate sind Text, JSON, Binärdaten, Hex Strings oder auch Protocol Buffer.
::: {#exr-mqtt}
- Teste nun den MQTT mit unterschiedlichen Topics und Nachrichten.
- Teste einen weiteren Mosquitto Server auf einem anderen Raspberry Pi und teste die Kommunikation. Hierbei muss die IP Adresse entsprechend angepasst werden.
- Einigt Euch auf einen MQTT Broker und eine Topic-Struktur beispielweise `iot/temperature` und `iot/humidity` und publiziert und abonniert Nachrichten. Was fällt Euch auf, wenn Ihr die Nachrichten empfängt?
- Welche Angaben sollten zusätzlich zu den Messwerten in der Payload der Nachrichten enthalten sein?
:::
::: {.content-hidden unless-meta="solution"}
::: {#sol-mqtt}
Beim Testen des MQTT Protokolls fällt auf, dass die Nachrichten die Messages an keine Struktur gebunden sind. Die Angaben in der Payload sollten idealerweise strukturiert sein für eine einfache maschinelle Weiterverarbeitung der Daten. Oft wird hierfür das JSON Format verwendet, welches eine flexible Strukturierung der Daten ermöglicht. Jedoch vergrössert sich hiermit auch die Datenmenge, die übertragen wird. Dies ist je nach Anwendung zu berücksichtigen.
Beispiel für eine JSON Nachricht: für eine Temperaturmessung von 22°Celsius mit relevanten Informationen wie Zeitstempel und Geräteinformationen und Projektangaben.
```json
{
"temperature": 22.0,
"unit": "Celsius",
"timestamp": "2021-10-01T12:00:00",
"sensor": "BME688",
"device": "RPI_01",
"project": "IoT Monitoring"
}
```
:::
:::
Falls der Mosquitto Brokers und Clients nicht installiert sind, können diese mit folgenden Befehlen installiert werden.
``` bash
sudo apt install mosquitto -y
sudo apt install mosquitto-clients -y
sudo systemctl enable mosquitto.service
sudo systemctl status mosquitto
```
::: hint
[MQTTBox](https://apps.microsoft.com/detail/9NBLGGH55JZG) und [MQTT Explorer](https://mqtt-explorer.com) sind zwei MQTT Clients, die für die Entwicklung und das Testen von MQTT Applikationen verwendet werden können. Jedoch scheinen diese nicht mehr oder eher sporadisch weiterentwickelt zu werden.
:::
## Aufgabe 2: MQTT mit Python verwenden
Nun verwenden wir die Bibliothek `paho-mqtt` in Python um MQTT Messages zu senden oder empfangen. Folgende zwei Code Snippets zeigen wie ein Publisher und Subscriber in Python minimal implementiert werden können.
![Device sendet Sensordaten und Topic an den MQTT Broker, ein weiteres Gerät abonniert (subscribe) dieses Topic und kann so die gesendeten Daten an das entsprechende Topic empfangen. In dieser Übung über ein Python Script für *Publish* und *Subscribe*](images/mqtt-sensor-subscribe.jpg)
**Script 1:** `mqtt_sub.py` - Subscriber
```python
import paho.mqtt.client as mqtt
ip = "127.0.0.1" # <1>
topic = "iot/temperature" # <2>
# Callback Funktion für den Verbindungsaufbau
def on_connect(client, userdata, flags, rc): # <3>
print("Connected - code: "+str(rc))
client.subscribe(topic) # <4>
# Callback Funktion für eingehende Nachrichten
def on_message(client, userdata, msg): # <5>
print(msg.topic+" "+str(msg.payload)) # <5>
# Erstellen des MQTT Clients
client = mqtt.Client() # <6>
client.on_connect = on_connect # <6>
client.on_message = on_message # <6>
client.connect(ip, 1883, 60) # <7>
client.loop_forever() # <7>
```
1. IP Adresse des MQTT Brokers
2. Topic auf welches der Subscriber hört
3. Callback Funktion on_connect wird ausgeführt, wenn die Verbidnung steht
4. Subscription für das Topic
5. Callback Funktion on_publish wird ausgeführt, wenn eine Nachricht empfangen (publish) wird
6. Erstellen eines MQTT Clients und Zuweisung der Callback Funktionen
7. Verbindung zum MQTT Broker herstellen und auf eingehende Nachrichten warten (loop_forever)
**Script 2: **`mqtt_pub.py` - Publisher
```python
import paho.mqtt.publish as publish
ip = "127.0.0.1" # <1>
topic = "iot/temperature" # <1>
publish.single(topic, "22.0", hostname=ip, port=1883) # <2>
```
1. IP Adresse des MQTT Brokers und Topic definieren
2. Nachricht mit Topic an den MQTT Broker (ip,port) senden
::: {#exr-mqtt-python}
- Speichere die beiden Dateien `mqtt_pub.py` und `mqtt_sub.py` im Ordner `mqtt` ab.
- (Optional: Passe die IP Adresse des MQTT Brokers an, falls ein anderer MQTT Broker genutzt werden soll.)
- Öffne zwei Terminals und führe diese mit `python mqtt_pub.py` und `python mqtt_sub.py` aus.
:::
::: {.content-hidden unless-meta="solution"}
::: {#sol-mqtt-python}
Beide Scripts in je einer Konsole ausführen mit einer aktivierten virtuellen Environment in Python `source ~/.env/bin/activate` und `python mqtt_sub.py` und `python mqtt_pub.py`.
:::
:::
Falls die Library paho-mqtt nicht installiert ist, kann diese in der aktivierten virtuellen Environment `source ~/.env/bin/activate` mit `pip install paho-mqtt`.
## Aufgabe 3: Sensordaten mit MQTT übertragen
Passe nun das Script `mqtt_pub.py` an, so dass die Temperatur vom Sensor `BME688` ausgelesen und über MQTT übertragen wird. Die Temperatur soll alle 10 Sekunden übertragen werden.
Nutze hierfür das Script zum Auslesen der Sensordaten aus der Übung [E01 Luftqualität](E01_Luftqualitaet.qmd) und passe dieses an.
::: {#exr-mqtt-bme688}
- Speichere das `mqtt_pub.py` als `mqtt_pub_bme688.py` im Ordner `mqtt` ab.
- Ergänze das Script um die Funktionen zum auslesen der Temperatur des BME688 Sensors.
- Ergänze das Script für das Auslesen der Luftfeuchtigkeit und Luftdruck und ergänze die topics mit `iot/humidity` und `iot/pressure`.
- Erweitere das Script `mqtt_sub.py` um die Subscription für die Topics `iot/humidity` und `iot/pressure` und speichere es als `mqtt_sub_bme688.py` ab.
- Öffne zwei Terminals und führe diese mit `python mqtt_pub_bme688.py` und `python mqtt_sub_bme688.py` aus.
:::
::: {.content-hidden unless-meta="solution"}
::: {#sol-mqtt-bme688}
Beispielslösung mit Integration des BME688 Sensors als Publisher der Messwerte und einem Subscriber, der die Messwerte über mehrere Topics empfängt.
**Script 1:** `E07_mqtt_pub_bme688.py` - Publisher
```{.python}
#!/usr/bin/env python
import paho.mqtt.publish as publish
import bme680
import time
ip = "127.0.0.1"
interval = 3
try:
sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY)
except (RuntimeError, IOError):
sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY)
# Oversampling Einstellungen
sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)
sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_filter(bme680.FILTER_SIZE_3)
print('Sensordaten:')
try:
while True:
if sensor.get_sensor_data():
temperature = sensor.data.temperature
pressure = sensor.data.pressure
humidity = sensor.data.humidity
publish.single("iot/temperature", temperature, hostname=ip, port=1883)
publish.single("iot/pressure", pressure, hostname=ip, port=1883)
publish.single("iot/humidity", humidity, hostname=ip, port=1883)
output = '{0:.2f} C,{1:.2f} hPa,{2:.3f} %RH'.format(
sensor.data.temperature,
sensor.data.pressure,
sensor.data.humidity)
print(output)
time.sleep(interval)
except KeyboardInterrupt:
pass
```
**Script 2:** `E07_mqtt_sub_bme688.py` - Subscriber
```{.python}
import paho.mqtt.client as mqtt
ip = "127.0.0.1"
# Callback Funktion für den Verbindungsaufbau
def on_connect(client, userdata, flags, rc):
print("Connected - code: "+str(rc))
client.subscribe("iot/temperature")
client.subscribe("iot/pressure")
client.subscribe("iot/humidity")
# Callback Funktion für eingehende Nachrichten
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
# Erstellen des MQTT Clients
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(ip, 1883, 60)
client.loop_forever()
```
:::
:::
## Aufgabe 4: MQTT mit Node-RED verwenden
Node-Red\index{Node-Red} ist ein grafisches Entwicklungswerkzeug für IoT, ein low-code Tool für *event-driven applications*. Es bietet eine browserbasierte und datenstromorientierte "Flow" Programmierung für die Verarbeitung von Sensordaten (ähnlich wie FME oder graphische Modellierungswerkzeuge in GIS). Die Implementation von Node-Red ist in JavaScript und basiert auf node.js. Datenverarbeitungsflows können gespeichert und wiederverwendet werden. Im Arbeitsbereich (@fig-noderedmqttflow) können sogenannte Nodes, die unterschiedliche Funktionen erfüllen, zu einem Daten-"Flow" werden. Nodes können auch selbst erstellt werden. Es gibt eine Vielzahl von Nodes, die von der Community entwickelt wurden, die über den Node-Red Palette Manager installiert werden können. Core Nodes von Node-Red sind:
- **Inject Node**: Kann einen Flow über den Button direkt auslösen oder in regelmässigen Abständen mit Zeitstempel oder vordefinierten Nachrichten (msg) senden.
- **Debug Node**: Kann die [Nachrichten](https://nodered.org/docs/user-guide/messages) (msg) in Debug Sidebar anzeigen lassen.
- **Function Node**: Kann mit JavaScript [Funktionen](https://nodered.org/docs/user-guide/writing-functions) den Inhalt der Nachrichten (msg) verändern.
- **Change Node**: Ermöglicht das Ändern von Eigenschaften einer Nachricht (ohne den Funktion Node zu nützen) um beispielsweise Eigenschaften zu setzen, ändern oder löschen.
- **Switch Node**: Kann Nachrichten (msg) anhand von Regeln auswerten in verschiedene Ausgänge leiten (wie ein Switch Case in der Programmierung).
- **Template Node**: Kann über Eigenschaften einer Nachricht und einer Vorlage (Template) neue Nachricht nach Vorlage erstellen: `Nachricht: {{payload}}!` wird `Nachricht: 1570439577309 !`.
Node-Red kann über den Browser auf dem Raspberry Pi oder via Laptop gestartet werden. Öffne den Browser und gebe die IP Adresse des Raspberry Pi mit dem Port 1880 ein: `http://<ip-adresse>:1880`. Führt nun das Kurztutorial zu Node-Red aus: [Node-Red Getting Started: First Flow](https://nodered.org/docs/getting-started/first-flow). In diesem Tutorial wird ein Flow erstellt, der eine Nachricht mit einem Zeitstempel ausgibt.
![Node-Red Flow der Daten in das Topic *iot/temperature* published, und Nachrichten aus dem Topic *iot/temperature* subscribed.](images/node-red_mqtt_flow.png){#fig-noderedmqttflow}
::: {#exr-nodered-flow}
Erstelle einen Flow der Nachrichten an den MQTT Broker senden und Nachrichten vom MQTT Broker empfangen kann.
1. Füge hierfür einen Inject Node, einen Debug Node und einen MQTT Output Node hinzu. Öffne die Einstellungen des MQTT Output Nodes (siehe @fig-noderedmqttnodesetup) und setze die IP Adresse des MQTT Brokers und das Topic auf `iot/temperature`. Starte den Flow und überprüfe, ob die Nachrichten an den MQTT Broker gesendet werden.
2. Erstelle nun einen weiteren Flow, der die Nachrichten vom MQTT Broker empfängt und in der Debug Sidebar anzeigt. Füge hierfür einen MQTT Input Node (siehe @fig-noderedmqttnodesetup) und einen Debug Node hinzu. Öffne die Einstellungen des MQTT Input Nodes und setze die IP Adresse des MQTT Brokers und das Topic auf `iot/temperature`. Starte den Flow und überprüfe, ob die Nachrichten vom MQTT Broker empfangen werden.
3. Ergänze den Flow um einen MQTT Input Node für die Topics `iot/humidity` und `iot/pressure` und je einen Debug Node. Starte den Flow und überprüfe, ob die Nachrichten vom MQTT Broker empfangen werden.
:::
::: {.content-hidden unless-meta="solution"}
::: {#sol-nodered-flow}
Flows müssen bei jeder Änderung über den Button *Deploy* aktiviert werden, damit diese ausgeführt werden. Die Debug Nachrichten können in der Debug Sidebar auf der rechten Seite angezeigt werden.
:::
:::
![Node-Red MQTT Node Einstellungen setzen, (1) Name angeben, (2) Server Einstellungen öffnen und (3) IP Adresse des MQTT Brokers setzen, (4) subscribe to single topic wählen und (5) Topic `iot/temperature` setzen.](images/node-red_mqtt_setup.jpg){#fig-noderedmqttnodesetup}
::: hint
Flows stoppen: Um einen Flow in der Ausführung zu stoppen, kann dieser über den Tab Flow (rechte Maustaste) deaktiviert werden (disable flow) und mit einem erneuten Übernehmen (Deploy) wird der Flow gestoppt.
:::
## Aufgabe 5: Node-Red MQTT mit InfluxDB verwenden
InfluxDB ist eine Datenbank, die für die Erfassung, Speicherung, Verarbeitung und Visualisierung von Zeitreihendaten entwickelt wurde. Zeitreihendaten sind Datenpunkte, die in zeitlicher Sequenz erfasst wurden und bestehen in der Regel aus aufeinanderfolgenden Messungen aus derselben Quelle, wie beispielsweise die Temperaturdaten des BME688.
![IoT Datenfluss mit Node-Red MQTT und InfluxDB. Python Script publiziert (publish) die Sensormesswerte und das Topic an den MQTT Broker, NodeRed abonniert (subscribe) ein oder mehrere Topics und speichert die Sensormesswerte in einer InlfuxDB Datenbank.](images/mqtt-sensor-broker-influxdb.jpg)
InfluxDB organisiert die Zeitreihendaten in *Buckets* (anstatt Datenbanken) und Messungen (Measurements). Ein Bucket kann mehrere Messungen enthalten, wobei Messungen Felder und Tags enthalten können [@influxdata2023]. Eine Messung enthält *Felder* mit key-value Paaren von Messwerten, die sich über die Zeit ändern. *Tags* sind key-value Paare, die sich nicht über die Zeit ändern und für die Filterung und Gruppierung verwendet werden können.
Das Tutorial [Getting Started](https://docs.influxdata.com/influxdb/v2/get-started/) zeigt die ersten Schritte mit InfluxDB^[Die Dokumentation über die [InfluxDB key concepts](https://docs.influxdata.com/influxdb/v2/reference/key-concepts/) und das [InfluxDB Schema Design](https://docs.influxdata.com/influxdb/v2/write-data/best-practices/schema-design/) führen übersichtlich die Konzepte Best Practices des Schema Designs und effiziente Abfragen ein.].
![Datenorganisation in der InfluxDB, über Buckets und Measurements, mit Tags für Metadaten, Feldern für die Speicherung der Messwerte und dem Zeitstempel.](images/influxdb_structure.png)
::: cheatsheet
Bucket
: Ein Bucket ist ein benannter Container zur Speicherung der Zeitreihendaten. Buckets können mehrere Messungen enthalten und sind die oberste Ebene der Organisation in InfluxDB.
Measurement
: Eine Messung ist eine logische Gruppierung von Zeitreihendaten, mehreren Einzelnmessungen (Data Point, points). Alle Messungen sollten dieselben Tags enthalten. Messungen können mehrere Tags und Felder enthalten
Data Point
: Ein Datenpunkt ist eine Einzelnmessung, die zu einem bestimmten Zeitpunkt erfasst wurde. Ein Datenpunkt besteht aus einem *mesurement*, *field set*, *tag set* und einem *timestamp*.
Tags
: Tags sind key-value Paare, die sich nicht (oder selten) über die Zeit ändern und für die Filterung und Gruppierung verwendet werden können. Tags können für die Organisation und Strukturierung der Daten verwendet werden und werden indiziert. Die Indexierung ermöglicht eine effiziente Abfrage und Aggregation der Daten.
Fields
: Felder sind key-value Paare von Messwerten, die sich über die Zeit ändern, wie Temperatur, Luftdruck etc. Felder können für die Speicherung von Messwerten verwendet werden. Felder werden nicht indiziert.
Timestamp
: Der Zeitstempel ist der Zeitpunkt, zu dem die Messung erfasst wurde. Der Zeitstempel wird in InfluxDB automatisch hinzugefügt, wenn er nicht explizit in der Messung definiert ist.
:::
Die graphische Oberfläche von InfluxDB kann über den Browser auf dem Raspberry Pi oder via Laptop gestartet werden. Öffnet nun den Browser und gebe die IP Adresse des Raspberry Pi mit dem Port 8086 ein: `http://<ip-adresse>:8086`.
Erstellt über die linke Menuleiste unter *Load Data* einen neuen Bucket mit dem Namen `iot`, falls dieser nicht schon existiert. Kopiert unter *load Data / API Tokens* den Token für den Zugang zur Datenbank.
Diese Angaben (*bucket* und *API Token*) werden für den InfluxDB Node in Node-Red benötigt. Die Einstellungen des InfluxDB Node benötigen die Angaben, wohin die Daten in der Datenbank gespeichert werden (links in @fig-noderedinfluxdb) mit Angaben zum Bucket (Datenbankname), Organisation^[wird bei der Erstellung der Datenbank definiert] und measurement und die Serververbindung (rechts in @fig-noderedinfluxdb) mit der IP Adresse und das Token für den Zugang zur Datenbank.
::: hint
Falls keine Nodes für InfluxDB in Node-Red vorhanden sind, kann die Erweiterung `node-red-contrib-influxdb` über das Hauptmenu *Palette verwalten* im Tab *Installation* installiert werden.
:::
![Einstellungen der InflxDB Nodes in Node-Red, links: Einstellungen zur Datenbank (1) mit Angaben zur Organisation (5), Bucket (6) und Namen der Messung *measurement* (7), rechts: Einstellungen zur Datenbankverbindung (2) mit der URL und Port der InfluxDB (3) und dem API Token (4), für den Zugang zur Datenbank.](images/node-red_influxdb_setup.jpg){#fig-noderedinfluxdb}
Die Messwerte können direkt in die InfluxDB geschrieben werden, jedoch fehlen da noch die Tags, die für die Filterung und Gruppierung verwendet werden können. Diese können über den Change Node hinzugefügt werden, wie in @fig-noderedpayload gezeigt. Hierbei wird der Wert der Payload in ein Feld mit dem Namen *temperature* geschrieben und die Tags *device* und *sensor* werden hinzugefügt.
Dieselbe Struktur kann alternativ auch mit dem Function Node erstellt werden, siehe @fig-noderedpayload rechts. Hierbei wird der Wert der Payload in ein Feld mit dem Namen *temperature* geschrieben und die Tags *device* und *sensor* werden hinzugefügt. Die Bezeichnung der Messung *temperature* wird im InfluxDB Node definiert oder kann im Function Node überschrieben werden.
![Über den Change Node, wie auch den Function Node kann mit JavaScript der Inhalt der Payload verändert werden und diesen für den Import in die InfluxDB angepasst werden.](images/node-red_influxdb_change_function_node.jpg){#fig-noderedpayload}
```javascript
msg.payload = [{
temperature:msg.payload // <1>
}, { device:"RPI_01", sensor:"BME688" }]; // <2>
msg.measurement="temperature"; // <3>
return msg;
```
1. Werte der Payload in Payloadstruktur für die InfluxDB schreiben
2. Tags der Messung zuweisen
3. Optional *measurement* kann im InfluxDB Node oder im Funktionsknoten definiert werden
InfluxDB bietet über das Menu *Data Explorer* eine einfache Möglichkeit die Daten zu visualisieren. Der Query Builder (@fig-influxdbdataexplorer) hilft bei der Erstellung von Abfragen mit der über die Fields und Tags gefiltert werden kann, die dann über den Button *Submit* ausgeführt und dargestellt werden können. Die erstellte Query kann über den *Script Editor* (@fig-influxdbdataexplorer) angezeigt werden.
![Über den *Data Explorer* können in InfluxDB einfach Abfragen zusammengestellt und über *submit* visualisiert werden](images/influxdb_data_explorer.png){#fig-influxdbdataexplorer}
::: {#exr-nodered-influxb}
- Erstellt nun einen Flow der die Nachrichten des Topics `iot/temperature` vom MQTT Broker empfängt und in die InfluxDB schreibt.
- Erstellt erst einen flow der nur die Nachrichten ohne Tags in die InfluxDB schreibt
- Ergänzt den Flow mit einem Change oder Function Node um die Tags *device* und *sensor* hinzuzufügen.
- Visualisiert den Temperaturverlauf des BME688 in der InfluxDB mit dem *Data Explorer* und studiert die Flux Abfragesprache.
- Erstellt einen Flow der die Nachrichten der Topics `iot/humidity` und `iot/pressure` vom MQTT Broker empfängt und in die InfluxDB schreibt.
- (Optional) erstellt im Menu *Dashboard* eine Visualisierung der Messwerte.
:::
::: {.content-hidden unless-meta="solution"}
::: {#sol-nodered-influxb}
Die Flows können in NodeRed als JSON Dateien exportiert werden. Das Lösungsbeispiel für diese Übung ist in der Datei: `E07_mqtt_node-red_influxdb_flow.json` abgelegt. Damit die Datenübertragung funktioniert muss der MQTT Broker und die InfluxDB auf dem Raspberry Pi laufen. Das Python Skript `mqtt_pub_bme688.py` muss ebenfalls ausgeführt werden, um die Daten zu senden. Dann schreiben die erstellten Flows die Daten auch in die InfluxDB. Wie in den Abbildungen aufgezeigt. Das Skript für die Darstellung der Daten auf dem Dashboard für das Filtern der Daten werden in der nächsten Übung für Grafana verwendet.
:::
:::
## Aufgabe 6: InfluxDB mit Grafana verwenden
Grafana ist eine Open-Source Anwendung für die grafische Darstellung von Daten aus den verschiedenen Datenquellen, wie Postgres, SQLite oder InfluxDB. Über Grafana können interaktive Dashboards mit vielen Visualisierungsansätzen erstellt werden. In dieser Übung wird Grafana mit der InfluxDB Datenbank verwendet.
::: hint
**Monitoring der Lichtverschmutzung am Nachthimmel**
TESS (Telescope Encoder and Sky Sensor) ist ein Photometer [@Zamorano2016] für das Stars4All Citizen Science Projekt mit dem Ziel die Lichtverschmutzung weltweit in der Nacht zu vermessen, welche nicht nur für die Umwelt problematisch ist, sondern auch für astronomische Beobachtungen. Die TESS Geräte senden von verschiedenen Standorten weltweit ihre Messungen welche über der folgende Dashboard mit Grafana der Öffentlichkeit zur Verfügung gestellt werden. Dashboard: [https://tess.dashboards.stars4all.eu/](https://tess.dashboards.stars4all.eu/), Messungen der Lichtverschmutzung am Beispiel des Naturparks Gantrisch in der Schweiz. [https://tess.dashboards.stars4all.eu/d/datasheet_stars926/stars926?orgId=1](https://tess.dashboards.stars4all.eu/d/datasheet_stars926/stars926?orgId=1)
![Grafana Dashboard der Messdaten des TESS Photometes im Naturpark Gantrisch dem ersten Dark Sky Park der Schweiz](images/mqtt_grafana_tess4all.png)
:::
Öffnet nun den Browser und gebt die IP Adresse des Raspberry Pi mit dem Port 3000 ein: `http://<ip-adresse>:3000`. Unter Connections / Data Sources können Grafana Datenquellen hinzugefügt werden, wählt nun *InfluxDB* um Grafana mit der InfluxDB zu verbinden. Setzt folgende Einstellungen (@fig-grafanainfluxdb) und speichert diese:
- *Query Language*: Wählt in den Einstellungen zu *Query Language* die Abfragesprache `Flux`.
- *HTTP*: Setzt die IP Adresse des Raspberry Pi und den Port 8086: `http://localhost:8086`.
- *Auth*: aktiviert *Basic Auth*
- *Basic Auth Details*: Setzt den InfluxDB Benutzer und das Passwort für die InfluxDB
- *InfluxDB Details*: Setzt die InfluxDB Organisation *fhnw*, den *API Token*, und den InfluxDB Bucket *iot*.
![InfluxDB als Datenquelle in Grafana hinzufügen mit den entsprechenden Angaben.](images/mqtt_grafana_influxdb_settings.png){#fig-grafanainfluxdb}
Ist die Verbindung erstellt, können neue Dashboards erstellt werden. Die Queries, die für die Visualisierung verwendet werden sollen, können über den *Query Builder* in InfluxDB erstellt und in Grafana beim Erstellen der Panels (@fig-grafanainfluxdbquery) reinkopiert werden.
![Flux Queries der Datenabfragen im Data Explorer können in Grafana für die Visualisierung kopiert und genutzt werden.](images/mqtt_grafana_influxdb_query.png){#fig-grafanainfluxdbquery}
::: {#exr-influxb-grafana}
- Erstellt eine Verbindung zwischen Grafana und der InfluxDB.
- Erstellt ein Dashboard mit einer Visualisierung der Temperatur, Luftfeuchtigkeit und Luftdruck des BME688 Sensors.
:::
::: {.content-hidden unless-meta="solution"}
::: {#sol-influxb-grafana}
Die Dashboards können ganz unterschiedlich gestaltet werden. Wichtig für die Lösung der Übung ist eine erfolgreiche Verbindung zu InfluxDB siehe @fig-grafanainfluxdb, sowie die Nutzung der Flux Queries aus InfluxDB für die Visualisierung in Grafana siehe @fig-grafanainfluxdbquery.
:::
:::
## Aufgabe 7: InfluxDB mit Python verwenden (optional)
Anstatt mit Node-Red können die Daten des Sensors direkt in die InfluxDB geschrieben werden. Folgender Code zeigt wie die Daten des BME688 Sensors mit Python ausgelesen und in die InfluxDB geschrieben werden können. Teste erst, ob der `influxdb-client` installiert ist und installiere diesen falls nicht mit dem Befehl `pip3 install influxdb-client`. Folgendes Tutorial zeigt wie die Daten mit Python in die InfluxDB geschrieben werden können: [Getting Started with Python and InfluxDB v2.0](https://www.influxdata.com/blog/getting-started-with-python-and-influxdb-v2-0/).
![Direktes Speichern der Sensormessdaten in der Influxdb ohne MQTT Protokoll. Hierbei gilt zu beachten, dass beide Geräte eine aktive Verbindung haben.](images/mqtt-sensor-influxdb.jpg)
```python
from datetime import datetime
import time
from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS
# Generieren ein Token in der InfluxDB UI unter dem Tab "Data / Tokens Tab"
token = "<influxdb-token>"
org = "fhnw"
bucket = "iot"
client = InfluxDBClient(url="http://localhost:8086", token= token, org= org)
write_api = client.write_api(write_options = SYNCHRONOUS)
temperature = 22.0
data = Point("measures").tag("sensor","BME688").tag("device","RPI_01").field("temperature", temperature)
write_api.write(bucket = bucket, record = data)
```
::: {#exr-python-influxb}
Schreibe nun mit Hilfe des Tutorials und dem Beispielcode ein Python Script, welches die Temperatur, Luftfeuchtigkeit und Luftdruck des BME688 Sensors ausliest und in die InfluxDB schreibt.
:::
::: {.content-visible when-profile="chapter"}
## Referenzen
:::