Triggering output when a number changes by x within y time period

I'm looking to turn on a fan when humidity rises 10% with a 5 minute time period. The humidity sensor might report the rise over multiple reports so I can't just compare it to the last change. Any ideas on how to accomplish this?

Do you mean that if it keeps on rising at 9% every 5 minutes you don't want it reported? So, for example, starting at 50%, then after 5 mins it is at 59% and after another 5 it is at 68% and so on?

That is correct, but if its 52% at minute 2 and then 62% at minutes 7, I do want the trigger to fire. So its a rolling window.

I think you will need to implement a rolling buffer of values (with timestamps) in a function node. That can easily be done using an array and the push and shift methods (Pop, Push, Shift and Unshift Array Methods in JavaScript). Then you can check the current time against the first one in the buffer, check the rate, and drop ones off the front when they are over 5 minutes ago.

One more clarification you need to think about. What do you want to happen if it goes up 10% in 1 minute? The answer to that will affect the code in the function node.

I'd expect it to trigger once the 10% was hit, as long as it was within 5 minutes. I wouldn't necessarily want to wait the full 5 minutes to trigger the fan.

You need to work out a detailed algorithm before it can be coded. Forget about how to implement it and work out exactly what needs to be done each time you get a new sample.

This seems to encapsulate what I want:

Current sample comes in
Remove any samples older than 5 minutes
for each stored sample
  if Current sample - stored sample >= 10 then 
    trigger output
    break out of loop
store current sample

I guess I can turn this into JS pretty easily. Will the list of stored samples persist between runs or do I need to keep it in a global variable?

That seems reasonable.

It won't automatically be saved between messages in the Function node. To do that you have to use the node-red Context. Since this is private to this node you can use the node context. See the node red docs Working with Context, and also the one on Writing Functions to see how that is done.

Rather than loop through the array comparing each one you could find the minimum value in the array and compare that. To do that you can use the Math.min() function along with the array destructuring operator, so if the array is called rollingBuffer then you can say
let min = Math.min(...rollingBuffer)
which will give you the minimum value. Don't forget to check that there is something in the array before that, testing rollingBuffer.length

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.