Node-RED as Alternative Rule Engine

rules
node-red
Tags: #<Tag:0x00007f212ef6e5b8> #<Tag:0x00007f212ef6e3b0>

(Rgerrans) #1

Node-RED is a visual wiring tool for the Internet of Things.”

From an Openhab perspective it a visual tool that can replace the builtin rules engine.

There is a good discussion thread already running here around Node-RED. The purpose of this tutorial is specifically how to replace the functionality of the Openhab rules engine with Node-RED utilizing @Peter_De_Mangelaere‘s nodes for easily connecting to Openhab.

Update 8/18 I have fully migrated my deployment over to MQTT using the built in MQTT nodes (http://noderedguide.com/tag/mqtt/#h.5zaw60nvfsyj) You just need to replace any input / ouput nodes in the below example with MQTT nodes. The one item of note is you can’t (or at least I haven’t figured out how to) request a status from the MQTT broker like you can in the OpenHAB nodes. Instead you have to store any state information in a Node-RED flow or global variable like I defined below.

As of OpenHabian v1.3, node-red is now part of the standard package.

In addition to the Openhab nodes, I’d highly recommend installing the BigTimer node. With these in place you can replicate all the functionality of the current rule capabilities of Openhab. The following is a breakdown of the OH rules capabilities and how to replicate them in Node-RED.

I also just found another set of contributed nodes to help with home automation, norelite - https://flows.nodered.org/node/norelite I will start experimenting with them and likely update this tutorial to incorporate their functionality in place of some of my workarounds (like stored variables).

This is just meant as a starting point based on my first few weeks working with Node-RED. There is still much more to cover and I will try to continue to update this over time as I learn new ways of using the tools.

Table of Contents

Rule Triggers

In Openhab, here are different categories of rule triggers:

  • Item(-Event)-based triggers: They react on events on the openHAB event bus, i.e. commands and status updates for items
  • Time-based triggers: They react at special times, e.g. at midnight, every hour, etc.
  • System-based triggers: They react on certain system statuses.

Event-based Triggers
The following shows each of the different Event-based Trigger types in Openhab and how to replicate them in Node-Red

Item <item%gt; received command [<command>] / Item <item> received update [<state>]
STATUS CHANGE:
To capture a change in an item’s state in Node-Red (note, if the state doesn’t change, i.e. an update with the same state, this trigger won’t work), you use an Openhab2 In node from the Home_Automation section of your node pallet.

These nodes track send a message that contains the item’s state every time it changes from the top channel, and a full output of all the data associated with the items change in state from the bottom channel. Connecting to the top channel creates the same trigger event as the “Item received command” or “Item received update” triggers in Openhab. To limit the trigger to a specific “[]” or “[]” you need to add a Switch node and connect it to the first channel.

This switch node can now be setup to reflect the command(s) that you want to trigger an event on by setting logic equal to the [] or “[]” you want to base your trigger on. Each additional rule you add creates an additional output channel on the switch corresponding to the order of your rules in the node.

NO STATUS CHANGE:
If you want to catch when an item has been updated but the actual state of the item might be the same after the command or update, then you have to take a different approach. You need to use the second channel of an Openhab2 In node and add a switch node to look for an update to the status.

Item <item> changed [from <state>] [to <state>]
To create a trigger around an item state being changed you need to use the second channel of an Openhab2 In node. If all you want to do is trigger an event when an item is changed irrespective of the from/to, you need to evaluate if the node received a changed state event.

If you want to evaluate a change from a specific value, then you can use a switch which evaluates the “msg.payload.payload.oldValue” property to read the old state to create a “Item changed [from ]” trigger.

Similarly, if you want to evaluate the “[to <state>]” you need to add a second switch that checks the “msg.payload.payload.value” property.

If you also want to evaluate both the “[from <state>]” and “[to <state>]” you need to put these switches in serial to create the equivalent of an “and” condition in “if statement”

Time-based triggers
To create rules to trigger at a specific time like the Openhab “Time cron <cron expression>" trigger, is where the addon node BigTimer comes in. This node not only replaces the Time based triggers but also sunrise / sunset based triggers that you would normally use the Astro Binding for.

From the BigTimer info:

Bigtimer is probably the ultimate Node-Red timer, sending messages for start and end conditions at any time, day, month or special day.
In the simplest case, Bigtimer requires no input and you need only to consider the first output. But Bigtimer can be much more.
The first output sends out a message at your set ON or OFF times (and if the repeat tickbox is ticked - every minute)
The second output simply sends the state - 1 or 0 every minute as well as echoing the status in msg.state and msg.time. (from v1.5.6 onwards several properties have been added to msg)
The third output sends an optional message for both states - suitable for speech output or a log (this happens only at ON or OFF time).
The input can be used as an override.

System-based triggers
I have not yet experimented with System-based triggers but will update this section if/when I do.

Scripts

Scripts in OpehHab are the portion after the trigger where you design the additional logic and actions of your rules. I’ve tried to capture as many common types of script actions as possible below and will continue to add to this list based on feedback to this tutorial and my own experience.

Variables
In Node-Red you have two different types of variables:

  • Flow Variables (or in Node-Red speak Flow Context) - are available to any flows on a tab. This is similar to how a variable defined in a rule file is available to any rules contained within that file
  • Global Variables (Global Context) - these variables are available to any flows within your Node-Red deployment. These replace the virtual switches that most people use to store variables across rules files.

To define a variable in Node-Red, you utilize the Change nodes.

You can either transfer the payload (state) from the item node:

or enter a set value:

If…then Statements
In Node-Red you utilize the Switches to replicate If…Then statements from Openhab rules. To replicate multiple “and (&&)” or “or (||)” checks you use either serial (and) or parallel (or) flows. Or in this case if((Check1 || Check2) && Check3 && Check4)

Each Switch can either check the value of the item coming in or the value of a Flow or Global variable.

If you want to base your checks on the status of other items in OpenHab, you have two ways to do this. One option is to assign a state change to a variable as shown above (Variables)

The other is to use an openhab2-get node to lookup the item’s state. Because this node returns a single response object containing item name, label, state, etc. You then need to do a logic check on a slightly modified topic to specify which you want to use.



Case Statements
Do to the fact that a single Switch node can evaluate an item state or variable against multiple conditions, it is easy to use these to replicate a Case Statement.

Actions
Actions are the core of Openhab rules within the Script section. Here are how to reproduce the Core Actions from Openhab within NodeRed.

Event Bus Related Actions
[.sendCommand() / .postUpdate()]

In the Openhab2 Nodes there is are openhab2-out nodes for sending commands or updates to Items. To specify the or you can either use the msg.payload coming in from your previous nodes, change it before it gets to the openhab2-out node using a Change node, or use the Payload override field within the openhab2-out node. To specify whether you are doing a sendCommand or postUpdate you can either specify it in the your msg.topic upstream of the openhab2-out node or use the Topic property of the node to specify.

Timers
Timers are used for a number of different scenarios in Openhab. I’ve tried to capture many of those scenarios below and how to reproduce them in Node-Red.

Delay an Action
Most timers are used to delay a specific action until a relative later point in time (i.e. turning off a light after a specific time interval). Node-Red has a Delay node for performing this same time of set time delay.

Block Other Actions During a Defined Time Period
Many times in Openhab when you don’t want an action occurring within a certain time frame of a previous action, you do so by setting a timer in the first action and then checking if a timer is still active when a second action tries to occur. In Node-Red there are a couple of different ways to accomplish this depending on some of the nuances involved. One is to use a “Rate Limit” within a delay and telling the delay to drop any messages that come in during the delay.

You can also use the Trigger node in Node-Red. These nodes are very flexible, allowing you to send actions at the start of a time period or at the end or during both. You can also extend the triggers if certain events happen. So for example if you have a motion sensor trigger a light on and then want it to turn off after the last trigger from your motion sensor you could use a trigger as follows:

As you’ll see, there are many different ways with Delays and Triggers that you can approach solving the same problem.

Logging
Logging is one of the big strengths of Node-Red. You can create immediate Debug outputs that you can see from the edit window or to File nodes to write entries to an external log file.

Notifications

While Node-RED has some addon Nodes to help support different types of notifications, I wanted to still be able to leverage some of the built in functionality of OpenHAB as well. This required setting up necessary OpenHAB items and rules to interfact into OpenHAB’s functionality.

Broadcast Notifications
Through the OpenHAB Cloud Connector http://docs.openhab.org/addons/io/openhabcloud/readme.html you are able to use the mobile apps to both access your system and receive broadcast notifications http://www.myopenhab.org/. To integrate this into Node-RED requires an item to carry the notification information and a rule to trigger the notification.

Item Definition:

String  vNotification  "Notification [%s]"`

Notifications.rules:

rule "Send Notification"
when
	Item vNotification received update
then
	sendBroadcastNotification(vNotification.state.toString)
end

And finally a Node-RED flow to send the notification. Here I used a change node to create my text message:
image
image

You can also use the template node to include other payloads or topics into your notification message:
image
image

If you want to add a time stamp to your message I was able to put together the following to create a plain language time stamp (i.e. 3:32 pm)


For cut-and-paste purposes:

msg.payload =  msg.payload + new Date().toLocaleTimeString('en-US',{timeZoneName: 'short'});
return msg;

Audio & Voice
OpenHAB has the ability to play audio files and convert text-to-speech: http://docs.openhab.org/configuration/multimedia.html. To take advantage of this integration we follow a similar approach as we did for the Broadcast Notifications above using a combination of a custom item and a rule combined with a Node-RED flow.

First to trigger a text-to-voice (assuming you have already setup everything in OpenHAB as per above).

Item Definition:

String vSpeech

Speech.rules:

rule "Send Speech"
when
Item vSpeech received update
then
say(vSpeech.state.toString)
end

And finally a NodeRed flow to tie it together.
image

I went a step further with mine to control the volume levels during and after sending speech (turning it up while the speech is broadcast and turning it back down). So I created a sub-flow (https://github.com/node-red/node-red/wiki/Design:-subflows
image
image

Similarly for sending an Audio file saved to your conf/sounds directory:

Item Definition:

String vSound

Sound.rules:

rule "Send Sound"
when
	Item vSound received update
then
    playSound(vSound.state.toString)
end

And Node-RED flow:
image
image

Email
For email you can choose to use the SendMail binding http://docs.openhab.org/addons/actions/mail/readme.html or alternatively you can do it directly from Node-RED using the email node https://flows.nodered.org/node/node-red-node-email. The one trick I did apply here is I didn’t want to configure each node instance with my smtp server information and I wanted the ability to turn on and off the ability to send email (so I didn’t spam my wife when I was testing) so instead created an email subflow and a control flow.

Email Subflow:
image
image
image

Control Flow:
image
image
image

Change Log
06.27.2017

  • Updated Item <item> changed [from <state>] [to <state>]
  • Fixed missing <>
  • Revised Item <item%gt; received command [<command>] / Item <item> received update [<state>] to differentiate between a change in status vs. just an update (where the status might not change)
    07.04.2017
  • Updated * If…then Statements to include the openhab-get node for checking item state
    08.03.2017
  • Added reference to node-red nodes - norelite
    08.18.2017
  • Added Notifications Section
  • Added notes on integrating with MQTT

Node-RED as a rule/script engine for openHAB
Washing Machine State Machine
Defining 'things' in paper UI and code
Node-RED as a rule/script engine for openHAB
Multiple events from one change to group
Controlling OpenHAB by Telegram?
Anyone has created a Scene using Tasmota Sonoff Switch
Finding the Xtend syntax really frustrating for writing rules. Can I write rules in another scripting language?
Testers for Verisure openHAB 2 binding
Install OpenHab on Windows or Ubuntu?
Do i missed something / menu and theme not available
Alexa skills using a Local MyOpenHAB server
Node-RED as a rule/script engine for openHAB
(steve1) #2

Looks very interesting. Does Node-RED support turning flows into nodes that can be displayed in the side bar? A related question is whether a flow can be parameterized and reused by instantiating a flow with specific parameters. For example, if I have a complex flow for a type of device and I have 20 of those devices, can I create a flow component that can be reused for each device by just specifying the device-specific parameters for each device?


(Rgerrans) #3

I haven’t played with them yet but Node-RED has the concept of sub-flows which are reusable flows that are treated like a node in your main flows - https://github.com/node-red/node-red/wiki/Design:-subflows


(Eurico Borges) #4

You should put this info in the Wiki. not just in the forum.


(Rgerrans) #5

Which Wiki?


(Eurico Borges) #6

I was thinking on http://docs.openhab.org/tutorials/


( ) #7

Hey @rgerrans, great to see this thread after just a few days!! :wink:

@eurico_borges I’d prefer the tutorials to stay in the “Tutorials & Examples” section. This way people can discuss solutions and related problems as well as post related solutions or alternatives. The article can also be modified and updated more easily here.

However, I’d be happy to include the tutorial in the list of recommended tutorials in the second half of: http://docs.openhab.org/tutorials


(steve1) #8

Maybe I missed something, but BigTimer doesn’t seem to completely replace cron triggers since the time specifications are at the minute resolution. For higher resolution triggers (e.g., every 15 seconds) there is a cron node in Node-RED.


(Joe Lawrence) #9

Can the two rule engines co-exist??? IE Can I use both?


(Rgerrans) #10

Good catch. BigTimer looks to me to be more of an on/off timer (with minute heart beat which I find useful for resetting my schedule status following a restart). It doesn’t look like it’s designed to do repeat triggers. That’s one nice thing about Node-RED is all the different contributed nodes.

In addition to the cron nodes, you could also just put a loop with a timed delay in your flow to cause a repeat during your on window. Like this:

Edit: Just realized this approach won’t turn off. There should be a way with a trigger instead of a delay to inject an off into the flow, Will have to play with it later,


(Rgerrans) #11

Yes. I’m running mine in parallel while I transition my rules over.

In addition, I created an OH rule/virtual text item last night to be able to do a sendBroadcastNottification going forward so that I can still send notifications to the OH Mobile App once i migrate all my rules to node-RED so I anticipate still using the OH rules for at least that (I’ll add it to the tutorial when I get a gap of free time).


(Joe Lawrence) #12

Thanks, you’re doing exactly what I was looking to do. Always good to have extra tools!!


(Rgerrans) #13

Ok, got a chance to play some more and went with a trigger so that I could use the off from BigTimer to stop the trigger. Needed to add a slight delay otherwise it would get ahead of itself and stop early:

[{"id":"74a1374d.a28838","type":"bigtimer","z":"864e4169.fd187","outtopic":"","outpayload1":"","outpayload2":"","name":"Big Timer","lat":"39","lon":"-104","starttime":"840","endtime":"840","startoff":"38","endoff":"39","offs":0,"outtext1":"ON","outtext2":"OFF","timeout":1440,"sun":true,"mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"jan":true,"feb":true,"mar":true,"apr":true,"may":true,"jun":true,"jul":true,"aug":true,"sep":true,"oct":true,"nov":true,"dec":true,"day1":0,"month1":0,"day2":0,"month2":0,"day3":0,"month3":0,"day4":0,"month4":0,"day5":0,"month5":0,"d1":0,"w1":0,"d2":0,"w2":0,"d3":0,"w3":0,"d4":0,"w4":0,"d5":0,"w5":0,"suspend":false,"random":false,"repeat":true,"atstart":true,"x":257,"y":1821.5,"wires":[[],["e4d8d363.87072"],[]]},{"id":"e4d8d363.87072","type":"rbe","z":"864e4169.fd187","name":"","func":"rbe","gap":"","start":"","inout":"out","x":445,"y":1823,"wires":[["32ddf819.85a888"]]},{"id":"a3d03eb1.e04cd","type":"debug","z":"864e4169.fd187","name":"Test","active":true,"console":"false","complete":"payload","x":860,"y":1823,"wires":[]},{"id":"6de1b43b.0e8f0c","type":"trigger","z":"864e4169.fd187","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"5","extend":false,"units":"s","reset":"0","name":"","x":735,"y":1964,"wires":[["32ddf819.85a888"]]},{"id":"32ddf819.85a888","type":"switch","z":"864e4169.fd187","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"0","vt":"str"}],"checkall":"true","outputs":2,"x":637,"y":1823,"wires":[["a3d03eb1.e04cd","3cc6d2d5.1ceb5e"],["3cc6d2d5.1ceb5e"]]},{"id":"3cc6d2d5.1ceb5e","type":"delay","z":"864e4169.fd187","name":"","pauseType":"delay","timeout":"250","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":581,"y":1965,"wires":[["6de1b43b.0e8f0c"]]}]

(Joe Lawrence) #14

This is the best tuturial I found for installing Node-Red on a Windows machine. Node-Red Windows install


(Joe Lawrence) #15

Also the Windows installs to the following directory as the Node-Red “root” for lack of a better term:

C:\Users\Username\AppData\Roaming\npm\node_modules\node-red

(Sam Turner) #16

Thanks for sharing, great write up, very inspiring. As much as I try to “do things properly” when I am pulling my hair out trying to make sense of the Astro binding and timers in general. It is nice to have options :slight_smile:


(steve1) #17

There was a discussion in another thread about processing scene definitions defined through a UI. Assuming the scene definitions were communicated as a simple JSON array of item name/command pairs, how could those commands be communicated to openHAB items in a Node-RED flow? It seems like the openHAB output nodes must be hard-coded to a specific item name. That would be a problem in this case because the scene definitions are defined at run time. Is it possible to define the output item name using a message field? Some other way?


(Joe Lawrence) #18

The command line in the above referenced web page is incorrect, it is missing a --, use the command line supplied at Node-Red!!!


(Rgerrans) #19

Unfortunately that is way past my capabilities. I know that Node-RED can parse a json file and I’ve seen references to nodes for creating dynamic flows, so maybe…


(steve1) #20

I did some more digging last night and I’m about 98% sure that it can’t be done with the existing openHAB2 output nodes. If someone needs that capability, I think it could be implemented using the MQTT event bus binding approach (or we could modify the openHAB2 output node implementation).