MQTT Connector
What Is It?
The MQTT Connector is the inbound data gateway of the ALP-CONNEX platform. It subscribes to MQTT topics from IoT devices and sensors, extracts values from incoming JSON messages, and writes them into the central data store (Valkey). From there, other connectors — such as the IEC 104 Connector — can pick up the data and deliver it to SCADA systems.
In short: the MQTT Connector is responsible for bringing your IoT data into the system.
How It Works
- The connector connects to an MQTT broker as a subscriber.
- When a message arrives on a subscribed topic, the JSON payload is parsed.
- Values are extracted using configurable JSON path expressions.
- The extracted values are converted to the appropriate IEC 104 data type.
- The results are written to the central data store for other connectors to use.
IoT Sensor → MQTT Broker → MQTT Connector → Valkey → IEC 104 / other connectors
Connection Details
| Setting | Default |
|---|---|
| Protocol | MQTT 3.1.1 over TCP |
| Broker Port | 1883 (unencrypted) |
| TLS Port | 8883 (encrypted) |
| Mode | Client (subscriber) |
Mappings — The Core Concept
A mapping is the central configuration element. Each mapping tells the connector:
- Where to find the data — which JSON field in the MQTT message contains the value.
- Where to store it — which IEC 104 address (CASDU + IOA) the value maps to.
- What type it is — whether the value is a number, boolean, or text.
Example
Imagine an IoT sensor publishes temperature data to an MQTT topic with this JSON payload:
{
"data": {
"temperature": 23.5,
"humidity": 61.2
},
"timestamp": "2026-01-15T10:30:00Z"
}
To bring the temperature into the IEC 104 system at CASDU 225, IOA 100, you would create a mapping with:
| Setting | Value | Explanation |
|---|---|---|
| Name | signal/temp | A descriptive name for this mapping |
| CASDU | 225 | The station address in IEC 104 |
| IOA | 100 | The data point address in IEC 104 |
| Type | Type 36 (Float) | Because temperature is a decimal number |
| Value Path | data.temperature | Where to find the value in the JSON |
| Value Type | float | The data type of the extracted value |
| Timestamp Path | timestamp | Where to find the timestamp in the JSON |
The result: every time the sensor publishes a new temperature reading, it automatically appears in the IEC 104 system as data point CASDU 225 / IOA 100.
JSON Path Expressions
The Value Path tells the connector where to find a specific value within a JSON message. It uses a simple dot notation:
| JSON Path | What It Accesses |
|---|---|
temperature | A top-level field |
data.value | A nested field |
data.sensor.reading | A deeply nested field |
sensors[0] | The first element of an array |
readings[1].temp | A field inside an array element |
Practical Examples
Given this JSON payload:
{
"location": "Room A",
"sensors": [
{ "type": "temperature", "value": 22.3 },
{ "type": "humidity", "value": 58.1 }
],
"battery": 87
}
| To extract... | Use this path |
|---|---|
| Battery level | battery |
| Temperature | sensors[0].value |
| Humidity | sensors[1].value |
Supported Data Types
Each mapping specifies an IEC 104 data type that determines how the extracted value is stored and transmitted:
| Type | Name | Best For | Example Values |
|---|---|---|---|
| Type 1 | Single Point | On/off states | true/false, 0/1 |
| Type 13 | Measured Normalized | Normalized measurements | Proportional values, percentages |
| Type 30 | Single Point with Timestamp | On/off states with time | Switch changes |
| Type 36 | Float with Timestamp | Measurements | 23.5, -10.2, 0.95 |
Recommendation: Use Type 36 for all analog measurements (temperature, voltage, current, etc.) and Type 30 for binary states (on/off, open/closed).
Automatic Type Conversion
The connector can automatically detect and convert value types from the JSON payload:
| JSON Value | Detected As |
|---|---|
true / false | Boolean |
42 | Integer |
23.5 | Floating-point number |
"text" | String |
If the detected type does not match the target IEC 104 type, the connector converts it automatically:
| From | To | Example |
|---|---|---|
| Boolean → Number | true → 1, false → 0 | |
| String → Number | "42" → 42 | |
| String → Boolean | "true", "1", "yes" → true | |
| Float → Integer | 3.7 → 3 (truncated) |
Value Maps
For cases where sensor data uses text labels instead of numbers, you can define a value map — a lookup table that translates text values to numeric values:
| Sensor Sends | Mapping | IEC 104 Receives |
|---|---|---|
"open" | "open": 1 | 1 |
"closed" | "closed": 0 | 0 |
"unknown" | "unknown": -1 | -1 |
This is useful when IoT devices report states as human-readable strings rather than numeric codes.
Configuration
The connector is configured in two ways:
- Management UI / API — The primary method. When you create an MQTT connector in the Management UI and link mappings to it, the configuration is stored in the database and automatically pushed to the connector via Valkey.
- Command-line / TOML file — For initial startup parameters (connector ID, broker connection, Valkey connection, log level). A TOML configuration file can be generated with the
config-gensubcommand.
Startup Parameters
These parameters are passed via command line or TOML file when starting the connector:
| Parameter | Description | Required | Default |
|---|---|---|---|
--id | Unique connector ID (from the Management UI) | Yes | — |
--log-level | Log verbosity (trace, debug, info, warning, error, critical, off) | No | info |
--mapping | Path to a local mapping file (overrides mappings from Valkey) | No | — |
--config | Path to a TOML configuration file | No | — |
MQTT subcommand — Connection to the MQTT broker:
| Parameter | Description | Default |
|---|---|---|
--broker | MQTT broker hostname | 127.0.0.1 |
--port | MQTT broker port | 1883 |
--client-id | MQTT client identifier | alp-connex-mqtt |
Redis subcommand — Connection to Valkey:
| Parameter | Description | Default |
|---|---|---|
--host | Valkey host (with optional port, e.g., valkey:6379) | 127.0.0.1 |
--port | Valkey port (overrides port in --host) | 6379 |
--pwd | Valkey password | — |
--stream-max-length | Maximum length of the Redis stream | 1000 |
Dynamic Configuration Updates
When you change a connector's settings or linked mappings in the Management UI, the backend pushes the updated configuration to Valkey. The connector detects the change and automatically reloads — no manual restart required.
Partial Mapping Loading
The connector uses graceful error handling when loading mappings. If one or more mappings contain errors (e.g., invalid JSON path, missing required fields), the connector:
- Logs the specific error for each invalid mapping
- Continues loading all valid mappings
- Reports how many mappings were successfully loaded
This ensures that a single misconfigured mapping does not prevent the entire connector from operating. Check the connector logs for details on any mappings that failed to load.
The backend publishes connector configuration and mapping data to Valkey under:
connectors:{CONNECTOR_ID}:config — connector settings (host, port, log level)
connectors:{CONNECTOR_ID}:mapping — linked mapping definitions
Mapping Configuration
Mappings are defined as structured JSON documents and managed through the ALP-CONNEX Management UI. Each mapping specifies:
{
"name": "signal/temp",
"type": 36,
"casdu": 225,
"ioa": 100,
"data": {
"value": { "type": "float", "path": "data.temperature" },
"timestamp": { "type": "datetime", "path": "timestamp" }
}
}
You do not need to write JSON manually — mappings are created and managed through the Management UI.
Mapping File
As an alternative to the Management UI, the MQTT Connector can load mappings from a JSON file at startup. This is useful for automated deployments or when the Management UI is not available.
A mapping file contains a list of mappings, each specifying:
- topic — The MQTT topic to subscribe to
- type — The IEC 104 data type (1, 30, or 36)
- casdu / ioa — The IEC 104 address for this data point
- data.value — Where to find the value in the JSON payload (path + type)
- data.timestamp (optional) — Where to find the timestamp
Example mapping file with a boolean sensor and a float sensor:
{
"version": "1.0.0",
"mappings": [
{
"topic": "sensor/door",
"type": 30,
"casdu": 223,
"ioa": 100,
"data": {
"value": { "type": "bool", "path": "data.state" }
}
},
{
"topic": "sensor/temperature",
"type": 36,
"casdu": 225,
"ioa": 200,
"data": {
"value": { "type": "float", "path": "data.temperature" },
"timestamp": { "type": "datetime", "path": "timestamp" }
}
}
]
}
The mapping file is mounted into the container as a read-only volume and referenced via the --mapping command-line parameter. See the Deployment Guide for a complete Docker Compose example.
Data Flow Summary
1. IoT device publishes JSON to MQTT topic
↓
2. MQTT Connector receives the message
↓
3. JSON path extracts the value (e.g., data.temperature → 23.5)
↓
4. Type conversion (if needed)
↓
5. Value written to Valkey as: process:image:casdu:225:ioa:100
↓
6. IEC 104 Connector detects the change
↓
7. SCADA client receives the updated value
Limitations
- Subscriber only — The connector receives data from MQTT. Publishing back to MQTT topics is planned but not yet available in all configurations.
- Single broker — Each connector instance connects to one MQTT broker at a time.
- JSON payloads — The connector expects JSON-formatted messages. Binary or plain-text payloads are not supported.
For technical implementation details, see the BookStack - ALP-CONNEX MQTT Connector.