123
Senior Member
Back in December, in the Roll Call thread, I made a passing reference to MQTT and how I wished Premise supported it. After quite a bit of code-wrestling (and it's not over yet) I'm pleased to report I've taught Premise to speak fluent MQTT.
In a nutshell, if a Light's Brightness changes from 0.25 to 0.75 (25% to 75%) Premise will announce it via MQTT. Anything external to Premise that speaks MQTT is able to receive the message (like another Home Automation system, a UI client, a relay, etc). Premise also listens for MQTT messages and will act on them. For example, it can receive an MQTT message to set the Light's Powerstate to off.
In an ideal world, I would've implemented this new functionality as a native Premise driver. However, I was unwilling to invest the substantial time needed to write a driver in C++ and incorporate all the finer points of the MQTT protocol. It was too steep a learning curve (for me). I turned to open-source software to get the job done. In other words, this solution requires another resource to work. That resource is Node-Red. I have it running on a Raspberry Pi but there's a version available for Windows (which I have not tried).
Unfamiliar with Node-Red? It's called the 'Visual wiring tool for the Internet of Things'. Here's an entertaining tutorial:
https://www.youtube.com/watch?v=WxUTYzxIDns
I created a driver called SyseventBroker (implemented as a Module) that sends/receives data to Node-Red via TCP. All of Premise's state-changes (sysevents) are transmitted, in JSON format, to Node-Red. A 'flow' in Node-Red converts it into an MQTT message and 'publishes' it to an MQTT Broker (more open-source software in the form of Mosquitto running on the Raspberry Pi). The same flow receives MQTT messages and converts them into a format more palatable to Premise. The flow sends them to SyseventBroker (via TCP) which converts them into actions (turn lights on/off, adjust the thermostat, arm the security panel, etc).
It may look like there are many links in this chain but the transit time is virtually instantaneous.
[ Light turns ON --(sysevent)--> SyseventBroker ] ===(TCP)===> [ Node-Red --(flow)--> MQTT ] ===(TCP)===> [ Mosquitto MQTT Broker ] ===(TCP)===> [ MQTT Client ]
The first challenge I encountered is that Premise has no 'sysevent highway'. By that I mean there's no single place where you can monitor all sysevents (state-changes) taking place within Premise. If there is such a place, I'm unaware of it. My solution was to extend each and every Device class. Now when any Device's property changes state, it reports it directly to SyseventBroker. In turn, SyseventBroker passes the state-change on to Node-Red which publishes it as an MQTT message.
There's still work to be done. For starters there's still much more testing I want to do because I've already learned, the hard way, that its possible to create a nasty little feedback loop. How? Easy, if you're handling temperature values! Premise stores temperature in Kelvin, so if you send it out via MQTT in Fahrenheit (for convenience), it'll get echoed back to Premise in Fahrenheit. Except Premise will handle it as Kelvin! This causes another state-change that is sent out in Fahrenheit, echoed back in Fahrenheit, treated like Kelvin and ... the whole mess goes round and round like this until you stop it. I've mitigated the endless looping but not the problem of receiving temperature in Fahrenheit or Celsius (it *must* be in Kelvin). It's glitches like this that may demand design changes so more testing is needed.
I also want to add a 'heartbeat' function to SyseventBroker so that it can monitor the health of its TCP connection to Node-Red.
In a nutshell, if a Light's Brightness changes from 0.25 to 0.75 (25% to 75%) Premise will announce it via MQTT. Anything external to Premise that speaks MQTT is able to receive the message (like another Home Automation system, a UI client, a relay, etc). Premise also listens for MQTT messages and will act on them. For example, it can receive an MQTT message to set the Light's Powerstate to off.
In an ideal world, I would've implemented this new functionality as a native Premise driver. However, I was unwilling to invest the substantial time needed to write a driver in C++ and incorporate all the finer points of the MQTT protocol. It was too steep a learning curve (for me). I turned to open-source software to get the job done. In other words, this solution requires another resource to work. That resource is Node-Red. I have it running on a Raspberry Pi but there's a version available for Windows (which I have not tried).
Unfamiliar with Node-Red? It's called the 'Visual wiring tool for the Internet of Things'. Here's an entertaining tutorial:
https://www.youtube.com/watch?v=WxUTYzxIDns
I created a driver called SyseventBroker (implemented as a Module) that sends/receives data to Node-Red via TCP. All of Premise's state-changes (sysevents) are transmitted, in JSON format, to Node-Red. A 'flow' in Node-Red converts it into an MQTT message and 'publishes' it to an MQTT Broker (more open-source software in the form of Mosquitto running on the Raspberry Pi). The same flow receives MQTT messages and converts them into a format more palatable to Premise. The flow sends them to SyseventBroker (via TCP) which converts them into actions (turn lights on/off, adjust the thermostat, arm the security panel, etc).
It may look like there are many links in this chain but the transit time is virtually instantaneous.
[ Light turns ON --(sysevent)--> SyseventBroker ] ===(TCP)===> [ Node-Red --(flow)--> MQTT ] ===(TCP)===> [ Mosquitto MQTT Broker ] ===(TCP)===> [ MQTT Client ]
The first challenge I encountered is that Premise has no 'sysevent highway'. By that I mean there's no single place where you can monitor all sysevents (state-changes) taking place within Premise. If there is such a place, I'm unaware of it. My solution was to extend each and every Device class. Now when any Device's property changes state, it reports it directly to SyseventBroker. In turn, SyseventBroker passes the state-change on to Node-Red which publishes it as an MQTT message.
There's still work to be done. For starters there's still much more testing I want to do because I've already learned, the hard way, that its possible to create a nasty little feedback loop. How? Easy, if you're handling temperature values! Premise stores temperature in Kelvin, so if you send it out via MQTT in Fahrenheit (for convenience), it'll get echoed back to Premise in Fahrenheit. Except Premise will handle it as Kelvin! This causes another state-change that is sent out in Fahrenheit, echoed back in Fahrenheit, treated like Kelvin and ... the whole mess goes round and round like this until you stop it. I've mitigated the endless looping but not the problem of receiving temperature in Fahrenheit or Celsius (it *must* be in Kelvin). It's glitches like this that may demand design changes so more testing is needed.
I also want to add a 'heartbeat' function to SyseventBroker so that it can monitor the health of its TCP connection to Node-Red.