MQTTSuite
|
The MQTTSuite project is a lightweight MQTT integration system and consist of three applications MQTTBroker, MQTTIntegrator and MQTTBridge powered by SNode.C, a single threaded, single tasking framework for networking applications written entirely in C++. Due to it's little resource usage it is especially usable on resource limited systems.
SNode.C is dual-licensed under MIT and GPL-3.0 (or any later version). You can choose between one of them if you use this work.
SPDX-License-Identifier: MIT OR GPL-3.0-or-later
Volker Christian (me@vchrist.at or Volker.Christian@fh-hagenberg.at)
The installation of the MQTTSuite is straight forward:
The main development of MQTTSuite takes place on a Debian Sid style Linux system. Since Debian Bookworm it compiles also on Debian stable. Though, it should compile cleanly on every Linux system provided that all required tools and libraries are installed.
MQTTSuite is known to compile and run successful on
The most version-critical dependencies are the C++ compilers.
Either GCC or clang can be used but they need to be of an up to date version because SNode.C uses some new C++20 features internally.
MQTTSuite requires some external tools and depends on a view external libraries. Some of these libraries are directly included in the MQTTSuite.
This libraries are already integrated directly in the MQTTSuite. Thus they need not be installed by hand
To install all dependencies on Debian style system
and than just run
After installing all dependencies MQTTSuite can be cloned from github, compiled and installed.
It is a good idea to utilize all processor cores and threads for compilation. Thus e.g. on a Raspberry Pi append -j5
to the make
or ninja
command.
As a starting point, it is assumed that local ssh and sftp access to the router exist and that the router is connected to the Internet via the WAN port.
Note: You do not need to deploy SNode.C by hand as this framework is pulled in by the following procedure automatically.
Deploying SNode.C on an OpenWRT router involves a view tasks:
MQTTSuite needs to be cross compiled on a Linux host system to be deployable on OpenWRT. Don't be afraid about cross compiling it is strait forward.
First, download and extract a SDK-package of version 23.05.0-rc1 or later from the OpenWRT download page into an arbitrary directory <DIR>.
For example to download and use the SDK version 23.05.0-rc1 for the Netgear MR8300 Wireless Router (soc: IPQ4019) run
to create the SDK directory openwrt-sdk-<version>-<architecture>-<atype>_<compiler>-<cverstion>_<libc>_<abi>.Linux-x86_64
what from now on is referred as <SDK_DIR>.
In this example the values of the placeholder are:
Second step is to patch the default OpenWRT package feeds to add the SNode.C feed (MQTTSuite is provided by this feed) by executing
In the third step, all source packages required to compile SNode.C are installed.
The SDK is configured in the fourth step.
Default values for all configuration options can be used safely.
Nevertheless, to customize the configuration of the base framework SNode.C run
and navigate to Network -> SNode.C
.
In the last step, MQTTSuite is cross-compiled.
The two steps, Install Packages, and Cross Compile (at most the last one) take some time as
To parallelize the compilation use the switch -j<thread-count>
of make
or ninja
where <thread-count> is the number of CPU-threads dedicated to cross compile SNode.C and its dependencies.
Note: For MQTTBroker and all it's build dependencies the created ipk-packages can be found in the directory <SDK_DIR>bin/packages/\<architecture\>
.
After cross compilation, MQTTSuite can be deployed.
The mqttsuite_<version>_<architecture>.ipk
and snode.c-*_<version>_<architecture>.ipk
packages must be downloaded to and installed on the router by executing
on the router. Use the option --force-reinstall
in cast you want to reinstall the same version by overwriting the currently installed files.
Note: On first install of MQTTSuite and SNode.C you will for sure get errors about missing dependent packages from the primary OpenWRT package repository. Just install them as usual using opkg and than go on to install MQTTSuite and SNode.C again.
During package installation a new unix group with member root is created, used for the group management of config-, log-, and pid-files.
Note: A logout/login is necessary to activate the new group assignment.
The MQTTBroker supports multiple connection methods across various protocols. Additional connection protocols e.g. Bluetooth can be easily added in the mqttbroker.cpp
source code.
All aspects like port numbers, sun paths etc. can be configured using the SNode.C configuration system either in-code, on the command line or via a configuration file.
In case an encrypted access is required suitable certificates needs to be provided also.
Note: A session store needs to be configured in case the current sessions shall be made persistent in case the MQTTBroker is stopped by using the command line option --mqtt-session-store <path-to-session-store-file>
.
Note: In case the MQTTBroker should also act as an integrated MQTTIntegrator a mapping description file needs to be provided via the command line option --mqtt-mapping-file <path-to-mqtt-mapping-file.json>
.
Note: The path to the HTML templates for the MQTTBroker Web Interface can be configured by providing the command line option --html-dir <dir-of-html-templates>
. The default directory /var/www/mqttsuite/mqttbroker
is already configured in mqttbroker.cpp
.
Note: All three options can be made persistent by storing their values in a configuration file by appending the switch --write-config
or -w
on the command line.
MQTT clients can connect via IPv4 and IPv6 using both encrypted and unencrypted channels.
Protocol | Encryption | Local Port | Instance |
---|---|---|---|
IPv4 | No | 1883 | in-mqtt |
IPv4 | Yes | 8883 | in-mqtts |
IPv6 | No | 1883 | in6-mqtt |
IPv6 | Yes | 8883 | in6-mqtts |
For local communication, the broker also supports Unix domain sockets.
Encryption | Local Sun Path | Instance |
---|---|---|
No | /tmp/mqttbroker-un-mqtt | un-mqtt |
Yes | /tmp/mqttbroker-un-mqtts | un-mqtts |
Clients can connect via WebSockets using both IPv4 and IPv6.
Protocol | Encryption | Local Port | Request Target | Sec-WebSocket-Protocol | Instance |
---|---|---|---|---|---|
IPv4 | No | 8080 | / or /ws | mqtt | in-http |
IPv4 | Yes | 8088 | / or /ws | mqtt | in-https |
IPv6 | No | 8080 | / or /ws | mqtt | in6-http |
IPv6 | Yes | 8088 | / or /ws | mqtt | in6-https |
The MQTTBroker Web Interface provides real-time visibility into active client connections.
Protocol | Encryption | Local Port | Request Target | Instance |
---|---|---|---|---|
IPv4 | No | 8080 | / or /clients | in-http |
IPv4 | Yes | 8088 | / or /clients | in-https |
IPv6 | No | 8080 | / or /clients | in6-http |
IPv6 | Yes | 8088 | / or /clients | in6-https |
The MQTTBroker supports multiple connection methods across various protocols. Additional connection protocols e.g. Bluetooth can be easily added in the mqttintegrator.cpp
source code.
All aspects like port numbers, sun paths etc. can be configured using the SNode.C configuration system either in-code, on the command line or via a configuration file.
In case an encrypted access is required suitable certificates needs to be provided also.
Note: A session store needs to be configured in case the current sessions shall be made persistent in case the MQTTIntegrator is stopped by using the command line option --mqtt-session-store <path-to-session-store-file>
.
Note: A mapping description file needs to be provided via the command line option --mqtt-mapping-file <path-to-mqtt-mapping-file.json>
. This JSON file is used to provide the IoT logic by mapping mqtt messages received from a mqtt broker to outgoing mqtt messages. The translation of topics and messages are described by that file.
Note: Both options can be made persistent by storing their values in a configuration file by appending the switch --write-config
or -w
on the command line.
Protocol | Encryption | Remote Port | Instance |
---|---|---|---|
IPv4 | No | 1883 | in-mqtt |
IPv4 | Yes | 8883 | in-mqtts |
IPv6 | No | 1883 | in6-mqtt |
IPv6 | Yes | 8883 | in6-mqtts |
Encryption | Remote Sun Path | Instance |
---|---|---|
No | /tmp/mqttbroker-un-mqtt | un-mqtt |
Yes | /tmp/mqttbroker-un-mqtts | un-mqtts |
Protocol | Encryption | Remote Port | Requested Target | Sec-WebSocket-Protocol | Instance |
---|---|---|---|---|---|
IPv4 | No | 8080 | /ws | mqtt | in-wsmqtt |
IPv4 | Yes | 8088 | /ws | mqtt | in-wsmqtts |
IPv6 | No | 8080 | /ws | mqtt | in6-wsmqtt |
IPv6 | Yes | 8088 | /ws | mqtt | in6-wsmqtts |
Note: All instances are active after installation.
Note: To inactivate (disable) instances selectively as they are not needed for communication the command line switch --disabled
must be used on that instances.
The logic of an IoT application is described by a JSON mapping description file. This file describes the translation of topics and messages of incoming mqtt messages from a mqtt broker. The translated topics and messages are send back to the broker.
The JSON structure of that file (example) needs to fulfill a well defined JSON schema definition.
The big Structure of the JSON mapping description consists of three objects:
discover_prefix
: The prefix topic-level of the discover topics of an application (currently not used).connection
: This object describes options for the MQTT connection.mapping
: This object describes the mappings of incoming topics|messages to outgoing topics/messages.topic_level
is eithertopic_level
s can be recursively nested to create a topic_level
tree.The topic_level
object can contain a subscription
object, which forces the MQTTIntegrator to subscribes for this topic. This subscription
object describes concrete topic to topic and message to message mappings.
Three different kinds of <mapping-section>
exist:
message
.message
.The static
mapping section describes the mapped topic and the message mapping where the incoming message is string-matched to string-values specified in the message_mappings
array section.
The value
mapping section describes the mapped topic and the message mapping where the incoming message is available in the variable message
and is interpreted as value of an inja template.
The json
mapping section can be used in case the incoming message is a JSON object. The actual mapping is controlled by an inja template. The JSON object is accessible in the template as elements of the template JSON variable message
.
E.g. the JSON message
is rendered by the above mapping_template
as 5 to 11pm.