1 Motivation und Zielsetzung

Oft sollen Sensordaten in einem Gebäude als Beispiel durch Microcontroller oder „Edge Gateways” transportiert werden und anschließend in der Cloud verarbeitet werden. Für sehr viele batteriebetriebene Low-Power-Sensoren mit sehr begrenzter Verarbeitungsleistung und Speicherkapazität ist TCP als Übertragungsweg nicht leichtgewichtig genug und um eine möglichst leichtgewichtige Verbindung für diese Anwendungsfälle zu ermöglichen, werden MQTT-SN-Netzwerke verwendet welche „UDP” benutzen.

Ziel von diesem Beitrag ist es, eine mögliche Prototyp-Implementierung einer „MQTT-SN-Bridge” für batteriebetriebene Low-Power-Sensoren zu erläutern, welcher Daten durch simulierte Endgeräte-Clients über das MQTT-SN-Netwerk zu versendet, welche anschließend per HTTP an die „Google Cloud Functions” weitergeleitet werden, um diese dort zu verarbeiten.

1.1 High-Level Architektur

Die folgende Abbildung zeigt die High-Level Architektur der Implementierung:

Abbildung 1.1: High-Level Architektur

Abbildung 1.1 zeigt das Szenario des Prototypen. Die „Google Cloud Functions” werden direkt über HTTP aufgerufen und die Sensordaten die über MQTT-SN (RSM-Broker) im Gateway eintreffen und durch die MQTT/HTTP-Bridge einen Protokollwechsel (MQTT auf HTTP) erleben, werden mit Testwerten in den Cloud-Funktionen geloggt und mit einem Zeitstempel als HTTP-Antwort zurückgegeben.

2 Der Begriff MQTT-SN

MQTT-SN steht für „MQTT for Sensor Networks”, das auf eingebettete Geräte in Nicht- TCP/IP-Netzwerken abzielt. MQTT-SN ist ein Publish/Subscribe-Messaging-Protokoll für drahtlose Sensornetzwerke (WSN) mit dem Ziel, das MQTT-Protokoll über die Reichweite der TCP/IP-Infrastruktur für Sensor- und Aktorlösungen hinaus zu erweitern. MQTT-SN sieht größtenteils MQTT ähnlich, z. B. Connect/Subscribe/Publish-Befehl, der eigentliche Unterschied zwischen MQTT-SN und MQTT ist die TopicID, die den Topicnamen in MQTT ersetzt. Topic-IDs ist eine 16-Bit-Ganzzahl, die für einen Topicnamen steht. Gerät und Broker verwenden den REGISTER-Befehl, um die Zuordnung zwischen Topic-ID und Themenname auszuhandeln.

2.1 MQTT-SN Charakteristiken

MQTT-SN führt Gateways in sein Netzwerk ein. Das Gateway übersetzt zwischen MQTTSN und MQTT, tauscht Nachrichten zwischen Gerät und MQTT-Broker aus und es gibt einen Mechanismus namens Gateway Discovery, der es dem Gerät ermöglicht, Gateways automatisch zu finden. MQTT-SN unterstützt weiterhin auch eine Sleeping-Client-Funktion, die es dem Gerät ermöglicht, sich selbst herunterzufahren, um für eine Weile Strom zu sparen. Das Gateway muss Downlink-Veröffentlichungsnachrichten für schlafende Geräte puffern und diese Nachrichten an Geräte senden, sobald sie wach sind.

Abbildung 2.1: MQTT-SN Sleep-Verfahren

Abbildung 2.1 zeigt das „Sleep-Verfahren”. Hierbei wird der Sleep-Timer wird gestoppt, wenn der Server/Gateway eine PINGREQ vom Client empfängt. Wie die CONNECTNachricht enthält diese PINGREQ-Nachricht die Client-ID. Der identifizierte Client befindet sich dann im äwakeZustand. Wenn der Server/Gateway Nachrichten für den Client gepuffert hat, sendet er diese Nachrichten an den Client. Die Übertragung von Nachrichten an den Client wird vom Server/Gateway durch eine PINGRESP-Nachricht beendet, d.h. der Server/Gateway betrachtet den Client als schlafend und startet den Sleep-Timer erneut, nachdem er die PINGRESP-Nachricht gesendet hat. Wenn der Server/das Gateway keine Nachrichten für den Client gepuffert hat, antwortet er sofort mit einer PINGRESPNachricht, versetzt den Client wieder in den Ruhezustand und startet den Sleep-Timer für diesen Client neu.

2.2 MQTT-SN RSM Broker Architektur

Abbildung 2.2: Really Small Message Broker (RSMB) Architektur

Der RSM-Broker fungiert sowohl als MQTT-SN-Broker als auch als MQTT-Broker, der Nachrichten zwischen MQTT-SN-Clients und MQTT-Clients (UDP <-> TCP) zulässt, wie in Abbildung 2.2 dargestellt. Der RSM-Broker1 der hier im Prototypen im Rahmen dieser Ausarbeitung verwendet wird, setzt auf der Codebasis vom MQTT-Mosquitto-Broker2 auf, da der Mosquitto-Broker derzeit keine Unterstützung für das MQTT-SN-Protokoll bietet. MQTT-SN ist insbesondere für die ressourcenbeschränkten Geräte mit begrenzten Verarbeitungs- und und Speicherressourcen optimiert, so dass die MQTT-SN Headerund Payload-Strukturen im Vergleich zu MQTT einfach und kurz in der Länge sind. Ein Topic-Name gemäß MQTT könnte z. B. haus/sensor1 sein. Unter MQTT-SN könnte ein verkürzter Topic-Name verwendet werden wie z. B. s1.

3 Serverless Computing

Serverless Computing ist eine Methode zur Bereitstellung von Backend-Diensten auf „As- Used-Basis”. Ein „serverless” Anbieter ermöglicht es Benutzern, Code zu schreiben und bereitzustellen, ohne sich Gedanken über die zugrunde liegende Infrastruktur machen zu müssen. Serverless Computing ermöglicht es Entwicklern, Backend-Dienste auf flexibler „Pay-as-you-go“-Basis zu erwerben, was bedeutet, dass Entwickler nur für die von ihnen genutzten Dienste bezahlen müssen. Das ist wie der Wechsel von einem Handy-Datentarif mit monatlich festem Limit zu einem Tarif, bei dem nur jedes tatsächlich genutzte Datenbyte abgerechnet wird. Die wesentlichen Vorteile von „Serverless Computing” sind, das diese Architektur im Allgemeinen sehr kostengünstig ist, da herkömmliche Cloud- Anbieter von Backend-Diensten (Serverzuweisung) häufig dazu führen, dass der Benutzer für ungenutzten Speicherplatz oder ungenutzte CPU-Zeit bezahlt. Ein weiterer wichtiger Vorteil ist, das Entwickler, die eine serverlose Architektur verwenden, sich keine Gedanken über Richtlinien zur Skalierung ihres Codes machen müssen. Der serverlose Anbieter übernimmt die gesamte Skalierung nach Bedarf. Serverlose Architekturen sind eine natürliche Erweiterung der Ideen aus der serviceorientierten Architektur (SOA). In der serverlosen Architektur werden alle benutzerdefinierten Funktionen als isolierte, unabhängige und oft granulare Funktionen geschrieben, die in einem zustandslosen Cloud-Service wie bei „Google-Cloud-Functions” oder „AWS Lambda” ausgeführt werden [Serverless Architectures on AWS: With Examples Using AWS Lambda].

3.1 Google Cloud Functions

Die „Google-Cloud-Functions” können hauptsächlich in zwei Arten von Funktionen unterteilt werden:

HTTP-Funktion:

Das sind Funktionen, die durch Aufrufen der für die Funktion zugewiesenen oder erstellten HTTP-URL ausgelöst oder ausgeführt werden können.

Hintergrundfunktion:

Die Hintergrundfunktion ist im Grunde eine Art Funktion, die bei Ereignissen externer oder anderer Cloud-Dienste ausgelöst wird. Beispielsweise kann das Hinzufügen/Löschen von Dateien in Ihrem Cloud-Speicher die Cloud-Funktion auslösen.

Abbildung 3.1: Stimmungsanalyse mit GCP-Funktionen

„Google-Cloud-Functions” können in verschiedensten Anwendungsfällen eingesetzt werden. Abbildung 3.1 zeigt z.B. einen Anwendungsfall im Rahmen einer Stimmungsanalyse (Sentiment analysis) im „Natural Language Processing”.

3.2 Kaltstart von Funktionen

Bei allen „Serverless”-Computing-Anbietern gibt es irgendeine Form von einem Kaltstart der Funktionen, die sich nicht eliminieren lassen. Selbst wenn eine einzelne Instanz (Funktion) am Leben erhalten wird durch anpingen, kann das System eine beliebige Anzahl anderer Instanzen hochfahren, um die aktuelle Last zu bewältigen. Diese neuen Instanzen haben auch einen Kaltstart. Wenn die Last dann abnimmt, werden die unnötigen Instanzen heruntergefahren. Google Cloud bietet die Möglichkeit eine Mindestanzahl von Instanzen (Funktionen) anzugeben, die aktiv bleiben sollen. Diese Option bietet die Möglichkeit „Kaltstarts” zu reduzieren, allerdings nicht zu eliminieren. Der Vorteil von Serverless besteht darin, dass ein eigener Server nicht verwaltet oder skaliert werden muss und nur für das bezahlt wird, was tatsächlich an Ressourcen verwendet wird. Der Nachteil ist offensichtlich der unvorhersehbare Kaltstart von Funktionen. Oft sind Cloud-Funktionen im Allgemeinen am besten geeignet, um nur eine (kleine) Aufgabe zu erfüllen. Vor diesem Hintergrund sollte der Cloud-Funktionscode sauber und klein gehalten werden, um nur eine Aufgabe auszuführen. Ein Beispiel wäre eine „Hintergrund-Funktion”, die eine Datei oder ein Datensatz schreibt oder eine Überprüfung, die durchgeführt werden muss.

Abbildung 3.2: Übersicht Kalt vs. Warmstart (https://stackoverflow.com/questions/51782742/how-can-i-keep-google-cloud-functions-warm)

Abbildung 3.2 zeigt das der Kaltstart einer Funktion zwischen 6 und 9 Sekunden liegen kann. Beim Warmstart sind es maximal 2,07 Sekunden.

4 Aufbau der Kommunikation

Das folgende Diagramm zeigt den Ablauf der Ende-zu-Ende Kommunikation vom Prototypen.

Abbildung 4.1: Ablauf der Kommunikation mit den GCP-Funktionen

Im ersten Schritt senden simulierte Sensoren die Daten an das Gateway. Der RSM-Broker erhält diese Nachricht per UDP und ein weiterer MQTT-Client im Gateway kann diese Nachricht durch den Broker über TCP konsumieren. Ist die Nachricht einmal in der Middleware des „Backends” angekommen, wird diese durch die MQTT/HTTP-Bridge Komponente verarbeitet und als Payload über einen HTTP-Client an die Google-Cloud- Funktion gesendet. Für diesen Prototypen wurden insgesamt drei verschiedene Google- Cloud-Funktionen implementiert. Die Funktion „gcpPayloadTimestamp” nimmt die Daten von einem Sensor entgegen und setzt beim Eintreffen einen Zeitstempel auf diesen Datensatz und liefert das Ergebnis als HTTP-Antwort zurück. Die Funktion „countFunction” zählt den Wert („value” als Key im JSON-Format) um eins hoch und liefert dann das Ergebnis zurück. Die letzte Funktion „jsonToCSV” konvertiert die Werte (JSON-Values) in ein CSV-Format (Comma-separated values).

4.1 Umsetzung

Um die Sensordaten und die Clients auf den Feldgeräten zu simulieren, wurden „MQTTSN Command Line Tools” verwendet, die vollständig in C implementiert sind. Diese Kommandos wurden über ein Shell-Skript aufgerufen, welches in sekündlichen Abständen Daten über das „Publish Command” auf ein definiertes „MQTT-SN Topic” veröffentlicht, welche dann bei dem RSM-Broker im Gateway ankommen. Mit diesem CLI-Befehl wird eine Nachricht auf dem Topic „s1” an den RSM-Broker veröffentlicht:


./mqtt -sn -pub 127.0.0.1 -p 1885 -t s1 -m "{" sensor_id ":"1" ," value ":21}"

Listing 1: MQTT-SN CLI Publish auf Port 1885 (UDP)

Das Shell-Skript, welches drei MQTT-SN-Clients simuliert und in diesem Fall immer 5 Sekunden wartet (sleep 5) bis die nächsten Daten veröffentlicht werden, sieht wie folgt aus:


#!/ bin/bash
# MQTT -SN Clients Simulation Script

n=1

while [ $n -le 20 ]
do
./mqtt -sn -pub 127.0.0.1 -p 1885 -t s1 -m '{" sensor_id ":"1" ," value ":21} '
./mqtt -sn -pub 127.0.0.1 -p 1885 -t s2 -m '{" sensor_id ":"2" ," value ":33} '
./mqtt -sn -pub 127.0.0.1 -p 1885 -t s3 -m '{" sensor_id ":"3" ," value ":5}'
sleep 5

let "n+=1"
done

Listing 2: MQTT-SN-Clients Shell-Skript (mqtt_sn_clients_simulator.sh)

Weiterhin bieten die „MQTT-SN-Tools” Features wie Keep Alive-Pings, manuelle und automatische Client-ID Generierung, vordefinierte Topic-IDs und kurze Topic-Namen, abonnieren von Topics (Subscribe) und noch einige weitere Features. Einschränkungen der Tools sind z.B. eine Paketlänge von höchstens 255 Bytes, kein automatisches erneutes Versenden verlorener Pakete, kein Quality of Service (QoS) Level 2.

4.2 RSM Broker Konfiguration

Damit MQTT-SN-Clients über UDP und MQTT-Clients über TCP eine Verbindung mit dem RSM-Broker aufbauen können, muss der Broker wie folgt konfiguriert werden:


# RSMB Configuration
trace_output protocol
#listen for MQTT -SN traffic on UDP port 1885
listener 1885 INADDR_ANY mqtts
ipv6 true
#listen for MQTT connections on TCP port 1886
listener 1886 INADDR_ANY
ipv6 true

Listing 3: RSM Broker Konfiguration (rsmbconfig.conf)

Die MQTT-SN-Clients müssen den Port 1885 nutzen und die MQTT-Clients den Port 1886. Bevor der RSM-Broker gestartet werden kann, muss er zu erst im Verzeichnis rsmb/src mit „make” kompiliert werden. Danach kann der RSM Broker mit der definierten Brokerconfig über den CLI-Befehl gestartet werden (Listing 4).


./ broker_mqtts rsmbconfig.conf

4.3 Die MQTT/HTTP-Bridge

Ein Python-Skript dient als „Übersetzer” der die MQTT-Nachrichten der Sensoren, auf das HTTP-Protokoll überträgt und die Nachrichten dann als HTTP-Payload an die Cloud- Functions weitergegeben werden durch die HTTP-POST Methode. Folgendes Listing zeigt das Python-Skript welches als Bridge dient:


import paho.mqtt.client as mqtt
import requests
from requests.structures import CaseInsensitiveDict

def on_connect(client , userdata , flags , rc):
 client.subscribe ("s1")
 client.subscribe ("s2")
 client.subscribe ("s3")

def on_message(client , userdata , msg):
 m_decode = str(msg.payload.decode ("utf -8", "ignore "))
 invoke_gcp_function(msg.topic , m_decode)

def invoke_gcp_function(topic , sensorData):

 if topic == "s1":
    currentFunctionRoute = "https ://....function -1"
 elif topic == "s2": 
    currentFunctionRoute = "https ://....function -2"
 elif topic == "s3": 
    currentFunctionRoute = "https ://....function -3"

 headers = CaseInsensitiveDict ()
 headers ["Content -Type"] = "application/json"
 response = requests.post(currentFunctionRoute , headers=headers , data = sensorData)
 print(response.status_code)

client = mqtt.Client ()
client.on_connect = on_connect
client.on_message = on_message
client.connect (" localhost", 1886, 60)
client.loop_forever ()

Listing 5: MQTT/HTTP-Bridge Python-Skript

In der MQTT/HTTP-Bridge werden zwei Clients verwendet, einmal der Paho-MQTTClient6 und einmal der requests-HTTP-Client7. In der „on_connect”-Methode subscriben wir unseren MQTT-Client an die Topics „s1,s2,s3” und wenn eine Nachricht vom MQTTSN- Client im RSM-Broker eintrifft, erhält unser MQTT-Client ebenfalls die Nachricht in der „on_message”-Listener-Methode. Ist die MQTT-SN-Nachricht dann in unserer MQTT/HTTP-Bridge eingetoffen, wird die Methode „invoke_gcp_functions” aufgerufen und innerhalb dieser Methode wird geprüft ob es sich um die validen Topicnamen „s1,s2” oder „s3” handelt und dementsprechend wird dann die GCP-Funktion per HTTPClient mit den Sensordaten als Payload aufgerufen und am Ende wird der Response-Code (200 wenn alles geklappt hat) ausgegeben. In dem Fall geben wir nur den Statuscode aus, es könnten auch die verarbeiteten Daten der GCP-Funktionen ausgegeben werden (Response-Body) oder diese Daten auch evtl. in einer Erweiterung in eine Datenbank ablegen etc.

4.4 Implementierung der GCP-Funktionen

Folgende Abbildung zeigt die drei angelegten „Google Cloud Functions” für diese Implementierung des Prototypen:

Abbildung 4.1: GCP-Funktionen

Für alle Funktionen werden automatisch 256 MB Speicher allokiert und der Aufruf der Funktionen wird über HTTP und unautorisiert zugleassen. In einem wirklich echten Szenario sollte HTTPS genutzt werden und nur autorisierte Zugriffe erlaubt sein. Die Implementierung der GCP-Funktion basiert auf der JavaScript-Laufzeitumgebung „Node.js”, allerdings bietet Google auch eine Umsetzung der Funktionen mit der Programmiersprache Go, Java oder auch C# .NET an wie in Abbildung 4.2 zu sehen ist.

Die Abbildungen 4.3, 4.4 und 4.5 zeigen die im Kapitel „Methodik” erwähnten implementierten GCP-Funktionen für diesen Prototypen:

Abbildung 4.2: Auswahl der Programmiersprache für GCP-Funktionen
Abbildung 4.3: Implementierte GCP-Funktion „gcpPayloadTimestamp”
Abbildung 4.4: Implementierte GCP-Funktion „countFunction”
Abbildung 4.5: Implementierte GCP-Funktion „jsonToCSV”

Google bietet für die „GCP-Functions” ein recht schnelles „Deployment” an und es können z.B. Metriken eingesehen werden wie Ausführungszeiten oder Aufrufe der Funktionen. Weiterhin können Berechtigungen vergeben werden, Logeinträgen eingesehen werden oder auch Variablen gesetzt werden.

5 Evaluation und Ergebnisse

Um IoT-Anwendungen durchführbar und allgegenwärtig zu machen, ist eine der wichtigsten Überlegungen der geringe Stromverbrauch von IoT-Geräten, damit sie lange Zeit ohne Batteriewechsel auskommen können. MQTT ist ein Protokoll, das leichtgewichtig ist, aber einen TCP/IP-Stack benötigt, um zu funktionieren. Wenn die Sensorknoten jedoch nicht über einen TCP/IP-Stack verfügen, ist MQTT-SN, das nicht auf TCP/IP angewiesen ist, optimal. MQTT-SN ist ausschließlich für Sensornetzwerke entwickelt worden. MQTT-SN verwendet UDP, das verbindungslos ist und den Verbindungs-Overhead im Vergleich zu TCP/IP reduziert. Auch die automatische Erkennung von Brokern und die Verwendung von Topic-IDs reduziert die Größe jedes Pakets, das mit MQTT-SN übertragen wird. Durch die Verringerung der Paketgröße wird der für die Erstellung und Übertragung von Daten erforderliche Stromverbrauch stark reduziert. Die Verwendung eines Gateways zusätzlich zum Broker ermöglicht es dem Sensornetzwerk, mit anderen MQTT-Clients und sogar mit anderen Netzwerken zu kommunizieren. Neben der Möglichkeit den RSM-Broker zu nutzen, bietet MQTT-SN zwei Varianten eines Gateways an, einmal das „Transparente Gateway” und einmal ein „Aggregierendes Gateway”.

Transparentes Gateway:

Für jeden MQTT-SN-Client wird ein transparentes Gateway eine MQTT-Verbindung zum MQTT-Server aufbauen und aufrechterhalten. Diese MQTT-Verbindung ist ausschließlich für den durchgängigen und nahezu transparenten Nachrichtenaustausch zwischen dem Client und dem Server reserviert. Es werden so viele MQTT-Verbindungen zwischen dem GW und dem Server bestehen, wie MQTT-SN-Clients mit dem GW verbunden sind. Das transparente GW führt eine SSyntaxÜbersetzung zwischen den beiden Protokollen durch.

Abbildung 5.1: MQTT-SN Transparentes Gateway

Aggregierendes Gateway:

Anstelle einer MQTT-Verbindung für jeden angeschlossenen Client verfügt ein aggregierendes GW nur über eine MQTT-Verbindung zum Server. Alle Nachrichtenaustausche zwischen einem MQTT-SN-Client und einem aggregierenden GW enden am GW. Das GW entscheidet dann, welche Informationen an den Server weitergegeben werden. Obwohl die Implementierung komplexer ist als das transparente GW, kann ein aggregierendes GW hilfreich sein, da die Anzahl der MQTT-Verbindungen reduziert wird.

Abbildung 5.2: MQTT-SN Aggregierendes Gateway

5.1 Rückblick

Die Umsetzung des Prototypen im Rahmen dieser Ausarbeitung war gut umzusetzen und durch einige fertige Bausteine wie dem RSM-Broker konnte eine schnelle Kommunikatation vom MQTT-SN Client bis hin zur Google Cloud realisiert werden. Weiterhin gibt es einige Tools und Clients die sich einfach einsetzen lassen um auch Verbindungen zu simulieren und ein Testnetzwerk aufzubauen. Das eigene Prototypen-Gateway mit der MQTT/HTTP-Bridge ließ sich relativ einfach als Python-Skript realisieren. IoT-Protokolle sind leichtgewichtig konzipiert, um batteriebetriebe Geräte mit wenig Speicher zu unterstützen. Die Implementierung der Clients für solche Protokolle ist meistens einfach gehalten und schnell umsetzbar. Das Anlegen der „Google Cloud Functions” verlief reibungslos und war ebenfalls schnell umsetzbar. Das Serverless-Computing bietet die Möglichkeit schnell Backend-Funktionalität umzusetzen, besonders wenn für Sensordaten eine Cloud-Anbindung nötig ist.