Need help creating a percentage timer

Hi Everybody.
My first post ever

So I am a bit new. I need to make a percentage time with a UI like a slider (with value on top) or something. The slide rage must me 0 - 100%.
The timer must never stop unless it receive a Stop or start payload.
The interval are 60sec.
How it works.
So if the timer is set to 100% is must stay on (59sec "on", 1sec "off"), if set to 50% it will run 30sec "on", 30sec "off". When set to 25% it must stay "on" 15sec and 45sec "off" ect.

Like the one found in pivots. Just a link
HQ4E03S48Z1, Eagle percentage timer, 60 sec, 24v DC — PIVOT PARTS NZ LTD

Can anybody help me with this it will be much appreciated.
Kind Regards. :grinning:

Something like this?

[{"id":"486331473707d1f0","type":"tab","label":"Timer","disabled":false,"info":"","env":[]},{"id":"76555f3c369988cb","type":"ui_slider","z":"486331473707d1f0","name":"","label":"slider","tooltip":"","group":"ef4f2259df8e9444","order":0,"width":0,"height":0,"passthru":false,"outs":"end","topic":"topic","topicType":"msg","min":0,"max":"100","step":"1","className":"","x":290,"y":460,"wires":[["1e2ccd19d6f09df0"]]},{"id":"4f6f36549af674c8","type":"change","z":"486331473707d1f0","name":"","rules":[{"t":"set","p":"loop.maxtimeout","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"#:(memoryOnly)::timer","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":460,"wires":[["88d8131ca2c2538c"]]},{"id":"1e2ccd19d6f09df0","type":"range","z":"486331473707d1f0","minin":"0","maxin":"100","minout":"0","maxout":"60","action":"scale","round":false,"property":"payload","name":"","x":410,"y":460,"wires":[["331eb14478eb4222"]]},{"id":"24e2543dee7d6aab","type":"debug","z":"486331473707d1f0","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1690,"y":460,"wires":[]},{"id":"2e614df05c573784","type":"looptimer-advanced","z":"486331473707d1f0","duration":"1","units":"Second","maxloops":"60","maxtimeout":"60","maxtimeoutunits":"Second","name":"","x":1040,"y":460,"wires":[["8bf4a48ac1ee77e0"],[]]},{"id":"8ddea48acdaa427e","type":"calculator","z":"486331473707d1f0","name":"","inputMsgField":"payload","outputMsgField":"payload","operation":"dec","constant":"1","round":true,"decimals":0,"x":1390,"y":460,"wires":[["e759fa715c3c35af"]]},{"id":"8bf4a48ac1ee77e0","type":"change","z":"486331473707d1f0","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"#:(memoryOnly)::timer","tot":"flow"},{"t":"delete","p":"loop","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1220,"y":460,"wires":[["8ddea48acdaa427e"]]},{"id":"e759fa715c3c35af","type":"change","z":"486331473707d1f0","name":"","rules":[{"t":"set","p":"#:(memoryOnly)::timer","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1550,"y":460,"wires":[["24e2543dee7d6aab"]]},{"id":"331eb14478eb4222","type":"calculator","z":"486331473707d1f0","name":"","inputMsgField":"payload","outputMsgField":"payload","operation":"inc","constant":"1","round":true,"decimals":0,"x":540,"y":460,"wires":[["4f6f36549af674c8"]]},{"id":"88d8131ca2c2538c","type":"calculator","z":"486331473707d1f0","name":"","inputMsgField":"loop.maxtimeout","outputMsgField":"loop.maxtimeout","operation":"dec","constant":"1","round":true,"decimals":0,"x":870,"y":460,"wires":[["2e614df05c573784"]]},{"id":"ef4f2259df8e9444","type":"ui_group","name":"Default","tab":"68441a133274969a","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"68441a133274969a","type":"ui_tab","name":"Slider timer","icon":"dashboard","disabled":false,"hidden":false}]

Not sure what you mean by on and off with a timer, but this will countdown from the desired percentage of 60 seconds until it reaches zero. You could just add a variable like msg.state to equal "on" when the value of msg.payload is anything but 0 and "off" when msg.payload equals 0.

Have a look at node-red-contrib-timeprop, it will do the on/off cycling for you.

What do you want it to do when it reaches the max of 60sec? Repeat?

Do you want it to output a msg every second of "on/off", or to output a countdown? Or do you want it to send "on" once and then send "off" when the time has elapsed?

Here you go. Try this. If you change the percentage the process will have to cycle once to adapt to the new setting.

Percent Timer


[{"id":"06a5897c9cc61dd0","type":"function","z":"d867d702.3f5658","name":"% Timer","func":"// initialize counter\nif (typeof (context.counter) === 'undefined') context.counter = flow.get(\"Counter\") || 0; \n// initialize percentage but it is set (and saved) by slider\nvar percentage = flow.get(\"Percent\") || 100;  \n// initialize control\nif (typeof (context.control) === 'undefined') context.control = flow.get(\"Control\") || true;  // default is run\n// increment counter\nif (msg.topic === \"clock\")   context.counter = context.counter + 1;             \n// control start / stop \n\nif (msg.topic === \"control\" && msg.payload === \"toggle\")\n{\n   if (!context.control) context.control = true   // not running, with toggle, run now\n   else     // must be  running, wwith toggle, stop running\n   {\n      context.control = false;\n      flow.set(\"Control\", context.control);\n      var result = { payload: false}; \n      node.status({ fill: \"red\", shape: \"ring\", text: \"Stopped: \" + context.counter + \" State: \" + result.payload });\n      return result;     // just keep sending off \n   }\n}  \n\n// make percentage\nvar on_period = 60 * (percentage / 100);    \n\nif (context.counter > on_period || context.counter === 60) var result = {payload: false}\nelse result = {payload: true}; \nnode.status({ fill: \"green\", shape: \"dot\", text: \"Running: \" + context.counter + \" State: \" + result.payload });\n\n\ncontext.counter = (context.counter > 59) ? 0 : context.counter;  // reset minute counter\nflow.set(\"Counter\", context.counter);\n\n// watch the variables for testing\n//node.warn(context.counter + \"' \" + on_period + \", \" + percentage + \"' \" + result.payload);\nreturn result;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1016,"y":450,"wires":[["707b5dcad62a3564"]]},{"id":"3f5c419f13323657","type":"inject","z":"d867d702.3f5658","name":"clock","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"clock","payload":"true","payloadType":"bool","x":874,"y":491,"wires":[["06a5897c9cc61dd0"]]},{"id":"ccd71b87003641d5","type":"ui_slider","z":"d867d702.3f5658","name":"Slider","label":"slider","tooltip":"","group":"","order":15,"width":0,"height":0,"passthru":false,"outs":"end","topic":"percent","topicType":"str","min":0,"max":"100","step":1,"className":"","x":996,"y":396,"wires":[["c1e040157b587223"]]},{"id":"c1e040157b587223","type":"change","z":"d867d702.3f5658","name":"Save Setting","rules":[{"t":"set","p":"Percent","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1117,"y":396,"wires":[[]]},{"id":"8b06c7568b8e99b5","type":"inject","z":"d867d702.3f5658","name":"Boot","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"Percent","payloadType":"flow","x":895,"y":396,"wires":[["ccd71b87003641d5"]]},{"id":"cb2ac63bafeefeb7","type":"inject","z":"d867d702.3f5658","name":"On / Off","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"control","payload":"toggle","payloadType":"str","x":875,"y":450,"wires":[["06a5897c9cc61dd0"]]},{"id":"707b5dcad62a3564","type":"debug","z":"d867d702.3f5658","name":"Result","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1140,"y":450,"wires":[]}]

You can feed the timer directly into the timeprop node. Job done.

Hi HaroldPetersInskipp.

I am from south africa so may have problem explaing. But wil get maybe a video.

Yes, the time must alway run, it used in irrigation system.
When set to 50% the time must turn on the relay for 30sec and the turn off the relay to 30sec. The total time of the timer must be 60sec and scaled from 0 - 100%.

To Start the repeating cycly the timer can receive Start payload.
To Stop the timer it can receive the a stop payload.
The pivot can water the land 4days not stop. Unless we get load shedding.

Is Your Eagle Percentage Timer Working? - YouTube

Thanks Again for the help

Hi StrongTown.

I all check it right away.

Still trying to learn jave.

Hi StrongTown.

Your skill are crazy COOOL. Can you assist with ON/OFF buttons. And maybe if reboot it will remember the last state it was in. (between on or off)
Kind Regards

:slightly_smiling_face: :upside_down_face: :slightly_smiling_face: :upside_down_face: :slightly_smiling_face:

Have you tried the node I suggested? Disclaimer, I am the author.

It's kinda neat that a guy stuck under the snow in Canada can help someone with irrigation in South Africa. That's awesome. Here, try this:


[{"id":"06a5897c9cc61dd0","type":"function","z":"d867d702.3f5658","name":"% Timer","func":"// initialize counter\nif (typeof (context.counter) === 'undefined') context.counter = flow.get(\"Counter\") || 0;\n// initialize percentage, set (and saved) by slider\nvar percent = (typeof (msg.payload) === 'number') ? (msg.payload / 100) : (flow.get(\"Percent\") / 100 || 1);\n// initialize last run state setting\nif (typeof(context.running) === 'undefined') context.running = flow.get(\"Run_State\"); \nif (typeof(context.running) === 'undefined') context.running = true;  // default is run // default is run\n// init vars, button label layout\nvar result, led_color = \"grey\", button = { label: \"Init\", txt_color: \"gold\", led: led_color };\n// process control start / stop \nif (msg.topic === \"control\" && msg.payload === \"toggle\")\n{ context.running = (context.running) ? false : true; flow.set(\"Run_State\", context.running);  }\n\nif (!context.running)  // system is set to OFF, let's exit\n   {\n      result = { payload: false}; \n      button = { label: \"Irrigation off  <font color=grey> [--] \", txt_color: \"lightgrey\", led: \"grey\" };\n      node.status({ fill: \"red\", shape: \"ring\", text: \"Stopped: \" + context.counter + \" State: \" + result.payload });\n      return [button, result];     // just keep sending off \n   }\n\n// make percentage\nvar on_period = 60 * percent;     \n// process clock tick\nif (msg.topic === \"clock\")   context.counter = context.counter + 1;    \nvar clock = (context.counter < 10) ? \"0\"+context.counter : context.counter;  // keeps clock display neater\n\nif (context.counter > on_period || context.counter === 60) { led_color = \"red\"; result = {payload: false};}\nelse { led_color = \"lime\"; result = {payload: true} }; \n\nbutton = { label: \"Irrigation on   <font color=gold> [\" + clock + \"] \", txt_color: \"lime\", led: led_color };\nnode.status({ fill: \"green\", shape: \"dot\", text: \"Running: \" + context.counter + \" State: \" + result.payload });\n\ncontext.counter = (context.counter > 59) ? 0 : context.counter;  // reset minute counter\nflow.set(\"Counter\", context.counter);\n\n// watch the variables for testing\n//node.warn(context.counter + \"' \" + on_period + \", \" + context.percentage + \"' \" + result.payload);\nreturn [button, result];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1020,"y":500,"wires":[["78f480f45e75474b"],["9dd3ea4155430dcf"]]},{"id":"3f5c419f13323657","type":"inject","z":"d867d702.3f5658","name":"clock","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"clock","payload":"true","payloadType":"bool","x":890,"y":500,"wires":[["06a5897c9cc61dd0"]]},{"id":"c1e040157b587223","type":"change","z":"d867d702.3f5658","name":"Save Setting","rules":[{"t":"set","p":"Percent","pt":"flow","to":"payload","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":1120,"y":565,"wires":[[]]},{"id":"8b06c7568b8e99b5","type":"inject","z":"d867d702.3f5658","name":"Boot","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"Percent","payloadType":"flow","x":898,"y":565,"wires":[["a160564fd65065e6"]]},{"id":"a160564fd65065e6","type":"ui_slider","z":"d867d702.3f5658","name":"Percent","label":"Timer %","tooltip":"","group":"926eb72c21d005a7","order":0,"width":0,"height":0,"passthru":false,"outs":"end","topic":"topic","topicType":"msg","min":"1","max":"100","step":1,"className":"","x":1008,"y":564,"wires":[["c1e040157b587223","06a5897c9cc61dd0"]]},{"id":"78f480f45e75474b","type":"ui_button","z":"d867d702.3f5658","name":"On / Off","group":"926eb72c21d005a7","order":15,"width":0,"height":0,"passthru":false,"label":"<font size = 3>{{msg.label}} <font color={{msg.led}}><i class=\"fa fa-circle\" ></i>","tooltip":"<font size = 3><font color = black>Click to toggle","color":"{{msg.txt_color}}","bgcolor":"black","className":"","icon":"","payload":"toggle","payloadType":"str","topic":"control","topicType":"str","x":1020,"y":455,"wires":[["06a5897c9cc61dd0"]]},{"id":"9dd3ea4155430dcf","type":"debug","z":"d867d702.3f5658","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1175,"y":505,"wires":[]},{"id":"926eb72c21d005a7","type":"ui_group","name":"Control","tab":"bf3ff3d2dc2786e4","order":10,"disp":true,"width":"6","collapse":false,"className":""},{"id":"bf3ff3d2dc2786e4","type":"ui_tab","name":"Irrigation","icon":"dashboard","order":7,"disabled":false,"hidden":false}]
3 Likes

The node suggested by @colin really is perfect for this then.

Here is a flow I've created for you using his node:

[{"id":"486331473707d1f0","type":"tab","label":"Timer","disabled":false,"info":"","env":[]},{"id":"76555f3c369988cb","type":"ui_slider","z":"486331473707d1f0","name":"","label":"slider","tooltip":"","group":"ef4f2259df8e9444","order":1,"width":0,"height":0,"passthru":false,"outs":"end","topic":"topic","topicType":"msg","min":0,"max":"100","step":"1","className":"","x":310,"y":180,"wires":[["775d0a30edf1682e","5920e75cb955c5d8"]]},{"id":"b39154fe744054f7","type":"ui_button","z":"486331473707d1f0","name":"","group":"ef4f2259df8e9444","order":2,"width":0,"height":0,"passthru":true,"label":"Start","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"start","payloadType":"str","topic":"topic","topicType":"msg","x":250,"y":120,"wires":[["e1eaf14dd0f75d67","17407d860044f890","0b9cee65e1d1d436"]]},{"id":"8c3d4a3b3b785562","type":"ui_button","z":"486331473707d1f0","name":"","group":"ef4f2259df8e9444","order":3,"width":0,"height":0,"passthru":true,"label":"Stop","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"stop","payloadType":"str","topic":"topic","topicType":"msg","x":250,"y":80,"wires":[["e1eaf14dd0f75d67","1fd169f541e736b3","0b9cee65e1d1d436"]]},{"id":"832766e356511ad9","type":"timeprop","z":"486331473707d1f0","name":"","cycleTime":"60","deadTime":0,"triggerPeriod":"1","invert":false,"x":560,"y":180,"wires":[["2ce960a75d65dc45"]]},{"id":"775d0a30edf1682e","type":"range","z":"486331473707d1f0","minin":"0","maxin":"100","minout":"0","maxout":"1","action":"scale","round":false,"property":"payload","name":"","x":430,"y":180,"wires":[["832766e356511ad9"]]},{"id":"af5485270512d6aa","type":"change","z":"486331473707d1f0","name":"0/on, 1/off","rules":[{"t":"change","p":"payload","pt":"msg","from":"1","fromt":"num","to":"off","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":"0","fromt":"num","to":"on","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":840,"y":180,"wires":[["bf539a01fee57ead","b44147c113571022","78dabf7f381fe4d6"]]},{"id":"bf539a01fee57ead","type":"debug","z":"486331473707d1f0","name":"output every second","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1140,"y":180,"wires":[]},{"id":"b44147c113571022","type":"rbe","z":"486331473707d1f0","name":"","func":"rbe","gap":"","start":"","inout":"out","septopics":true,"property":"payload","topi":"topic","x":970,"y":220,"wires":[["f0be1db8d989507d"]]},{"id":"f0be1db8d989507d","type":"debug","z":"486331473707d1f0","name":"output only when changed","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1150,"y":220,"wires":[]},{"id":"e1eaf14dd0f75d67","type":"change","z":"486331473707d1f0","name":"","rules":[{"t":"set","p":"#:(memoryOnly)::gate","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":120,"wires":[[]]},{"id":"2ce960a75d65dc45","type":"switch","z":"486331473707d1f0","name":"flow.gate","property":"#:(memoryOnly)::gate","propertyType":"flow","rules":[{"t":"eq","v":"start","vt":"str"},{"t":"eq","v":"stop","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":700,"y":180,"wires":[["af5485270512d6aa"],[]]},{"id":"78dabf7f381fe4d6","type":"ui_text","z":"486331473707d1f0","group":"ef4f2259df8e9444","order":5,"width":0,"height":0,"name":"","label":"Timer value","format":"{{msg.payload}}","layout":"row-spread","className":"","x":1110,"y":80,"wires":[]},{"id":"2ddba3b1ef0517f9","type":"inject","z":"486331473707d1f0","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"num","x":130,"y":120,"wires":[["b39154fe744054f7"]]},{"id":"9ecda3bbd195b8b9","type":"inject","z":"486331473707d1f0","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"num","x":130,"y":80,"wires":[["8c3d4a3b3b785562"]]},{"id":"1fd169f541e736b3","type":"change","z":"486331473707d1f0","name":"stop/off","rules":[{"t":"change","p":"payload","pt":"msg","from":"stop","fromt":"str","to":"off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":40,"wires":[["78dabf7f381fe4d6","bcbd53e66f56bbb8"]]},{"id":"bcbd53e66f56bbb8","type":"debug","z":"486331473707d1f0","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1110,"y":40,"wires":[]},{"id":"5920e75cb955c5d8","type":"change","z":"486331473707d1f0","name":"save slider value","rules":[{"t":"set","p":"#:(memoryOnly)::slider","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":220,"wires":[[]]},{"id":"17407d860044f890","type":"change","z":"486331473707d1f0","name":"get slider value","rules":[{"t":"set","p":"payload","pt":"msg","to":"#:(memoryOnly)::slider","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":160,"y":180,"wires":[["76555f3c369988cb","775d0a30edf1682e"]]},{"id":"07b522ea1c19711d","type":"inject","z":"486331473707d1f0","name":"inject once","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"num","x":150,"y":220,"wires":[["17407d860044f890"]]},{"id":"a4064cf1f4c89e7f","type":"ui_text","z":"486331473707d1f0","group":"ef4f2259df8e9444","order":4,"width":0,"height":0,"name":"","label":"Timer state","format":"{{msg.payload}}","layout":"row-spread","className":"","x":630,"y":80,"wires":[]},{"id":"0b9cee65e1d1d436","type":"change","z":"486331473707d1f0","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"stop","fromt":"str","to":"stopped","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":"start","fromt":"str","to":"started","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":80,"wires":[["a4064cf1f4c89e7f"]]},{"id":"59d385c58f7474e5","type":"comment","z":"486331473707d1f0","name":"Connect to one of these","info":"","x":1140,"y":260,"wires":[]},{"id":"0752fa269bada327","type":"comment","z":"486331473707d1f0","name":"Use dashboard or connect input here","info":"","x":160,"y":40,"wires":[]},{"id":"ef4f2259df8e9444","type":"ui_group","name":"Default","tab":"68441a133274969a","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"68441a133274969a","type":"ui_tab","name":"Slider timer","icon":"dashboard","disabled":false,"hidden":false}]

1 Like


This one is asking For calculator..
Which one must I install...

Sorry From Slow Reply, Field Electrician/Technician For WaiktoSA..

Almost never home

This one works nicely.

I am curious as to why you want a slider in percent rather then just the number of seconds you want the "on" period to be (slider select set 1 to 60) but perhaps there is a reason.

The farmers are old school and dont like change. There timers has dial or +/- buttons and they all work on %-on. We have lost of cable theft on on pivot.
image.
So the main idea to this is replacing if with "my system". That will act like an alarm.

That looks good too. Here is my result, just seems to meet my preference for node layout and Dashboard representation..

Awesome. Thanks for the picture. Hope it all works out for you.

1 Like

Why you are not using a simple range node to translate from percent in seconds?

[
    {
        "id": "b0f2a83d866e15db",
        "type": "range",
        "z": "ebe8134f6b5af26c",
        "minin": "0",
        "maxin": "100",
        "minout": "0",
        "maxout": "60",
        "action": "scale",
        "round": false,
        "property": "payload",
        "name": "",
        "x": 650,
        "y": 1320,
        "wires": [
            [
                "0ad56a79ed273b16"
            ]
        ]
    }
]

[HaroldPetersInskipp] used it nicely.