Skip to content

Commit

Permalink
Add support for MQTT client (#256)
Browse files Browse the repository at this point in the history
Add support for MQTT client

Closes #130.

Below follows the list of commit messages squashed into this single commit.

* Add third-party headers for Eclipse Paho MQTT C client

* Update Readme.txt to include Eclipse Paho MQTT C client

* Add static libraries of Eclipse Paho MQTT C client for Linux

Built at drone.io (https://drone.io/github.com/tbeu/paho.mqtt.c/files) with custom Makefile:

```
AR = ar -ru
RM = rm -f

CFLAGS = -O3
CPPFLAGS = -DNDEBUG
INC =

TARGETDIR = linux64

# The names of the four different libraries to be built
MQTTLIB_C = paho-mqtt3c
MQTTLIB_CS = paho-mqtt3cs
MQTTLIB_A = paho-mqtt3a
MQTTLIB_AS = paho-mqtt3as

MQTT3A_OBJS = \
	Clients.o \
	Heap.o \
	LinkedList.o \
	Log.o \
	Messages.o \
	MQTTAsync.o \
	MQTTPacket.o \
	MQTTPacketOut.o \
	MQTTPersistence.o \
	MQTTPersistenceDefault.o \
	MQTTProtocolClient.o \
	MQTTProtocolOut.o \
	Socket.o \
	SocketBuffer.o \
	StackTrace.o \
	Thread.o \
	Tree.o \
	utf-8.o

MQTT3C_OBJS = \
	Clients.o \
	Heap.o \
	LinkedList.o \
	Log.o \
	Messages.o \
	MQTTClient.o \
	MQTTPacket.o \
	MQTTPacketOut.o \
	MQTTPersistence.o \
	MQTTPersistenceDefault.o \
	MQTTProtocolClient.o \
	MQTTProtocolOut.o \
	Socket.o \
	SocketBuffer.o \
	StackTrace.o \
	Thread.o \
	Tree.o \
	utf-8.o

ALL_OBJS = $(MQTT3A_OBJS) $(MQTT3C_OBJS)

TS := $(shell /bin/date -u)

all: clean versioninfo lib$(MQTTLIB_A).a lib$(MQTTLIB_C).a

versioninfo:
	@echo "#ifndef VERSIONINFO_H" > src/VersionInfo.h
	@echo "#define VERSIONINFO_H" >> src/VersionInfo.h
	@echo "#define BUILD_TIMESTAMP \""$(TS)"\"" >> src/VersionInfo.h
	@echo "#define CLIENT_VERSION \"1.1.0\""  >> src/VersionInfo.h
	@echo "#endif /* VERSIONINFO_H */" >> src/VersionInfo.h

lib$(MQTTLIB_A).a: $(MQTT3A_OBJS)
	$(AR) $@ $(MQTT3A_OBJS)
	cp $@ Library/$(TARGETDIR)/$@

lib$(MQTTLIB_C).a: $(MQTT3C_OBJS)
	$(AR) $@ $(MQTT3C_OBJS)
	cp $@ Library/$(TARGETDIR)/$@

%.o: src/%.c
	$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c -o $@ $<

clean:
	$(RM) $(ALL_OBJS)
	$(RM) *.a
```

* Add dynamic link and import libraries of Eclipse Paho MQTT C client for Windows

Built with Visual Studio 2010 (/MD flag)

* Fix client version info (set 1.1.0 consistently)

* Update static libraries of Eclipse Paho MQTT C client to 1.2.1 for Linux

* Update libraries of Eclipse Paho MQTT C client to 1.2.1 for MSVC

* Update third-party headers for Eclipse Paho MQTT C client to 1.2.1

* Build Eclipse Paho MQTT C client with SSL support

* Update README.md

[ci skip]

* Add cmake rule to build dummy libraries crypto and ssl for MSVC and MinGW

* Add cmake rule to build test_MDDMQTT

* Add cmake rule to build ITI_MDDLCM and ITI_MDDMQTT

* Add support for MQTT client

* Build classic Eclipse Paho MQTT C client with Websocket support

Remove unused asynchronous Eclipse Paho MQTT C client libraries

* Fix Linux compilation

* Build classic Eclipse Paho MQTT C client with Websocket support

* Test it at Travis CI

* Fix link order

* Fix format arguments

* Fix link order

* Build with -fPIC -DOPENSSL_PIC

* Specify full path

* Link against libdl

* Build with no-dso

* Fix buffer termination

* Can skip the retryInterval parameter

See eclipse/paho.mqtt.c#528 (comment)

* Use transparent logo

[ci skip]

* Log errors at Travis CI

* Fix buffer termination

* Add tracing

* Use MAC address as part of clientID

* Unsubscribe in dtor

* Remove explicit references to OpenSSL

* Update third-party headers for Eclipse Paho MQTT C client to 1.3.0

* Update libraries of Eclipse Paho MQTT C client to 1.3.0 for MSVC

* Update static libraries of Eclipse Paho MQTT C client to 1.3.0 for Linux

* Add SimulationX specific libraries

* Update dummy libraries

* Update all SimulationX specific libraries

* Initialize critical section before trying to establish connection

* Disable cleansession for MQTT v5.0

* Set MDDSHAREDLIBRARY

* Update SimulationX specific libraries
  • Loading branch information
tbeu authored and bernhard-thiele committed Sep 26, 2018
1 parent f4bd76a commit 057b979
Show file tree
Hide file tree
Showing 58 changed files with 5,539 additions and 14 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -47,6 +47,7 @@ script:
- ./test_MDDSharedMemory
- ./test_MDDUDPSocket
- ./test_MDDLCM
- ./test_MDDMQTT
- cd ../..

notifications:
Expand Down
240 changes: 238 additions & 2 deletions Modelica_DeviceDrivers/Blocks/Communication.mo

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions Modelica_DeviceDrivers/Blocks/Examples/TestSerialPackager_MQTT.mo
@@ -0,0 +1,77 @@
within Modelica_DeviceDrivers.Blocks.Examples;
model TestSerialPackager_MQTT
"Example for combining MQTT and SerialPackager blocks with deactivated autoBufferSize / useBackwardPropagatedBufferSize"
extends Modelica.Icons.Example;
Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.Packager packager(useBackwardPropagatedBufferSize=false, userBufferSize=36) annotation(Placement(transformation(extent={{-40,62},{-20,82}})));
Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddReal addReal(
nu=1,
n=3) annotation(Placement(transformation(extent={{-40,34},{-20,54}})));
Modelica.Blocks.Sources.RealExpression realExpression[3](y=sin(time)*{1,2,3}) annotation(Placement(transformation(extent={{-80,34},{-60,54}})));
Modelica_DeviceDrivers.Blocks.Communication.MQTTSend mqttSend(
autoBufferSize=false,
userBufferSize=36,
address="test.mosquitto.org",
channel_send="mdd-example") annotation(Placement(transformation(
origin={-30,-44},
extent={{-10,-10},{10,10}},
rotation=270)));
Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.AddInteger addInteger(nu=1) annotation(Placement(transformation(extent={{-40,-26},{-20,-6}})));
Modelica.Blocks.Sources.IntegerExpression integerExpression(
y=integer(10*sin(time))) annotation(Placement(transformation(extent={{-80,-26},{-60,-6}})));
Modelica_DeviceDrivers.Blocks.Communication.MQTTReceive mqttReceive(
autoBufferSize=false,
userBufferSize=36,
address="test.mosquitto.org",
channel_recv="mdd-example") annotation(Placement(transformation(
origin={40,50},
extent={{-10,-10},{10,10}},
rotation=270)));
Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetReal getReal(
nu=1,
n=3) annotation(Placement(transformation(extent={{30,10},{50,30}})));
Modelica_DeviceDrivers.Blocks.Packaging.SerialPackager.GetInteger getInteger annotation(Placement(transformation(extent={{30,-48},{50,-28}})));
Packaging.SerialPackager.AddFloat addFloat(
nu=1,
n=2) annotation(Placement(transformation(extent={{-40,2},{-20,22}})));
Packaging.SerialPackager.GetFloat getFloat(
nu=1,
n=2) annotation(Placement(transformation(extent={{30,-18},{50,2}})));
Modelica.Blocks.Sources.RealExpression realExpression1[2](y=sin(time)*{1,2}) annotation(Placement(transformation(extent={{-78,2},{-58,22}})));
equation
connect(integerExpression.y, addInteger.u[1]) annotation (Line(
points={{-59,-16},{-42,-16}},
color={255,127,0}));
connect(realExpression.y, addReal.u) annotation (Line(
points={{-59,44},{-42,44}},
color={0,0,127}));
connect(packager.pkgOut, addReal.pkgIn) annotation (Line(
points={{-30,61.2},{-30,54.8}}));
connect(mqttReceive.pkgOut, getReal.pkgIn) annotation (Line(
points={{40,39.2},{40,30.8}}));
connect(realExpression1.y, addFloat.u) annotation (Line(
points={{-57,12},{-42,12}},
color={0,0,127}));
connect(addReal.pkgOut[1], addFloat.pkgIn) annotation (Line(
points={{-30,33.2},{-30,22.8}}));
connect(addFloat.pkgOut[1], addInteger.pkgIn) annotation (Line(
points={{-30,1.2},{-30,-5.2}}));
connect(mqttSend.pkgIn, addInteger.pkgOut[1]) annotation (Line(
points={{-30,-33.2},{-30,-26.8}}));
connect(getReal.pkgOut[1], getFloat.pkgIn) annotation (Line(
points={{40,9.2},{40,2.8}}));
connect(getInteger.pkgIn, getFloat.pkgOut[1]) annotation (Line(
points={{40,-27.2},{40,-18.8}}));
annotation (
Documentation(info="<html>
<p>
The <code>mqttSend</code> block sends to the MQTT test broker <a href=\"http://test.mosquitto.org/\">test.mosquitto.org</a> at topic &quot;mdd-example&quot;. The <code>mqttReceive</code> block subscribes to the same broker at the same topic &quot;mdd-example&quot;. Consequently, the <code>mqttReceive</code> block receives what the <code>mqttSend</code> block sends.
</p>
<p>
<b>Note:</b> There is no causality between the <code>mqttSend</code> block and the <code>mqttReceive</code> block. Therefore the execution order of the blocks is not determined. Additionally, the <code>mqttReceive</code> block starts an own receiving thread, so that the time the data was received is not equal to the time the external function within the <code>mqttReceive</code> block was called. This indeterminism may also show up in the plots.
</p>
</html>"),
experiment(
StopTime=5,
StartTime=0),
Diagram(graphics={Bitmap(extent={{-11,-52.3},{25,-40}}, fileName="modelica://Modelica_DeviceDrivers/Resources/Images/pahologo.png")}));
end TestSerialPackager_MQTT;
1 change: 1 addition & 0 deletions Modelica_DeviceDrivers/Blocks/Examples/package.order
Expand Up @@ -17,3 +17,4 @@ TestInputKeyboardKey
TestHardwareIOComedi
TestSerialPackager_TCPIP
TestSerialPackager_LCM
TestSerialPackager_MQTT
52 changes: 52 additions & 0 deletions Modelica_DeviceDrivers/Communication/MQTT.mo
@@ -0,0 +1,52 @@
within Modelica_DeviceDrivers.Communication;
class MQTT "A driver for Message Queue Telemetry Transport."
extends ExternalObject;
encapsulated function constructor "Creates an MQTT instance."
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.Communication.MQTT;
input String provider "\"tcp://\" - TCP, \"ssl://\" - encrypted TCP, \"ws://\" - websocket, , \"wss://\" - encrypted websocket";
input String address "IP address";
input Integer port = 1883 "Port";
input Boolean receiver "false - sender, true - receiver";
input String channel "Receive channel";
input Integer bufferSize = 16*1024 "Size of receive buffer";
input Integer QoS = 1 "Quality of service for receiver: 0 - at most once, 1 - at least once, 2 - exactly once";
input String clientID "Unique client identifier";
input String userName = "" "User name for authentication and authorisation";
input String password = "" "Password for authentication and authorisation";
input String trustStore = "" "Public digital certificates trusted by the client";
input String keyStore = "" "Public certificate chain of the client";
input String privateKey = "" "Private key of the client";
input Integer keepAliveInterval = 60 "Maximum time (in seconds) that should pass without communication between the client and the server";
input Boolean cleanSession = true "false - keep session state for this client at disconnect, true - discard session state at connect and disconnect";
input Boolean reliable = true "false - increase number of messages that can be in-flight simultaneously to 10, true - a published message must be completed (acknowledgements received) before another message can be sent";
input Integer connectTimeout = 30 "Connection timeout (in seconds)";
input Integer MQTTVersion = 0 "MQTT version: 0 - default: start with 3.1.1, and if that fails, fall back to 3.1, 3 - only try version 3.1, 4 - only try version 3.1.1, 5 - only try version 5.0";
input Integer disconnectTimeout = 10 "Disconnect timeout (in seconds)";
input Boolean enableServerCertAuth = true "false - disable verification of the server certificate, true - enable verification of the server certificate";
input Boolean verify = false "false - disable post-connect checks, true - enable post-connect checks, including that a certificate matches the given host name";
input Integer sslVersion = 0 "SSL/TLS version: 0 - default, 1 - TLS 1.0, 2 - TLS 1.1, 3 - TLS 1.2";
input Integer traceLevel = 0 "Trace level: 0 - none, 1 - maximum, 2 - medium, 3 - minimum, 4 - protocol, 5 - error, 6 - severe, 7 - fatal";
output MQTT mqtt;
external "C" mqtt = MDD_mqttConstructor(provider, address, port, receiver, QoS, channel, bufferSize, clientID, userName, password, trustStore, keyStore, privateKey, keepAliveInterval, cleanSession, reliable, connectTimeout, MQTTVersion, disconnectTimeout, enableServerCertAuth, verify, sslVersion, traceLevel)
annotation (
Include = "#include \"MDDMQTT.h\"",
Library = {"paho-mqtt3cs", "pthread", "ssl", "crypto"},
__iti_dll = "ITI_MDDMQTT.dll",
__iti_dllNoExport = true);
end constructor;

encapsulated function destructor "Destroys an MQTT instance."
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.Communication.MQTT;
input MQTT mqtt;
external "C" MDD_mqttDestructor(mqtt)
annotation (
Include = "#include \"MDDMQTT.h\"",
Library = {"paho-mqtt3cs", "pthread", "ssl", "crypto"},
__iti_dll = "ITI_MDDMQTT.dll",
__iti_dllNoExport = true);
end destructor;
end MQTT;
37 changes: 37 additions & 0 deletions Modelica_DeviceDrivers/Communication/MQTT_.mo
@@ -0,0 +1,37 @@
within Modelica_DeviceDrivers.Communication;
package MQTT_ "Accompanying functions for the MQTT object"
extends Modelica_DeviceDrivers.Utilities.Icons.DriverIcon;
encapsulated function read
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.Communication.MQTT;
import Modelica_DeviceDrivers.Packaging.SerialPackager;
input MQTT mqtt;
input SerialPackager pkg;
external "C" MDD_mqttReadP(mqtt, pkg)
annotation (
Include = "#include \"MDDMQTT.h\"",
Library = {"paho-mqtt3cs", "pthread", "ssl", "crypto"},
__iti_dll = "ITI_MDDMQTT.dll",
__iti_dllNoExport = true);
end read;

encapsulated function sendTo
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.Communication.MQTT;
import Modelica_DeviceDrivers.Packaging.SerialPackager;
input MQTT mqtt;
input String channel "Transmit Channel";
input SerialPackager pkg;
input Boolean retained "Retained flag";
input Integer deliveryTimeout "Delivery timeout";
input Integer dataSize "Size of data";
external "C" MDD_mqttSendP(mqtt, channel, pkg, retained, deliveryTimeout, dataSize)
annotation (
Include = "#include \"MDDMQTT.h\"",
Library = {"paho-mqtt3cs", "pthread", "ssl", "crypto"},
__iti_dll = "ITI_MDDMQTT.dll",
__iti_dllNoExport = true);
end sendTo;
end MQTT_;
2 changes: 2 additions & 0 deletions Modelica_DeviceDrivers/Communication/package.order
Expand Up @@ -12,3 +12,5 @@ TCPIPSocketClient
TCPIPSocketClient_
LCM
LCM_
MQTT
MQTT_
4 changes: 4 additions & 0 deletions Modelica_DeviceDrivers/Resources/CMakeLists.txt
Expand Up @@ -23,6 +23,10 @@ include_directories(src/include)
include_directories(Include)

if (MSVC OR MINGW)
# Dummy Windows crypto library for uniform treatment of GCC and MS Visual C within Modelica
add_subdirectory(src/DummyCryptoLibrary)
# Dummy Windows ssl library for uniform treatment of GCC and MS Visual C within Modelica
add_subdirectory(src/DummySSLLibrary)
# Dummy Windows rt library for uniform treatment of GCC and MS Visual C within Modelica
add_subdirectory(src/DummyRTLibrary)
# Dummy Windows X11 library for uniform treatment of GCC and MS Visual C within Modelica
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 057b979

Please sign in to comment.