Hello,
Maybe this could be useful for you. It’s not a custom node but nearly
This is a subflow I build:
[{"id":"60288551.9399d4","type":"subflow","name":"elapsedTime","info":"","category":"","in":[{"x":60,"y":60,"wires":[{"id":"2cdff5f2.09a772"}]}],"out":[{"x":620,"y":60,"wires":[{"id":"287cb861.3f1bc","port":0}]}],"env":[{"name":"targetTime","type":"num","value":"0","ui":{"icon":"font-awesome/fa-history","label":{"en-US":"Target Time"},"type":"input","opts":{"types":["num"]}}}],"color":"#DDAA99","status":{"x":620,"y":140,"wires":[{"id":"4ff652da.75a3bc","port":0}]}},{"id":"d1cc3968.edcc9","type":"inject","z":"60288551.9399d4","name":"","props":[{"p":"payload"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"tick","payloadType":"str","x":110,"y":140,"wires":[["2cdff5f2.09a772"]]},{"id":"2cdff5f2.09a772","type":"function","z":"60288551.9399d4","name":"Timer","func":"const targetTime = env.get(\"targetTime\");\nlet elapsedTime = flow.get(\"elapsedTime\") || 0;\nconst runningNow = flow.get(\"runningNow\") || false;\nswitch (msg.payload) {\n case \"start\":\n if (!runningNow && elapsedTime !== targetTime) {\n flow.set(\"runningNow\", true);\n msg.payload = \"start\";\n msg.targetTime = targetTime;\n msg.elapsedTime = elapsedTime;\n msg.topic = \"output\";\n } else {\n msg.payload = false;\n }\n break;\n case \"stop\":\n if (runningNow && elapsedTime !== targetTime) {\n flow.set(\"runningNow\", false);\n node.send({payload:\"stop\",topic:\"output\",targetTime:targetTime,elapsedTime:elapsedTime});\n msg.payload = \"stopped at \" + elapsedTime + \"s elapsed of \" + targetTime + \"s target\";\n } else {\n msg.payload = false;\n }\n break;\n case \"reset\":\n if (elapsedTime !== 0) { flow.set(\"elapsedTime\", 0) }\n msg.payload = \"elapsed time reset, now 0s of \" + targetTime + \"s target elapsed\";\n break;\n case \"tick\":\n if (runningNow && elapsedTime + 1 < targetTime) {\n elapsedTime += 1;\n flow.set(\"elapsedTime\", elapsedTime);\n msg.payload = \"elapsed time: \" + elapsedTime + \"s of \" + targetTime + \"s target\";\n } else if (runningNow && elapsedTime + 1 >= targetTime) {\n flow.set(\"elapsedTime\", elapsedTime + 1);\n flow.set(\"runningNow\", false);\n node.send({payload:\"stop\",topic:\"output\",targetTime:targetTime,elapsedTime:elapsedTime + 1});\n msg.payload = targetTime + \"s target reached\";\n } else {\n msg.payload = false;\n }\n break;\n}\nif (!msg.payload) { return null; }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":250,"y":60,"wires":[["4ff652da.75a3bc","287cb861.3f1bc"]]},{"id":"4ff652da.75a3bc","type":"function","z":"60288551.9399d4","name":"status format","func":"let status = {};\nstatus.text = msg.payload;\nif(flow.get(\"runningNow\")){\n status.fill = \"green\";\n status.shape = \"dot\";\n} else {\n status.fill = \"yellow\";\n status.shape = \"ring\";\n}\nmsg.payload = status;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":470,"y":140,"wires":[[]]},{"id":"287cb861.3f1bc","type":"function","z":"60288551.9399d4","name":"OutputFormat","func":"if (msg.topic === \"output\") {\n if (msg.elapsedTime !== msg.targetTime) {\n msg.targetReached = false;\n } else {\n msg.targetReached = true;\n }\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":480,"y":60,"wires":[[]]},{"id":"66de909d.3817d8","type":"subflow:60288551.9399d4","z":"235a0def.b0da5a","name":"","env":[{"name":"targetTime","value":"12","type":"num"}],"x":510,"y":720,"wires":[["5584e6cb.4a2878"]]},{"id":"12f62a63.78df76","type":"inject","z":"235a0def.b0da5a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"start","payloadType":"str","x":290,"y":720,"wires":[["66de909d.3817d8"]]},{"id":"224caa7b.0e5e0e","type":"inject","z":"235a0def.b0da5a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"stop","payloadType":"str","x":290,"y":780,"wires":[["66de909d.3817d8"]]},{"id":"78fc7f60.6fe248","type":"inject","z":"235a0def.b0da5a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"reset","payloadType":"str","x":290,"y":840,"wires":[["66de909d.3817d8"]]},{"id":"5584e6cb.4a2878","type":"debug","z":"235a0def.b0da5a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":730,"y":720,"wires":[]}]
You can configure your target time in the subflow menu.
If you send
start as a
msg.payload
It will start the timer running and send a
msg.payload
of
start from the subflow which will than run until it reaches the configured target time upon which the subflow will send a
msg.payload
of
stop and stop the timer.
You can also stop/pause it at any point with a
msg.payload
of
stop which will stop/pause the timer and also send a
msg.payload
of
stop from the subflow.
Each
start or
stop payload send from the subflow also includes a handful of other useful
msg
properties:
every
msg
object has a
msg.targetTime
property which shows the the value of the set target time. in addition there is a
msg.ellapsedTime
property which is the time that the timer has already run towards the configure target. Lastly there is also a Boolean value in
msg.targetReached
which is
false as long as the elapsed time is below the target time and becomes
true in the final
msg
send by the subflow when the target time is reached.
Finally to reset the the elapsed time simply simply send a msg.payload
of reset to the subflow which will reset the elapsed time to 0.
The subflow is based on an inject node that sends a tick every second within the subflow. When a start message is received a flow var within the subflow gets set to true. As long as this runningNow var is true the subflow adds to the elapsed time based on its internal tick. As soon as a stop is send or the target is reached the runningNow var becomes false again and counting stops. The subflow also shows the progress in its status below the node.
Here are its internals:
If you would want to change the subflow to minute accuracy you would only have to change the tick inject to inject every minute. This would probably be more appropriate for your usecase.
Maybe you can salvage the basic principle of this subflow for your pool pump.
Johannes