Node-Red

Wait, websocket endpoint for events? Is this documented somewhere?

No, I'm talking about using node red to integrate MQTT with the web based integration of hub link. Haven't looked into it to see if it would work, but could always just create an App to manage things with Virtual Devices if that didn't work.

There was a community post several months back where someone called it out, and I've seen it mentioned a few times, but it's not documented.

I found that a lot of the app-based integration options added latency for safety or slowed the hub down over time. I figured I could add a little complexity with nodered, but use it to do a lot of the heavy lifting and get a lot in return.

I use a hassio VM running on my NAS for simplicity and ease of management. That has nodered, Mqtt and influx db containers running. I also get data streamed into influx from Hubitat this way.

I've got a nodered project for the whole thing, I'll look into making it public. It's definitely in the hack/WIP phase and I'm not a developer so user beware.

1 Like

Well can I ask for the websocket URL for listening to the events on Hubitat? Is that the live logging URL I saw in another solution?

Right now I've got an app I repurposed from SmartThings that sends events to my custom solution via webhooks. I'm not noticing any performance implications, but if I could just have my solution connect to a websocket endpoint and parse everything, that may be preferable.

ws://hubitat/eventsocket

2 Likes

This is amazing. This totally changes how I'm getting events from Hubitat. Thank you!

Just discovered this too. Now the opportunities really open up!

Is there any more documentation?

I know, right?!

So I didn't find any documentation, but here's how I'm doing it in my .NET Core code. Basically whenever the websocket sends an event, I deserialize it and raise it as a System.Event in my code, so then I can look at all my automations and see if any of them subscribe to events from the device that sent it.

1 Like

Guess we are meant to be smart enough to figure it out ... looks like you are making progress.

Thanks for sharing!

1 Like

I have way too much code in node-red! In fact I have just bought an HE in order to remove all but the most essential rubbish. Some of the things that are easy in RuleEngine are messy in node-red, though you do find yourself repeating "patterns".

Stuff I really really want to remove from node-red

  • the Google Home "integration" implementation which took me a long time to get stable.
  • The simpler monitoring (e.g. is washing machine on, motion lighting),
  • all the weird home built device integration stuff (eg 6-LED Information panels which is 150 nodes on its own)

And other automation stuff I never got around to.

Here's a rough copy of a sketch that integrates Hubitat, MQTT and Home Assistant. It's not very well documented, but you should be able to work with it if you know Node-Red.

The Config node at the top needs to be tweaked for your installation of the Maker API App (Hubitat IP, Maker API App ID and Access Token.) You'll also need to set your MQTT server in the two MQTT nodes and may need to change the url on the websocket listener.

From there, it's just a matter of setting up the Maker API App with the devices you want to control and setting up Home Assistant for your MQTT broker and enabling auto discovery. You can run everything using HASSIO on a raspberry pi or VM and use the MQTT and Node-Red Addons.

[{"id":"5d1597b5.fb5dc8","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"9fcc6f08.06431","type":"http in","z":"5d1597b5.fb5dc8","name":"","url":"/mqttweb/push/:platform","method":"post","upload":false,"swaggerDoc":"","x":240,"y":300,"wires":[["8275f94b.3e5878","366e87e9.bdd828"]]},{"id":"8275f94b.3e5878","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":500,"y":200,"wires":[]},{"id":"8b72eb2e.0b7448","type":"http response","z":"5d1597b5.fb5dc8","name":"","statusCode":"200","headers":{},"x":840,"y":300,"wires":[]},{"id":"49662e81.790a5","type":"mqtt out","z":"5d1597b5.fb5dc8","name":"","topic":"","qos":"","retain":"","broker":"d637a738.68b148","x":830,"y":500,"wires":[]},{"id":"366e87e9.bdd828","type":"change","z":"5d1597b5.fb5dc8","name":"Prepare MQTT Message","rules":[{"t":"set","p":"topic","pt":"msg","to":"$join([$string($flowContext(\"config.mqtt_prefix\")),$string(payload.platform),$string(payload.device),$string(payload.attribute),$string($flowContext(\"config.mqtt_state_suffix\"))], '/')","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"payload.state","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":380,"wires":[["49662e81.790a5","3d6a1859.8cd618"]]},{"id":"c01c257e.694b08","type":"catch","z":"5d1597b5.fb5dc8","name":"","scope":["9fcc6f08.06431","49662e81.790a5","366e87e9.bdd828"],"x":830,"y":360,"wires":[["f9a5aa1f.b54158","2f103c0d.489b34"]]},{"id":"f9a5aa1f.b54158","type":"http response","z":"5d1597b5.fb5dc8","name":"","statusCode":"500","headers":{},"x":980,"y":340,"wires":[]},{"id":"32de4617.9cccda","type":"comment","z":"5d1597b5.fb5dc8","name":"New event push from web","info":"Section that makes an endpoint to push new MQTT messages to from the web. \n\n\nExpects the format:\n```\n{ \"platform\": \"hubitat\",\n \"device\": \"MYDEVICE01\",\n \"attribute\": \"motion\",\n \"state\": \"active\"\n}\n```","x":190,"y":140,"wires":[]},{"id":"7ea6096c.3c5b98","type":"http in","z":"5d1597b5.fb5dc8","name":"","url":"/mqttweb/get","method":"get","upload":false,"swaggerDoc":"","x":230,"y":760,"wires":[["aa177cd2.30b0e"]]},{"id":"ba72a90.b2e0758","type":"mqtt in","z":"5d1597b5.fb5dc8","name":"","topic":"ha/+/+/+/cmd","qos":"2","broker":"d637a738.68b148","x":230,"y":900,"wires":[["cc6123c9.0c96a"]]},{"id":"23aa66ae.33552a","type":"comment","z":"5d1597b5.fb5dc8","name":"Retrieve Commands from MQTT","info":"","x":250,"y":820,"wires":[]},{"id":"cc6123c9.0c96a","type":"switch","z":"5d1597b5.fb5dc8","name":"","property":"$split(topic,\"/\")[1]","propertyType":"jsonata","rules":[{"t":"eq","v":"smartthings","vt":"str"},{"t":"eq","v":"hubitat","vt":"str"},{"t":"eq","v":"homeassistant","vt":"str"},{"t":"eq","v":"blueiris","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":5,"x":410,"y":900,"wires":[[],["fc823e26.9596e"],[],[],[]],"outputLabels":["smartthings","hubitat","homeassistant","","other"]},{"id":"fc823e26.9596e","type":"link out","z":"5d1597b5.fb5dc8","name":"MQTT to Hubitat Output","links":["14a9f701.a16fd9"],"x":675,"y":880,"wires":[]},{"id":"a71ddd30.56933","type":"link in","z":"5d1597b5.fb5dc8","name":"MQTT Output","links":["8947dadf.ddbf98","7d9f56e0.67f6b8","ba55732a.ddd17"],"x":575,"y":500,"wires":[["9fbd7e85.f1c4a","49662e81.790a5"]]},{"id":"1a76da84.b7b1f5","type":"config","z":"5d1597b5.fb5dc8","name":"","properties":[{"p":"config","pt":"flow","to":"{}","tot":"json"},{"p":"config.mqtt_prefix","pt":"flow","to":"ha","tot":"str"},{"p":"config.mqtt_state_suffix","pt":"flow","to":"state","tot":"str"},{"p":"config.mqtt_cmd_suffix","pt":"flow","to":"cmd","tot":"str"},{"p":"hubitat_ip","pt":"flow","to":"hassio","tot":"str"},{"p":"hubitat_maker_token","pt":"flow","to":"1234zxc","tot":"str"},{"p":"hubitat_maker_app_id","pt":"flow","to":"134","tot":"str"}],"active":true,"x":130,"y":80,"wires":[]},{"id":"8c9496c.3b57968","type":"http in","z":"5d1597b5.fb5dc8","name":"","url":"/mqttweb/discovery/:platform","method":"post","upload":false,"swaggerDoc":"","x":220,"y":600,"wires":[["8d77ff45.84c07","758251ce.f9c3b","b778284d.3df338"]]},{"id":"7ffcdadb.0683f4","type":"switch","z":"5d1597b5.fb5dc8","name":"","property":"req.params.platform","propertyType":"msg","rules":[{"t":"eq","v":"smartthings","vt":"str"},{"t":"eq","v":"hubitat","vt":"str"},{"t":"eq","v":"homeassistant","vt":"str"},{"t":"eq","v":"blueiris","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":5,"x":610,"y":660,"wires":[[],["25cd93f3.a1f65c"],[],["b4cf4686.7162b8"],[]],"outputLabels":["smartthings","hubitat","homeassistant","","other"]},{"id":"50022e4f.1f0ac","type":"link out","z":"5d1597b5.fb5dc8","name":"Hubitat Discovery to Home Assistant","links":["4f6d4959.d2fb78"],"x":1155,"y":680,"wires":[]},{"id":"8d77ff45.84c07","type":"change","z":"5d1597b5.fb5dc8","name":"","rules":[{"t":"set","p":"config","pt":"msg","to":"config","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":680,"wires":[["7ffcdadb.0683f4"]]},{"id":"9fbd7e85.f1c4a","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":670,"y":540,"wires":[]},{"id":"68615af5.ef4384","type":"link in","z":"5d1597b5.fb5dc8","name":"Web Bridge Discovery Input","links":["639f2b68.9ce224","94fd5f0e.ae487","791fa86b.6321b8"],"x":235,"y":660,"wires":[["8d77ff45.84c07"]]},{"id":"b4cf4686.7162b8","type":"change","z":"5d1597b5.fb5dc8","name":"","rules":[{"t":"set","p":"config.devicePrefix","pt":"msg","to":"BI","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":700,"wires":[["50022e4f.1f0ac"]]},{"id":"25cd93f3.a1f65c","type":"change","z":"5d1597b5.fb5dc8","name":"","rules":[{"t":"set","p":"config.devicePrefix","pt":"msg","to":"HE","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":840,"y":620,"wires":[["50022e4f.1f0ac"]]},{"id":"b778284d.3df338","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":710,"y":780,"wires":[]},{"id":"758251ce.f9c3b","type":"http response","z":"5d1597b5.fb5dc8","name":"","statusCode":"200","headers":{},"x":520,"y":580,"wires":[]},{"id":"aa177cd2.30b0e","type":"http response","z":"5d1597b5.fb5dc8","name":"","statusCode":"200","headers":{},"x":500,"y":760,"wires":[]},{"id":"54ed5b6.b1dfba4","type":"comment","z":"5d1597b5.fb5dc8","name":"Device Discovery","info":"","x":160,"y":560,"wires":[]},{"id":"1441e577.1bf58b","type":"link in","z":"5d1597b5.fb5dc8","name":"MQQT Event Push Input","links":["bab56929.0c4f78"],"x":175,"y":420,"wires":[["366e87e9.bdd828"]]},{"id":"3d6a1859.8cd618","type":"switch","z":"5d1597b5.fb5dc8","name":"Check for request","property":"res","propertyType":"msg","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":630,"y":300,"wires":[["8b72eb2e.0b7448"]]},{"id":"2f103c0d.489b34","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":1050,"y":400,"wires":[]},{"id":"ed020679.19a898","type":"websocket in","z":"5d1597b5.fb5dc8","name":"Hubitat Event Stream","server":"","client":"fe9107d9.d7c468","x":220,"y":1200,"wires":[["eb8a63f0.474ce"]]},{"id":"eb8a63f0.474ce","type":"json","z":"5d1597b5.fb5dc8","name":"","property":"payload","action":"obj","pretty":false,"x":410,"y":1200,"wires":[["e8da958a.d03778","dddff7e3.196968"]]},{"id":"c60c6981.421278","type":"change","z":"5d1597b5.fb5dc8","name":"convert event to our format","rules":[{"t":"set","p":"event","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"payload.device","pt":"msg","to":"event.deviceId","tot":"msg"},{"t":"set","p":"payload.attribute","pt":"msg","to":"event.name","tot":"msg"},{"t":"set","p":"payload.state","pt":"msg","to":"event.value","tot":"msg"},{"t":"set","p":"payload.platform","pt":"msg","to":"hubitat","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":740,"y":1200,"wires":[["bab56929.0c4f78"]]},{"id":"e8da958a.d03778","type":"switch","z":"5d1597b5.fb5dc8","name":"","property":"payload.source","propertyType":"msg","rules":[{"t":"eq","v":"DEVICE","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":550,"y":1200,"wires":[["c60c6981.421278"]]},{"id":"bab56929.0c4f78","type":"link out","z":"5d1597b5.fb5dc8","name":"Hubitat Event Stream Post Conversion","links":["1441e577.1bf58b"],"x":895,"y":1200,"wires":[]},{"id":"c7d09d2b.b6c08","type":"http request","z":"5d1597b5.fb5dc8","name":"","method":"GET","ret":"txt","url":"","tls":"","x":370,"y":1360,"wires":[["59dc9284.00075c"]]},{"id":"8ba133ed.fe51a","type":"change","z":"5d1597b5.fb5dc8","name":"","rules":[{"t":"set","p":"req.params.platform","pt":"msg","to":"hubitat","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":740,"y":1360,"wires":[["791fa86b.6321b8"]]},{"id":"791fa86b.6321b8","type":"link out","z":"5d1597b5.fb5dc8","name":"Hubitat Discovery Flow Out","links":["68615af5.ef4384"],"x":915,"y":1360,"wires":[]},{"id":"36d6ff89.99639","type":"inject","z":"5d1597b5.fb5dc8","name":"","topic":"","payload":"","payloadType":"date","repeat":"300","crontab":"","once":true,"onceDelay":0.1,"x":110,"y":1380,"wires":[["913ea46a.015ab8"]]},{"id":"2ea690c3.b11b","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":670,"y":1520,"wires":[]},{"id":"59dc9284.00075c","type":"json","z":"5d1597b5.fb5dc8","name":"","property":"payload","action":"obj","pretty":false,"x":510,"y":1360,"wires":[["8ba133ed.fe51a","2ea690c3.b11b"]]},{"id":"6e0f0033.7c64b","type":"comment","z":"5d1597b5.fb5dc8","name":"Websocket Event to MQTT","info":"May need to change your websocket definition if your hub has a different id or you don't have a dns server","x":230,"y":1140,"wires":[]},{"id":"fafdb19a.6174","type":"comment","z":"5d1597b5.fb5dc8","name":"Discover via Maker API","info":"","x":200,"y":1320,"wires":[]},{"id":"14a9f701.a16fd9","type":"link in","z":"5d1597b5.fb5dc8","name":"MQTT to Hubitat Input","links":["93acba0.f32c648","fc823e26.9596e"],"x":275,"y":1620,"wires":[["28088d0a.d10772"]]},{"id":"e49fd615.b32f68","type":"comment","z":"5d1597b5.fb5dc8","name":"Execute MQTT Commands","info":"","x":250,"y":1560,"wires":[]},{"id":"486b8571.734cfc","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":1010,"y":1560,"wires":[]},{"id":"28088d0a.d10772","type":"change","z":"5d1597b5.fb5dc8","name":"","rules":[{"t":"set","p":"deviceID","pt":"msg","to":"$split(topic, '/')[2]","tot":"jsonata"},{"t":"set","p":"attribute","pt":"msg","to":"$split(topic, '/')[3]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":1640,"wires":[["c4dc540f.354f98"]]},{"id":"eba9ad17.a980f","type":"change","z":"5d1597b5.fb5dc8","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"$join(\t [\t \"http:/\",\t $flowContext(\"hubitat_ip\"),\t \"apps/api\",\t $flowContext(\"hubitat_maker_app_id\"),\t \"devices\",\t deviceID,\t command\t \t ],\t '/'\t\t) & (\t $exists(parameter) ? (\"/\" & parameter) : \"\"\t) & \"?access_token=\" & $flowContext(\"hubitat_maker_token\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":1680,"wires":[["486b8571.734cfc","24ecc018.0d704"]]},{"id":"c4dc540f.354f98","type":"function","z":"5d1597b5.fb5dc8","name":"Set command","func":"switch(msg.attribute) {\n case 'switch':\n msg.command = msg.payload;\n break;\n case 'level':\n msg.command = \"setLevel\";\n msg.parameter = msg.payload;\n break;\n default: \n msg.command = msg.payload;\n break;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":630,"y":1660,"wires":[["eba9ad17.a980f"]]},{"id":"24ecc018.0d704","type":"http request","z":"5d1597b5.fb5dc8","name":"","method":"GET","ret":"txt","url":"","tls":"","x":1240,"y":1600,"wires":[["4a8bc556.2bb6ec"]]},{"id":"4a8bc556.2bb6ec","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1430,"y":1580,"wires":[]},{"id":"dddff7e3.196968","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":677.5,"y":1259,"wires":[]},{"id":"913ea46a.015ab8","type":"change","z":"5d1597b5.fb5dc8","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"$join(\t [\t \"http:/\",\t $flowContext(\"hubitat_ip\"),\t \"apps/api\",\t $flowContext(\"hubitat_maker_app_id\"),\t \"devices/all\"\t \t ],\t '/'\t\t) & (\t $exists(parameter) ? (\"/\" & parameter) : \"\"\t) & \"?access_token=\" & $flowContext(\"hubitat_maker_token\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":1420,"wires":[["c7d09d2b.b6c08","7625a9c1.bae908"]]},{"id":"f051d67c.9c3cd8","type":"comment","z":"5d1597b5.fb5dc8","name":"Hubitat Integration","info":"Handle listening to event stream, pulling devices to manage from the Maker API and processing commands from MQTT into Maker API calls","x":130,"y":1100,"wires":[]},{"id":"660429ee.773a88","type":"comment","z":"5d1597b5.fb5dc8","name":"Home Assistant Integration","info":"Parse device information and turn it into pushes to MQTT to support Home Assistant's native discovery. Should automatically create devices and entities in Home Assistant for whatever passes through as long as it matches the format. \n\nYou should not need to change the home assistant import config but it's there in case you want to add additional transforms, etc. ","x":130,"y":1740,"wires":[]},{"id":"4f6d4959.d2fb78","type":"link in","z":"5d1597b5.fb5dc8","name":"Discovery Input","links":["5eba5b74.300294","50022e4f.1f0ac"],"x":175,"y":2000,"wires":[["d915d6c0.eb08b8","f60ca12b.94306"]]},{"id":"ce2feda2.5d87a","type":"split","z":"5d1597b5.fb5dc8","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":430,"y":2020,"wires":[["87aeec0e.5061d","badc58bb.c0a658"]]},{"id":"87aeec0e.5061d","type":"change","z":"5d1597b5.fb5dc8","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"device","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":2060,"wires":[["3abdda7.9322726"]]},{"id":"2bc078c5.56fa98","type":"config","z":"5d1597b5.fb5dc8","name":"Home Assistant Import Config","properties":[{"p":"config.blacklist","pt":"flow","to":"DeviceWatch-DeviceStatus,checkInterval,indicatorStatus,dataType,values,lockCodes","tot":"str"},{"p":"config.bLookup","pt":"flow","to":"{\"water\":{\"device_class\":\"moisture\",\"payload_on\":\"wet\",\"payload_off\":\"dry\"},\"smoke\":{\"device_class\":\"smoke\",\"payload_on\":\"detected\",\"payload_off\":\"clear\"},\"motion\":{\"device_class\":\"motion\",\"payload_on\":\"active\",\"payload_off\":\"inactive\"},\"contact\":{\"device_class\":\"opening\",\"payload_on\":\"open\",\"payload_off\":\"closed\"},\"sound\":{\"device_class\":\"sound\",\"payload_on\":\"detected\",\"payload_off\":\"not detected\"},\"tamper\":{\"device_class\":\"vibration\",\"payload_on\":\"detected\",\"payload_off\":\"clear\"},\"carbonMonoxide\":{\"device_class\":\"safety\",\"payload_on\":\"detected\",\"payload_off\":\"clear\"},\"shock\":{\"device_class\":\"safety\",\"payload_on\":\"detected\",\"payload_off\":\"clear\"},\"vibration\":{\"device_class\":\"vibration\",\"payload_on\":\"detected\",\"payload_off\":\"clear\"},\"acceleration\":{\"device_class\":\"moving\",\"payload_on\":\"detected\",\"payload_off\":\"clear\"}}","tot":"json"},{"p":"config.sLookup","pt":"flow","to":"{\"temperature\":{\"unit_of_measurement\":\"°F\"},\"battery\":{\"unit_of_measurement\":\"% B\",\"icon\":\"mdi:battery\"},\"power\":{\"unit_of_measurement\":\"W\"},\"voltage\":{\"unit_of_measurement\":\"V\"},\"humidity\":{\"unit_of_measurement\":\"% H\",\"icon\":\"mdi:water-percent\"},\"energy\":{\"unit_of_measurement\":\"kWh\"},\"illuminance\":{\"unit_of_measurement\":\"lux\",\"icon\":\"mdi:brightness-5\"},\"powerLow\":{\"unit_of_measurement\":\"W\"},\"powerHigh\":{\"unit_of_measurement\":\"W\"},\"current\":{\"unit_of_measurement\":\"A\"},\"currentLow\":{\"unit_of_measurement\":\"A\"},\"currentHigh\":{\"unit_of_measurement\":\"A\"},\"amperage\":{\"unit_of_measurement\":\"A\"}}","tot":"json"},{"p":"config.sDefaults","pt":"flow","to":"{\"force_update\":true}","tot":"json"},{"p":"config.customize","pt":"flow","to":"{}","tot":"json"},{"p":"config.ha_prefix","pt":"flow","to":"homeassistant","tot":"str"},{"p":"config.device_name_prefix","pt":"flow","to":"HE","tot":"str"}],"active":true,"x":190,"y":1840,"wires":[]},{"id":"342ae531.54249a","type":"split","z":"5d1597b5.fb5dc8","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"attributeName","x":570,"y":2360,"wires":[["e4ca37f6.5c81b8"]]},{"id":"e4ca37f6.5c81b8","type":"function","z":"5d1597b5.fb5dc8","name":"create home assistant mqtt discovery config message","func":"var config = flow.get('config');\nvar platform = '';\n\n\n//var node_id = msg.device.id + '_' + msg.attributeName;\nvar node_id = msg.req.params.platform + '-' + msg.device.id;\n//var ob_id = msg.device.id + ((['level','switch'].indexOf(msg.attributeName) == -1)? `_${msg.attributeName}` : '');\n//var ob_id = node_id + '_' + msg.attributeName;\nvar ob_id = msg.attributeName;\nvar friendly_name = msg.device.label + ((['level','switch'].indexOf(msg.attributeName) == -1)? ` ${msg.attributeName}` : '');\n\nvar c = {};\n\n\n// Setup base config object with friendly name\nvar e = {\n //\"name\": msg.config.devicePrefix + ' ' + friendly_name,\n \"unique_id\": node_id + '-' + ob_id,\n \"device\": msg.device.config,\n \"name\": friendly_name\n};\n\n//set topic prefix for actual device communication vs the config topic\nvar topicPrefix = [msg.config.mqtt_prefix, msg.req.params.platform, msg.device.id].join('/');\n\n// Add specific settings for the light platform\nif (msg.attributeName == 'level'){\n e.brightness_state_topic= [topicPrefix,'level',msg.config.mqtt_state_suffix].join('/');\n e.brightness_command_topic= [topicPrefix,'level',msg.config.mqtt_cmd_suffix].join('/');\n e.brightness_scale= 99;\n platform = 'light';\n} \n\n// Add specific settings for both light and the switch platform\nif (['level','switch'].indexOf(msg.attributeName) > -1){\n e.command_topic= [topicPrefix,'switch',msg.config.mqtt_cmd_suffix].join('/');\n e.payload_on =\"on\";\n e.payload_off= \"off\";\n e.state_topic = [topicPrefix,'switch',msg.config.mqtt_state_suffix].join('/');\n if (msg.attributeName == 'switch')\n platform = 'switch';\n}\nelse {\n // We're setting up a sensor attribute\n e.state_topic = [topicPrefix,msg.attributeName,msg.config.mqtt_state_suffix].join('/');\n \n // Add specific settings if it matches our binary sensor list\n if(msg.attributeName.match(config.bReg)){\n var binary_lookup = flow.get('config.bLookup');\n Object.assign(e,binary_lookup[msg.attributeName]);\n platform = 'binary_sensor';\n }\n \n // Or Add specific sensors if we match our known sensor type list\n else if(msg.attributeName.match(config.sReg)){\n var sensor_lookup = flow.get('config.sLookup');\n e = Object.assign({},config.sDefaults,sensor_lookup[msg.attributeName],e);\n platform = 'sensor'\n }\n // Or Treat it as a generic sensor\n else {\n platform = 'sensor';\n e = Object.assign({},config.sDefaults,e);\n }\n}\n\n\nvar topic =\n [\n config.ha_prefix,\n platform,\n node_id,\n ob_id,\n 'config'\n ].join('/');\n\n\n\n/*var payload = {\n \"topic\": topic,\n \"content\": e,\n //\"entity\": platform + '.' + ob_id\n \"entity\": platform + '.' + friendly_name.replace(/\\s+/g, '_').replace(/[^A-z0-9\\s]/g,'').toLowerCase()\n};\n*/\n\nmsg.topic = topic;\nmsg.payload = e;\n\nreturn msg;","outputs":1,"noerr":0,"x":760,"y":2460,"wires":[["e9c3174b.4c0378"]]},{"id":"3abdda7.9322726","type":"change","z":"5d1597b5.fb5dc8","name":"Clear Device Split and Prepare to Process Attrs","rules":[{"t":"set","p":"payload","pt":"msg","to":"device.attributes","tot":"msg"},{"t":"delete","p":"parts","pt":"msg"},{"t":"delete","p":"device.attributes","pt":"msg"},{"t":"set","p":"device.config","pt":"msg","to":"{\t\"name\": device.label,\t\"identifiers\": [$join([req.params.platform, device.id], '-')]\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":2120,"wires":[["1d0be0e7.eb2aff","eb6ad0c8.f81a7"]]},{"id":"badc58bb.c0a658","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":670,"y":1980,"wires":[]},{"id":"d915d6c0.eb08b8","type":"function","z":"5d1597b5.fb5dc8","name":"Prepare regex","func":"\nvar config = flow.get('config');\n\nconfig.sReg = '^(' + Object.keys(config.sLookup).join('|') + ')$';\nconfig.bReg = '^(' + Object.keys(config.bLookup).join('|') + ')$';\n\n\n//node.log(`binary lookup is: ${JSON.stringify(config.bLookup)}`);\n//node.log(`sensor lookup is: ${JSON.stringify(config.sLookup)} `);\n\n\n\nflow.set('config', config);\n/*\nfunction filterSwitch(t, cur, ind, arr) {\n //var lightFound = arr.some(checkLight);\n //var lightFound = arr.some(x => x.name === 'level');\n var re= new RegExp('(^|,)'+ cur.name+'(?:,|$)');\n\tif ( (cur.name == \"switch\" && arr.some(x => x.name === 'level')) || (processed.includes(cur.name)) || (flow.get('config.blacklist').match(re)) ){\n \t//node.log(`found switch and checklight is true. t= ${JSON.stringify(t)}`);\n \treturn t;\n }\n else {\n processed.push(cur.name);\n return t.concat(cur);\n }\n}\n\n\n\nvar processed = [];\nmsg.payload = msg.device.attributes.reduce(filterSwitch, []); \n\nnode.log('attributes are: '+ JSON.stringify(msg.payload));\n*/\nreturn msg;","outputs":1,"noerr":0,"x":240,"y":2120,"wires":[["ce2feda2.5d87a"]]},{"id":"f60ca12b.94306","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":410,"y":1920,"wires":[]},{"id":"ba55732a.ddd17","type":"link out","z":"5d1597b5.fb5dc8","name":"","links":["a71ddd30.56933"],"x":1135,"y":2280,"wires":[]},{"id":"e9c3174b.4c0378","type":"json","z":"5d1597b5.fb5dc8","name":"","property":"payload","action":"str","pretty":false,"x":790,"y":2380,"wires":[["ba55732a.ddd17","9210b506.66eec8"]]},{"id":"ec73bb7f.df7a18","type":"change","z":"5d1597b5.fb5dc8","name":"Pass current state to MQTT","rules":[{"t":"set","p":"topic","pt":"msg","to":"$join([config.mqtt_prefix, req.params.platform, device.id,attributeName,config.mqtt_state_suffix],'/')","tot":"jsonata"},{"t":"set","p":"retain","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":820,"y":2280,"wires":[["ba55732a.ddd17"]]},{"id":"fc9f79f2.630ec8","type":"comment","z":"5d1597b5.fb5dc8","name":"Discovery Processing","info":"Process discovery notifications from the bridge and create new devices","x":100,"y":1960,"wires":[]},{"id":"9210b506.66eec8","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1090,"y":2360,"wires":[]},{"id":"1d0be0e7.eb2aff","type":"function","z":"5d1597b5.fb5dc8","name":"Dedupe lights and switches and remove blacklisted attributes","func":"\nvar blacklist = flow.get('config.blacklist');\n\nfunction filterSwitch(t, cur, ind, arr) {\n var re= new RegExp('(^|,)'+ cur+'(?:,|$)');\n\tif ( (cur == \"switch\" && arr.some(x => x === 'level')) || blacklist.match(re) ){\n \t//node.log(`found switch and checklight is true. t= ${JSON.stringify(t)}`);\n \tdelete msg.payload[cur];\n \treturn t;\n }\n else {\n return t.concat(cur);\n }\n}\n\n\nObject.keys(msg.payload).reduce(filterSwitch, []); \n\n//node.log('attributes are: '+ JSON.stringify(msg.payload));\n\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":2280,"wires":[["342ae531.54249a"]]},{"id":"eb6ad0c8.f81a7","type":"split","z":"5d1597b5.fb5dc8","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"attributeName","x":630,"y":2220,"wires":[["ec73bb7f.df7a18"]]},{"id":"3330818b.7064ce","type":"comment","z":"5d1597b5.fb5dc8","name":"Create Home Assistant Discovery MQTT Entries","info":"","x":240,"y":2200,"wires":[]},{"id":"49ebdba.8462f24","type":"comment","z":"5d1597b5.fb5dc8","name":"Pass current states of attributes if we have them","info":"","x":960,"y":2200,"wires":[]},{"id":"7625a9c1.bae908","type":"debug","z":"5d1597b5.fb5dc8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":440,"y":1480,"wires":[]},{"id":"bf1e703c.9276e","type":"comment","z":"5d1597b5.fb5dc8","name":"","info":"","x":120,"y":40,"wires":[]},{"id":"d637a738.68b148","type":"mqtt-broker","z":"","name":"hassio","broker":"hassio","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"fe9107d9.d7c468","type":"websocket-client","z":"","path":"ws://hubitat/eventsocket","tls":"","wholemsg":"false"}]
3 Likes

Hey thanks @chris, I have tried this and it's working pretty well. I previously created a similar nodeRED flow converting the 'homie3' MQTT discovery protocol into HomeAssistant's discovery protocol (homie3 is a vendor agnostic alternative to the HA MQTT discovery protocol).
This was really to link the Athom Homey home controller into HA, there is an app that does the reverse too i.e. HA devices into Homey.

Very interested in this Chris as I would like the same. I am not sure it will be too easy via hub link - even though that's ideally where it should be done to keep things tidy. Such a shame to have to create yet another Hubitat link app that does almost the same things .. via virtual devices.

keep me posted... Kevin

Thank you very much for sharing Chris! I've only been running it for a few hours now but already like the results. I had quite a few issues with the MQTT bridge Hubitat-HomeAssistant a few weeks back which made me try local HA zha and z-wave. I upgraded to the lastest Hassio and it messed up my zigbee buttons (which barely worked to begin with). So I decided to put the hubitat (Nortek) USB zigbee stick back in the hubitat and try to make them talk to each other again. And here we are.... Thanks again!

@chris
This is brilliant
I wish to keep my NodeRed installation on my HA and use for interface and then hubitat to slowly replace the WINK2.... but if I can run both alongside eachother with the HA controlling both = heaven.

HI @chris
I imported the NodeRed flow into my HA installation and I see the config node being set as unknown.
"This node is a type unknown to your installation of Node-RED."
What am I missing for a pallet?

Ok I tried installing the following:

That should be the right one. I use that node to make it easier to share things, but setting flow variables in one place right at startup without having to edit any files.

1 Like

Does this go from:
Hubitat Maker API -> Node-Red -> MQTT Broker -> Home Assistant?
Trying to follow this.
Is it bidirectional?

1 Like

@chris does this work with the Mosquitto broker as well on HA?
also echoing @keithcroshaw here is it bidirectional?

Thanks @chris this is working perfectly. Probably a bit late but yes communication is bi-directional. In addition to what chris mentioned you should also make sure that your base topic matches the mqtt discovery prefix in homeassistant. That caught me out because I was already using devices that publish to 'homeassistant' rather than 'ha'. Changed that and everything is working great. Communication is very fast.