# Delay node: drop intermediate, except last

**URL:** <https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810>\
**Category:** Feature Requests\
**Created:** [22 February 2022 11:37 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810 "2022-02-22T11:37:23Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 11:37 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/1 "2022-02-22T11:37:23Z")

</div>

I'd like to extend the delay node to allow dropping intermediate messages; but always send the last **of the rate-limited messages** (if any) after the limit.

use-case: I use node-red to control my thermostat; in some cases there's some _flickering_ on/off that I'm trying to avoid, but the last message should always be passed through (to avoid leaving the heater on _forever_).

Would a PR be accepted for this, or should I look towards a custom component/fork?

Other thoughts/suggestions are of course also welcome

Thanks!

---

<div class="post-metadata">

**Author:** ![knolleary](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/knolleary/32/3_2.png) [@knolleary](https://discourse.nodered.org/u/knolleary)\
**Post date:** [22 February 2022 11:42 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/2 "2022-02-22T11:42:22Z")

</div>

I can't quite visualise what you mean.

Can you describe it in real terms of an example sequence of messages? How would the node be configured and what messages should/shouldn't pass through?

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [22 February 2022 11:43 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/3 "2022-02-22T11:43:21Z")

</div>

Maybe use a trigger node set to send nothing, then wait, then send last message received after a suitable de-bounce time as well/instead

---

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 11:52 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/4 "2022-02-22T11:52:42Z")

</div>

given:

- flow to calculate if the heater needs to be turned on (based on several factors)
- service node to actually turn the heater on/off

The delay/rate limit node would sit in between to limit controls towards the heater, while always ensuring it matches the intended state (after the rate limit period)

Let's say the that flow (within seconds of each other) sends: on, off, on, off, on, off

Using the delay node in rate-limit configuration (let's say to 1msg per minute), it would pass through an on; but never turn it off.

As the flow is based on several infrequent events, it could take a considerable time before the flow outputs another (for simplicity's sake) off signal, actually turning the heater on.

The proposal would: pass through an on (right away) and (providing there are no extra inputs within a minute) send an "off" after the delay (so the heater would've effectively been turned on for a minute; instead of several on/off cycles in rapid succession.); similar to debouncing a switch.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [22 February 2022 11:53 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/5 "2022-02-22T11:53:24Z")

</div>

> [@jonasd](#):
>
> in some cases there's some _flickering_ on/off that I'm trying to avoid,

It sounds like you need a bit of hysteresis on the compare, so it does not switch on till just below the target, then does not switch off again till just above.

---

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 12:04 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/6 "2022-02-22T12:04:02Z")

</div>

Ideally, yes. But there are 2 issues with that:

1. the update gap is significant (the fluctuations would be rather big)
2. it's not actually controlled by just 1 source; the (central) heater is connected to the house's heating system, the above can occur even if each individual source had some hysteresis implemented.

To me this feels like quite a generic function that can be useful in several cases... but (I guess I missed it before -- I could swear I searched for debounce before 😂 ) the [debounce](https://flows.nodered.org/node/node-red-contrib-debounce) node should actually already do exactly what I want & described 😃 -- still willing to contribute it into the core delay node though

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [22 February 2022 12:07 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/7 "2022-02-22T12:07:34Z")

</div>

Does the debounce node do anything that the Trigger node doesn't?

---

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 12:18 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/8 "2022-02-22T12:18:08Z")

</div>

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/b/d/bda9bbc38bcec9d2f5e8486a68cf6ad824a5b931.png)  
Should at least get very close, thanks!  
The only thing that feels missing (but would be better suited as an extension there then) is to add a "then send" condition to "only if more messages arrived"

Could we potentially do something to improve discoverability? (node aliases for search?)  
I don't really think of _trigger_ when thinking of limiting/debouncing 🙂

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [22 February 2022 13:39 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/9 "2022-02-22T13:39:13Z")

</div>

I don't think the debounce node will do exactly what you have specified there, but I also suspect it is not what you want. Consider what would happen if it received On, then 55 secs later Off and another 10 secs later On. The result would be that it was On for 1 minute, off for 5 secs, then back on again.

What is it that you are actually trying to achieve? Is it that you want to have a minimum on and/or off time? If so then which?

---

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 14:15 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/10 "2022-02-22T14:15:56Z")

</div>

🤔 debounce ([as documented by Rx](https://reactivex.io/documentation/operators/debounce.html)) would actually slow the "then back on again" message down by the debounce time too. (resulting in 1min on, 1 min off, then back on)

What I'm _actually_ trying to achieve is to limit toggling the (gas-based) heater too frequently.

---

<div class="post-metadata">

**Author:** ![cymplecy](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/cymplecy/32/2773_2.png) [@cymplecy](https://discourse.nodered.org/u/cymplecy)\
**Post date:** [22 February 2022 14:18 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/11 "2022-02-22T14:18:31Z")

</div>

Could I suggest you give us a couple of sequences of input (with timing info) and what you'd want as an output in each case and then we can hopefully give you some suggestions to achieve your aim 🙂

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [22 February 2022 14:32 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/12 "2022-02-22T14:32:42Z")

</div>

> [@jonasd](#):
>
> limit toggling the (gas-based) heater too frequently.

So is that the same as specifying a minimum on and or off time? In other words if it comes on then it will stay on for a least a minute before going off again? And possible the inverse too?  
I use a minimum On time on my oil fired boiler so that it does not just switch on for 5 seconds, for example.

---

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 14:34 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/13 "2022-02-22T14:34:52Z")

</div>

Boils down to it, yes.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [22 February 2022 14:35 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/14 "2022-02-22T14:35:18Z")

</div>

Which? Min ON, OFF or both?

---

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 15:04 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/15 "2022-02-22T15:04:45Z")

</div>

Sorry, both ideally

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [22 February 2022 15:43 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/16 "2022-02-22T15:43:24Z")

</div>

I have a function for that, but I can't immediately see a simple way with core nodes. Perhaps someone will accept today's challenge to do that.

```auto
// expects a sequence of messages containing numbers 1 and 0
// Stretches both 1 and 0 states to the specified minimum length

var minWidth = 5 * 1000; // min width in msec

var initialState = 0; // initial state
var timer = context.get('timer') || 0;
var lastSentValue = context.get('lastSentValue'); // the value sent last time
if (typeof lastSentValue === 'undefined') {
    // set initial value to the quiescent state
    lastSentValue = initialState;
}
context.set('newValue', msg.payload); // the value to switch to when timer has run down

// if the new value is different to previous value past on and the timer is not running 
// then pass the new value on immediately and start the timer, the timer stops it 
// changing again till it has run out
if (msg.payload != lastSentValue && timer === 0) {
    // leave msg.payload at new value and set lastSentValue to that
    lastSentValue = msg.payload;
    context.set('lastSentValue', lastSentValue);
    startTimer();
} else {
    // otherwise always pass on the same value as last time, which may be the 
    // new value also
    msg.payload = lastSentValue;
}
return msg;

// only call this if the timer is not already running
function startTimer() {
    var timer = setTimeout(function () {
        // clear the timer in the context
        context.set('timer', null);
        // the timer has run down so can now send the new state
        var newValue = context.get('newValue');
        // have we changed the state?
        if (newValue != context.get('lastSentValue')) {
            // yes, remember it and restart the timer to extend this one if necessary
            // and set holdoff true if we are going to 0
            context.set('lastSentValue', newValue);
            startTimer();
        }
        node.send({ payload: newValue });
    }, minWidth);
    context.set('timer', timer);
}

```

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [22 February 2022 15:52 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/17 "2022-02-22T15:52:23Z")

</div>

I'm not sure why just a simple trigger won't suffice - I must be missing something...  
If set to pass existing message - then wait a minute and then send last message received - that should filter out any bounces - and meet the criteria of only switching at most once per minute. If it happens to go 1 -\> 0 -\> 1 during that time it will send another 1 at the end which won't change the state... if you need to filter duplicate messages then follow this with a filter node.

What am I missing ?

---

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 15:53 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/18 "2022-02-22T15:53:21Z")

</div>

I made this thread as I'm up for adding this to core; but wanted to discuss specifics first 😉

options:

1. Do we make the addition to the "trigger" node (checkbox or list entry to NOT send the _original_ message, but only latest if changed =\> caveat = a message sent seconds after the "final" message would simply go through, as it's not a rate limit
2. (original proposal, **preferred** ) extend rate limit to add a "queue last intermediate message" (or similar); which -if present- would send the queued message **counting towards the rate limit** =\> requested behaviour would be present  
f.e. given a 1msg/minute rate limit: "if it received On, then 55 secs later Off and another 10 secs later On." =\> sends on, queue's off after 55sec, sends off 5 sec later, queue's On 5sec later, sends On 55sec later

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [22 February 2022 15:55 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/19 "2022-02-22T15:55:07Z")

</div>

or 3 - use a filter node to filter out messages that aren't a change of state...

---

<div class="post-metadata">

**Author:** ![jonasd](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jonasd/32/57149_2.png) [@jonasd](https://discourse.nodered.org/u/jonasd)\
**Post date:** [22 February 2022 15:55 UTC](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810/20 "2022-02-22T15:55:19Z")

</div>

Trigger (unless I understand it incorrectly) would have the following edge-case:

> [@Colin](#):
>
> Consider what would happen if it received On, then 55 secs later Off and another 10 secs later On. The result would be that it was On for 1 minute, off for 5 secs, then back on again.

> [@dceejay](#):
>
> or 3 - use a filter node to filter out messages that aren't a change of state...

Above example would still be a state change, so _just_ a filter wouldn't solve this. (and "extend delay if new message arrives" could cause it to get stuck in a specific unwanted state if there are too many inputs received)

Would you be ok with accepting a PR for option 2 described above?

[Next page](https://discourse.nodered.org/t/delay-node-drop-intermediate-except-last/58810.md?page=2)
