TwinCAT and MQTT – Part 1 Getting started

In a previous post I showed how to get started with Home Assistant and TwinCAT using Beckhoffs ADS. During research for this project I also stumbled over MQTT and I decided to do some test projects with it. In this series of post I will show the basis of MQTT communication with TwinCAT. Followed by some more advanced examples using JSON.

Used hardware:

For this post I made use of this hardware:

  • A development laptop
  • IPC C6015 from Beckhoff which will be our PLC. The IPC has Windows 10 IOT installed and TwinCAT 3 4022.
  • EtherCAT bus coupler EK1100
    • EL1008 – 8 channel digital input.
      • a button connected to channel 1
    • EL2008 – 8 channel digital output.
      • a green led connected to channel 1
    • EL3314 – 4 Channel thermouple input (temperature measurement).
      • J-Thermocouple connected to channel 1.

MQTT a short introduction

MQTT is an extremely lightweight publish/subscribe messaging transport protocol usually running over TCP-IP. Because it is such a lightweight protocol MQTT is widely used in IOT devices. But it is also supported by many home automation applications like Home Assistent. A MQTT network consists of one MQTT message broker, with one or more clients connected to it. Each client can publish message to the broker specified with a topic name. And each client can subscribe to message with a specified topic name. The broker thus receives all the messages and will publish them to the subscribed clients.

In this serie of posts I will use the Mosquitto message broker. This broker is open source, light weight and easy to use. An overview of how the MQTT broker in this post takes it place in the data flow:

MQTT network overview

Setting up the MQTT broker

I installed the Mosquitto broker on my Windows 10 laptop. To start the broker open command prompt, change the directory to the Mosquitto installation folder, and run Mosquitto. For debugging run Mosquitto with the ‘-v’ parameter to show all logging. Make sure you allow Mosquitto in your firewall!

Publish a message with TwinCAT

With the broker installed it’s time to to set up the PLC and send some data. Create a new PLC project in TwinCAT with a default ‘Main’ program. Then install the library TC3_IOTBase. In the main program add the following variables:

PROGRAM MAIN
VAR
    fbMqttClient: FB_IotMqttClient; // MQTT client.
    TopicToPublish : STRING(255) := 'Temperatures'; // Mqtt topic on which we will broadcast the acual temperatures
    MessageToPublish : STRING(255); //String to send.
    fbSendMessageIntervalTimer : TON := (PT:=T#1S); //Interval timer for broadcasting.

    ai_RoomTemperature AT %I* : INT; //Actual room temperature, linked to thermocouple
END_VAR

The variable ‘fbMqttClient‘ the main component here. It handles the communication from and to the message broker. ‘TopicToPublish‘ is the variable we use to indicate the topic we are publishing on. In this example we use a fixed topic: ‘Temperatures’.

MessageToPublish‘ will be the published string and is assigned in the program. The ‘fbSendMessageIntervalTimer ‘ timer defines the interval on which the messages will be published. The ‘ai_RoomTemperature‘ variable is linked to phsyical input with an connected thermocouple. Purely to make this example a bit more concrete ๐Ÿ™‚ .

In the implementation part of the main program write the following code:

 
IF _TaskInfo[GETCURTASKINDEXEX()].FirstCycle THEN
    fbMqttClient.sHostName := '192.168.xxx.xxx';
    fbMqttClient.nHostPort := 1883;
    fbMqttClient.sTopicPrefix := '';
    fbMqttClient.sClientId := 'Publishing PLC';
END_IF

fbMqttClient.Execute(bConnect := TRUE);

IF fbMqttClient.bConnected THEN
    fbSendMessageIntervalTimer(IN:=TRUE);
    IF fbSendMessageIntervalTimer.Q THEN
        fbSendMessageIntervalTimer(IN:=FALSE);
        MessageToPublish := CONCAT('Room temperature: ',REAL_TO_STRING(ai_RoomTemperature / 10.0));
    
        fbMqttClient.Publish(sTopic:= TopicToPublish,
            pPayload:= ADR(MessageToPublish),
            nPayloadSize:= LEN2(ADR(MessageToPublish))+1,
            eQoS:= TcIotMqttQos.AtMostOnceDelivery,
            bRetain:= FALSE,
            bQueue:= FALSE);
    END_IF
END_IF

The first part of the program configures the MQTT client. Specify the IP address of the Mosquitto broker, which in my case is my development laptop IP address. We also name the MQTT client here which is particularly useful for debugging. Notice that theย  configuration of the MQTT client only happens during the first cycle of the PLC!.

The line ‘fbMqttClient.Execute(bConnect := TRUE);’ connects the client to the broker. This method must be called cyclic to keep the connection alive!

The last part of the program checks if the connection is alive and if so it composes a message on interval and publishes it. In this example we publish a message ‘Room temperature: **.*’ The publish method take a couple of arguments. a string containing the topic name, the address of the text to send and the size of the message. The other arguments are food for another post.

Running this program we immediately notice the arrival of message in the Mosquitto broker. The messages are easily identified by the named client : ‘Publishing PLC’.

Reading data with a smartphone

The fun thing with MQTT is that almost al devices supporting TCP-IP can implement it. This could mean a total different PLC brand like Siemens. But it could also be a smartphone! On my android smartphone I downloaded and installed the MQTT Dash app. with the smartphone being on the same network you can connect MQTT dash to the Mosquitto browser and subscribe to topic ‘Temperatures’.

Subscribe on a topic with TwinCAT

Receiving data on you phone is fun, but this post is about TwinCAT and MQTT ๐Ÿ™‚ . So I created a second separate PLC project. With again a single main program. Which makes by project structure as seen in this picture:

In the declaration part of the main program add the following variables:

PROGRAM MAIN
VAR
    fbMqttClient: FB_IotMqttClient;
    fbMessageQueue: FB_IotMqttMessageQueue;
    fbMessage: FB_IotMqttMessage;
    Subscribed:BOOL;
    TopicToSubscribe : STRING(255) := 'Temperatures'; // Mqtt topic on which we will subscribe
    ReceivingTopic:STRING(255);
    ReceivingData:STRING(255);
END_VAR

Same as in the program publishing data the variable ‘fbMqttClient‘ is the main function block to connect with the broker. ‘fbMessageQueue‘ is a queue which stores the received messages. The ‘fbMessage‘ is function block which contains the received messages.

Further we have a boolean ‘subscribed‘ indicating if we are subscribed to a topic and a variable ‘TopicToSubscribe‘ containing the string ‘Temperatures‘ the topic we will subscribe to. The variables ‘ReceivingTopic‘ and ‘ReceivingData‘ are used for storing the received messages.

In the implementation part of the main code add the following code:

 
IF _TaskInfo[GETCURTASKINDEXEX()].FirstCycle THEN
    fbMqttClient.sHostName := '192.168.xx.xx';
    fbMqttClient.nHostPort := 1883;
    fbMqttClient.sTopicPrefix := '';
    fbMqttClient.ipMessageQueue := fbMessageQueue;
    fbMqttClient.sClientId := 'Subscribing PLC';
END_IF

fbMqttClient.Execute(bConnect :=true);

IF fbMqttClient.bConnected THEN
    IF NOT Subscribed THEN
        Subscribed := fbMqttClient.Subscribe(sTopic:=TopicToSubscribe,
        eQoS:=TcIotMqttQos.AtMostOnceDelivery);
    END_IF
END_IF

IF fbMessageQueue.nQueuedMessages โ€บ 0 THEN
    IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
         fbMessage.GetTopic(pTopic:=ADR(), nTopicSize:=SIZEOF(ReceivingTopic) );
         fbMessage.GetPayload(pPayload:=ADR(ReceivingData), nPayloadSize:=SIZEOF(ReceivingData), bSetNullTermination:=FALSE);
    END_IF
END_IF

Configuration and connecting are the same as with the publishing client, however we do now specify to the client the ‘fbMessageQueue‘ in which we want the messages stored. After the configuration and connecting the programs checks for an active subscription onto a topic. If this is not the case the programs subscribes to the topic ‘Temperatures’.

After that we continuously monitor our message queue. If a message is send to the queue we immediately dequeue it and store its topic and content in the variables ‘ReceivingTopic‘ and ‘ReceivingData‘.

Running both our PLC programs at the same time we immediately notice more data traffic at the Mosquitto broker:

Mosquitto receiving and publishing data

Each time the broker receives a message from ‘Publishing PLC’ it directly sends this messages to the ‘Subscribing PLC’.

Of course we check the message also in the online view:

 

Conclusion

Enough lecture for this post! This post covered the first setup of TwinCAT and MQTT with some basic examples. Even with a small side step showing the data on a smart phone! Part 2 we will go in more detail about composing messages using JSON.

Gerhard Barteling

Gerhard is a mechatronic engineer with a predilection for software engineering.