IotMqttSampleUsingCallback
Beispiel zur MQTT Kommunikation über eine Callback-Methode
In diesem Beispiel wird die Kommunikation zu einem MQTT Broker dargestellt. Es werden Nachrichten verschickt („Publish“) und empfangen. Dies erfolgt in zwei Schritten. Zuerst wird entschieden, welche Nachrichten generell empfangen werden sollen („Subscribe“). Anschließend werden, während dem zyklischen Aufruf der FB_IotMqttClient.Execute()-Methode, neue Nachrichten über eine Callback-Methode empfangen.
Projektstruktur
- 1. Erstellen Sie ein TwinCAT-Projekt mit einer SPS und fügen Sie die Tc3_IotBase als Bibliotheksreferenz an.
- 2. Die Callback-Methode, in der die empfangenen MQTT-Nachrichten bereitgestellt werden, möchten Sie selbst implementieren. Damit der TwinCAT-Treiber diese Methode aufrufen kann, wird das Prinzip der Vererbung genutzt. Legen Sie zunächst einen Funktionsbaustein an und lassen Sie diesen von dem Funktionsbaustein FB_IotMqttClient erben. In diesem Funktionsbaustein können Sie bereits Teile der MQTT-Kommunikation kapseln. Im Beispiel werden hier empfangene Nachrichten ausgewertet. Deklarieren Sie aus diesem Grund Variablen für Topic und Payload.
{attribute 'c++_compatible'}
FUNCTION_BLOCK FB_MyMqtt EXTENDS FB_IotMqttClient
VAR
(* received message *)
{attribute 'TcEncoding':='UTF-8'}
sTopicRcv : STRING(255);
{attribute 'TcEncoding':='UTF-8'}
sPayloadRcv : STRING(255);
END_VAR
- 3. Legen Sie die Methode OnMqttMessage() an und überschreiben Sie die Basisimplementierung.
- 4. Die Methode mit der von Ihnen vorzunehmenden Implementierung wird nicht in der Applikation aufgerufen, sondern implizit vom Treiber. Dieser Callback findet während des zyklischen Triggerns des Clients statt und kann je nach Anzahl der seit dem letzten Trigger empfangenen Nachrichten keinmal, einmal oder mehrfach erfolgen. Wie folgendes Code Snippet zeigt, implementieren Sie in diesem Beispiel nur eine einfache Auswertung.
{attribute 'c++_compatible'}
{attribute 'pack_mode' := '4'}
{attribute 'show'}
{attribute 'minimal_input_size' := '4'}
METHOD OnMqttMessage : HRESULT
VAR_IN_OUT CONSTANT
topic : STRING;
END_VAR
VAR_INPUT
payload : PVOID;
length : UDINT;
qos : TcIotMqttQos;
repeated : BOOL;
END_VAR
VAR
nPayloadRcvLen : UDINT;
END_VAR
-----------------------------------------------------------------------
SUPER^.nMessagesRcv := SUPER^.nMessagesRcv + 1;
STRNCPY( ADR(sTopicRcv), ADR(topic), SIZEOF(sTopicRcv) );
nPayloadRcvLen := MIN(length, DINT_TO_UDINT(SIZEOF(sPayloadRcv))-1);
MEMCPY( ADR(sPayloadRcv), payload, nPayloadRcvLen );
sPayloadRcv[nPayloadRcvLen] := 0; // ensure a null termination of received string
OnMqttMessage := S_OK;
- 5. Die weiteren Schritte sind ähnlich zum Beispiel MQTT Kommunikation mithilfe einer Message-Queue.
Legen Sie einen Programmbaustein an und deklarieren Sie eine Instanz von Ihrem zuvor definierten Funktionsbaustein FB_MyMqtt sowie zwei Hilfsvariablen, um den Programmablauf bei Bedarf steuern zu können.
PROGRAM PrgMqttCom
VAR
fbMqttClient : FB_MyMqtt;
bSetParameter : BOOL := TRUE;
bConnect : BOOL := TRUE;
END_VAR
- 6. Deklarieren Sie für die zu verschickende MQTT-Nachricht zwei Variablen für Topic und Payload. Im Beispiel soll jede Sekunde eine Nachricht verschickt werden.
(* published message *)
sTopicPub : STRING(255) := 'MyTopic';
sPayloadPub : STRING(255);
i: UDINT;
fbTimer : TON := (PT:=T#1S);
- 7. Deklarieren Sie für den Nachrichtenempfang eine Variable, die das zu empfangene Topic enthält.
bSubscribed : BOOL;
sTopicSub : STRING(255) := 'MyTopic';
- 8. Im Programmteil muss der MQTT Client zyklisch getriggert werden, um den Verbindungsaufbau zum Broker, den Verbindungserhalt und den Nachrichtenempfang zu gewährleisten. Setzen Sie die Parameter der gewünschten Verbindung und initialisieren Sie den Verbindungsaufbau mit dem Übergabeparameter
bConnect := TRUE
. Im Beispiel werden die Parameter einmalig vor dem Client-Aufruf im Programmcode zugewiesen. Weil dies meist nur einmalig nötig ist, können die Parameter auch bereits im Deklarationsteil bei der Instanziierung des MQTT Client angegeben werden. Nicht alle Parameter müssen zugewiesen werden. Im Beispiel ist der Broker lokal. Sie können auch die IP-Adresse oder den Namen angeben.
IF bSetParameter THEN
bSetParameter := FALSE;
fbMqttClient.sHostName := 'localhost';
fbMqttClient.nHostPort := 1883;
// fbMqttClient.sClientId := 'MyTcMqttClient';
fbMqttClient.sTopicPrefix := '';
// fbMqttClient.nKeepAlive := 60;
// fbMqttClient.sUserName := ;
// fbMqttClient.sUserPassword := ;
// fbMqttClient.stWill := ;
// fbMqttClient.stTLS := ;
END_IF
fbMqttClient.Execute(bConnect);
- 9. Sobald die Verbindung zum Broker aufgebaut wird, soll sich der Client auf ein bestimmtes Topic anmelden. Ebenso soll jede Sekunde eine Nachricht versandt werden.
Im Beispiel istsTopicPub = sTopicSub
, so dass ein Loopback entsteht. In anderen Applikationen unterscheiden sich die Topics typischerweise.
IF fbMqttClient.bConnected THEN
IF NOT bSubscribed THEN
bSubscribed := fbMqttClient.Subscribe(sTopic:=sTopicSub, eQoS:=TcIotMqttQos.AtMostOnceDelivery);
END_IF
fbTimer(IN:=TRUE);
IF fbTimer.Q THEN // publish new payload every second
fbTimer(IN:=FALSE);
i := i + 1;
sPayloadPub := CONCAT('MyMessage', TO_STRING(i));
fbMqttClient.Publish( sTopic:= sTopicPub,
pPayload:= ADR(sPayloadPub), nPayloadSize:= LEN2(ADR(sPayloadPub))+1,
eQoS:= TcIotMqttQos.AtMostOnceDelivery, bRetain:= FALSE, bQueue:= FALSE );
END_IF
END_IF
Voraussetzungen
Entwicklungsumgebung | Zielplattform | Einzubindende SPS-Bibliotheken |
---|---|---|
TwinCAT v3.1.4022.0 | IPC oder CX (x86, x64, ARM) | Tc3_IotBase, |