# Interval in IF-loop is 'deaf' for injecting input

**URL:** <https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093>\
**Category:** General\
**Created:** [15 July 2020 00:48 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093 "2020-07-15T00:48:06Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![melhof](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/melhof/32/25804_2.png) [@melhof](https://discourse.nodered.org/u/melhof)\
**Post date:** [15 July 2020 00:48 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/1 "2020-07-15T00:48:06Z")

</div>

Can someone tell me how to get this to work, or if it is an error in Node-Red?

I am programming a countdown interval in a function node.

But inside the IF loop, the clearInterval does not want to be triggered by injecting msg.topic == '0'.

```auto
if (msg.topic == '1') {
    var counter = 10;
    var countdown = setInterval(function(){
        global.get('gInside');
        node.send({"payload":(counter)});
        counter--;

    if (msg.topic == '0') {
        clearInterval(countdown);
    }
    
    else if (counter <5) {
        clearInterval(countdown);
    }
    }, 1000)
}

```

Strangely it works if i remove the first IF line, but i need this functionality to extend its use.

I tried many other (global)variables, statements, etc.

Just inside the IF loop the Interval does not want to listen anymore to injected information.

---

<div class="post-metadata">

**Author:** ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)\
**Post date:** [15 July 2020 02:30 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/2 "2020-07-15T02:30:00Z")

</div>

One thing I can see:

```auto
if (msg.topic == '1') {
    var counter = 10;
    var countdown = setInterval(function(){
        global.get('gInside');
        node.send({"payload":(counter)});
        counter--;

    if (msg.topic == '0') {
        clearInterval(countdown);
    }
    
    else if (counter <5) {
        clearInterval(countdown);
    }
    }, 1000)
}

```

Line 1: `if (msg.topic == '1')`  
That _lives_ all the way through.  
So if _msg.topic == '1'_ then when it gets to line.... 8 (blanks included) it won't work.

---

<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:** [15 July 2020 06:52 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/3 "2020-07-15T06:52:56Z")

</div>

Normal variables, such as your countdown variable, are recreated for each message received. So the countdown you clear when you get the clear message will not be the one containing the timer id.  
Therefore your countdown variable needs to be stored in the node context and picked up again when the next message comes in. When you clear it, set it to zero so you won't try and clear it again.

[Edit] Also, looking at your code again, the section

> [@melhof](#):
>
> ```auto
> if (msg.topic == '0') {
> clearInterval(countdown);
> }
>     
> else if (counter <5) {
> clearInterval(countdown);
> }
> 
> ```

should not be inside the setInterval function, it should be at the outer level. As @Trying_to_learn said, the topic will never change in there as that instance of the function only has access to the original message.

---

<div class="post-metadata">

**Author:** ![melhof](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/melhof/32/25804_2.png) [@melhof](https://discourse.nodered.org/u/melhof)\
**Post date:** [15 July 2020 13:59 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/4 "2020-07-15T13:59:43Z")

</div>

Thank you Trying\_to\_learn & Colin.

I get closer in understanding, but after many hours of searching it is still a mystery to me why it is not working.

The Function Node is now listening to the topic 1 & 0 input.  
But once started with 1 it keeps counting to 5 and than stops.

If i first inject a 1 the countdown starts.

If 0 is injected while running it just shows 10 in between. But the original counting keeps going down.

I don't understand why:

- The clearInterval from "if (counter \<5) " stops the Interval.
- The one from "if (msg.topic == '0')" does only restart an separate IF process putting out the number 10.  
But does not stop the countdown of the still running Interval.

```auto
var counter = 10;
var countdown = setInterval(function(){
    node.send({payload:(counter)});
   
    if (msg.topic == '1') {
        counter--;
    }
    
    if (counter <5) {
        clearInterval(countdown);
    }

    if (msg.topic == '0') {
        clearInterval(countdown);
    }
}, 1000)

```

Here the nodes exported:

```auto
[{"id":"9a551ca4.5b30b","type":"function","z":"d2d9018a.7d512","name":"Countdown","func":"var counter = 10;\n\nvar countdown = setInterval(function(){\n\n node.send({payload:(counter)});\n node.status({fill:\"green\",shape:\"ring\",text:(counter)});\n\n if (msg.topic == '1') {\n counter--;\n }\n \n if (counter <5) {\n clearInterval(countdown);\n node.status({fill:\"red\",shape:\"dot\",text:'finished'});\n }\n\n if (msg.topic == '0') {\n clearInterval(countdown);\n node.status({fill:\"red\",shape:\"dot\",text:'stopped'});\n \n }\n}, 1000)","outputs":1,"noerr":0,"initialize":"","finalize":"","x":350,"y":120,"wires":[["4400ea00.ee4d34"]],"icon":"font-awesome/fa-hourglass-1"},{"id":"913ccad1.53a7e8","type":"inject","z":"d2d9018a.7d512","name":"1","props":[{"p":"topic","v":"1","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","x":180,"y":120,"wires":[["9a551ca4.5b30b"]],"icon":"node-red/arrow-in.svg"},{"id":"4400ea00.ee4d34","type":"debug","z":"d2d9018a.7d512","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":530,"y":120,"wires":[]},{"id":"b9f004b9.08bc68","type":"inject","z":"d2d9018a.7d512","name":"0","props":[{"p":"topic","v":"0","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","x":170,"y":180,"wires":[["9a551ca4.5b30b"]],"icon":"node-red/arrow-in.svg"}]

```

---

<div class="post-metadata">

**Author:** ![bakman2](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bakman2/32/6207_2.png) [@bakman2](https://discourse.nodered.org/u/bakman2)\
**Post date:** [15 July 2020 14:19 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/5 "2020-07-15T14:19:56Z")

</div>

You are comparing numbers to strings.  
`msg.topic` is send as a number, ` if (msg.topic == '0') {` should be ` if (msg.topic === 0) {`  
same applies to `1`

But could you explain what you are trying to achieve ? What is the end goal of this function ? If you receive more messages on this node the interval will become confusing.

---

<div class="post-metadata">

**Author:** ![JGKK](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jgkk/32/18515_2.png) [@JGKK](https://discourse.nodered.org/u/JGKK)\
**Post date:** [15 July 2020 14:40 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/6 "2020-07-15T14:40:18Z")

</div>

As @Colin said above you need to save the countdown to a context variable and check for the topics outside of the set intervall. Everytime you send a message to a function node it creates an instance of the function that doesnt know about the other instances of the same function. So your only way to have a persistent value across multiple invoked instances of the function is said context var. Something like this:

```auto
var countdown = context.get("countdown") || false;
if (!countdown && msg.topic === 1) {
    var counter = 10;
    node.send({payload:(counter)});
    node.status({fill:"green",shape:"ring",text:(counter)});
    countdown = setInterval(function(){
        counter -= 1;
        if (counter < 5) {
            clearInterval(countdown);
            context.set("countdown", false);
            node.status({fill:"red",shape:"dot",text:'finished'});
            return;
        }
        node.send({payload:(counter)});
        node.status({fill:"green",shape:"ring",text:(counter)});
    }, 1000); 
    context.set("countdown", countdown);
} else if (msg.topic === 0 && countdown) {
    clearInterval(countdown);
    node.status({fill:"red",shape:"dot",text:'stopped'});
    context.set("countdown", false);
}
return null;

```

This is not really tested and of the top of my head. Be aware that this is only the recommended way if your default context store is memory as nodered cant serialise the interval function and you will get funny errors when the default is filesystem. In this case use something like `context.countdown = countdown;` which is the old deprecated way to set context variables that is still recommended for this sitiuation.

Johannes

---

<div class="post-metadata">

**Author:** ![melhof](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/melhof/32/25804_2.png) [@melhof](https://discourse.nodered.org/u/melhof)\
**Post date:** [15 July 2020 20:16 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/7 "2020-07-15T20:16:00Z")

</div>

It's for our advanced well pump, filter, drinking and irrigation system.  
As our up hill 'water tower container' sensors give only full or empty. I want to simulate on the dashboard: slow emptying over the day and when filling up.  
I had already programmed a count up & down function. But got stuck and trimmed the setInterval function down to find out how to stop and control it.

---

<div class="post-metadata">

**Author:** ![melhof](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/melhof/32/25804_2.png) [@melhof](https://discourse.nodered.org/u/melhof)\
**Post date:** [15 July 2020 20:44 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/8 "2020-07-15T20:44:22Z")

</div>

Thank you Johannes,  
That is a really great and comprehensive answer.  
Your function script works flawlessly!  
I will now build it out to simulate on the dashboard: slow emptying over the day and when filling up. As our up hill 'water tower container' sensors give only full or empty.

I am just a novice and learning to program Node-Red since a month now.  
So your explanation teaches me a lot and i can continue to work on the 'far to big' task of our comprehensive well pump, filter, drinking and irrigation water system. It advances slowly as i am learning. The piping system is complete after a month of work, the electronics 2/3 ready. And i already have 1/3 of the whole program done. But i have time and patience.  
I will share the whole project on the slack forum (and maybe also here) when finished.

---

<div class="post-metadata">

**Author:** ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)\
**Post date:** [15 July 2020 21:21 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/9 "2020-07-15T21:21:13Z")

</div>

You should mark that post as the solution.

That's an option near the `like` button.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [29 July 2020 21:21 UTC](https://discourse.nodered.org/t/interval-in-if-loop-is-deaf-for-injecting-input/30093/10 "2020-07-29T21:21:18Z")

</div>

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