How do you use setInterval ?

2,057 views
Skip to first unread message

peter adshead

unread,
May 29, 2016, 10:36:07 AM5/29/16
to Node-RED
I`m working on my first node which is going to be a simple count down timer which show the time ticking down via status , but not getting passed the first hurdle.
in this.on('input', function (msg) { XXXXX } function I`ve added a setInterval eg :-


 
// respond to inputs....
 
this.on('input', function (msg) {
 myVar
= setInterval(myTimer() ,1000);
 
});

 
function myTimer() {
 node
.send(msg);
 clearInterval
(myVar);
 
}



But that just gives me this error .

29 May 14:19:05 - [red] Uncaught Exception:
29 May 14:19:05 - TypeError: timer._repeat is not a function
    at wrapper [as _onTimeout] (timers.js:275:11)
    at Timer.listOnTimeout (timers.js:92:15)

What am I doing wrong ?, it should work in plain old Javascript.

 

peter adshead

unread,
May 29, 2016, 11:06:01 AM5/29/16
to Node-RED
I think I`ve found what wrong , it`s myTimer and not myTimer() .

Ben Hardill

unread,
May 29, 2016, 3:55:04 PM5/29/16
to Node-RED
Any reason to use set interval rather than the delay node?


On Sunday, 29 May 2016 15:36:07 UTC+1, peter adshead wrote:

peter adshead

unread,
May 29, 2016, 4:47:25 PM5/29/16
to Node-RED
it is just learning to make my own node`s and a timer is a good place to start and problem solve.

Julian Knight

unread,
Jun 1, 2016, 3:16:16 PM6/1/16
to Node-RED
You got it. myTimer() tries to RUN the function, myTimer simply passes it as a reference. To use the former, myTimer() would have to return a function - which is possible in JavaScript but VERY confusing!!

Ana

unread,
Jan 13, 2017, 12:39:05 PM1/13/17
to Node-RED
I have the same error and I tried your solution but it doesn't seem to work for me :(

I have attached a screenshot. Please help
Screenshot from 2017-01-13 23-06-56.png
Message has been deleted

steve rickus

unread,
Jan 13, 2017, 2:38:56 PM1/13/17
to Node-RED
Hi Ana,
As Peter mentioned and Julian confirmed, you need to pass a reference to the function, not try to run the function in the setInterval(...) call.

Try taking the parentheses off following the function name, like so:

setInterval(upload_random_image, 3600000);

This way, you are passing the function object itself as the first argument to the setInterval method. The way you have it now, you are actually invoking the upload_random_image() function, and passing its returned value as the first argument to setInterval(...)

Hope that make more sense now!
--
Steve

Ana

unread,
Jan 14, 2017, 12:42:18 AM1/14/17
to Node-RED
Hi Steve,

Thanks for replying! I have already tried what you suggested but it just keeps running without printing anything if I try that and then I have to forcefully stop the execution.

Mario Bianchi

unread,
Jan 14, 2017, 7:53:32 AM1/14/17
to Node-RED
Hi Peter, I learned like you the setInterval and setTimer function as well DOES NOT work on Node Red, You could use a delay node, or an inject node to get a base of time and then you go from there.

Below an example of a flow using the inject node as a time reference, you would also need to use global or flow variables to get persistence of the counter on each invocation.

[{"id":"4ae8ed43.4a2c54","type":"inject","z":"adc7a796.b92e38","name":"","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":190,"y":160,"wires":[["f19c7223.76414"]]},{"id":"f19c7223.76414","type":"function","z":"adc7a796.b92e38","name":"","func":"// get global variuable, if undefined initialize to zero\nvar c=global.get(\"c\")||0;\n//increment variable and store under \"c\" label\nglobal.set(\"c\",++c);\nmsg.payload=c;\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":160,"wires":[["92d7dc22.39fca"]]},{"id":"92d7dc22.39fca","type":"debug","z":"adc7a796.b92e38","name":"","active":true,"console":"false","complete":"false","x":470,"y":160,"wires":[]}]

Hope this helps.

Julian Knight

unread,
Jan 14, 2017, 8:59:53 AM1/14/17
to Node-RED
Here is a working example using timers. This from a function node that takes input from a wireless magnetic switch via MQTT and output's a message that is then sent onward to a Telegram bot.

msg.payload = msg.payload.command


// Calculate the elapsed time
function elapsed() {
   
var el = {};
   
// Milliseconds
   
if (context.openTime) {
        el
.ms = new Date() - context.openTime;
   
} else {
        el
.ms = 0;
   
}
   
// seconds
    el
.sec = Math.round( el.ms / 1000 ); // or .toFixed(numdp);
   
// minutes
    el
.min = Math.round( el.ms / 60000 ); // or .toFixed(numdp);
   
// return object
   
return el;
} // --- end of elapsed() --- //


// What to do after the timout interval
function action() {
   
// This will complete a timer so there is now one less
    context
.timers--;
   
   
// When countdown expires, check if door is still open
   
if ( context.state == "Open" ) {
       
// Check whether door has really been open all the time or whether
       
// it has been closed then reopened. In the later case, the elapsed
       
// time will be less than the timeout. Wouldn't need this if we could use clearTimeout()!
       
if ( elapsed()['ms'] >= timeout ) {
           
//node.warn( "Freezer door is still open! - triggered from timeout - Elapsed time: " + elapsed()['min'] );
           
// Send the msg downstream
            node
.send( {'payload': 'Freezer door has been open for ' + elapsed()['min'] + ' minutes!', 'timers': context.timers} );
           
// Set up another reminder in timeout's time (keep going till someone shuts the door!) & keep track of how many
            context
.timers++;
            setTimeout
(action, timeout);
       
} else {
           
//node.warn("Freezer door was closed then opened again - triggered from timeout - Elapsed time: " + elapsed()['min'] + ', Timers: ' + context.timers );
       
}
   
} else {
       
//node.warn("Freezer door already closed - triggered from timeout - Elapsed time: " + elapsed()['min'] + ', Timers: ' + context.timers );
   
}
   
} // --- End of action() --- //


// How many minutes do we want to wait until we trigger the alarm?
// 5 minute countdown = 5*60*1000= 300000
var timeout = 300000;


// Check how many timeouts we have started
if ( !('timers' in context) ) context.timers = 0;


if ( msg.payload == "On" ) {
    node
.warn( 'Freezer door opened, Timers: ' + context.timers );
   
   
// Keep track of how long the door is open
   
if (!context.openTime) context.openTime = new Date();
   
// Track state
    context
.state = "Open";
   
// Create a new timer & keep track of how many
    context
.timers++;
   
//context.timeout1 = setTimeout(action, timeout);
    setTimeout
(action, timeout);
} else {
    node
.warn( "Freezer door has been closed - Elapsed time: " + elapsed()['min'] + ', Timers: ' + context.timers );
   
// track state
    context
.state = "Closed";
   
// If the door was open a long time, send a msg that it is now closed
   
if ( elapsed()['ms'] >= timeout ) {
        node
.send( {'payload': 'Freezer door is now closed but was open for ' + elapsed()['min'] + ' minutes!', 'timers': context.timers} );
   
}
   
// Reset the open time
   
if (context.openTime) context.openTime = false;
   
// Cancel the timeout
   
//clearTimeout(context.timeout1);
}


You will note that this is fairly old code and still sets the context variables directly (not got round to updating it). Also note that the switch only triggers once. That kicks off a timer. When the timer expires it checks whether the Off signal was received and if not, it outputs a warning and starts a new timer. So I get a warning every timout interval (5min). If an Off signal had been received at some point, it knows that the door had been closed within the timeout period so it doesn't need to do anything.

When the function node recieves an "On" it starts timing because I don't want any warning output for 5 minutes.

The node's context variable has the following structure: { "timers": integer, "state": "Open" or "Closed", "openTime": dateobject }

Colin Law

unread,
Jan 14, 2017, 9:08:37 AM1/14/17
to node...@googlegroups.com
On 14 January 2017 at 12:53, Mario Bianchi <mariod...@gmail.com> wrote:
> Hi Peter, I learned like you the setInterval and setTimer function as well
> DOES NOT work on Node Red, You could use a delay node, or an inject node to
> get a base of time and then you go from there.

On the contrary, setInterval and setTimer work perfectly well in
function nodes in node-red.

Ana please copy/paste the full code of your function node here.

Colin
Reply all
Reply to author
Forward
0 new messages