Two versions of a run time recorder.
- using js interval
- using inject node with 1 sec interval
If you want to persist your data you have to uncomment the lines with the file property and delete the one without this property (you have to allow persiting in the config file of node red).
the one with the inject node seems to be better if you have many counters using the same one second input tick.
[{"id":"7d59ab9f9006822a","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"e67e5eb282e6cd54","type":"function","z":"7d59ab9f9006822a","name":"Run Time","func":"let s = context.get('s');\nlet d;\n\nif (msg.payload === \"tick\"){\n if (context.get('on_off') === true){\n myTimer();\n } \n return null;\n}\n\nif(msg.payload === \"on\"){\n context.set('on_off',true);\n context.get('s');\n return null;\n}\nelse if (msg.payload === \"off\"){\n context.set('on_off',false);\n context.set('s',s);\n return null; \n}\nelse if (msg.payload === \"reset\") {\n context.set('on_off',false);\n s = 0;\n d = hms(s);\n node.send({ payload: d });\n node.status({ fill: \"blue\", shape: \"ring\", text: d });\n context.set('s', s);\n return null;\n}\n\n//--------------------------------------------------------------------\n\nfunction myTimer() {\n s = context.get('s') + 1;\n d = hms(s);\n node.send({ payload: d });\n node.status({ fill: \"blue\", shape: \"ring\", text: d });\n context.set('s', s);\n}\n\n//--------------------------------------------------------------------\n\nfunction hms(ms) {\n //let t = Math.round(ms / 1000);\n let t = Math.round(ms); \n let h = (Math.floor(t / 3600)).toString();\n let m = (Math.floor(t % 3600 / 60)).toString();\n let s = (Math.floor(t % 3600 % 60)).toString();\n let r = h + \":\" + (\"0\" + m).slice(-2) + \":\" + (\"0\" + s).slice(-2);\n return r;\n}\nreturn msg;\n\n//--------------------------------------------------------------------","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nlet s = context.get('s') || 0;\nif (s === 0) {\n context.set('s', 0);\n}\ncontext.set('on_off',false);","finalize":"","libs":[],"x":420,"y":320,"wires":[["0a52339212febf35"]]},{"id":"a2c229d175da31ac","type":"inject","z":"7d59ab9f9006822a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"on","payloadType":"str","x":190,"y":300,"wires":[["e67e5eb282e6cd54"]]},{"id":"0a52339212febf35","type":"debug","z":"7d59ab9f9006822a","name":"runtime string","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":600,"y":320,"wires":[]},{"id":"85cdf7a9653377ac","type":"inject","z":"7d59ab9f9006822a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"off","payloadType":"str","x":190,"y":340,"wires":[["e67e5eb282e6cd54"]]},{"id":"5ce9c3677e9df258","type":"inject","z":"7d59ab9f9006822a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"1","topic":"","payload":"reset","payloadType":"str","x":190,"y":380,"wires":[["e67e5eb282e6cd54"]]},{"id":"4f717ba601592fad","type":"inject","z":"7d59ab9f9006822a","name":"tick every second","props":[{"p":"payload"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"tick","payloadType":"str","x":150,"y":260,"wires":[["e67e5eb282e6cd54"]]},{"id":"b731b43512e0f8cf","type":"inject","z":"7d59ab9f9006822a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"on","payloadType":"str","x":190,"y":100,"wires":[["4f5076f27d2d650d"]]},{"id":"dc1219d848226679","type":"debug","z":"7d59ab9f9006822a","name":"runtime string","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":600,"y":140,"wires":[]},{"id":"d6527d3ecd0309eb","type":"inject","z":"7d59ab9f9006822a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"off","payloadType":"str","x":190,"y":140,"wires":[["4f5076f27d2d650d"]]},{"id":"8373228e0d0e6ff2","type":"inject","z":"7d59ab9f9006822a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"1","topic":"","payload":"reset","payloadType":"str","x":190,"y":180,"wires":[["4f5076f27d2d650d"]]},{"id":"4f5076f27d2d650d","type":"function","z":"7d59ab9f9006822a","name":"Run Time","func":"let d;\nlet s = context.get('s');\n// let s = context.get('s',\"file\");\n\nif(msg.payload === \"on\"){\n context.get('s');\n// context.get('s',\"file\"); \n context.set('myInterval', setInterval(myTimer, 1000));\n return null;\n}\nelse if (msg.payload === \"off\"){\n clearInterval(context.get('myInterval'));\n context.set('s',s);\n //context.set('s',s,\"file\");\n return null; \n}\nelse if (msg.payload === \"reset\") {\n clearInterval(context.get('myInterval'));\n s = 0;\n d = hms(s);\n node.send({ payload: d });\n node.status({ fill: \"blue\", shape: \"ring\", text: d });\n context.set('s', s);\n// context.set('s',s,\"file\");\n return null;\n}\n\n//--------------------------------------------------------------------\n\nfunction myTimer() {\n s = context.get('s') + 1;\n// s = context.get('s',\"file\") + 1; \n d = hms(s);\n node.send({payload:d});\n node.status({ fill: \"blue\", shape: \"ring\", text: d });\n context.set('s', s);\n// context.set('s',s,\"file\"); \n}\n\n//--------------------------------------------------------------------\n\nfunction hms(ms) {\n //let t = Math.round(ms / 1000);\n let t = Math.round(ms); \n let h = (Math.floor(t / 3600)).toString();\n let m = (Math.floor(t % 3600 / 60)).toString();\n let s = (Math.floor(t % 3600 % 60)).toString();\n let r = h + \":\" + (\"0\" + m).slice(-2) + \":\" + (\"0\" + s).slice(-2);\n return r;\n}\nreturn msg;\n\n//--------------------------------------------------------------------","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nlet s = context.get('s',\"file\") || 0;\nif (s === 0) {\n context.set('s',0); \n// context.set('s',0, \"file\");\n}","finalize":"","libs":[],"x":420,"y":140,"wires":[["dc1219d848226679"]]}]