Help with javascript timer with pause/resume

1,024 views
Skip to first unread message

Richard Sears

unread,
Nov 8, 2017, 6:10:13 PM11/8/17
to Node-RED
With a lot of help from the node-red community (most notably Steve Rickus) I am building a simulator session tracking flow. I am making great progress but I have run into a bit of a wall. I am NOT a javascript person, so I am learning as I am going.

The basics are that someone can start a sim session, pause for a break or for maintenance, unpause from a break or maintenance and then stop the sim session. Anytime the session is paused for break or maintenance the countdown timer should pause.

When the sim session is started there is a selected amount of time the sim session is supposed to last. This information is sent to a gauge via a timer function to show the remaining time and send some pushbullet notifications when the session is close to ending and if it is stopped manually.

The part I am having trouble with is the pause and resume parts of the timer. 

This is what I have been able to make work, but any attempts to add the pause/resume function (was using this example) ends in disaster:

var session_start = (msg.payload.CE525.Start);
var session_time = (msg.payload.CE525.Session_Time);

var session_time_minutes = session_time*60;

starting_minutes = session_time_minutes * 60000;

var max_gauge_minutes = session_time_minutes+10;
var min_max = msg.ui_control = { "min":-0, "max":max_gauge_minutes };

if (session_start === true)
{
var count = session_time_minutes;
msg.payload=count;
node.send([null,msg]);
var countdown = setInterval(function() {count=count-1;msg.payload=count; node.send([null,msg]) }, 60000);
context.set('countdown',countdown);
}
else if (session_start === false)
{
var countdownstop  = context.get('countdown')
clearInterval(countdownstop);
var min_max = msg.ui_control = { "min":0, "max":240 };
msg.payload = ("CE525 Sim Session Ended Manually")
node.send([msg,msg]);
}

Any help would be greatly appreciated!


Richard Sears

unread,
Nov 8, 2017, 7:32:05 PM11/8/17
to Node-RED
I did find what looks to be a very simple way to make the timer work, I just do not have any clue how to take it from javascript and make it work with node-red!!

var d1 = new Date();
d1.setHours(1,30,0);

var t = 0;

function f(){
    var h= d1.getHours();
    var m= d1.getMinutes();
    var s=d1.getSeconds();
    m= (m<10)?"0"+m: m;
    s= (s<10)? "0"+s : s;
    
    var el= document.getElementById("inputid");
    el.value= h+":"+m+":"+s;
    d1.setSeconds(d1.getSeconds()-1);
    if( h==0 && m==0 && s==0 ) clearTimeout(t)
    t= setTimeout(f,1000);
}

function pause(){
    clearTimeout(t);
    document.getElementById("pauseButton").disabled = "disabled";
    document.getElementById("resumeButton").disabled = "";
}


function resume(){
    t= setTimeout(f,1000);
    document.getElementById("pauseButton").disabled = "";
    document.getElementById("resumeButton").disabled = "disabled";
}


and the html part of it:

<form><input type="text" id="inputid"></form>
<script type="text/javascript">f()</script>

<input id="pauseButton" type="button" value="Pause" onclick="pause()" />
<input id="resumeButton" type="button" value="Resume" onclick="resume()" disabled="disabled" />



I do not even need the seconds, just the hours and minutes :-)

Colin Law

unread,
Nov 9, 2017, 2:56:54 AM11/9/17
to node...@googlegroups.com
I only have my phone at the moment so not able to fully examine your function but do have a suggestion, which is a general point about how to develop an application. That is to split all issues relating to display and input from issues relating to the process itself. So in your case concentrate first on getting the timing to work and then worry about how to display it. This means, for example, that the timers should operate in milliseconds which will much simplify the code you posted. Once you have got that running, possibly just using inject and debug nodes to drive it and see what is happening, then worry about displaying the data and controlling from the dashboard. I always put display related stuff on separate tabs in the flow.

Colin

--
http://nodered.org
 
Join us on Slack to continue the conversation: http://nodered.org/slack
---
You received this message because you are subscribed to the Google Groups "Node-RED" group.
To unsubscribe from this group and stop receiving emails from it, send an email to node-red+unsubscribe@googlegroups.com.
To post to this group, send email to node...@googlegroups.com.
Visit this group at https://groups.google.com/group/node-red.
To view this discussion on the web, visit https://groups.google.com/d/msgid/node-red/96b4ce00-23ae-448b-af29-92d07383100b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

steve rickus

unread,
Nov 9, 2017, 11:54:50 AM11/9/17
to Node-RED
Richard,

Once again, you've posed an interesting problem: how to wire up a countdown timer with the ability to be paused/resumed...
Here is what I came up with:


The main input is a numeric payload with the initial number of seconds (or minutes, in your case). As long as the value is > 0, the number is decremented and held for a delay of 1 sec. That decremented value would normally be passed to your gauge, but if a msg.reset is received before the delayed time is up, the msg is never sent. Upon resume, the trick is to get the remaining full units of time and pass in msg.payload, along with a msg.delay of the fractional part left before hitting the pause button (or just use 1 if you don't care about the fractional time used before pausing the timer).

I would suggest importing the attached flow and making it into a subflow. This way you can use it wherever you need a timer, and not have to worry about the flow.time_remaining values colliding with each other or with any flow context variables in the main flow. I plan on doing that locally, and posting the whole solution on flows.nodered.org for future reference.

Of course, any alternate or simplified ways to provide this behavior are always welcome. For instance, I know I've seen function code that uses setTimeout() in a repeating loop to send a msg object, until some condition exists. While this is much more compact than my subflow, I'm never quite sure how to clean up these things, to release memory and timers (if that is even necessary in the function sandbox?). The other logical solution would be a contrib node that does the same thing -- a stopwatch of sorts that spits out incrementing/decrementing values and can be paused/resumed -- hmmm...
--
Steve


countdown-with-pause.json
Reply all
Reply to author
Forward
0 new messages