Configure MQTT Subscriptions
| Platform: | WebMobile |
|---|---|
| Plan Type: | BasicEssentialPremiumEnterprise |
| User Type: | RequesterFull UserAdministrator |
This article explains how to configure the MQTT subscriptions used by the MaintainXยฎ On-Premise Agent. Subscriptions define which MQTT topics the agent listens to, how it decodes their payloads, and how it names the resulting sensors in MaintainX.
For installation and the base settings.json skeleton, see Setup and Configure the MQTT On-Premise Agent.
Overviewโ
MQTT subscriptions are declared under the MqttSubscriptionSettings block of settings.json. Each subscription pairs a topic pattern with rules that tell the agent how to turn incoming payloads into sensor readings.
{
"MqttSubscriptionSettings": {
"Version": "v1",
"Subscriptions": [
{
"Topic": "factory/line1/+",
"SubscriptionType": "Custom",
"Payload": {
"Encoding": "Raw",
"Type": "Auto"
}
}
],
"IgnoredTopics": []
}
}
The agent supports several subscription types. The public types are:
SubscriptionType | When to Use |
|---|---|
Custom | Any MQTT broker. You control topic patterns, payload decoding, and field mapping. |
Sparkplug | Brokers using the Sparkplug B specification. |
Zigbee2MQTT | Brokers fronting a Zigbee2MQTT bridge. |
This page focuses on the Custom type, which is the most flexible and applies to any MQTT broker.
Subscription Anatomyโ
Each entry in Subscriptions is an object with the following fields:
| Field | Required | Description |
|---|---|---|
Topic | Yes | The MQTT topic pattern. It supports the + wildcard per segment. The # wildcard is not supported for Custom subscriptions. See Wildcard Rules. |
SubscriptionType | Yes | This field must be set to Custom for the configurations described on this page. |
Payload | Yes (for Custom) | An object that describes how to decode the payload. See Payload Encoding. |
Description | No | A free-text annotation. It has no effect on agent behavior and is useful for documenting your configuration. |
TimestampField | No | The top-level JSON field whose value is used as the reading timestamp. This applies only to Json encoding. |
The top-level MqttSubscriptionSettings block also accepts:
| Field | Required | Description |
|---|---|---|
Version | Yes | The schema version. Set this to "v1". |
Subscriptions | Yes | An array of subscription objects (at least one is required). |
IgnoredTopics | No | An array of topic patterns to exclude from processing. See Ignored Topics. |
Payload Encodingโ
The Payload.Encoding field selects one of two decoders:
Encoding | When to Use |
|---|---|
Raw | Each topic carries a single scalar value (a number, a boolean, or a string). |
Json | The topic carries a JSON object from which the agent extracts one or more fields. |
Raw Encodingโ
Use Raw when the entire MQTT payload is the value to record. One subscription with Raw encoding maps to 1 sensor per matched topic.
{
"Topic": "plant/boiler/temperature",
"SubscriptionType": "Custom",
"Payload": {
"Encoding": "Raw",
"Type": "Number",
"Unit": "ยฐC",
"FriendlyName": "Boiler Temperature"
}
}
Raw payload fields:
| Field | Required | Description |
|---|---|---|
Encoding | Yes | The encoding type. It must be set to "Raw". |
Type | Yes | The data type. It must be one of "String", "Number", "Boolean", or "Auto". See Type Auto: Automatic Type Inference. |
FriendlyName | No | The name to use for the sensor in MaintainX. It is subject to the Sensor Naming Matrix. |
Unit | No | The unit of measurement (e.g., ยฐC or psi). This applies only when Type resolves to a numeric value. |
Description | No | A free-text description shown on the sensor in MaintainX. |
JSON Encodingโ
Use Json when the payload is a JSON object and you want to extract one or more fields. Each field becomes a separate sensor in MaintainX.
{
"Topic": "plant/line1/+",
"SubscriptionType": "Custom",
"TimestampField": "ts",
"Payload": {
"Encoding": "Json",
"Fields": [
{
"Path": "data.temperature",
"Type": "Number",
"FriendlyName": "Temperature",
"Unit": "ยฐC"
},
{
"Path": "data.humidity",
"Type": "Number",
"FriendlyName": "Humidity",
"Unit": "%"
},
{
"Path": "data.online",
"Type": "Auto"
}
]
}
}
Json payload fields:
| Field | Required | Description |
|---|---|---|
Encoding | Yes | The encoding type. It must be set to "Json". |
Fields | Yes | An array of 1โ10 field mappings. Each field mapping becomes a sensor. |
Each entry in Fields accepts:
| Field | Required | Description |
|---|---|---|
Path | Yes | The dot-separated path to the value (e.g., data.temperature). Array indexes are supported using square brackets (e.g., data.readings[0].value). |
Type | Yes | The data type. It must be one of "String", "Number", "Boolean", or "Auto". |
FriendlyName | No | The name to use for the sensor. It is subject to the Sensor Naming Matrix. |
Description | No | A free-text description shown on the sensor. This field is mutually exclusive from DescriptionPath. |
DescriptionPath | No | The JSON path used to read the description from each payload. This field is mutually exclusive from Description. |
Unit | No | The static unit of measurement. This applies only to numeric types. This field is mutually exclusive from UnitPath. |
UnitPath | No | The JSON path used to read the unit from each payload. This applies only to numeric types. This field is mutually exclusive from Unit. |
The subscription-level TimestampField names a top-level JSON field whose value will be used as the reading timestamp. The agent supports both ISO-8601 strings and Unix epoch values (seconds, milliseconds, or microseconds). When TimestampField is set, that field is excluded from sensor extraction.
Type Auto: Automatic Type Inferenceโ
Type: "Auto" lets the agent decide a sensor's data type from the payload itself, instead of forcing you to declare it up front. It works for both Raw and Json encodings.
How Inference Worksโ
When the first matching payload arrives, the agent inspects the value and picks a type in this order:
- Boolean: Values that parse as
true/false(case-insensitive). - Number: Any value that parses as a decimal number, including integer-looking strings such as
42. - String: Anything else not covered by Boolean or Number values.
All numeric values are stored as double-precision floats. This keeps a sensor's storage stable when its values alternate between integers (3) and decimals (3.1), so you don't need to predict the future shape of your data.
Raw + Auto: JSON-Looking Payloads Are Skippedโ
Auto is meant for scalar values. If a Raw subscription with Type: "Auto" receives a payload that starts with { or [, the agent silently skips it and emits a debug log. Use Json encoding when your payload is structured.
Unit Handling Under Autoโ
The Unit field is only meaningful for numeric sensors. When Auto resolves to a Boolean or String, the configured Unit is suppressed and not stored on the sensor. This applies to both static Unit and dynamic UnitPath.
Example: Raw + Auto on a Wildcard Topicโ
A factory line publishes one value per topic, where the topic's last segment is the sensor's identifier. The agent should pick the right type for each sensor automatically:
{
"Topic": "factory/line1/+",
"SubscriptionType": "Custom",
"Payload": {
"Encoding": "Raw",
"Type": "Auto"
}
}
| Received Topic | Payload | Sensor Name | Inferred Type |
|---|---|---|---|
factory/line1/oven_temp | 185.4 | oven_temp | Number |
factory/line1/door_open | true | door_open | Boolean |
factory/line1/state | RUNNING | state | String |
Example: JSON + Auto on a Single Fieldโ
A device reports a single field that may be reported as either a boolean or a numeric:
{
"Topic": "devices/+/online",
"SubscriptionType": "Custom",
"Payload": {
"Encoding": "Json",
"Fields": [
{
"Path": "online",
"Type": "Auto",
"FriendlyName": "Connectivity"
}
]
}
}
The first payload received determines the sensor's data type. For details on what happens if later payloads use a different type, see Data Type Locking.
Data Type Lockingโ
A sensor's data type is set on first creation and never updated afterward. This applies to explicit types (Number, String, Boolean) and to Auto, where the first inferred type wins.
If a later payload for an existing sensor has a different type than the one stored at creation, the agent drops the payload and logs a one-time warning per sensor:
Sensor 'oven_temp' is stored as Double but received String. Payloads with mismatched types will be dropped. To change the sensor type, delete the sensor in MaintainX and let the agent re-create it.
The warning fires once per sensor per agent lifetime to avoid log spam. You should check logs immediately after a configuration change to ensure that no type mismatches are occurring and payloads are not being dropped.