Node-RED as Alternative Rule Engine

rules
node-red
Tags: #<Tag:0x00007fd30d899e40> #<Tag:0x00007fd30d899d00>

(Artyom Syomushkin) #61

Reliability looks already great, as I have one RPi running Codesys autonomously for half a year without any issues.


(Rohnny Swennen) #62

@rgerrans have you ever looked into node red in combination with the OH homekit binding ? There is a separate node red home kit binding that seems to support all homekit types (outlet, fan, garage door etc.)


https://swifting.io/blog/2017/04/05/39-homekit-devices-simulator-using-node-red-raspberry-pi/

I’m tempted to look into using node red to try to support other types of devices.
One way would be to drop the OH homekit binding and use the node red one but that would mean I would need to redefine all lights again in node red and manually map them, not the smartest way IMO (the bulk of the items are lights which work well in OH - homekit).

So wondering whether you have any experience? Would it be possible to have the IOS device connect to 2 separate homekit accessories (the openhab bridge accessory in parallel with the accessories defined in node red?). This way one could leave all lights and thermostats in OH and create non supported accessories like fans or outlets in node red and link them though to whoever they are represented in OH (dimmer, switch, contact etc …)


(Rgerrans) #63

Unfortunately I can’t help you there. I’m an Android guy so don’t know much about the capabilities / limitations of Homekit. Sorry.

If there is no added advantage of going direct from Node-RED to Homekit I wouldn’t move them over. My original setup was Node-RED as my rules engine and OH as the communication bus and UI interface. Once I jumped on the MQTT bus (as per my earlier post) I’ve started doing some direct connections from Node-RED or just to MQTT from other systems but for some items it’s as much because I can vs because I needed to.


(Joe Lawrence) #64

I’ve had this happen a few times, ended up using NSSM (Non-Sucking Service Manager), to run Node-Red as a service, and re-start on crash. I also get notices when Node-Red “bounces”. Haven’t had a string of rapid fire “bounces” yet, although NSSM has a decent way of handling multiple crashes by extending the time between each restart until it works. You can still stop the service and run Node Red in a “Dos box” for trouble shooting purposes.


(shawnmix) #65

@rgerrans - so I’ve just stumbled through this and great timing. I’m thinking about overhauling some things, and what better way than to uproot my rules!! :wink:

Anyhow, I have a few questions perhaps you can indulge. I’ve only been playing for about an hour but I wanted to ask about some specific cases:

  • Is there a way to input lines that would have normally been done with logInfo("rules.automation", "Some message Here"? I use this frequently to have a way to “indicate” in my logs somewhere that something happened due to my rules processing. I sometimes use this later as well for troubleshooting and identifying what actions happened when.
  • Is there a way to send 2 commands? Or perhaps more specifically a command an update? I have a common scenario in my switches (I believe we run the same type of rules with Case statements and the 1.2, 1.3, 1.4, etc for multiple taps). Specifically in mine, I always reset to 2.1 to enable “convenience” 1 touch off always in certain scenarios with mixed switches and to ensure that if the last scene run is run again, it will be picked up properly.
  • Can I use multiple inputs to a switch? In a scenario where I might have a When statement with a couple devices to monitor (in my scenario, some alarm system modes) where I need to evaluate the rule any time ANY of those items changes?
  • Lastly I know someone mentioned the HomeKit NodeRED stuff in here. I installed it on a whim and was tinkering around. But it seems that it is providing a whole lot more information and frankly I’m not a coder so all the JSON and other stuff is making my head spin. Could be the late hour! :wink: But I’m wondering what would be the basics to “translate” other Nodes into OH Nodes for proper control. I’m only investigating this further as the regular HomeKit integration currently isn’t working, but this one seems to at least present the items flawlessly for me.

(Rgerrans) #66

Best cure for boredom, blowing up your system and scrambling to get it back up and running before the WAF gets to low :wink:

I could think of a couple different approaches.

  • One would be to create a logging rule, and then pass your log message to a variable along the lines of what I did here: Broadcast Notifications
  • You can also use the Debug nodes to view it in real time
  • Finally, what I did for times that I want to capture events when I’m not running debug is build a node-red log file using the following subflow:
    image

Flow:

[{"id":"5642ea48.78faa4","type":"file","z":"1535d28d.7fd35d","name":"Log","filename":"/opt/node-red.log","appendNewline":true,"createDir":true,"overwriteFile":"false","x":699,"y":839,"wires":[]},{"id":"f2a13fb8.41799","type":"function","z":"1535d28d.7fd35d","name":"Timestamp","func":"msg.payload =  new Date().toLocaleTimeString('en-US',{month: '2-digit', day: '2-digit', year: '2-digit'}) + ' - ' + msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":483.4686508178711,"y":839.6844158172607,"wires":[["5642ea48.78faa4"]]}]

Not 100% sure I know what you are trying to do here but I assume send an initial state to your scene switch and then right after send a second state? If so, then I do that with a Trigger node. I fork the flow off my previous node with one going direct to the OH item and then run a parallel flow with a short delay on the Trigger node and the 2nd message you want sent as the output of the Trigger node. Something like this:

Yes, I do this quite a bit. The key I found if you need to do specific action after based on which input caused the event is to track/change the topic of your message to indicate the device (I use mqtt so convert the topic to simple descriptions so I can input it into a notification message). For example here I have my three door alarms going to a single Switch Node:

I haven’t written code in decades, so it took me a while to wrap my head around the JSON. Fortunately, Node-RED gives you a JSON node that will convert the JSON string into a message object which breaks apart the different components so you can use the message format msg.payload. to evaluate. For example I use a Nest node as below:


Which gives me a message object that looks like this:
image

So in my change node I pull the status from the “away” data object like this::

Hopefully all that info helps, let me know any specific clarifications or if I missed what you were asking


(shawnmix) #67

So this one is a bit tricky. I think the actual solution needs to be a new type of node, that is intended specifically for the log function. Or perhaps it needs to be added as another type of payload or msg (forgive my use of the terms). It should be Send Command, Post Update, and Log {type(info, debug, etc)}. Unfortunately using the item and trying to trigger a rule off this to post the logging won’t work. I tried this for something else and you run into issues when stuff fires off too fast. Honestly, it’s not extremely necessary, but I do like to use it as a way to easily identify in my logs when certain rules are running as mentioned for various purposes. Logging files or from the debug inside the NR interface would be of no help as it needs to appear in OpenHAB.log or Events.log like so (output from frontail):

2017-09-26 19:47:46.004 [vent.ItemStateChangedEvent] - master_bathroom_scene changed from 1.0 to 2.0
2017-09-26 19:47:46.030 [ome.event.ItemCommandEvent] - Item 'left_vanity_switch' received command OFF
==> /var/log/openhab2/openhab.log <==
2017-09-26 19:47:46.035 [INFO ] [rthome.model.script.rules.automation] - Master Bathroom - All OFF rule executed (1 Tap DOWN)
==> /var/log/openhab2/events.log <==
2017-09-26 19:47:46.051 [ome.event.ItemCommandEvent] - Item 'right_vanity_switch' received command OFF
2017-09-26 19:47:46.065 [ome.event.ItemCommandEvent] - Item 'master_bathroom_dimmer' received command 0
2017-09-26 19:47:46.082 [vent.ItemStateChangedEvent] - master_bathroom_dimmer changed from 100 to 0
2017-09-26 19:47:46.083 [GroupItemStateChangedEvent] - g_master_bathroom changed from ON to OFF through master_bathroom_dimmer
2017-09-26 19:47:46.088 [vent.ItemStateChangedEvent] - master_bathroom_scene changed from 2.0 to 2.1

Probably helps to provide a sample rule:

rule "Office Dimmer Scene"
when
  Item office_scene changed
then
{
  switch(office_scene.state){
    case 2.1 : {}
    case 1.3 : {
      sendCommand(office_dimmer, 100)
        logInfo("rules.automation", "Office Dimmer set to 100 - (2 Taps UP)")
      postUpdate(office_scene, 2.1)
    }
    case 2.3 : {
      sendCommand(office_dimmer, 1)
        logInfo("rules.automation", "Office Dimmer set to 1 - (2 Taps DOWN)")
      postUpdate(office_scene, 2.1)
    }
  }
}
end

========> Side note - you can see the use of the logInfo part I spoke about in the first section
So what I’m doing is if I see the 2 taps up, I turn the dimmer to 100%, if I see the 2 taps down, I turn the dimmer to 1%. My understanding of rules processing, first case match goes to end so I put the 2.1 as a catch to “expedite” the rules. Though it may just be completely unnecessary.

My goal here though, is to sendCommand to the dimmer, log an info event, and THEN, send a postUpdate to the scene state to reset to 2.1. I’ll spare you the boring explanation of why 2.1, but the point is if I walk into the office and want to use the Dim scene, then later turn the light to 100% using OH instead without touching the switch, then try to use the switch scene (taps down) again - it won’t work if the scene hasn’t been reset. Funny way our switches work - if you change the actual light item (or channel), it won’t affect the scene channel/item.

Should this just be as I’ve designed now?

Ok, I see so if you need to evaluate against WHICH device triggered the rule to fire, then you need to do some JSON manipulation to call it out? Or will this come from the msg.payload? Again, samples probably help but I think you have the right idea here already:

rule "Presence Based Automation"
when
  Item virtual_user1 changed or
  Item virtual_user2 changed or
  Item virtual_user3 changed
then

Ok, I think that does help. I’m still trying to wrap my head around and play around with the translation from one node to the next, and more specifically understanding the outputs. I’m having to put in a bunch of the debug pieces to see the output and start to piece it together. My main reason to want to understand this is that part someone suggested about HomeKit could be a FANTASTIC solution to a few of the items I have that don’t respond as well with the OH items - specifically the Thermostats and some other non-generic items. If you manage to get that working, please do share!! But I don’t have high hopes as I believe I saw you indicate you’re on Android :wink:

I imagine it should look something like this:
42 PM
But I need to figure out the way to translate the msg.payload from OH format to the necessary HomeKit format, and then back again into OH. Once I get that, this will be CLUTCH!

PS - Thanks for all the effort in putting together this little tutorial! This is fantastic!!


(shawnmix) #68

Oh and one more side question - organization. Is it advised to create a new “Flow” for each rule? Or can/should I put multiple similar rules into one “Flow”? I use the quotes on the term flow as I really see them as just tabs here, but I know it’s likely more than that as I see Flows have an ID, and I saw in some instances you seem to have included the flows you mentioned in a one liner type of format - presumably an export type capability?


(Rgerrans) #69

That is most likely not possible, unless they exposed the logInfo to the REST api since that is what the OH nodes are tied to.

I’m assuming you mean that it will inject the log message into OH logs (which I just tested and works fine) but that the message gets logged before the device triggers? If so you could always put a slight delay in front of your log message in Node-RED to make sure it comes out later though if you are only trying to figure out if your rule fired or not I’m not sure why the sequence in your log file is of issue. As far as the need to be in a single file, personally I actually break my OH into separate log files already for mqtt and zwave so I can turn on debug w/o over saturating my main log file. I then added the node-red logging and I just look at time stamps across the various files to figure out timing. A little more work on my part but not that big of a deal.

That looks about right from what I see you trying to do (assuming your items are all defined correctly). I don’t see you changing the msg.payload back to 2.1 before sending to the Office Reset unless you are doing it in the outbound node. I think you are good for not triggering a circular loop when changing the office scene back to 2.1 (which it looks like you trapped in your rule and left off your case switch in Node-RED so should be fine).

To add your logging to this, what I would do is just add another OH node to each change node that sends a message to a virtual logging string and then have a rule that fires off that string to insert the message into your OH log. So it would look something like this (remember I use mqtt not OH nodes now but same idea):

With the appropriate items defined and a rule like this:

rule "Logging"
when
	Item vLogMsg changed
then
    logInfo(vLogTopic.state.toString, vLogMsg.state.toString)
end

You could also attach your “Office Reset Scene” node (with the appropriate payload as per above) after the node that changes the vLogMsg item to get the sequence to follow as well.

Actually all you have to do using the OH Nodes is to use the msg.item in your switch rules to pull the item name.(not the item label) and then if you want to use a simpler name just change the topic or payload based on mapping the msg.item name (let me know if you want an example).

Correct, Android guy here so no need for HomeKit. I found for some of the other items I deal with I can find interfaces either direct to mqtt (hence my switch over), direct through Node-RED or now I’ve figured out how to interface directly into node.js so can get to them if someone wrote an interface there but no one wrote a wrapper for Node-RED yet. Sorry I can’t be of help there.

Personally, I group rules by “Flow” my flows tend to tie to specific physical rooms or groups of flows.

Most of my flows (also not sure why the use that word interchangable between a linked group of nodes and the tabs. Here I mean the groups of nodes) are isolated and I have multiple per tab. For this tutorial and most my responses I mock them up for simplicity to screen shot them. Here’s an example of what one of my tabs looks like if that helps to clarify:


(Jens Bruckmann) #70

The more I work with Node-RED the more I love it. It’s much more intuitive and better to debug than the native rule engine with its very special language.

I often used the functions changedSince oder historicState, like in this example:

                        if (! PlayerPaused.changedSince(now.minusMinutes(30), "influxdb") {
                            sendCommand(HomeEntertainmentMainSwitch,OFF)
                            sendCommand(BeamerSwitch,OFF)
                            sendCommand(LivingroomRenderer,OFF)
                            logInfo("Entertainment","Player on Pause for more than 30 minutes, powering off")
                    }

Is there a way to copy such a functionality in Node-RED?

Another question is, how can I e.g. count members of a group having a specific state like with these statements in xTend:

                if(gIndoorMotion.members.filter(m | m.changedSince(now.minusMinutes(presence_timeout), "influxdb")).size == 0) {
                    motion_occured = false
                    logInfo("PresenceCheck", "No motion occured during the last " + presence_timeout + " minutes")
            }

If those functions could be integrated in Node-RED I would start migrating all my rules in a moment.
If that is not possible I have the idea of using “proxy” items in Node-RED to set to then afterwards trigger a rule in xTend, use the functions in question and then to set another “proxy” item to a specific value to be handled in Node-RED again. But that would not be very comfortable and my intention is to replace xTend totally.


(Rgerrans) #71

What I would do is use a flow variable to store your old state and then use a Trigger node to fire your Off command @ 30 minutes (I don’t know what command comes from PlayerPaused to tell you it’s no longer paused so put it in as ??? and I now use mqtt but you can use the OH nodes instead)

[{"id":"a43d6014.e0288","type":"mqtt in","z":"1535d28d.7fd35d","name":"PlayerPaused","topic":"","qos":"2","broker":"35e878ff.e53308","x":426,"y":613,"wires":[["ed81ef67.482e2","d4e93074.de7a3"]]},{"id":"ed81ef67.482e2","type":"change","z":"1535d28d.7fd35d","name":"playerPausedOld","rules":[{"t":"set","p":"playerPausedOld","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":572,"wires":[[]]},{"id":"d4e93074.de7a3","type":"trigger","z":"1535d28d.7fd35d","op1":"","op2":"OFF","op1type":"nul","op2type":"str","duration":"30","extend":false,"units":"min","reset":"?????","name":"30 Minute Off","x":684,"y":625,"wires":[["896ca1c2.2b99","d3541aaf.22a328","9586ea6d.2e41a8"]]},{"id":"896ca1c2.2b99","type":"mqtt out","z":"1535d28d.7fd35d","name":"HomeEntertainmentMainSwitch","topic":"","qos":"","retain":"","broker":"35e878ff.e53308","x":970,"y":567,"wires":[]},{"id":"d3541aaf.22a328","type":"mqtt out","z":"1535d28d.7fd35d","name":"BeamerSwitch","topic":"","qos":"","retain":"","broker":"35e878ff.e53308","x":914,"y":620,"wires":[]},{"id":"9586ea6d.2e41a8","type":"mqtt out","z":"1535d28d.7fd35d","name":"LivingroomRenderer","topic":"","qos":"","retain":"","broker":"35e878ff.e53308","x":934,"y":670,"wires":[]},{"id":"35e878ff.e53308","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"nodered","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]

.

Use can probably use flow variables (haven’t used groups like you are so hard to suggest an approach) or as you identified use proxy items to carry information between Node-RED and rules. I’ve had to do that for a few rules that can only be captured in OH.


(Rohnny Swennen) #72

Well the advantage would mainly be you would be able to use other types in your IOS Home application like fans, garage door openers … (there is a fairly long list apple already supports) and as a result ask siri to “turn the fan on” or “open the garage”.

Good news is I managed to make it work, so for those interested have a look at this post
https://community.openhab.org/t/other-homekit-types-through-red-node/34002/3


(Rgerrans) #73

Glad you were able to get it to work and add to the depth of knowledge on extending Node-RED with OH. I’ll have to take a look to see if it fills any gaps, but since I don’t use Siri not sure it it will make sense for me.


(dalibor) #74

Any way to check switch status without overwriting the payload?
Second “if statement” example does what I want, there is the flow, then it comes to “openhab2 get” node to see if the “override” switch is on or off. But the thing is that the message gets overwrite by the node, and I would like to keep it, while still checking the switch state?
F.eks. I want to send notifications, where the message is in the payload, but I also want to prevent sending it if the openhab item is on/off (using openhab2-get node).
So basically

  1. msg.payload= “Waterleak!” ->
  2. openhab2-get check if “silence notification” is ON ->
  3. send email with msg.payload (from point 1.)

I would really like to avoid keeping track of switch values if possible, as I sometimes just need to go in and change something, and often would variable be outdated.

Any tips about this? I was thinking to save original msg globally before the check, then after the check to read it, but it doesn’t look very elegant (but then again, if it works…)


(Rgerrans) #75

I can think of a couple of approaches:

  • One would be to store the original payload into a flow variable like you were thinking and then switch back the payload to that variable if it passes your if statement.
  • Another option would be to use an if statement ahead of your check (so you are only checking if msg.payload == “Waterleak!” then if your openhab2-get check returns ==“ON” use a change node to set the payload to Waterleak ahead of your notification. Unless the value of your original payload is going to vary there is no need to use a variable.
  • One last way that gets you to a single node post openhab2-get is to use a delay node where it sends Nothing for the first message, has a short or 0 second delay and sends the “Waterleak” payload unless it gets a reset message of “OFF” (so basically using an if != “OFF” send payload) Kind of cludgy but would only take one node vs. two.

I tried figuring out if there was an easy way to add to the json object to include a msg.payload.notification value but just using a change node to move that the original message payload to that part didn’t work. Might be able to convert to an array object but I haven’t yet played with that enough to fully understand how arrays work using join/splits.


(dalibor) #76

Thanks, it looks like option one is most suitable for my scenario, as I would actually need to store several things beside payload (custom elements like topic, priority and maybe some others).

I am building some “communication” flow/subflow that has a link as input, and the messages can come from various other flows, and then be separated by priority (alert, notification, log…) and have some few other parameters as well. That is why option 2 is less desired, I would like it more contained and centralized.

It would be awesome if “openhab2-get” node could append original message somehow inside the new payload, but i guess temporarily storing old message before and restoring it after contacting openhab will (have to) work just fine :slight_smile:


(dalibor) #77

If someone else needs this scenario, it is one node that stores the original message with a function

flow.set(‘tempOrgMsg’,JSON.stringify(msg));
return msg;

then you check with openhab2-get if switch is on, after that you have a switch that stops the payload if it is OFF (like the example on the beginning)

[{“id”:“9b511355.08ed4”,“type”:“switch”,“z”:“26012d94.6ffd42”,“name”:“Current Plug state”,“property”:“payload.state”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“OFF”,“vt”:“str”},{“t”:“eq”,“v”:“ON”,“vt”:“str”}],“checkall”:“true”,“outputs”:2,“x”:770,“y”:540,“wires”:[[“15b0f703.d6ed79”],[]],“outputLabels”:[“Is OFF”,“Is ON”]}]

and then you read back original message with a function

var msg = JSON.parse(flow.get(‘tempOldMsg’));
return msg;

Works fine with my scenario, your mileage may vary


(Rgerrans) #78

Looks like you found a pretty simple approach. I got thinking later that these nodes might be of use: https://flows.nodered.org/node/norelite


(Rgerrans) #79

@dakipro just saw this which might be useful
https://www.npmjs.com/package/node-red-contrib-batcher


(dalibor) #80

I saw that one before for some other application (I want to collect and send log-type messages once a day), but it looks I have to use database for that (mysql, because that I know).

Not sure how link you shared applies for checking if a switch is on/off in openhab? If I understand from description, it just collects messages and when buffer is full it sends them as one message. It could perhaps hold messages until a switch is triggered back?
Or were you referring to some other scenario?

Anyway, since I am going to use database for log-type messages, I might as well log all communication and send it with the email. Just for a control, and if I was “offline” with the switch I would get missed communication the next day.

I would like daily report of activity, I like the way home-assistant does that with history overview https://home-assistant.io/components/history/
but that is perhaps separate project from node-red :slight_smile: (one could install home-assistant just for that functionality and monitor mqtt)