Ideas for elapsed time counter please


Just renovating our pool and about to go live next week. We will be using an EnviroSwim system that essentially does away with the need for chlorine and instead uses Copper to neutralise the water.

We want to initially run the pump (which the enviroswim needs to operate) about 4 hours a day (will fine tune this as the new system settles in).

I want to incorporate this with our whole house energy monitoring system - so depending on total solar input and other loads operating want to have the pool pump as the first thing to be sacrificed to maximise self usage and minimize grid draw during the day (refer to Barts post re HEMS etc).

As such there is the real possibility that the pool pump may be turned on and off many times a day - so i want to manage this and am for the target run time, and keep a running tally of the total number of minutes in operation that day.

I will be operating the pump using a Sonoff POW2 with Tasmota.

So throw some ideas at me as to how to track target run times, elapsed run times for the day (and the week) etc

Anyone know a custom node that would do this - and allow starting and stopping/pausing ? throughout the day

I have used Neil Cherrys MyTimeout Node previously and it has worked well - but i do not think i can programatically pause it, nor grab the countdown time etc ?


Maybe this could be useful for you. It’s not a custom node but nearly :wink:
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.



Hey Johannes,

This sounds great thanks - will pull it down and start playing today and let you know how i go

Thanks for all the time and the great write up on this one