This module provides an EPICS driver for the MQTT protocol, allowing EPICS clients to communicate with MQTT brokers and devices directly from EPICS.
Contributions are welcome - feel free to open issues and pull requests!
- Auto-update of EPICS PVS via
I/O Intrrecords; - Support for read/write flat MQTT topics (i.e, topics where the payload is a single value or array);
- Support for reading arbitrarily nested fields from JSON topic payloads;
- Support for MQTT QoS levels;
- Checks and reject invalid messages (based mostly on type-checking);
- Auto reconnection of broker;
- Planned - short term:
- Support for MQTT retained messages.
- Support for MQTT last will messages.
- Support for MQTT authentication and TLS.
Note: Virtually all features from the Paho C++ MQTT client are available to be implemented in this driver, so feel free to open an issue if you need a specific feature.
This module is built on top of Cosylab autoparamDriver, which uses the standard asyn interfaces for device support. For now, the supported interfaces are the following:
asynInt32asynFloat64asynUInt32DigitalasynOctetasynInt32ArrayasynFloat64ArraySee Implementation status to check the status of development of the interface you need.
- Install the dependencies:
Tested with the following versions.
- EPICS Base 7.0.8.1: https://github.com/epics-base/epics-base/releases/tag/R7.0.8.1
- Asyn 4.45: https://github.com/epics-modules/asyn/releases/tag/R4-45
- autoparamDriver 2.0.0: https://github.com/Cosylab/autoparamDriver/releases/tag/v2.0.0
- Paho 1.5.3: Follow these instructions.
Note: AutoparamDriver explicitly requires EPICS >= 7.0, see reference. For this reason, this module requires EPICS 7.0 or later to be built and used.
- Clone this repository:
git clone https://github.com/AndreFavotto/epicsMQTT.git-
Edit the
configure/RELEASEfile to include your paths to the dependencies:EPICS_BASE = /path/to/epics/base ASYN = /path/to/asyn AUTOPARAM = /path/to/autoparamDriver PAHO_CPP_INC = /path/to/paho/cpp/include #by default, should be /usr/local/include PAHO_CPP_LIB = /path/to/paho/cpp/lib #by default, should be /usr/local/lib
For now we have two macros for setting paho path because we build the module with separate linking flags -I and -L, but this might change soon.
-
Run
make. The library should now be ready for usage.
-
Include the module in your IOC build instructions:
-
Add asyn and mqtt to your
configure/RELEASEfile:## Other definitions ... ASYN = /path/to/asyn MQTT = /path/to/epicsMqtt ## Other definitions ...
-
Add the mqtt database definition and include the necessary libraries to your
yourApp/src/Makefile:#### Other commands ... yourIOC_DBD += mqtt.dbd #### Other commands ... yourIOC_LIBS += asyn yourIOC_LIBS += mqttSupport
-
-
In your database file, link the EPICS records and the MQTT topics through the
INPandOUTfields. The syntax is as follows:
field(INP|OUT, "@asyn(<PORT>) <FORMAT>:<TYPE> <TOPIC> [<FIELD>]")Where:
<PORT>is the name of the asyn port defined in theasynPortDriverconfiguration.<FORMAT>is the format of the payload:FLATorJSON.<TYPE>is the general type of the expected value [INT|FLOAT|DIGITAL|STRING|INTARRAY|FLOATARRAY].<TOPIC>is the MQTT topic to which the record will be subscribed/published.<FIELD>is the dot-separated path to the field to extract from a JSON payload (e.g.sensor.temperature). Arbitrary nesting is supported. Required whenFORMATisJSON.
Note on JSON write support: Writing to JSON-formatted topics is currently not supported. At the moment the driver has no way of knowing the JSON structure expected by the broker ahead of time for write records. For this reason, only
FLATformat can be used for output records.
Important: Due to the pub/sub nature of MQTT, ALL input records are expected to be I/O Intr.
Example:
record(ai, "$(P)$(R)AnalogIn"){
field(DESC, "Analog Input Record")
field(DTYP, "asynInt32")
field(SCAN, "I/O Intr")
field(INP, "@asyn($(PORT)) FLAT:INT test/analogtopic")
}
record(ai, "$(P)$(R)AnalogOut"){
field(DESC, "Analog Output Record")
field(DTYP, "asynInt32")
field(OUT, "@asyn($(PORT)) FLAT:INT test/analogtopic")
}Note: Several examples can be found in mqttExampleApp/Db for other record types.
- Load the module in your startup script using the following syntax:
mqttDriverConfigure(const char *portName, const char *brokerUrl, const char *mqttClientID, const int qos)Example:
# (... other startup commands ...)
epicsEnvSet("PORT", "test")
epicsEnvSet("BROKER_URL", "mqtt://localhost:1883")
epicsEnvSet("CLIENT_ID", "mqttEpics")
epicsEnvSet("QOS", "1")
mqttDriverConfigure($(PORT), $(BROKER_URL), $(CLIENT_ID), $(QOS))
# (... other startup commands ...)
dbLoadRecords("your_database.db", "PORT=$(PORT)")
iocInit()Below are the supported interfaces and their implementation status.
| Message type | Asyn Parameter Type | FORMAT:TYPE string to use |
Direction | Status |
|---|---|---|---|---|
| Integer | asynInt32 | FLAT:INT |
Read / Write | Supported |
| Float | asynFloat64 | FLAT:FLOAT |
Read / Write | Supported |
| Bit masked integers | asynUInt32Digital | FLAT:DIGITAL |
Read / Write | Supported |
| Strings | asynOctetRead/asynOctetWrite | FLAT:STRING |
Read / Write | Supported |
| Integer Array | asynInt32ArrayIn/asynInt32ArrayOut | FLAT:INTARRAY |
Read / Write | Supported |
| Float Array | asynFloat64ArrayIn/asynFloat64ArrayOut | FLAT:FLOATARRAY |
Read / Write | Supported |
| Integer | asynInt32 | JSON:INT |
Read only | Supported |
| Float | asynFloat64 | JSON:FLOAT |
Read only | Supported |
| Bit masked | asynUInt32Digital | JSON:DIGITAL |
Read only | Supported |
| String | asynOctetRead | JSON:STRING |
Read only | Supported |
Copyright (C) 2026 André Favoto
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.