Homebridge MQTT integration lets you control DIY sensors, relays and lights from the Apple Home app and Siri, even though HomeKit itself knows nothing about MQTT. In this tutorial you will install the mqttthing plugin, map topics to HomeKit characteristics for a temperature sensor, a switch, a dimmable light and a contact sensor, handle JSON payloads, and move the setup onto a private TLS broker.
How Homebridge Talks to MQTT
Homebridge is a Node.js server that emulates HomeKit accessories. Plugins provide the actual device logic. The most widely used MQTT plugin, homebridge-mqttthing, lets you declare an accessory in JSON and map each HomeKit characteristic to an MQTT topic: a get topic that Homebridge subscribes to for the current value, and a set topic it publishes to when you tap a tile or ask Siri.
Apple Home / Siri
|
(HomeKit, LAN)
|
Homebridge -- homebridge-mqttthing
|
(MQTT over TLS)
|
MQTT broker <--> ESP32, Tasmota, Zigbee2MQTT, scripts
Because the devices only ever talk to the broker, they can live on another network or another site. Homebridge only needs outbound access to the broker. If you want the background on this pattern first, the article on what an MQTT broker does explains publish and subscribe in plain terms.
Installing the mqttthing Plugin
If you use the Homebridge UI (the default in official images), open Plugins, search for mqttthing and install Homebridge Mqttthing. From the command line on a Homebridge host:
sudo npm install -g homebridge-mqttthing
sudo hb-service restart
Accessories are defined in the accessories array of config.json. The UI includes a form-based editor for the plugin, but the raw JSON is clearer for learning, so the examples below use it. You can paste them into Config > JSON Config.
A First Homebridge MQTT Accessory: Temperature Sensor
Start with the public test broker so you can watch everything happen. Pick a random string (here h3m8x2) to keep your topics separate in the shared public area.
{
"accessory": "mqttthing",
"type": "temperatureSensor",
"name": "Greenhouse Temperature",
"url": "mqtt://broker.connectmq.com:1883",
"mqttOptions": { "clientId": "hb-gh-temp-h3m8x2" },
"topics": {
"getCurrentTemperature": "connectmq/demo/h3m8x2/greenhouse/temperature"
},
"logMqtt": true
}
Save, restart Homebridge, then publish a reading:
mosquitto_pub -h broker.connectmq.com -p 1883 -i sim-h3m8x2 \
-t 'connectmq/demo/h3m8x2/greenhouse/temperature' -m '23.5' -r
The tile in Apple Home updates within a second. The -r flag makes the message retained, so after a Homebridge restart the last value is delivered immediately instead of the tile showing "No Response" until the next reading.
Switches and Lights with Commands
Controllable accessories need both a get and a set topic. Using separate topics for commands and confirmed state is good practice: Homebridge publishes the request, the device acts, and the device publishes its real state back.
{
"accessory": "mqttthing",
"type": "switch",
"name": "Vent Fan",
"url": "mqtt://broker.connectmq.com:1883",
"mqttOptions": { "clientId": "hb-fan-h3m8x2" },
"topics": {
"getOn": "connectmq/demo/h3m8x2/greenhouse/fan/state",
"setOn": "connectmq/demo/h3m8x2/greenhouse/fan/set"
},
"onValue": "ON",
"offValue": "OFF"
}
A dimmable light adds a brightness characteristic:
{
"accessory": "mqttthing",
"type": "lightbulb",
"name": "Grow Light",
"url": "mqtt://broker.connectmq.com:1883",
"mqttOptions": { "clientId": "hb-light-h3m8x2" },
"topics": {
"getOn": "connectmq/demo/h3m8x2/greenhouse/light/state",
"setOn": "connectmq/demo/h3m8x2/greenhouse/light/set",
"getBrightness": "connectmq/demo/h3m8x2/greenhouse/light/brightness",
"setBrightness": "connectmq/demo/h3m8x2/greenhouse/light/brightness/set"
},
"onValue": "ON",
"offValue": "OFF"
}
Watch what Homebridge sends while you tap the tiles:
mosquitto_sub -h broker.connectmq.com -p 1883 -i mon-h3m8x2 \
-t 'connectmq/demo/h3m8x2/greenhouse/#' -v
Handling JSON Payloads
Many devices publish one JSON document with several values rather than one topic per value. mqttthing accepts a topic object with an apply function, a short JavaScript body that receives message and returns the value to use.
{
"accessory": "mqttthing",
"type": "contactSensor",
"name": "Greenhouse Door",
"url": "mqtt://broker.connectmq.com:1883",
"mqttOptions": { "clientId": "hb-door-h3m8x2" },
"topics": {
"getContactSensorState": {
"topic": "connectmq/demo/h3m8x2/greenhouse/telemetry",
"apply": "return JSON.parse(message).door === 'open' ? 1 : 0;"
}
}
}
HomeKit's contact sensor uses 0 for detected (closed) and 1 for not detected (open), which is why the function maps open to 1. The same technique works on set topics to wrap a command in JSON, for example "apply": "return JSON.stringify({state: message});".
Mapping Common Device Types
HomeKit type (type) |
Key topics | Typical payload |
|---|---|---|
temperatureSensor |
getCurrentTemperature |
23.5 |
humiditySensor |
getCurrentRelativeHumidity |
64 |
switch / outlet |
getOn, setOn |
ON / OFF with onValue and offValue |
lightbulb |
getOn, setOn, getBrightness, setBrightness |
ON, 0-100 |
contactSensor |
getContactSensorState |
0 closed, 1 open |
motionSensor |
getMotionDetected |
true / false |
leakSensor |
getLeakDetected |
0 / 1 |
The plugin supports many more types, including garage doors, thermostats, fans and window coverings. Each has its own characteristic names; the plugin's README lists them all.
Connection Count and Client IDs
Every mqttthing accessory opens its own MQTT connection. Ten accessories therefore mean ten clients on the broker, each needing a unique client ID. Two consequences follow:
- Give every accessory its own
clientIdinmqttOptions. Duplicate IDs make the broker disconnect the earlier session, and accessories flicker between responding and not responding. - Count connections against your plan. The ConnectMQ free Serverless plan allows up to 25 concurrent connections, which covers Homebridge plus a modest number of devices. Larger setups fit the paid Serverless plan with up to 1,000.
If you need many accessories on a single connection, consider letting Home Assistant or Node-RED own the broker connection and expose HomeKit through their own HomeKit bridges.
Production: TLS and Credentials
Anything in the public test area can be read by anyone who guesses the topic, and someone could also publish to your set topics. Before controlling real equipment, create a private broker and switch every accessory to TLS:
{
"accessory": "mqttthing",
"type": "switch",
"name": "Vent Fan",
"url": "mqtts://broker.connectmq.com:8883",
"username": "YOUR_USERNAME",
"password": "YOUR_PASSWORD",
"mqttOptions": { "clientId": "YOUR_CLIENT_ID" },
"topics": {
"getOn": "site1/greenhouse/fan/state",
"setOn": "site1/greenhouse/fan/set"
},
"onValue": "ON",
"offValue": "OFF"
}
Node.js trusts the Let's Encrypt chain used by ConnectMQ out of the box, so no CA file is required. On ConnectMQ, client IDs are bound to the credentials issued in the portal, so when you need several connections, issue a credential set per accessory group and keep track of which ID belongs where.
Running mqttthing as a Child Bridge
Homebridge can run a plugin as a child bridge: a separate process with its own HomeKit pairing. Enabling it for mqttthing (in the plugin settings, Bridge Settings) has two practical benefits. A crash or misbehaving accessory definition no longer takes down every other plugin, and restarting the child bridge after editing topics is faster than restarting all of Homebridge. You pair the child bridge once in the Home app, and accessories added to it later appear automatically.
It is also worth publishing a retained availability topic from each device with a last will of offline. mqttthing can use it through the getOnline topic together with onlineValue and offlineValue, so Apple Home shows a device as not responding when it really is offline instead of displaying a stale value.
Troubleshooting Homebridge MQTT
- Accessory shows No Response. No value has arrived on the
gettopic since Homebridge started. Publish retained state from devices, or check the topic for typos withlogMqtt: true. - Tile toggles back by itself. The device is not publishing its new state on the
gettopic, or publishes a value that does not matchonValue. - Constant reconnect messages in the log. Duplicate client IDs or wrong credentials. Look for
Connection refusedand the reason in the Homebridge log. - Siri says the device is not responding but the app works. Usually a HomeKit hub (Apple TV or HomePod) issue rather than MQTT; check that the hub can reach Homebridge on the LAN.
Where to Go Next
Homebridge gives you the Apple side; the devices still need to publish sensible topics. The ESPHome MQTT guide shows how to build sensors that publish state and accept commands, and the smart home MQTT topic structure article helps you design topics that stay manageable. If Home Assistant runs alongside Homebridge, see Home Assistant with an external MQTT broker. For the broader context of combining devices and logic, read the IoT automation guide, and to understand why a hosted MQTT broker beats a broker on the Homebridge Pi for remote access, compare the options there.
Connect Homebridge to ConnectMQ
ConnectMQ gives Homebridge a private, TLS-secured broker reachable from any network, with a live topic explorer to debug your accessories as you configure them. Create a free Serverless broker at app.connectmq.com, no credit card needed, and paste the generated credentials into your mqttthing accessories.
Frequently Asked Questions
Does HomeKit support MQTT natively?
No. HomeKit uses its own accessory protocol, so you need a bridge such as Homebridge with an MQTT plugin to translate between the two.
Can I control Homebridge MQTT devices when I am away from home?
Yes, through a HomeKit home hub as usual. Because the devices talk to a cloud broker, they can even be at a different site from Homebridge.
Why do my sensors show No Response after a restart?
Homebridge has not yet received a value. Publish state messages with the retain flag so the broker delivers the last value as soon as Homebridge subscribes.
Is mqttthing the only Homebridge MQTT plugin?
No, but it is the most general one. Other plugins target specific ecosystems such as Zigbee2MQTT or Tasmota and can be simpler if you use only those devices.



