Tutorials

openHAB MQTT Binding Tutorial: Broker, Things and Channels

Set up the openHAB MQTT binding: add a broker bridge Thing, create Generic MQTT Things and channels, parse JSON, link Items, publish from rules and test it.

Updated · 8 min read

openHAB MQTT Binding Tutorial: Broker, Things and Channels

The openHAB MQTT binding connects openHAB to any MQTT broker in two layers: a broker Thing (a bridge that holds the connection: host, port, TLS, credentials) and one or more Generic MQTT Things underneath it, whose channels map individual topics to openHAB Items. Install the binding, add the broker, add a Thing with a channel per value, link Items — and every message on those topics updates your Items, while commands from the UI or rules are published back.

This tutorial walks through both the UI and the text-file configuration, shows how to parse JSON payloads, and how to verify every hop from the command line.

Prerequisites

  • openHAB 4.x or newer with the MQTT Binding installed (Settings → Add-on Store → Bindings → MQTT).
  • The JSONPath Transformation add-on if your devices send JSON (most do).
  • A broker. openHAB does not include one, so run Mosquitto locally or use a hosted broker. The examples use broker.connectmq.com with TLS on port 8883 and test topics under testmqtt/openhab/....

Step 1: the broker bridge Thing

In the UI go to Settings → Things → + → MQTT Binding → MQTT Broker and fill in:

ParameterValueNotes
Broker Hostname/IPbroker.connectmq.comNo mqtt:// prefix
Broker Port88831883 without TLS
Secure ConnectiononMust match the port
ProtocolTCPWebSockets is also available
MQTT VersionV5V3 means 3.1.1
Client IDopenhab-homeUnique per broker
Username / Passwordyour broker credentials
Keep Alive60Seconds

Leave certificate and public-key pinning off when your broker uses a public certificate that renews automatically: pinning stores the first certificate it sees and fails after the broker rotates it. If you need to troubleshoot the TLS side, see testing a TLS connection.

The broker Thing should switch to ONLINE within a few seconds. If it shows OFFLINE - COMMUNICATION_ERROR, the status detail contains the reason — usually a port/TLS mismatch or wrong credentials.

You can also configure a Last Will (lwtTopic, lwtMessage), plus birth and shutdown messages, so other systems know whether openHAB is connected — useful when a dashboard or Node-RED depends on it.

Step 2: a Generic MQTT Thing and its channels

Add Generic MQTT Thing, choose the broker as its bridge, then add channels on the Channels tab. Each channel has a type and, at minimum, a state topic:

Channel typeItem typeTypical payloads
Text value (string)StringAny text
Number value (number)Number (with unit)21.5
Percentage value (dimmer)Dimmer0–100
On/Off switch (switch)SwitchON/OFF (configurable)
Open/Close contact (contact)ContactOPEN/CLOSED
Color value (color)Colorr,g,b or h,s,b
Rollershutter (rollershutter)RollershutterUP/DOWN/STOP, percent
Date/Time, Location, ImageDateTime, Location, ImageISO date, lat,lon, binary
Trigger (trigger)— (rules only)Button events

The important channel parameters:

  • State Topic — openHAB subscribes here and updates the Item.
  • Command Topic — openHAB publishes here when the Item receives a command. Use a different topic from the state topic (e.g. .../set), otherwise your own commands come back as state updates.
  • Incoming Value Transformations — e.g. JSONPATH:$.temperature.
  • Outgoing Value Format — a format string such as %s or {"state":"%s"} to wrap commands in JSON.
  • Retained — publish commands as retained messages; see retained messages before turning this on.
  • Custom On/Open Value and Custom Off/Closed Value — map device payloads such as 1/0 or true/false.
  • Is Command (postCommand) — treat incoming values as commands instead of state updates, so they trigger other bindings and rules.

The same configuration as text files

For version control, define the broker and Things in a .things file:

conf/things/mqtt.things
Bridge mqtt:broker:connectmq "ConnectMQ broker" [
    host="broker.connectmq.com", port=8883, secure=true,
    certificatepin=false, publickeypin=false,
    protocol="TCP", mqttVersion="V5",
    clientID="openhab-home", username="username", password="password",
    keepAlive=60, qos=1
] {
    Thing topic livingroom "Living room" [
        availabilityTopic="testmqtt/openhab/livingroom/status",
        payloadAvailable="online", payloadNotAvailable="offline"
    ] {
        Channels:
            Type number : temperature "Temperature" [
                stateTopic="testmqtt/openhab/livingroom/sensor",
                transformationPattern="JSONPATH:$.temperature", unit="°C" ]
            Type number : humidity "Humidity" [
                stateTopic="testmqtt/openhab/livingroom/sensor",
                transformationPattern="JSONPATH:$.humidity", unit="%" ]
            Type switch : lamp "Lamp" [
                stateTopic="testmqtt/openhab/livingroom/lamp/state",
                commandTopic="testmqtt/openhab/livingroom/lamp/set",
                on="ON", off="OFF" ]
            Type trigger : button "Wall button" [
                stateTopic="testmqtt/openhab/livingroom/button" ]
    }
}

The channel UID is mqtt:topic:connectmq:livingroom:<channel>. Link Items to it:

conf/items/livingroom.items
Number:Temperature   LivingRoom_Temperature "Temperature [%.1f %unit%]" { channel="mqtt:topic:connectmq:livingroom:temperature" }
Number:Dimensionless LivingRoom_Humidity    "Humidity [%.0f %%]"        { channel="mqtt:topic:connectmq:livingroom:humidity" }
Switch               LivingRoom_Lamp        "Lamp"                      { channel="mqtt:topic:connectmq:livingroom:lamp" }

Two channels share one state topic and extract different JSON fields — the normal pattern for multi-sensor devices. The availabilityTopic marks the Thing OFFLINE when the device's Last Will fires.

Publishing from rules

The broker Thing exposes a publishMQTT action, handy for notifications or for talking to devices that have no Thing:

conf/rules/mqtt.rules
rule "Publish lamp changes as an event"
when
    Item LivingRoom_Lamp changed
then
    val mqtt = getActions("mqtt", "mqtt:broker:connectmq")
    mqtt.publishMQTT("testmqtt/openhab/events/lamp", newState.toString, false)
end

rule "Wall button pressed"
when
    Channel "mqtt:topic:connectmq:livingroom:button" triggered
then
    LivingRoom_Lamp.sendCommand(if (LivingRoom_Lamp.state == ON) OFF else ON)
end

For catch-all listeners, add a Publish trigger channel on the broker Thing itself: its state topic accepts wildcards (testmqtt/openhab/+/event), and rules receive topic#payload as the event.

Test every hop

Inbound — publish a fake sensor reading and watch the Items change:

Simulate the sensor
mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -u "$MQTT_USER" -P "$MQTT_PASS" \
  -t 'testmqtt/openhab/livingroom/sensor' -m '{"temperature": 21.5, "humidity": 48}'

mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -u "$MQTT_USER" -P "$MQTT_PASS" \
  -t 'testmqtt/openhab/livingroom/status' -m online -r

events.log (/var/log/openhab/events.log on Linux packages) should show Item 'LivingRoom_Temperature' changed from NULL to 21.5 °C.

Outbound — subscribe to the command topic and flip the switch in the UI, or from the openHAB console:

Watch commands from openHAB
mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -u "$MQTT_USER" -P "$MQTT_PASS" -t 'testmqtt/openhab/#' -v

# in another shell: openhab-cli console, then
openhab> openhab:send LivingRoom_Lamp ON

You should see testmqtt/openhab/livingroom/lamp/set ON. The online MQTT client works just as well for both directions if you prefer a browser.

Watch openHAB's MQTT traffic in the browser

When nothing happens, raise the log level in the console with log:set DEBUG org.openhab.binding.mqtt and log:set DEBUG org.openhab.core.io.transport.mqtt. Typical findings: the Item is linked to a different channel UID, the JSONPath does not match (the value stays NULL and a transformation warning is logged), or the topic differs by one character — paste both into the topic matcher to check.

Auto-discovery: Homie and Home Assistant

The binding also understands two discovery conventions. Devices that announce themselves via the Homie convention or Home Assistant MQTT discovery (Tasmota, ESPHome, Zigbee2MQTT with discovery enabled) appear in the openHAB Inbox with their channels pre-built. That saves typing, but generic Things remain the most predictable option for custom firmware and for devices such as Shelly or Zigbee2MQTT when you want full control of topic names. Whichever you choose, a consistent smart home topic design keeps the channel configuration short.

The openHAB MQTT binding is simple once the two layers click: one broker Thing per connection, Generic MQTT Things with one channel per value, Items linked to channels. Start with a single channel, prove it with mosquitto_pub and events.log, then add the rest of the house.

Frequently asked questions

Does openHAB include an MQTT broker?

No. Current openHAB versions only ship the MQTT binding, which is a client. You need a separate broker such as Mosquitto on the same machine, or a managed broker reachable over the network.

Why is my openHAB MQTT broker Thing OFFLINE?

The status detail usually says why: wrong host or port, TLS enabled on a plain port (or the reverse), bad credentials, or a client ID already in use. Enable DEBUG logging for org.openhab.binding.mqtt and org.openhab.core.io.transport.mqtt to see the exact error.

How do I read one value from a JSON payload in openHAB?

Install the JSONPath Transformation add-on and set the channel's incoming transformation to JSONPATH:$.temperature (or whatever path you need). Several channels can share the same state topic, each extracting a different field.