Node-Red Palette: Common Choices

I have a question - what are you guys using to do "wait until" event/conditions in NR?

Two answers, kinda.

Home Assistant has a node that has "wait until" a certain state occurs. It's pretty handy. I'm only using it for two things at present (home Assistant).

In a similar vein, yesterday I removed node-red-contrib-bool-gate because it was 4 years old, and may have been the source of my Node Red errors/crashing. I migrated a few flows to ultimate-boolean, but it's real messy, requiring lots of nodes to get the data into right format. I searched and modified some code that goes in a function node, which I've re-purposed for all my wait tasks (with multiple feeds).

Here it is. I'm no coder. Improvements welcome. Just dump it in a function node. For a wait, just remove the other two ELSE-IF's below.

context.garage1 = context.garage1 || 'closed';
context.garage2 = context.garage2 || 'inactive';

if (msg.topic === 'CS - Garage Door') {
  context.garage1 = msg.payload.value;
}
else if (msg.topic === 'CS - Garage (Hanging)') {
    context.garage2 = msg.payload.value;
}

if (context.garage1 == 'open' && context.garage2 == 'active') {
    node.status('Changing')
    global.set("garage_door", "Changing");
    return {topic: 'Garage', payload: 'Changing'}
 }
else if (context.garage1 == 'open' && context.garage2 == 'inactive') {
    node.status('Open')
    global.set("garage_door", "open");
    return {topic: 'Garage', payload: 'open'}
 } 
else if (context.garage1 == 'closed' && context.garage2 == 'inactive'){
    node.status('Closed')
    global.set("garage_door", "closed");
    return {topic: 'Garage', payload: 'closed'}
 }
1 Like

This was the only thing that came up in my search. I don't use HA so not sure it these nodes will work outside of HA (ie I'm trying to recreate in NR one of my RM rules which uses "wait until" ).

Thanks for posting - I shall have a try of it!

A stop-gap measure would be a looping switch node with a certain delay. Now this is less than ideal, due to wasting unnecessary cycles on checking over and over, but I think it is more a limitation of the base platform, i.e. needing messages to trigger an action. Because for a wait until to work, the first message would have to come in to trigger it, and then in a perfect world, a second one would come in once you have met the condition. Something, now that I think about it, you could probably do with the HE nodes and the Send Events selected on a device node and a switch node, and potentially the use of context variables to decide if you are in a "wait until" loop at the moment of checking.

2 Likes

thanks @mike @cjkeenan - just posted a test flow that does this.Node-Red Flow Samples/Sharing

That kind of looks like a Finite State Machine.. here is a simple example I am using for home/away stuff...

That's what I was thinking after seeing your and others posts a few days ago before I raised the question but I wanted to get something going quick without getting up to speed with FSM nodes or more json. Past this there's no doubt a wealth of useful stuff once you get past the scary bits.

1 Like

I am not really all that familiar with FSMs having never used them. For my simple case it seems to work well. The JSON bit just defines the transitions. There is another node that doesn't use it:

The concept can be a little mind bending especially for more complex situations.

I was wondering if you or anyone has used the node-red-contrib-persistent-fsm much? The reason I ask is that have started working with it. It has a lot of things to recommend it. I like the interface for building the FSM along with the graphical representation that it generates automatically.

But..... and it is a big but, I have found that once I integrated it into a flow, I was getting some really weird behavior out of node red. For example, I had the output going to a switch node that then sent triggers to various actions I wanted to have happen when it reached specific states. So far so good. I was having debugging issues with the downstream flows and so wanted to take the FSM out of the flow temporarily and trigger the downstream manually. I did this by removing the connection from the fsm to the switch node. This is where it got bizarre. After redeploying the flow, the switch node would see and then process a duplicate of the exact same msg that it had last received from the FSM node. It would do this every time I would do a redeploy.

I have since replicated this behavior with a debug node. All in all, a strange event. I am thinking about abandoning it for one of the other fsm options or just using it think about the states but not even use an fsm.

Has anyone tried this and experienced this behavior?

I have not used the persistent-fsm node. I use the node-red-contrib-finite-state-machine as I like the ability to configure via JSON but still get the nice diagram.

I've never really used FSM in any of my prior stuff so tend to get a little confused when going beyond the simpler models.

Thanks for the quick feedback. I will probably try that one. It looks more powerful (though more complex as lots of thinking in terms of JSON). That said, I build a lot of function nodes so complexity in pursuit of a desired outcome isn't the worst thing.

1 Like

It's just that in my years of coding I never used the FSM concept so it is not something I am completely comfortable with yet. I think it is a cool idea and can be used to solve specific problems but imagine there is a complexity limit were it becomes impractical.

I do like writing function nodes too - easy compact way of getting things done the way you want. Keep in mind that the function node runs in a sandbox so can potentially slow things down if calling it iteratively etc. not sure about the impact of the sandbox so striking it out.

At home I almost always only have 2-3 states max, so no real reason to use a FSM.

FSM can be really handy when you have a LOT of states and transition scenarios, though. Or if you want to do something different specifically on the specific transition happening, and not just the new state. I use it at work a lot on complex controls. That said, I always found FSM more work than benefit with only 2-3 states.

1 Like

Well for my simple learning use-case - a 4 state transition (home/away/guest-home/guest-away) it's working pretty well. Much beyond that and I guess I would have to start mainlining ibuprofen for the epic headaches that would occur... :laughing: :dizzy_face:

I have seen a lot of references to the potential slowdown from function nodes (including ways to get around the sandboxing at the cost of security risk), but have never been able to experience a downside. There is one downside, it makes it hard to share with anyone that has less javascript experience than you have and for complex functions any programmer regardless of experience can have a hard time slogging through someone else's code.

The new nice answer is encapsulate your function nodes in a subflow then convert your subflow to a custom module!!!! Works great!!!!

1 Like

That would work great as long as you don't put any flow specific info into the function code itself (a quick and slightly hacky workaround).

Yep - but you can control a lot of that through environment variables and msg properties.

I am starting to play around with custom modules because I can create a set of nodes for my clients that are not as easily messed with and I can update via remote access . It's very promising so far.

The example situation I am trying to learn is this:
I have an old iPhone that sits in place as a podcast player. I found however that the battery eventually went dead and took the phone down with it from constantly being 100% charged. So no I have started to charge it, then turn off the outlet let it run down and then restart charging by powering the outlet back up.

I have found that when the power comes up, because it is connected a speaker via bluetooth, it starts playing, so I have to disconnect it temporarily from bluetooth before turning on the power. This is the diagram of the FSM:
image

If this works out well (and I think it is very close other than the weird redeploy behavior with the persistent-fsm node), then I plan to go after climate control where I factor in all of these things:

  1. Upstairs vs Downstairs Thermostat/System
  2. Heating/Cooling/Off
  3. Fan On/Circulate/Auto
  4. Future weather forecast (willing to let it get a little uncomfortable if nature will heat or cool my house tomorrow)
  5. Room by room temperature (potentially driving Fan condition)

I hope to eventually have automated dampers for airflow, but the list above is enough complexity to get started.

How do you detect the power situation? through the smart plug? Also how does the system know the device's bluetooth has been connected or not?

Here's my take on that FSM - but again I am still new to this concept so ymmv.

Sample FSM - requires the node-red-contrib-finite-state-machine

[{"id":"7c7d6927.99e3b8","type":"finite-state-machine","z":"af91369d.586338","name":"","fsmDefinition":"{\"state\":{\"status\":\"iPhoneCharged_BTConnected\"},\"transitions\":{\"iPhoneCharged_BTConnected\":{\"low_charge\":\"iPhoneNotCharged_BTConnected\",\"bt_disconnected\":\"iPhoneCharged_BTDisconnected\"},\"iPhoneCharged_BTDisconnected\":{\"low_charge\":\"iPhoneNotCharged_BTDisconnected\",\"bt_connected\":\"iPhoneCharged_BTConnected\"},\"iPhoneNotCharged_BTConnected\":{\"full_charge\":\"iPhoneCharged_BTConnected\",\"bt_disconnected\":\"iPhoneCharged_BTDisconnected\"},\"iPhoneNotCharged_BTDisconnected\":{\"full_charge\":\"iPhoneCharged_BTDisconnected\",\"bt_connected\":\"iPhoneNotCharged_BTConnected\"}}}","sendInitialState":true,"sendStateWithoutChange":false,"showTransitionErrors":false,"x":730,"y":2880,"wires":[["a107ad4c.acd0d"]]},{"id":"9847816c.c5905","type":"inject","z":"af91369d.586338","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"low_charge","x":410,"y":2800,"wires":[["7c7d6927.99e3b8"]]},{"id":"e5092892.105dc8","type":"inject","z":"af91369d.586338","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"full_charge","x":410,"y":2840,"wires":[["7c7d6927.99e3b8"]]},{"id":"13de600d.e37ca","type":"inject","z":"af91369d.586338","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"bt_connected","x":410,"y":2920,"wires":[["7c7d6927.99e3b8"]]},{"id":"7ee08740.a97f48","type":"inject","z":"af91369d.586338","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"bt_disconnected","x":420,"y":2960,"wires":[["7c7d6927.99e3b8"]]},{"id":"a107ad4c.acd0d","type":"switch","z":"af91369d.586338","name":"iPhoneCharged_BTConnected \\n iPhoneCharged_BTDisconnected \\n iPhoneNotCharged_BTConnected \\n iPhoneNotCharged_BTDisconnected","property":"payload.status","propertyType":"msg","rules":[{"t":"eq","v":"iPhoneCharged_BTConnected","vt":"str"},{"t":"eq","v":"iPhoneCharged_BTDisconnected","vt":"str"},{"t":"eq","v":"iPhoneNotCharged_BTConnected","vt":"str"},{"t":"eq","v":"iPhoneNotCharged_BTDisconnected","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":1090,"y":2880,"wires":[["9811a637.f37668"],["826246ab.d01458"],["6b6a2b37.708874"],["8a72cf27.6f95e"]]},{"id":"9811a637.f37668","type":"debug","z":"af91369d.586338","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.status","targetType":"msg","statusVal":"","statusType":"auto","x":1510,"y":2820,"wires":[]},{"id":"826246ab.d01458","type":"debug","z":"af91369d.586338","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.status","targetType":"msg","statusVal":"","statusType":"auto","x":1510,"y":2860,"wires":[]},{"id":"6b6a2b37.708874","type":"debug","z":"af91369d.586338","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.status","targetType":"msg","statusVal":"","statusType":"auto","x":1510,"y":2900,"wires":[]},{"id":"8a72cf27.6f95e","type":"debug","z":"af91369d.586338","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.status","targetType":"msg","statusVal":"","statusType":"auto","x":1510,"y":2940,"wires":[]}]