{"id":508,"date":"2021-07-02T10:48:28","date_gmt":"2021-07-02T08:48:28","guid":{"rendered":"https:\/\/www.iot-embedded.de\/iot-2021\/?p=508"},"modified":"2021-07-02T10:48:30","modified_gmt":"2021-07-02T08:48:30","slug":"komponenten-des-backend-von-smart-drive","status":"publish","type":"post","link":"https:\/\/www.iot-embedded.de\/iot-2021\/smart-drive\/komponenten-des-backend-von-smart-drive\/","title":{"rendered":"Komponenten des Backend von Smart Drive"},"content":{"rendered":"\n<p>Komponenten des Backend von Smart Drive<\/p>\n\n\n\n<p>Unser Backend ist fertig und lauff\u00e4hig. Im Folgenden werden die einzelnen Komponenten unseres Backend dokumentiert und der Weg der Sensordaten von der Erfassung bis zur grafischen Darstellung im Frontend dargestellt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u00dcberblick<\/h2>\n\n\n\n<p>Die folgende Darstellung zeigt den Aufbau unseres Backend.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"826\" height=\"512\" src=\"https:\/\/www.iot-embedded.de\/iot-2021\/wp-content\/uploads\/sites\/5\/2021\/06\/Backend-Architektur.png\" alt=\"\" class=\"wp-image-531\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2021\/wp-content\/uploads\/sites\/5\/2021\/06\/Backend-Architektur.png 826w, https:\/\/www.iot-embedded.de\/iot-2021\/wp-content\/uploads\/sites\/5\/2021\/06\/Backend-Architektur-300x186.png 300w, https:\/\/www.iot-embedded.de\/iot-2021\/wp-content\/uploads\/sites\/5\/2021\/06\/Backend-Architektur-768x476.png 768w\" sizes=\"(max-width: 826px) 100vw, 826px\" \/><figcaption>Architektur des Backend von Smart Drive<\/figcaption><\/figure>\n\n\n\n<p>Jedes Quadrat in der Abbildung stellt einen Docker-Container dar. Die Rechtecke gliedern diese Container in logische Einheiten. Diese sind hier zum einen das Smart Drive Backend und zum anderen unsere eigene Instanz von Gitlab. Wie das \u00e4u\u00dfere Rechteck zeigt, laufen alle Container auf einem einzigen Webserver und somit auf einem einzigen Docker-Host. Zum Zugriff auf den Webserver sind drei M\u00f6glichkeiten dargestellt. Die Kreise links au\u00dferhalb des Servers stellen die IoT-Devices unserer Kunden dar und die rechts abgebildeten Personen die dazu geh\u00f6renden Kunden. Die Person unterhalb des Servers steht f\u00fcr das Entwicklungsteam von Smart Drive, das mit der Gitlab-Instanz \u00fcber git-Befehle interagiert. Das Deployment der Komponenten unseres Backends erfolgt dann automatisiert durch unsere eigene Gitlab-Instanz.<\/p>\n\n\n\n<p>Die Pfeile im oberen Teil der Abbildung bilden von links nach rechts den Weg der Sensorwerte von der Erfassung durch Sensoren bis zum Kunden ab. Wenn neue Software im System eingespielt wird, beginnt der Weg beim Entwicklerteam und l\u00e4uft \u00fcber die Gitlab-Instanz bis zum Deployment im Smart Drive Backend.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dokumentation der einzelnen Komponenten<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">MQTT-Broker<\/h3>\n\n\n\n<p>Als MQTT-Broker kommt Eclipse Mosquitto zum Einsatz. Die Software wird als <a href=\"https:\/\/hub.docker.com\/_\/eclipse-mosquitto\/\" target=\"_blank\" rel=\"noopener\">fertiges Docker Image auf Docker Hub<\/a> bereitgestellt, sodass die Anwendung sofort einsatzf\u00e4hig ist und lediglich konfiguriert werden muss. Ziel der Konfiguration ist es, einen Verbindungsaufbau nur mit Benutzername und Passwort zu erlauben. Au\u00dferdem soll der Standard Port 1883 verwendet werden.<\/p>\n\n\n\n<p>Die Konfigurationsdatei zu den oben genannten Anforderungen besteht aus den folgenden Zeilen.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">listener 1883\nallow_anonymous false\npassword_file \/mosquitto\/config\/pw\n<\/pre>\n\n\n\n<ul><li><i>listener 1883<\/i> sorgt daf\u00fcr, dass der MQTT-Broker auf Port 1883 lauscht. Die nachfolgenden Zeilen beziehen sich dann auf den Listener an diesem Port. Es w\u00e4re m\u00f6glich auf anderen Ports weitere Listener mit anderen Einstellungen zu erstellen.<\/li><li><i>allow_anonymous false<\/i> verbietet anonyme Verbindungen. Zur Herstellung ist also im Gegensatz zur fr\u00fcheren Konfiguration ein Benutzername und ein Passwort notwendig. Diese Einstellung sichert lediglich den Zugang zum Broker ab, jedoch nicht die \u00fcbertragenen Daten. Diese sind weiterhin unverschl\u00fcsselt. Ebenso die Zugangsdaten, welche somit ohne gro\u00dfen Aufwand abgeh\u00f6rt werden k\u00f6nnen. Daher ist die zus\u00e4tzliche Konfiguration der Verschl\u00fcsselung zum produktiven Betrieb unbedingt erforderlich.<\/li><li><i>password_file \/mosquitto\/config\/pw<\/i> gibt den Pfad zu der Datei an, die eine Liste aller Kombinationen aus Benutzernamen und Passwort enth\u00e4lt. Der Pfad bezieht sich auf das Dateisystem des Docker Containers. Hier wurde der Pfad gew\u00e4hlt an dem auch die Konfigurationsdatei selbst zu finden ist. Die Erstellung der Datei wird weiter unten beschrieben.<\/li><\/ul>\n\n\n\n<p>Der Inhalt der Passwortdatei muss mit einem mitgelieferten Tool generiert werden, damit die Passw\u00f6rter nicht im Klartext enthalten sind. Dazu werden alle gew\u00fcnschten Kombinationen aus Benutzername und Passwort zun\u00e4chst im Klartext in die Datei geschrieben. Dabei werden die einzelnen Kombinationen durch einen Zeilenumbruch getrennt sowie Benutzername und Passwort durch einen Doppelpunkt. Die weitere Verarbeitung der Datei erfolgt zu einem sp\u00e4teren Zeitpunkt, da der Container daf\u00fcr bereits laufen muss.<\/p>\n\n\n\n<p>Beim Start des Containers ist zu beachten, dass der Port 1883 nach au\u00dfen freigegeben wird und die beiden erstellten Dateien als Volume in das Dateisystem des Containers eingebunden werden. Beide Dateien m\u00fcssen im Container unter dem Pfad \/mosquitto\/config\/ zu finden sein. Aus den genannten Anforderungen ergibt sich der folgende Inhalt f\u00fcr docker-compose.yml. Dabei wird angenommen, dass die beiden oben erstellten Dateien im Home-Verzeichnis unter mqtt\/ zu finden sind.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">version: \"3\"\nservices:\n  mqtt:\n    image: eclipse-mosquitto:latest\n    container_name: iot-mqtt\n    restart: unless-stopped\n    ports:\n      - 1883:1883\n    volumes:\n      - $HOME\/mqtt\/mosquitto.conf:\/mosquitto\/config\/mosquitto.conf\n      - $HOME\/mqtt\/pw:\/mosquitto\/config\/pw\n<\/pre>\n\n\n\n<p>Ist die Datei docker-compose.yml mit diesem Inhalt erstellt, wird der Container mit<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">docker-compose up -d\n<\/pre>\n\n\n\n<p>gestartet. Bevor eine Verbindung per MQTT-Client beispielsweise aus Python heraus aufgebaut werden kann, muss die Passwort-Datei noch ins richtige Format gebracht werden. Dazu wird das Tool <i>mosquitto_passwd<\/i> im Docker Image mitgeliefert. Um die Datei entsprechend umzuwandeln, wird innerhalb des gerade gestarteten Containers ein entsprechender Befehl abgesetzt. Daf\u00fcr wird zun\u00e4chst eine innerhalb des Containers laufende shell aufgerufen. Bash ist nicht installiert, deshalb muss auf sh zur\u00fcckgegriffen werden. Dazu wird der folgende Befehl auf dem Docker Host aufgerufen.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">docker container exec iot-mqtt sh\n<\/pre>\n\n\n\n<p>Anschlie\u00dfend wechselt man mit<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">cd \/mosquitto\/config\n<\/pre>\n\n\n\n<p>in das Verzeichnis mit den beiden Dateien. Dort kann dann mit<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">mosquitto_passwd -U pw\n<\/pre>\n\n\n\n<p>die Umwandlung durchgef\u00fchrt werden. Mit exit wird die Shell des Containers verlassen und auf den Docker Host zur\u00fcckgekehrt. Betrachtet man nun den Inhalt der Passwort-Datei, ist zu sehen, dass die Passw\u00f6rter nicht mehr im Klartext zu sehen sind. Sollte immer noch kein Verbindungsaufbau m\u00f6glich sein, kann der Container gel\u00f6scht und eine neue Instanz gestartet werden. Die Datei bleibt dabei unber\u00fchrt, da sie in einem Docker Volume liegt.<\/p>\n\n\n\n<p>Nun sollte mit der Angabe der \u00f6ffentlichen IP des Webservers, dem Port 1883 sowie einer in der Passwort-Datei angegebenen Kombination aus Benutzername und Passwort ein Verbindungsaufbau zum Broker m\u00f6glich sein. Somit ist die erste Komponente des Smart Drive Backend einsatzbereit.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">MQTT-Receiver<\/h3>\n\n\n\n<p>Damit die per MQTT versandten Messwerte in der Datenbank gespeichert werden, ist ein St\u00fcck Software notwendig, dass diese Aufgabe \u00fcbernimmt. Dazu wird das entsprechende Topic am zuvor aufgesetzten MQTT-Broker abonniert, die Messwerte aus der empfangenen Nachricht gelesen und in entsprechende Datentypen umgewandelt und anschlie\u00dfend pro Messwert eine Zeile in eine Datenbanktabelle geschrieben.<\/p>\n\n\n\n<p>Das Programm wurde in Python implementiert und basiert auf dem bereits gezeigten <a href=\"https:\/\/www.iot-embedded.de\/iot-2021\/smart-drive\/mqtt-mit-python\/\" data-type=\"post\" data-id=\"121\">Skript zum Empfang von MQTT Nachrichten<\/a>. Daher wird dieser Teil nicht weiter erl\u00e4utert. Neu hinzu kommt die Datenbankanbindung. Als Datenbank kommt PostgreSQL zum Einsatz. Zur Verbindung mit PostgreSQL steht f\u00fcr Python die Bibliothek psycopg2 zur Verf\u00fcgung, die mit<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">pip install psycopg2-binary\n<\/pre>\n\n\n\n<p>installiert wird. Anschlie\u00dfend wird das Modul wie folgt importiert und die Verbindung zur Datenbank aufgebaut. Dazu m\u00fcssen zuvor die Verbindungsparameter in den entsprechenden Attributen der Klasse gespeichert werden.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">import psycopg2 as pg\nself._db_connection = pg.connect(\n    host     = self._db_host,\t\t# dazu sp\u00e4ter mehr\n    port     = self._db_port,\t\t# Standard: 5432\n    user     = self._db_user,\t\t# Datenbank User\n    password = self._db_password\t# Passwort f\u00fcr DB-User\n    dbname   = self._db_dbname\t\t# Name der Datenbank\n)\nself._db_cursor = self._db_connection.cursor()\n<\/pre>\n\n\n\n<p>Das Cursor Objekt wird sp\u00e4ter zum Ausf\u00fchren von SQL-Statements verwendet.<\/p>\n\n\n\n<p>Die empfangenen Nachrichten liegen als JSON String vor. Dabei ist zu beachten, dass immer eine Liste von Messwerten \u00fcbertragen wird, auch wenn nur ein einziger Messwert in einer Nachricht enthalten ist. In der Liste befindet sich also immer mindestens ein Objekt, das in den Attributen die Messwerte enth\u00e4lt. Um den String zu parsen, kann der empfangene Payload einfach an die Methode <i>loads()<\/i> des Moduls <i>json<\/i> \u00fcbergeben werden. Als Ergebnis erh\u00e4lt man eine Liste von Dictionaries, die in den Attributen <i>X_acceleration<\/i>, <i>Y_acceleration<\/i>, <i>Z_acceleration<\/i>, <i>X_rotation<\/i>, <i>Y_rotation<\/i> sowie <i>Z_rotation<\/i> die Messwerte des Sensors enth\u00e4lt. Au\u00dferdem wichtig sind die Attribute <i>_id<\/i> und <i>_device_uuid<\/i>, damit die Messwerte zeitlich korrekt sortiert werden und einem bestimmten Device und damit einem Kunden zugeordnet werden k\u00f6nnen. Zu beachten ist, dass alle Werte als String vorhanden sind, vor dem Schreiben in die Datenbank also in Float bzw. Integer umgewandelt werden m\u00fcssen. Der folgende Codeblock zeigt das Umwandeln des Payload in Objekte sowie den Aufruf einer weiteren Methode, der als Argumente die bereits umgewandelten numerischen Werte \u00fcbergeben werden.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">message_list = json.loads(message.payload)\nfor m in message_list:\n    self._write_message_to_db(\n        float(m['_id'][:13]) \/ 1000, # Division f\u00fcr Mikrosekunden\n        m['_device_uuid'],\n        float(m['X_acceleration']),\n        float(m['Y_acceleration']),\n        float(m['Z_acceleration']),\n        int(m['X_rotation']),\n        int(m['Y_rotation']),\n        int(m['Z_rotation'])\n    )\n<\/pre>\n\n\n\n<p>Als letzter Schritt werden nun die Werte in die Datenbanktabelle <i>drive_data<\/i> geschrieben. Dazu wird ein einfaches <i>INSERT<\/i>-Statement verwendet. Die Bibliothek psycopg2 erm\u00f6glicht das Einsetzen von Werten \u00fcber Platzhalter, die im einfachsten Fall als Tupel in entsprechender Reihenfolge \u00fcbergeben werden. Diese M\u00f6glichkeit ist selbst zusammengesetzten Strings in jedem Fall vorzuziehen, da hier automatisch bestimmte Zeichen maskiert werden und so vor SQL-Injections gesch\u00fctzt wird.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">self._db_cursor.execute(\n    \"\"\"INSERT INTO drive_data VALUES (\n        to_timestamp(%s),\n        %s,\n        %s,\n        %s,\n        %s,\n        %s,\n        %s,\n        %s\n    );\"\"\", (\n        timestamp,\n        device_id,\n        X_acc,\n        Y_acc,\n        Z_acc,\n        X_rot,\n        Y_rot,\n        Z_rot\n    )\n)\nself._db_connection.commit()\n<\/pre>\n\n\n\n<p>Da die Reihenfolge der Werte nicht explizit angegeben wird, muss die Reihenfolge der Spalten in der Datenbank eingehalten werden. Der Zeitstempel wird von den Devices als UNIX-Timestamp, also die Anzahl der Sekunden seit Anfang 1970, versandt. Im vorherigen Schritt wurde diese Ganzzahl bereits durch 1.000 dividiert, da die Zeit bis auf 1\/1.000 Sekunde genau angegeben ist. Die Funktion <i>to_timestamp()<\/i> der PostgreSQL-Datenbank wandelt einen solchen Wert in einen Timestamp um, der in einer Spalte vom Typ <i>TIMESTAMP<\/i> gespeichert wird. Liest man den Wert mit der hier verwendeten Python Bibliothek wieder aus, erh\u00e4lt man automatisch ein Objekt vom Typ <i>datetime<\/i>.<\/p>\n\n\n\n<p>Das fertige Programm wird in ein eigenes Docker Image verpackt und \u00fcber Gitlab CI\/CD <a href=\"https:\/\/www.iot-embedded.de\/iot-2021\/smart-drive\/automatisiertes-deployment-von-backend-komponenten\/\" data-type=\"post\" data-id=\"199\">automatisch auf dem Webserver deployed<\/a>. Durch dieses Vorgehen k\u00f6nnen \u00c4nderungen ohne Aufwand live gesetzt werden, wobei nur ein sehr kurzer Ausfall in Kauf zu nehmen ist, da alle Schritte automatisiert ablaufen und somit direkt hintereinander ausgef\u00fchrt werden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Datenbank<\/h3>\n\n\n\n<p>Als DBMS setzen wir in unserem Backend eine PostgreSQL-Datenbank ein. Die Entscheidung ist auf dieses Datenbanksystem gefallen, da hier vor allem im Vergleich zu MariaDB vielf\u00e4ltigere M\u00f6glichkeiten des Einsatzes von Machine Learning Technologien bereit stehen. So ist in PostgreSQL Python-Unterst\u00fctzung integriert und die wichtigsten Bibliotheken wie Numpy, Pandas PyTorch und Tensorflow in der Datenbank lauff\u00e4hig. Diese Technologien werden f\u00fcr unser datengetriebenes Gesch\u00e4ftsmodell sp\u00e4ter essentiell sein und daher bei der Auswahl ber\u00fccksichtigt. Weiterhin kann unser eingesetztes Frontend-Tool out-of-the-box eine PostgreSQL-Datenbank als Data Source verwenden. Damit ist die Integration auch hier gesichert.<\/p>\n\n\n\n<p>Die Anwendung steht auf <a href=\"https:\/\/hub.docker.com\/_\/postgres\/\" target=\"_blank\" rel=\"noopener\">Docker Hub als fertiges Docker Image<\/a> zur Verf\u00fcgung und kann somit ohne gro\u00dfen Aufwand in Betrieb genommen werden. \u00dcber Umgebungsvariablen m\u00fcssen lediglich das Passwort sowie der Name der Datenbank gesetzt werden. Damit die in der Datenbank gespeicherten Daten \u00fcber die Lebensdauer einer Container-Instanz hinaus persistent sind, wird das Verzeichnis <i>\/var\/lib\/postgresql\/data<\/i> in einem Volume gespeichert. Der Eintrag in der docker-compose.yml sieht wie folgt aus.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">  iot-db:\n    image: postgres:11-alpine\n    container_name: iot-db\n    restart: unless-stopped\n    environment:\n      - POSTGRES_PASSWORD=pw\n      - POSTGRES_DB=iot\n    volumes:\n      - $HOME\/iot\/db:\/var\/lib\/postgresql\/data\n<\/pre>\n\n\n\n<p>Es wird kein Port freigegeben, da die Datenbank au\u00dferhalb des Webservers aus Sicherheitsgr\u00fcnden nicht erreichbar sein soll. Das Image stellt jedoch automatisch den Port 5432 f\u00fcr eingehende Verbindungen zur Verf\u00fcgung. Da in unserem Szenario der MQTT-Receiver und das Frontend-Tool eine Verbindung herstellen und diese ebenfalls als Docker Container im selben Docker Netzwerk betrieben werden, ist die Datenbank f\u00fcr diese Komponenten erreichbar.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Grafana<\/h3>\n\n\n\n<p>Als Frontend-Tool, das unseren Kunden die Einsicht in ihre Fahrdaten erm\u00f6glicht, kommt Grafana zum Einsatz. Auch diese Anwendung steht als Docker Image zur Verf\u00fcgung. Die Verwendung des bereitgestellten Image ist in der <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/installation\/docker\/\" target=\"_blank\" rel=\"noopener\">Dokumentation von Grafana<\/a> erl\u00e4utert.<\/p>\n\n\n\n<p>Da die Weboberfl\u00e4che aus dem Internet erreichbar sein soll, wird der entsprechende Port freigegeben. Grafana nutzt standardm\u00e4\u00dfig den Port 3000. Dieser wird zun\u00e4chst beibehalten, sollte jedoch f\u00fcr den produktiven Einsatz auf den Standard-Port f\u00fcr SSL-Verbindungen 443 umgestellt werden. Wie bei den anderen Komponenten des Backend, wird ein Docker Volume verwendet, um die im Container anfallenden Daten zu speichern und diese \u00fcber die Lebensdauer des Containers hinaus zu sichern. \u00dcber Umgebungsvariablen sind einige Einstellungen zu setzen, darunter auch die \u00f6ffentliche Domain der Weboberfl\u00e4che. Insgesamt ergibt sich der folgende Eintrag f\u00fcr docker-compose.yml.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted block\">  iot-grafana:\n    image: grafana\/grafana\n    container_name: iot-grafana\n    restart: unless-stopped\n    ports:\n      - 3000:3000\n    user: \"1001\"\n    volumes:\n      - $HOME\/iot\/grafana:\/var\/lib\/grafana\n    environment:\n      - GF_SERVER_PROTOCOL=http\n      - GF_SERVER_DOMAIN=smart-drive.johannes-wessiepe.de\n      - GF_SERVER_ROOT_URL=http:\/\/smart-drive.johannes-wessiepe.de:3000\n      - GF_SECURITY_ADMIN_USER=user\n      - GF_SECURITY_ADMIN_PASSWORD=pw\n    labels:\n      - traefik.enable=true\n      - traefik.http.routers.iot-grafana.rule=Host(`smart-drive.johannes-wessiepe.de`)\n      - traefik.http.services.iot-grafana.loadbalancer.server.port=3000\n<\/pre>\n\n\n\n<p>Neu f\u00fcr diese Anwendung ist die Angabe einer User-ID mit <i>user: &#8222;1001&#8220;<\/i>. Diese ID wird f\u00fcr den User innerhalb des Containers verwendet. In diesem Fall wurde die ID des Users angegeben, der die Docker Container startet und somit Eigent\u00fcmer des Verzeichnis&#8216; des Docker Volume ist. Dies hat dann den Vorteil, dass die im Volume gespeicherten Daten auch au\u00dferhalb ohne root-Rechte mit voller Berechtigung verf\u00fcgbar sind. Die User-ID des aktuell angemeldeten User kann mit dem Befehl <i>id<\/i> ausgegeben werden.<\/p>\n\n\n\n<p>Damit die Weboberfl\u00e4che unter der Subdomain <i>smart-drive<\/i> erreichbar ist, muss in der Sektion <i>labels<\/i> die entsprechende Regel f\u00fcr den Reverse-Proxy angegeben werden. Dieser k\u00fcmmert sich dann automatisch um das korrekte Routing sowie die Erstellung und Erneuerung des SSL-Zertifikats per Let&#8217;s Encrypt. Das Zertifikat wird aktuell jedoch noch nicht eingesetzt, da SSL nur \u00fcber den Port 443 erlaubt ist.<\/p>\n\n\n\n<p>Um die Daten aus der PostgreSQL-Datenbank im Frontend darstellen zu k\u00f6nnen, wird die Datenbank als Data Source eingebunden. Dazu \u00f6ffnet man die Weboberfl\u00e4che und meldet sich mit den im Dockerfile festgelegten Daten als Administrator an. Danach kann im linken Men\u00fc unter <i>Configuration -&gt; Data Sources<\/i> eine neue Data Source vom Typ PostgreSQL angelegt werden. Als Verbindungsparameter tr\u00e4gt man die in den Umgebungsvariablen des Datenbank-Containers festgelegten Daten wie Passwort und Datenbankname ein. Als User steht standardm\u00e4\u00dfig <i>postgres<\/i> zur Verf\u00fcgung. Erreichbar ist die Datenbank im Docker Netzwerk unter dem Namen des Service, wie in der docker-compose.yml angegeben. In diesem Fall ist der Host <i>iot-db:5432<\/i>. Die \u00fcbrigen Einstellungen verbleiben auf den Standardwerten bzw. leer.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"680\" height=\"790\" src=\"https:\/\/www.iot-embedded.de\/iot-2021\/wp-content\/uploads\/sites\/5\/2021\/06\/Grafana-Data-Source.png\" alt=\"\" class=\"wp-image-532\" srcset=\"https:\/\/www.iot-embedded.de\/iot-2021\/wp-content\/uploads\/sites\/5\/2021\/06\/Grafana-Data-Source.png 680w, https:\/\/www.iot-embedded.de\/iot-2021\/wp-content\/uploads\/sites\/5\/2021\/06\/Grafana-Data-Source-258x300.png 258w\" sizes=\"(max-width: 680px) 100vw, 680px\" \/><figcaption>Data Source in Grafana einrichten<\/figcaption><\/figure>\n\n\n\n<p>Legt man jetzt ein neues Dashboard an, kann die soeben eingerichtete Data Source ausgew\u00e4hlt werden und Daten aus der Tabelle selektiert werden. <a href=\"https:\/\/www.iot-embedded.de\/iot-2021\/smart-drive\/datenvisualisierung-mit-grafana\/\" data-type=\"post\" data-id=\"435\">Das weitere Vorgehen wurde bereits in diesem Beitrag beschrieben<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Komponenten des Backend von Smart Drive Unser Backend ist fertig und lauff\u00e4hig. Im Folgenden werden die einzelnen Komponenten unseres Backend dokumentiert und der Weg der Sensordaten von der Erfassung bis zur grafischen Darstellung im Frontend dargestellt. \u00dcberblick Die folgende Darstellung<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[8],"tags":[],"_links":{"self":[{"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/posts\/508"}],"collection":[{"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/comments?post=508"}],"version-history":[{"count":7,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/posts\/508\/revisions"}],"predecessor-version":[{"id":533,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/posts\/508\/revisions\/533"}],"wp:attachment":[{"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/media?parent=508"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/categories?post=508"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/tags?post=508"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}