Thoughts on a general Zigbee to Homebridge (HomeKit) converter

I would like to discuss my assumptions before making a general device to HomeKit converter, or specifically Zigbee/MQTT to Homebridge-MQTT.

The Redmatic-HomeKit Zigbee node (alternative to homekit-bridged) has awesome no-config automatic creation and control of homekit accessories (lights and sensors) from zigbee-herdsman (node-red-contrib-zigbee instead of external zigbee2mqtt (same core)), but my hope is to elegantly (and much simpler and more errorprone) make my own converter from zigbee-herdsman or MQTT to Homebridge-MQTT, because of the latter's stability and dynamic nature.

This in turn made me think of adopting the homie-convention for MQTT to standardise all info and states in MQTT and node-red, before attempting to automatically convert to Homebridge-MQTT. But this may be overkill because of my simple plan which follows.

My early sketch idea is to inspect the "clusters" of the zigbee devices (at intervals and when a new one shows up) and set up a general rule set for different sets of clusters. Eg. if it has onOff, Level, and Color clusters it's probably a bulb or lightstrip, and a HomeKit light tile could be automatically created through Homebridge-MQTT. Depending on availability status reachability could be set in HomeKit automatically too.

If the device is too special it won't touch it and it would have to added to HomeKit and controlled by hand in node-red, which may be preferable for other things than lights and sensors anyway.

When it comes to running control and synchronization the hardest part is the color modes I think.

I'm not really a hardcore coder so I was thinking of implementing it as a subflow if I cant manage it all in a function node.

What do you think ?

EDIT: Should I be able to also put up a UI for this node/subflow the user could edit a device’s HomeKit configuration (or block/remove accessory) by Homebridge-MQTT’s dynamic nature without any restarts. A big change would be a remove and add behind the scenes.

Hey - I have JUST started using Node-RED and homekit-mqtt. I was thinking something similar.

Say I have a Tasmota device, or a custom ESP module that outputs to 'standard' topic names;
I then would like Node-RED to take those topics automatically, turn it into a JSON, and pipe it to homekit-mqtt's /homebridge/to/add, /homebridge/to/set etc.

Is that kind of what you are trying to do?


There is no homekit-mqtt, do you mean homebridge-mqtt or homekit2mqtt ?

I have thought about "converting" objects to the homebridge-mqtt format, problem is that every device has its own output; ie. input is custom, output is somewhat custom. Even if you would use the homie convention to make a conversion, it will be a lot of work to create a subflow or custom node to capture all the characteristics, and all the services. Adding a device is done only once.

Sorry yeah homebridge-mqtt.

But if someone could make just ONE as an example - say for a Lightbulb or a Thermostat; then people (like me!) could use that as a reference.

So inputs would be MQTT topics for on, off, Name, Characteristic, Service, LWT, etc. Then into a flow that converts it to JSON and adds the Characteristic, Service and the /to/set etc.

I’m way too new to have a crack right now. Bet someone would be able to knock out a basic flow to cover this example relatively easily looking at the power of Node-RED and what people have previously come up with.

Beauty of Node-RED is the flow could be customed/tweaked by the user afterwards?


Michael Riksman

Basic concept in a function node when you receive a 1 or 0 from a tasmota device (ie. from stat/RESULT) :

m = msg.payload // expects input: 1 or 0 
node.send({topic:'homebridge/to/set',payload:{"name":"Ventilator Lamp","service_name":"ventilator_lamp","characteristic":"On","value":true}})
node.send({topic:'homebridge/to/set',payload:{"name":"Ventilator Lamp","service_name":"ventilator_lamp","characteristic":"On","value":false}})

This will set the homekit icon only.

To control a device from homekit, you need to listen on homebridge/from/set/#

Or you could use a change node:

[{"id":"92755e4f.3ecf4","type":"change","z":"44735c9c.d8a4b4","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t    \"topic\":\"homebridge/to/set\",\t    \"payload\": {\t        \"name\":\"Ventilator Lamp\",\t        \"service_name\":\"ventilator_lamp\",\t        \"characteristic\":\"On\",\t        \"value\":payload=1? true: false\t    }\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":720,"wires":[["7e728c67.999b54"]]},{"id":"3cae8379.3cba2c","type":"inject","z":"44735c9c.d8a4b4","name":"","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":680,"wires":[["92755e4f.3ecf4"]]},{"id":"18bfa237.331b2e","type":"inject","z":"44735c9c.d8a4b4","name":"","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":740,"wires":[["92755e4f.3ecf4"]]},{"id":"7e728c67.999b54","type":"debug","z":"44735c9c.d8a4b4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":570,"y":720,"wires":[]}]
1 Like

I like it! :slight_smile:

@cflurin - edit - that actually doesn't work because you cannot change properties outside msg.payload, needs a seperate change for the topic. (try setting the debug node to complete msg object and see)

You are right > this should work:

[{"id":"92755e4f.3ecf4","type":"change","z":"44735c9c.d8a4b4","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t    \"name\":\"Ventilator Lamp\",\t    \"service_name\":\"ventilator_lamp\",\t    \"characteristic\":\"On\",\t    \"value\":payload=1? true: false\t}\t","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"homebridge/to/set","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":1000,"wires":[["7e728c67.999b54"]]},{"id":"3cae8379.3cba2c","type":"inject","z":"44735c9c.d8a4b4","name":"","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":960,"wires":[["92755e4f.3ecf4"]]},{"id":"18bfa237.331b2e","type":"inject","z":"44735c9c.d8a4b4","name":"","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":1020,"wires":[["92755e4f.3ecf4"]]},{"id":"7e728c67.999b54","type":"debug","z":"44735c9c.d8a4b4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":570,"y":1000,"wires":[]}]

Hmmm. Can you somehow make a MQTT topic dynamic?
homekit-mqtt has the Name, Service_Name and Characteristic - I'd like to use them as Topic names
That way, I can work on reusing code...

You cannot (or at least not the mqtt-in node), the out node you can by sending the correct topic with msg.topic

You can capture everything (topic:homebridge/from/set/#) and filter from there with a switch node.
But the example in your screenshot will never work like that.

Why no change node and write the payload as you want/need for the esp ?

So in MQTT-Out I can set the Topic to msg.topic?

Why wouldn’t my current flow work?

Yeah I probably could change my ESP code. I am just learning Node-RED and this is a great little exercise to learn.

1 Like

Why wouldn’t my current flow work?

Because the mqtt node is not configured correctly (see the red triangle), but you can make it work. Are you planning to only control the ESP from homekit ? Is it not easier to just run Tasmota on your ESP ?

If you send:

{topic:"blabla", payload:"bla"}

to an MQTT out node (which has been configured, ie. set QOS and retain flag), it will work.
You cannot receive from "dynamic" topics, then you would need to listen to # and filter it.

Excellent. Will try tomorrow. I had already planned/worked out I’d need to have an MQTT-In and filter. Just saw the MQTT-Out had Topic in the config, and thought I couldn’t have dynamic Topics on MQTT-Out.

I don’t know a lot about Tasmota. I plan to use it on some generic Tuya based switches and dimmers using tuya-convert. Using MQTT seems easy enough for basic switches. But when I saw homebridge-mqtt uses JSON and homebridge/to/set, I thought Tasmota might not handle it? You have any examples on how to configure a Tasmota to work directly with homebridge-mqtt? Also. How would you get a Tasmota device to respond to a homebridge/to/set command? The Tasmota would have to parse the JSON and determine if the message was for itself?

With the ESP32 development module I plan on using for the blinds; it will connect with a Dooya DD7002B hub via RS485 serial to get position feedback (rare with 433MHz battery operated roller blinds). It will need to send a serial command and receive a response, parse it, and publish to MQTT topics. Not sure if Tasmota firmware would have that flexibility? Especially when I can get an ESP32 development board and a UART to RS485 converter for cheap.

PLUS. I am working on using an ESP32 module for controlling addressable LED strips. I know Tasmota has decent software for this - BUT - you can’t make custom animations in Tasmota, so I’m stuck with writing my own custom code to do it.

Thanks for your time.

This is working pretty well so far as an automated handler for homebridge-mqtt.

Handles Tasmota devices with multiple switches (POWER, POWER2, POWER3), and Outlets with Power Consumption (uses Current to determine OutletInUse). Handles odd edge cases where a device has two services and requires the use of /add/service; works well, a two switch device is joined together in the Home app.

flows.txt (13.1 KB)

How do you assemble an array from multiple messages?

Also, concerning this converting between HomeKit and other systems, my biggest problem is colorspace conversion. Ref. Colourspace, HomeKit Bridged, and Ikea Color Bulb

Join node.

@bohtho please create a new thread if you have further questions.
This thread was started for a different issue, which has been answered.