Suche

Dialog der Maschinen

Eclipse Paho

Anfang 2012 gründete sich das Paho-Projekt unter der Schirmherrschaft der Eclipse Foundation mit dem Ziel, Open-Source-Implementierungen von M2M-Protokollen bereitzustellen. Zurzeit wird die Referenzimplementierung des MQTT-Protokolls in Form von Clients für Java und C bereitgestellt. Das Paho-Projekt ist zwar noch recht jung, die Java- und C-Implementierungen werden jedoch seit Jahren bei IBM und Eurotech, die auch die initiale Implementierung bereitgestellt haben, eingesetzt und sind für den produktiven Einsatz geeignet. Wir sehen uns nun die Paho-Bibliothek für Java genauer an und implementieren einen Client, der Nachrichten sendet und einen Client, der die Nachrichten empfängt.

Implementierung eines Clients

Bevor wir mit der Implementierung der Clients beginnen können, muss zunächst die Eclipse-Paho-Bibliothek in unser neu erstelltes Projekt eingebunden werden. Die Paho-Bibliothek war zum Zeitpunkt des Schreibens des Artikels noch nicht im Maven Central Repository, deshalb wird sie im Beispielprojekt mitgeliefert. Das Beispielprojekt ist bei Github verfügbar und kann unter [3] heruntergeladen werden. Alternativ kann die Paho-Bibliothek vom Eclipse Git Repository unter [4] heruntergeladen und mittels Ant selbst gebaut werden.

Publish

Wir implementieren zunächst einen Client, der ein Thermometer und einen Helligkeitssensor simuliert und jede Sekunde einen Datensatz an einen öffentlich zugänglichen Broker sendet. Zunächst müssen wir eine Instanz der Klasse MqttClient erzeugen (Listing 1). Als Parameter für den Konstruktor werden der URL zum Broker und eine eindeutige Client-ID benötigt. Als Client-ID bietet sich die MAC-Adresse des Rechners an, da sie eindeutig ist. Zusätzlich wird noch -pub an die Client-ID angehängt, da unsere zwei unabhängigen Clients (einer zum Senden, einer zum Empfangen) sonst dieselbe Client-ID hätten. Es ist wichtig, dass die Client-ID eindeutig ist, da der MQTT Broker pro ID nur einen Client zulässt. Falls schon ein Client mit derselben ID gerade eine Verbindung zum Broker aufgebaut hat, wird die Verbindung des „älteren“ Clients abgebrochen. Die maximale Länge einer Client-ID beträgt 23 Zeichen.

Listing 1
public class Publisher {
  public static final String BROKER_URL = "tcp://broker.mqttdashboard.com:1883";
  private MqttClient client;

  public Publisher() {
      String clientId = Utils.getMacAddress() + "-pub";
      try {
          client = new MqttClient(BROKER_URL, clientId);
        } catch (MqttException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

Nachdem wir eine Instanz von MqttClient haben, können wir uns mittels der connect(…)-Methode zum Broker verbinden (Listing 2). Die connect(…)-Methode bietet uns an, eine Instanz von MqttConnectOptions zu übergeben. Wir erzeugen ein neues Objekt von MqttConnectOptions und setzen cleanSession auf „false“. Damit signalisieren wir dem Broker, dass wir bei einer Verbindung zum Broker mit einer alten Session weiterarbeiten möchten, falls der Client schon einmal verbunden war. Damit ist es möglich, dass bei einer Quality of Service von 1 oder 2 (siehe Kasten „Quality of Service“) keine ausstehenden Nachrichten verloren gehen. Zusätzlich geben wir für den Client ein „Last Will and Testament“ (LWT) Topic an. Ein LWT Topic ist ein Topic, für den der Broker eine Nachricht sendet, falls die Verbindung zu einem Client unvorhergesehen abbricht. Damit ist es möglich, interessierte Clients zu benachrichtigen, dass ein anderer Client nicht mehr an der Kommunikation teilnimmt.

Listing 2
 MqttConnectOptions options = new MqttConnectOptions();
 options.setCleanSession(false);
 options.setWill(client.getTopic("homeautomation/LWT"), "I'm gone".getBytes(), 0, false);

 client.connect(options);

Zuletzt implementieren wir eine einfache Endlosschleife, in der der Publish-Client jede Sekunde einen zufälligen Wert für die Helligkeit an das Topic homeautomation/brightness und einen zufälligen Temperaturwert an das Topic homeautomation/temperature sendet (Listing 3). Dazu holen wir uns ein Topic Object mittels der Methode client.getTopic(…)und führen dort die Methode publish(…)mit unserer gewünschten MqttMessage aus. Um zu überprüfen, dass die Nachricht auch wirklich gesendet wurde, kann man auf der Seite http://www.mqttdashboard.com das gewünschte Topic abonnieren und sehen, was bisher an den Broker gesendet wurde.

Listing 3
public static final String TOPIC_TEMPERATURE = "homeautomation/temperature";

//... 
           while (true) {
                publishBrightness();
                Thread.sleep(500);
                publishTemperature();
                Thread.sleep(500);
            }
//...

 private void publishTemperature() throws MqttException {
        final MqttTopic temperatureTopic = client.getTopic(TOPIC_TEMPERATURE);

        final int temperatureNumber = Utils.createRandomNumberBetween(20, 30);
        final String temperature = temperatureNumber + "°C";

        temperatureTopic.publish(new MqttMessage(temperature.getBytes()));
    }
//publishBrightness() wird analog zu publishTemperature() implementiert
Quality of Service

Das MQTT-Protokoll definiert drei Arten von Quality of Services (QoS):

  • QoS 0: At most once delivery
  • QoS 1: At least once delivery
  • QoS 2: Exactly once delivery

Mit einem QoS definiert ein Client, wie wichtig es ist, dass die Nachricht auch wirklich bei den Empfängern ankommt. Ein QoS von 0 bedeutet, dass die Nachricht meistens einmal ankommt. Es ist unter gewissen Umständen auch möglich, dass eine Nachricht mehrmals oder auch gar nicht beim Empfänger ankommt. QoS 1 bedeutet, dass garantiert wird, dass die Nachricht mindestens einmal bei den Empfängern ankommt. QoS 2 bedeutet, dass garantiert wird, dass die Nachricht genau einmal bei den jeweiligen Empfängern ankommt. Je höher der QoS-Level ist, desto weniger performant wird die Übertragung, da eine zusätzliche Kommunikation zwischen den Clients und dem Broker nötig ist, um sicherzustellen, dass die Nachricht auch wirklich angekommen ist.

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.