MQTT Home Assistant - IoT
The bridge normalises KNX telegrams into structured messages that can be consumed by IoT transports (MQTT, REST, Modbus) and accepts flow inputs to write back to the KNX bus. It mirrors the runtime logic of the Node-RED editor help and shows how to hook the node to third-party connectors.
Operating mode
The node has a Mode selector:
- IoT bridge (default) — the behaviour described below: a list of mappings that turn KNX telegrams into MQTT/REST/Modbus output messages and back.
- MQTT / Home Assistant (native) — the node connects directly to an MQTT broker and bridges KNX ↔ MQTT both ways, publishing Home Assistant MQTT Discovery so KNX appears automatically in Home Assistant. No
mqtt in/mqtt outwiring is needed.
MQTT / Home Assistant mode
Requirements: an MQTT broker reachable by both Node-RED and Home Assistant, with the MQTT integration enabled in HA. All entities are grouped under a single HA device named after the node.
| Field | Purpose |
|---|---|
| KNX bus connection | Stand-alone (default): the node talks to the KNX gateway directly and shows no input/output pins. Flow messages: the node exposes an input pin and an output pin — wire the output of a KNXUltimate node in Universal mode to the input (KNX bus → MQTT) and the output pin to the input of another KNXUltimate node in Universal mode (MQTT → KNX bus). |
| Broker URL / Username / Password | MQTT broker connection. |
| Base topic | Root of the state/command topics (default knx-ultimate). |
| Publish HA discovery / Discovery prefix | Enable Home Assistant MQTT Discovery and set its prefix (default homeassistant). |
| Entity name format | How the HA entity names are built from the ETS import, whose names start with the group-address path, e.g. (Lights->Ground floor) Living room. Options: As imported from ETS (default), Name first (Living room (Lights->Ground floor)), Name only (Living room), Name + group address (Living room (0/1/2)). |
| Group addresses to expose | Checkbox list of every address imported in the gateway (ETS). Ticked addresses become HA entities, typed automatically from the DPT (switch, sensor, binary_sensor, number, text). Filter + Select all / none; all selected by default. Each row also has a Read only toggle: a read-only address is still published to Home Assistant (state visible) but never accepts commands back to the KNX bus (switches become binary_sensors, numbers become sensors). The Set read only / Clear read only buttons apply it to all currently shown addresses. |
| Covers & Thermostats | Composite entities that aggregate several addresses (see below). |
Covers & Thermostats
Covers and thermostats combine several group addresses into one HA entity, so they can’t be derived from a single DPT - add them in the list:
- Cover: Up/Down GA (1.008), optional Stop GA (1.007), optional Set/Status position GA (5.001). Invert position maps KNX (0% = open) to Home Assistant (100% = open).
- Thermostat: current temperature GA (9.001), setpoint set/status GA (9.001), optional On/Off GA (1.001 → off/heat), plus min/max temperature and step.
Datapoint types are read from the ETS import when available, otherwise from KNX defaults. For reliable status, the addresses used by covers/thermostats should be present in the ETS import.
Native KNX integration vs MQTT bridge. If Home Assistant already talks to KNX through its built-in KNX integration, covers/climate are configured there with group addresses and this MQTT bridge is not needed. Use this mode when Node-RED owns the KNX bus and Home Assistant sees everything over MQTT.
Mapping recap
| Field | Purpose | Notes |
|---|---|---|
| Label | Friendly name | Used in the status text and msg.bridge.label. |
| GA / DPT | KNX group address and datapoint | Set via ETS CSV autocomplete or manually. |
| Direction | KNX→IoT, IoT→KNX, Bidirectional | Determines which pins are active. |
| Channel type | MQTT / REST / Modbus | Changes the meaning of Target. |
| Target | Topic, base URL or zero-based Modbus address | Modbus requires a protocol address from 0 to 65535, not a 4xxxx reference. |
| Modbus format / Unit ID / Area / Data type | Flex or legacy message contract and register definition | New mappings should use Flex; a missing format remains legacy for compatibility. |
| Template | String payload formatter | Use placeholders {{value}}, {{ga}}, {{type}}, {{target}}, {{label}}, {{isoTimestamp}}. |
| Scale / Offset | Numeric conversion | Applied KNX→IoT; inverse is used IoT→KNX. |
| Timeout / Retry | Pass-through hints | Convey the desired retry/window to downstream nodes. |
Typical transports
MQTT broker
- Publishing: wire output 1 to the core
mqtt outnode. The bridge setsmsg.topicandmsg.payloadso you can publish directly. - Subscribing: connect a core
mqtt innode to the bridge input. Payloads are converted according to the mapping and written to KNX. The ack on output 2 confirms the write.REST API
- Bridge output 1 into the core
http requestnode (or contrib nodes such asnode-red-contrib-http-request). - The bridge copies
bridge.methodtomsg.methodand the formatted template tomsg.payloadso you can push JSON payloads or form data to webhooks.Modbus registers
The IoT Bridge is a message adapter for node-red-contrib-modbus. It does not create a TCP/serial client and does not poll devices; install a package version compatible with your Node-RED runtime and configure those parts in the external Modbus nodes.
| Area | Read FC | Write FC | Direction |
|---|---|---|---|
| Coil | 1 | 5 | KNX ↔ Modbus |
| Discrete input | 2 | — | Modbus → KNX only |
| Holding register | 3 | 6 | KNX ↔ Modbus |
| Input register | 4 | — | Modbus → KNX only |
For new rows choose Flex Write compatible, set Unit ID, Area and Data type, and enter the zero-based protocol address in Target. A KNX value sent to a coil produces FC5; a value sent to a holding register produces FC6. Output 1 is directly compatible with modbus-flex-write:
msg.payload = {
value: 215,
fc: 6,
unitid: 1,
address: 9,
quantity: 1
}
To bring data back, connect the data output of modbus-flex-getter or modbus-read to the bridge input. Flex Getter provides the request (fc, unitid, address, quantity) in msg.modbusRequest; Modbus Read preserves it in msg.input.payload. The returned values array may be in msg.payload or msg.values. The bridge supports both message shapes. Enable Keep Msg Properties on Flex Getter. One read response may cover several configured addresses, and the bridge selects the correct array element for each matching row.
Only one bit or one 16-bit register is supported per mapping: bool, uint16 or int16. Multiword values, 32-bit/float decoding and byte/word-order conversion are outside this adapter. Scale and offset use raw = KNX × scale + offset; Modbus → KNX applies the inverse. Read KNX values on deploy does not poll Modbus.
Mappings without modbusMessageFormat keep the legacy scalar output with top-level msg.address and msg.modbusFunction, so saved flows are not silently migrated.
Example flows
KNX → MQTT status topic
[
{
"id": "bridge1",
"type": "knxUltimateIoTBridge",
"z": "flow1",
"server": "gateway1",
"name": "Light bridge",
"emitOnChangeOnly": true,
"readOnDeploy": true,
"acceptFlowInput": true,
"mappings": [
{
"id": "map-light",
"enabled": true,
"label": "Living light",
"ga": "1/1/10",
"dpt": "1.001",
"direction": "bidirectional",
"iotType": "mqtt",
"target": "knx/light/living",
"method": "POST",
"modbusFunction": "writeHoldingRegister",
"scale": 1,
"offset": 0,
"template": "{{value}}",
"property": "",
"timeout": 0,
"retry": 0
}
],
"wires": [["mqttOut"],["debugAck"]]
},
{
"id": "mqttOut",
"type": "mqtt out",
"name": "MQTT status",
"topic": "",
"qos": "0",
"retain": "false",
"broker": "mqttBroker",
"x": 520,
"y": 120,
"wires": []
},
{
"id": "debugAck",
"type": "debug",
"name": "KNX ack",
"active": true,
"tosidebar": true,
"complete": "true",
"x": 520,
"y": 180,
"wires": []
}
]
MQTT command → KNX feedback
[
{
"id": "mqttIn",
"type": "mqtt in",
"name": "MQTT command",
"topic": "knx/light/living/set",
"qos": "1",
"datatype": "auto",
"broker": "mqttBroker",
"x": 140,
"y": 200,
"wires": [["bridge1"]]
}
]
Combine both snippets in the same flow to round-trip KNX ↔ MQTT with acknowledgements.
REST snapshot payload
{
"id": "bridge-rest",
"type": "knxUltimateIoTBridge",
"name": "Power meter bridge",
"mappings": [
{
"label": "Total active power",
"ga": "2/1/20",
"dpt": "9.024",
"direction": "knx-to-iot",
"iotType": "rest",
"target": "https://example/api/knx/power",
"method": "POST",
"template": "{\"value\":{{value}},\"ga\":\"{{ga}}\",\"ts\":\"{{isoTimestamp}}\"}"
}
]
}
Pipe output 1 into an http request node pointing at the same URL. Use the response to log success or retry via the bridge metadata (bridge.retry).
Modbus register write
- Mapping:
Target = 9,Channel type = Modbus,Format = Flex Write compatible,Unit ID = 1,Area = Holding register,Data type = uint16. - Wire bridge output 1 directly to
modbus-flex-write; no Function node is required. - Wire a
modbus-readormodbus-flex-getterresponse to the bridge input for Modbus → KNX. - Import
examples/IoT Bridge - Modbus Flex Adapter.jsonfor a manual, non-polling starter flow.Tips & troubleshooting
- Leave
Targetempty only for MQTT/REST mappings that should inherit the nodeoutputtopic; Modbus Flex needs an address. emitOnChangeOnlyis useful for High frequency sensors; disable it when you need every telegram (e.g., counters).- Output 2 acknowledges the value actually dispatched to KNX; it is not a physical Modbus write/read confirmation.
- A manual reference such as
40010commonly maps to address9, but always verify the device documentation. Happy bridging!
- Leave