MQTT Client Library for Automation Runtime based on eclipse/paho.mqtt.c
This repository includes compiled binary MQTT client libraries for Automation Runtime. The libraries are based on
The libraries come in two different forms
IotMqtt
IotMqtt is a Function Block based Library with Publish and Subscribe functionality that enables easy usage within
the CYCLIC IEC environment. Basically this is what you need when you want to communicate with a broker using MQTT.
The client is based on the MQTTAsync
which is capable of running multiple simultaneous connections on the same PLC.
PahoMQTT
PahoMQTT is the static library with direct access to the paho.mqtt.c API which is used by the IotMqtt library as a driver. The PahoMQTT library should only be used in special cases, where you need to enable special commands from the mqtt stack. It offers basic compatibility for projects that have previously been using PahoMQTT from the https://github.com/br-automation-com/PahoMQTT_Library repository, whereas some minor modifications are needed for these applications. Please see Compatibility with Older PahoMQTT versions for more info on this.
The libraries have been built for following runtime versions:
These version have no strict dependency on that very AR version, but you should try to use a Library version as close to the AR version as possible.
OpenSSL 1.1.1g
and paho.mqtt.c 1.3.5
ARsim
versions have the last version
number .1
, like 4.73.1
and PC targets (with more than 128 sockets) have the last version number .9
, like 4.73.9
.OpenSSL 1.1.1g
and paho.mqtt.c 1.3.7
ArSim
, PC
or PLC
.IotMqttRegParPublish
, IotMqttRegParSubscribe
and GoogleIotCredentials
OpenSSL 1.1.1g
and paho.mqtt.c 1.3.8
IotMqttPublish
andIotMqttRegParPublish
OpenSSL 1.1.1g
and paho.mqtt.c 1.3.8
The IotMqtt library enables simple usage within IEC programs. It consists on 3 different types of Function Blocks:
Every time a new connection with a MQTT broker is desired, an IotMqttClient FUB must be used. Then, depending on the pubish/subscribe needs, it is possible to associate from 0 to 50 IotMqttPublish
or IotMqttSubscribe
FUBs. IotMqttRegParPublish
and IotMqttRegParSubscribe
also count as IotMqttPublish
or IotMqttSubscribe
Here are some simple samples. Before running them, it is important to change the ClientID parameter to a customized one, since the ClientID must be unique in the broker.
Publish sample: This sample shows how to connect, and publish MQTT messages to a topic
PROGRAM _CYCLIC
IotMqttParameters.ServerUri := 'broker.hivemq.com';
IotMqttParameters.Port := 1883;
IotMqttParameters.ClientID := 'B&R_SimplePublishSample';
IotMqttClient_0.Enable := TRUE;
IotMqttClient_0.Connect := TRUE;
IotMqttClient_0.IotMqttLink := ADR(IotMqttLink);
IotMqttClient_0.Parameters := IotMqttParameters;
IotMqttClient_0();
PublishMessage := 'This is a sample message being sent';
IotMqttPublish_0.Enable := TRUE;
IotMqttPublish_0.IotMqttLink := IotMqttClient_0.IotMqttLink;
IotMqttPublish_0.Topic := ADR('B&R_TestTopic/SimplePublishSample');
IotMqttPublish_0.Buffer := ADR(PublishMessage);
IotMqttPublish_0.BufferLength := brsstrlen(ADR(PublishMessage));
IotMqttPublish_0();
END_PROGRAM
PROGRAM _EXIT
IotMqttClient_0(Enable := FALSE);
IotMqttPublish_0(Enable := FALSE);
END_PROGRAM
Subscribe: This sample shows how to connect, subscribe to a topic and read MQTT messages
PROGRAM _CYCLIC
IotMqttParameters.ServerUri := 'broker.hivemq.com';
IotMqttParameters.Port := 1883;
IotMqttParameters.ClientID := 'B&R_SimpleSubscribeSample';
IotMqttClient_0.Enable := TRUE;
IotMqttClient_0.Connect := TRUE;
IotMqttClient_0.IotMqttLink := ADR(IotMqttLink);
IotMqttClient_0.Parameters := IotMqttParameters;
IotMqttClient_0();
IotMqttSubscribe_0.Enable := TRUE;
IotMqttSubscribe_0.IotMqttLink := IotMqttClient_0.IotMqttLink;
IotMqttSubscribe_0.Topic := ADR('B&R_TestTopic/SimpleSubscribeSample');
IotMqttSubscribe_0.RecievedTopic := ADR(ReceivedTopic);
IotMqttSubscribe_0.RecievedTopicSize:= SIZEOF(ReceivedTopic);
IotMqttSubscribe_0.QueueSize := 50;
IotMqttSubscribe_0.Buffer := ADR(ReceiveBuffer);
IotMqttSubscribe_0.BufferSize := SIZEOF(ReceiveBuffer);
IotMqttSubscribe_0();
END_PROGRAM
PROGRAM _EXIT
IotMqttClient_0(Enable := FALSE);
IotMqttSubscribe_0(Enable := FALSE);
END_PROGRAM
RegPar Publish and Subscribe samples: This sample demonstrates how to use these two Function Blocks to send a json serialized PLC structure (publish) and to receive and parse a json message to a PLC structure (subscribe).
PROGRAM _CYCLIC
pvname := 'RegParPub:testVar';
testVar;
IotMqttParameters.ServerUri := 'broker.hivemq.com';
IotMqttParameters.Port := 1883;
IotMqttParameters.ClientID := 'B&R_SimplePublishSample585';
IotMqttClient_0.Enable := TRUE;
IotMqttClient_0.Connect := TRUE;
IotMqttClient_0.IotMqttLink := ADR(IotMqttLink);
IotMqttClient_0.Parameters := IotMqttParameters;
IotMqttClient_0();
IotMqttRegParPublish_0.Enable := TRUE;
IotMqttRegParPublish_0.IotMqttLink := IotMqttClient_0.IotMqttLink;
IotMqttRegParPublish_0.Topic := ADR('B&R_TestTopic/RegParPublishSample');
IotMqttRegParPublish_0.PvName := ADR(pvname);
IotMqttRegParPublish_0.PublishMode := IOTMQTT_PUB_MODE_TRIGGER;
IotMqttRegParPublish_0.DataFormat := IOTMQTT_VAR_JSON;
IotMqttRegParPublish_0();
IotMqttRegParSubscribe_0.Enable := TRUE;
IotMqttRegParSubscribe_0.IotMqttLink := IotMqttClient_0.IotMqttLink;
IotMqttRegParSubscribe_0.DataFormat := IOTMQTT_VAR_JSON;
IotMqttRegParSubscribe_0.Topic := ADR('B&R_TestTopic/RegParSubscribeSample');
IotMqttRegParSubscribe_0.QoS := 0;
IotMqttRegParSubscribe_0.QueueSize := 50;
IotMqttRegParSubscribe_0.ReceiveBufferSize := 50000;
IotMqttRegParSubscribe_0();
END_PROGRAM
PROGRAM _EXIT
IotMqttClient_0(Enable := FALSE);
IotMqttRegParPublish_0(Enable := FALSE);
END_PROGRAM
Library configuration: This sample shows how to change the logging behaviour and file devices that the library uses. The library works with the default parameters, making its use optional.
PROGRAM _INIT
IotMqttConfigParams.UseLogger := TRUE;
IotMqttConfigParams.LoggerName := 'IotMqtt';
IotMqttConfigParams.UseFile := TRUE;
IotMqttConfigParams.LogFileDevice := 'USER';
IotMqttConfigParams.LogFileName := 'IotMqttLog';
IotMqttConfigParams.AppendTimestamp := FALSE;
IotMqttConfigParams.OverwritteLogs := TRUE;
IotMqttConfigParams.LogLevel := IOTMQTT_LOG_LEVEL_PROTOCOL;
IotMqttConfigParams.PersistenceFileDevice := 'PERSIST';
IotMqttConfig(ADR(IotMqttConfigParams));
END_PROGRAM
It is possible to use more than one client, just declare a new IotMqttLink variable, a new parameters variable and associate them with a new IotMqttClient FUB.
DNS service:
When accessing servers by hostname instead of IP address (usually when the broker is on the Internet), it is needed to activate and configure the DNS service.
If the PLC is using a DHCP server to get its IP address, we can set the option Get DNS from DHCP server
, otherwise at least one DNS server must be provided.
Default gateway:
If using a DHCP server or our broker is in the local network, it can be left blank. Otherwise, the IP of the device providing access to the Internet, normally a modem or router, must be written in this field:
Some MQTT connections will need to use certificates. They can be stored in the project's certificate store or in a user defined File Device.
Depending where they are, we will need to add a prefix to the certificate name in the program. When using the certificate store we will use the following prefixes depending on which container they are:
In case the certificates are stored in the file system, then the prefix is the name of the file device. E.g.
If the certificate is stored in the default file device, it's not needed to write the file device as prefix.
IotMqtt is able to generate log files to help us diagnose connections or simply keep a register of connection errors. For this functionality, it will use the File Device IOTMQTT
as default, that the user needs to prepare in the CPU configuration, in the project.
Using the function IotMqttConfig
in the _INIT
part of the client program, it is possible to change the default File Device as well as choosing the log level (verbosity), the name of the output file and if we also want log messages to be written in the logger.
This function will only make an effect the first time is called, so it is not possible to adjust those parameters on runtime.
Messages sent or received with QoS (Quality of Service) > 0 have the possibility of being stored in the PLC's flash memory or CF until they have been correctly processed. This will keep messages alive in case of network problems, getting rid of them just when a confirmation of delivery has arrived.
To use this feature it must be enabled in the client parameters structure. It will use the file device IOTMQTT
as default but it can be changed with the function IotMqttConfig
Additionally to the Publish and Subscribe samples shown above, more samples are provided inside the Samples directory. There you will find programs the following samples:
As mentioned in the Introduction, only use PahoMQTT directly in special circumstances, for legacy reasons or when you need to access the C-API of the paho.mqtt.c directly. For any other use cases, or new projects, refer to the IotMqtt instead.
In order to find the headerfiles, set the following Additional Include Directory
in the Build Options
of your configuration (Under Project/Change Runtime Versions..)
The PahoMQTT
only comes as a static archive, meaning you need to link you task towards
the archive files in the SG4
or SG4/Arm
directory of the PahoMQTT library.
Further, and very important is that you cannot assign the library to a CPU, as it contains no .br
file.
Therefore remove it from your CPU configuration if it showed up there, you link directly to the archive file instead.
Archive File Directories:
Library Archive Files (order of the files is important):
PahoMQTT_s
OpenSSL_s
ar_posix_s
arsystem
rtk_lib
PahoMQTT_s
OpenSSL_s
ar_posix_s
arsystem
rtk_lib
PahoMQTT_s
OpenSSL_s
ar_posix_s
arsystem
rtk_lib
PahoMQTT_s
OpenSSL_s
ar_posix_s
AR
PahoMQTT_s
OpenSSL_s
ar_posix_s
AR
PahoMQTT_s
OpenSSL_s
ar_posix_s
AR
PahoMQTT_s
OpenSSL_s
ar_posix_s
AR
Specify a File Device called CERTS
under CPU Configuration to a Folder that is accesible from AR.
As mentioned in the introduction, the PahoMQTT library offers basic compatibility with older versions of the library.
A benefit with the new version, additional to being built on new paho and openssl sources, is that it also runs on ArSim.
Please see the chapter above (Using PahoMQTT) for basic settings that need to be made when using PahoMQTT.
Four double checking your code, you can find a "converted version" of the SampleParam
task under LegacySamples
.
As the libary only comes as an archive, the PahoMQTT_Cyclic
and PahoMQTT_Init
cannot be declared inside the .var
file
anymore and need to be declared inside the c-code. Further, the PahoMQTT.h
is not part of the <AsDefaults.h>
but need
to be specifically included.
If not already set, you need to Enable declaration of PLC variables (_GLOBAL, _LOCAL)
in the Project/Settings.
Example:
#include <bur/plctypes.h>
#include "PahoMQTT.h"
#ifdef _DEFAULT_INCLUDES
#include <AsDefault.h>
#endif
void sample(unsigned long param_adr);
_LOCAL PahoMQTT_Init_typ PahoMQTT_Init_0;
_LOCAL PahoMQTT_Cyclic_typ PahoMQTT_Cyclic_0;
File devices work in the same way as for IotMqtt, with the difference that the former CERTS
filedevice is used as a default file device,
to maintain compatibility with the former PahoMQTT. If you need to access files from other devices, you should use //DEVICENAME/path/filename.ext
.
If the Logger is activated, the output is no longer directed to the AR logger, but placed inside a PahoMQTTLog.txt
located under the CERTS
filedevice.
This logfile uses the standard Paho output file format, and has unix lineendings (LF instead of CRLF). Therefore open the logfile in an editor that can understand
that format, like Notepad++.
If you dont see any logging, even though you have set a high log level, it is probably because you set the loglevel before starting the asynchronous thread,
meaning it was started Suspended. In that case, trigger the activation of the log by changing the PahoMQTT_Cyclic_0.LogLevel. Anything above 0 (for example: 1)
will activate the PROTOCOL
log. If you really have some debugging issues with your solution and you dont know what is going on, you can activate the
trace log to see which Paho functions are being called by setting the loglevel to 10, but only do this if youre in trouble - its very verbose.
Example of the PahoMQTTLog.txt
on LogLevel 1
=========================================================
Trace Output
=========================================================
=========================================================
Trace Output
Product name: Eclipse Paho Synchronous MQTT C Client Library
Version: 1.3.5
Build level: 2020-09-15 21:58
OpenSSL version: OpenSSL 1.1.1g 21 Apr 2020
OpenSSL flags: -DBR_AUTOMATION_RUNTIME
OpenSSL build timestamp: 2020-09-01
OpenSSL platform: BR_AUTOMATIONRUNTIME
OpenSSL directory: OPENSSLDIR: "//OSSLROOT"
=========================================================
20201001 114500.061 2176 SamplePara -> PUBLISH msgid: 100 qos: 1 retained: 0 rc 0 payload len(18): Hello World plain!
20201001 114500.061 2176 SamplePara <- PUBACK msgid: 100
20201001 114500.361 2176 SamplePara -> PUBLISH msgid: 101 qos: 1 retained: 0 rc 0 payload len(18): Hello World plain!
20201001 114500.361 2176 SamplePara <- PUBACK msgid: 101
20201001 114500.681 2176 SamplePara -> PUBLISH msgid: 102 qos: 1 retained: 0 rc 0 payload len(18): Hello World plain!
20201001 114500.681 2176 SamplePara <- PUBACK msgid: 102
20201001 114500.981 2176 SamplePara -> PUBLISH msgid: 103 qos: 1 retained: 0 rc 0 payload len(18): Hello World plain!
20201001 114500.981 2176 SamplePara <- PUBACK msgid: 103
The former PahoMQTT also contained basic Log functionality which has been removed completely. If you need to fill anything
into the Paho logfile alongside other loggings as you might previosly have done using the PahoLog..
functions, simply use
printf
.
Example:
printf("here is my result:%i\n", res);