# Counting to three

**URL:** <https://discourse.nodered.org/t/counting-to-three/14875>\
**Category:** General\
**Created:** [28 August 2019 23:07 UTC](https://discourse.nodered.org/t/counting-to-three/14875 "2019-08-28T23:07:22Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kitus](https://avatars.discourse-cdn.com/v4/letter/k/71c47a/32.png) [@kitus](https://discourse.nodered.org/u/kitus)\
**Post date:** [28 August 2019 23:07 UTC](https://discourse.nodered.org/t/counting-to-three/14875/1 "2019-08-28T23:07:22Z")

</div>

Hello,

I currently have several automations in Home Assistant that will roll down the covers and awning, they however rely on a poll state node which monitors one of my outdoor sensors (wind and rain).

I would like to refine the logic a bit and have NR count to three before triggering the action. I'm very new to function nodes (as a matter of fact I've been avoiding them for months) but I came up with this:

```auto
var count = flow.get('count')||0;
count++;
msg.payload=count;
flow.set('count',count);
if (count>=3) {
    msg.payload=count;
    count=0;
    flow.set('count',count);
    return msg;
}

```

I think it works but I'm not happy with the looks of it. I'm sure it can be done more efficiently and nicely, specially with the condition "count\>=3"; I had to give in and include "\>" because at some point I notice count had gone beyond 3, and I was in a forever loop.

Many thanks in advance,

---

<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:** [28 August 2019 23:14 UTC](https://discourse.nodered.org/t/counting-to-three/14875/2 "2019-08-28T23:14:30Z")

</div>

You initialize `count` and immediately increment it with 1, puzzling...

What are you counting ? You can possibly solve it by using the trigger node instead.

---

<div class="post-metadata">

**Author:** ![kitus](https://avatars.discourse-cdn.com/v4/letter/k/71c47a/32.png) [@kitus](https://discourse.nodered.org/u/kitus)\
**Post date:** [29 August 2019 06:06 UTC](https://discourse.nodered.org/t/counting-to-three/14875/3 "2019-08-29T06:06:00Z")

</div>

> [@bakman2](#):
>
> You initialize `count` and immediately increment it with 1, puzzling...

Don’t be too hard on me please, I did not code for 12 years. It may feel trivial to most of the people here, but I feel I have a very long road ahead... functions, messages, topics, etc. feel daunting but I see so much potential in NR that it has brought back my interest in coding.

```auto
count++;

```

could very well be the last sentence now that you mention it 😊

> [@bakman2](#):
>
> What are you counting ? You can possibly solve it by using the trigger node instead.

I am just trying to refrain my automations from triggering the first time the condition I’ve defined us true. For example, I have an automation that rolls down the shutters when the outdoor rain gauge detects rain. What I want to do is for that condition to be true 3 times before I roll down the shutters and not the very first time rain is detected.

---

<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:** [29 August 2019 06:32 UTC](https://discourse.nodered.org/t/counting-to-three/14875/4 "2019-08-29T06:32:35Z")

</div>

Looks fine to me. Easy to read and understand in 6 months time when you need to. Leave the count++ where it is. Only thing you don't need to do is the first msg.payload=count

---

<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:** [29 August 2019 07:20 UTC](https://discourse.nodered.org/t/counting-to-three/14875/5 "2019-08-29T07:20:57Z")

</div>

Yes you are right that it is daunting from your perspective, I am looking at NR too much now I think of it 😉

It can be simplified like:

```auto
c = context.get('count')||0
node.status({text:"count: "+c})

if(c>2){
    context.set('count',0)
    return msg
}else{
    c++
    context.set('count',c)
}

```

I am using node context here so that the count applies to the function node itself, it will send the payload on 3, but it starts at 0, so that is at the 4th time.

Flow example

```auto
[{"id":"3668033d.c117ec","type":"inject","z":"681f8bde.8887bc","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":168,"y":588,"wires":[["b13355ec.4394a8"]]},{"id":"b13355ec.4394a8","type":"function","z":"681f8bde.8887bc","name":"","func":"c = context.get('count')||0\nnode.status({text:\"count: \"+c})\n\nif(c>2){\n context.set('count',0)\n return msg\n}else{\n c++\n context.set('count',c)\n}\n\n\n ","outputs":1,"noerr":0,"x":302,"y":588,"wires":[["aa7d9085.c1b55"]]},{"id":"aa7d9085.c1b55","type":"debug","z":"681f8bde.8887bc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":462,"y":588,"wires":[]}]

```

---

<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:** [29 August 2019 08:19 UTC](https://discourse.nodered.org/t/counting-to-three/14875/6 "2019-08-29T08:19:47Z")

</div>

As is often the case there are numerous ways of coding stuff, and it is down to personal preference which way to go. I would probably do it slightly differently

```auto
let count = context.get('count')||0
if (++count >=3) {
    count = 0
} else {
    msg = null
}
node.status({text:`count: ${count}`})
context.set('count',count)
return msg

```

I like to have all the context gets at the start and save them all at the end. It is very easy with a more complex function to forget to save variables back.  
Also I don't like to have returns in the middle of a function, it can easily cause confusion. Setting msg to null in the `else` clause means that the `return msg` at the end does nothing.

---

<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:** [29 August 2019 09:22 UTC](https://discourse.nodered.org/t/counting-to-three/14875/7 "2019-08-29T09:22:53Z")

</div>

> [@bakman2](#):
>
> You initialize `count` and immediately increment it with 1, puzzling...
> 
> What are you counting ? You can possibly solve it by using the trigger node instead.

I'll play "devil's advocate" here.

```auto
var count = flow.get('count')||0;
count++;

```

What am I missing?  
He sets/gets **count** from `flow.get( )` and increments it.  
So?

@kitus  
Just one thing looking at your first post:

```auto
var count = flow.get('count')||0;
count++;
msg.payload=count;
flow.set('count',count);
if (count>=3) {
   msg.payload=count;
   count=0;
   flow.set('count',count);
   return msg;
}

```

I don't get why you `flow.set( )` twice?  
Line 4 saves the value. Then you check if count \>= 3  
If it is, increment and save - - - **agin**?

Good luck with it. It is good to see you are trying. There is nothing wrong with making mistakes.  
I know and can speak from experience.  
(As I am sure many will confirm)

---

<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:** [29 August 2019 09:43 UTC](https://discourse.nodered.org/t/counting-to-three/14875/8 "2019-08-29T09:43:44Z")

</div>

> [@Trying\_to\_learn](#):
>
> I don't get why you `flow.set( )` twice?

Think about the `else` case.

---

<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:** [29 August 2019 09:44 UTC](https://discourse.nodered.org/t/counting-to-three/14875/9 "2019-08-29T09:44:34Z")

</div>

it is set again because it is (re)set to 0 before being saved - but only if it was \>-3. So there is no mistake there. (hereby confirming what you said 😉

---

<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:** [29 August 2019 09:50 UTC](https://discourse.nodered.org/t/counting-to-three/14875/10 "2019-08-29T09:50:48Z")

</div>

> [@Colin](#):
>
> Think about the `else` case.

Sorry Colin. which `else`?

I say @dceejay's reply. Ok, got it now. But now sort of confused with your mentioning the `else` - which I take it as being implied from the `if / then`

---

<div class="post-metadata">

**Author:** ![Paul-Reed](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/paul-reed/32/66906_2.png) [@Paul-Reed](https://discourse.nodered.org/u/Paul-Reed)\
**Post date:** [29 August 2019 09:58 UTC](https://discourse.nodered.org/t/counting-to-three/14875/11 "2019-08-29T09:58:43Z")

</div>

I haven't loaded up your flow, but shouldn't there be a time element in this, so it only triggers if you have 3 alerts within say, 30 minutes?  
Presently, if you get 1 alert at 10am, another at 3pm, and then a third alert 3 hours later at 6pm, the shutter would close.

The same would apply if you got 2 alerts on Thursday, and didn't get the 3rd alert until Saturday - 2 days later.

---

<div class="post-metadata">

**Author:** ![kitus](https://avatars.discourse-cdn.com/v4/letter/k/71c47a/32.png) [@kitus](https://discourse.nodered.org/u/kitus)\
**Post date:** [29 August 2019 16:47 UTC](https://discourse.nodered.org/t/counting-to-three/14875/13 "2019-08-29T16:47:37Z")

</div>

Absolutely. I feel dumb!! How stupid of me!!

Will work on addressing that too. If you have a clever way to control that and care to share it, I would appreciate it.

Thanks

---

<div class="post-metadata">

**Author:** ![kitus](https://avatars.discourse-cdn.com/v4/letter/k/71c47a/32.png) [@kitus](https://discourse.nodered.org/u/kitus)\
**Post date:** [29 August 2019 16:57 UTC](https://discourse.nodered.org/t/counting-to-three/14875/14 "2019-08-29T16:57:39Z")

</div>

> [@Trying\_to\_learn](#):
>
> It is good to see you are trying. There is nothing wrong with making mistakes.  
> I know and can speak from experience.  
> (As I am sure many will confirm)

Many thanks for your support!! 🙂

---

<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:** [29 August 2019 18:09 UTC](https://discourse.nodered.org/t/counting-to-three/14875/15 "2019-08-29T18:09:22Z")

</div>

> [@Trying\_to\_learn](#):
>
> Sorry Colin. which `else` ?

There is only one `if` so there can be no confusion over which `else` case I was referring to. There is no `else` code, but the case can still occur (which is the test failing). If the first write were removed then there would be nothing saving the incremented value as there is no code for the `else` case. In the solution I proposed the write is delayed till the end so only one is needed, but it is necessary to set msg to null instead.

---

<div class="post-metadata">

**Author:** ![Paul-Reed](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/paul-reed/32/66906_2.png) [@Paul-Reed](https://discourse.nodered.org/u/Paul-Reed)\
**Post date:** [29 August 2019 21:03 UTC](https://discourse.nodered.org/t/counting-to-three/14875/16 "2019-08-29T21:03:47Z")

</div>

> [@kitus](#):
>
> If you have a clever way to control that and care to share it, I would appreciate it.

I've written a little flow which will only provide an output if 3 messages are passed in within a certain time period.  
The output is currently `true` but could be anything that you want.  
The function node code is;

```auto
// number of seconds before timestamps expire
// eg for 30 minutes const t = 1800;
const t = 20;

// get the saved array
ar = flow.get("ar")||[];

// obtain a timestamp
var d = new Date();
var ts = d.getTime();

// add new timestamp to array
ar.push(ts);

// delete timestamps from array which are older than 't'
var oldest = ts - (1000 * t);
ar = ar.filter(function(v) { return v > oldest; });

// if number of timestamps in array is equal to or
// greater than 3, send a msg & clear the array
if (ar.length >= 3) {
    node.send({payload:true});
    ar = [];
    node.status({text:ar.length});
} else {
    node.status({text:ar.length});
}

// save the array
flow.set("ar", ar);

```

and the flow is;

```auto
[{"id":"602346eb.660218","type":"inject","z":"c53060.842a0fa","name":"","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":200,"y":910,"wires":[["d016499f.e065c8"]]},{"id":"858f959.d528868","type":"debug","z":"c53060.842a0fa","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":540,"y":910,"wires":[]},{"id":"d016499f.e065c8","type":"function","z":"c53060.842a0fa","name":"","func":"// number of seconds before timestamps expire\nconst t = (10);\n\n// get the saved array\nar = flow.get(\"ar\")||[];\n\n// obtain a timestamp\nvar d = new Date();\nvar ts = d.getTime();\n\n// add new timestamp to array\nar.push(ts);\n\n// delete timestamps from array which are older than 't'\nvar oldest = ts - (1000 * t);\nar = ar.filter(function(v) { return v > oldest; });\n\n// if number of timestamps in array is equal to or\n// greater than 3, send a msg & clear the array\nif (ar.length >= 3) {\n node.send({payload:true});\n ar = [];\n node.status({text:ar.length});\n} else {\n node.status({text:ar.length});\n}\n\n// save the array\nflow.set(\"ar\", ar);\n","outputs":1,"noerr":0,"x":370,"y":910,"wires":[["858f959.d528868"]]}]

```

---

<div class="post-metadata">

**Author:** ![kitus](https://avatars.discourse-cdn.com/v4/letter/k/71c47a/32.png) [@kitus](https://discourse.nodered.org/u/kitus)\
**Post date:** [29 August 2019 23:15 UTC](https://discourse.nodered.org/t/counting-to-three/14875/17 "2019-08-29T23:15:50Z")

</div>

I bow to you. Thank you so much!! Will use your code in my automations 🙂

Many many thanks!!!

---

<div class="post-metadata">

**Author:** ![kitus](https://avatars.discourse-cdn.com/v4/letter/k/71c47a/32.png) [@kitus](https://discourse.nodered.org/u/kitus)\
**Post date:** [31 August 2019 11:31 UTC](https://discourse.nodered.org/t/counting-to-three/14875/18 "2019-08-31T11:31:01Z")

</div>

Thanks @Paul-Reed for the code above. I like how clean it looks. I see you are using functions that I did not even now existed. I like how clean it looks.

---

<div class="post-metadata">

**Author:** ![Paul-Reed](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/paul-reed/32/66906_2.png) [@Paul-Reed](https://discourse.nodered.org/u/Paul-Reed)\
**Post date:** [31 August 2019 19:15 UTC](https://discourse.nodered.org/t/counting-to-three/14875/19 "2019-08-31T19:15:30Z")

</div>

> [@kitus](#):
>
> Thanks @Paul-Reed for the code above

You are welcome  
I enjoyed the challenge!

---

<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:** [1 September 2019 08:09 UTC](https://discourse.nodered.org/t/counting-to-three/14875/20 "2019-09-01T08:09:02Z")

</div>

I wonder whether a slightly different approach would achieve what you need without resorting to function nodes. Rather than requiring a certain number of messages before passing the value on it requires the input to be maintain the same state for a certain time (5 seconds in this example).

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/8/823f350ca04f40b945388468aebbf261221bda39.png)

```auto
[{"id":"ec018307.e0a388","type":"debug","z":"514a90a5.c7bae8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":641,"y":325,"wires":[]},{"id":"c6db66aa.9c3688","type":"inject","z":"514a90a5.c7bae8","name":"","topic":"","payload":"open","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":157,"y":293,"wires":[["8510b965.3f5868"]]},{"id":"614774fa.f90814","type":"inject","z":"514a90a5.c7bae8","name":"","topic":"","payload":"close","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":157,"y":350,"wires":[["8510b965.3f5868"]]},{"id":"25e323f7.6d88f4","type":"trigger","z":"514a90a5.c7bae8","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"5","extend":true,"units":"s","reset":"","bytopic":"all","name":"Debounce 5 sec","x":458,"y":325,"wires":[["ec018307.e0a388"]]},{"id":"8510b965.3f5868","type":"rbe","z":"514a90a5.c7bae8","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":299,"y":325,"wires":[["25e323f7.6d88f4"]]}]

```

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [2 September 2019 07:34 UTC](https://discourse.nodered.org/t/counting-to-three/14875/21 "2019-09-02T07:34:22Z")

</div>

If I were being picky, there are some `var`s in there that could be `const`. Doesn't really make much difference to code this small but would still be good practice to use const where a variable shouldn't change after being first set.

Also a bug, `ar =` should be `const ar =` - note that, in JavaScript, objects and arrays **can** be changed even when set with `const`, you just can't completely replace them with some thing different.

```javascript
// Won't work
const ar = {}
ar = "fred"

// Will work
const ar = {}
ar.myproperty = "fred"

```

OK, actually I see that you do replace `ar` later on so the line should be `let ar =` or `var ar =`

[Next page](https://discourse.nodered.org/t/counting-to-three/14875.md?page=2)
