I have been using Node-RED for Homeassistant automations for some time now. I was previously using other timer nodes implementations for my automations (looptimer, stoptimer etc.) but didn't find any timer nodes that offer looping and delay functionality along with starting, stopping, pausing, continuing and resetting all in one node. Also I haven't created any Node-RED nodes before so I gave it a go.
node-red-contrib-controltimer offers looping and delay behaviour. The timer can be started, reset, stopped, paused and continued - this applies to both the looping and delay behaviour. The actions can be enabled or disabled as required. Controltimer has two outputs - the first one outputs the message when timer is triggered (delay expires or interval is triggered) and the second one outputs the message when the running timer is stopped or paused.
It offers some more configuration options to aspire to be the only universal timer you would need in your flows.
State chart:
Example flow to test it out:
[ { "id": "e3c81493.d9d2f8", "type": "tab", "label": "ControlTimer Example", "disabled": false, "info": "" }, { "id": "e9565a66.765b58", "type": "inject", "z": "e3c81493.d9d2f8", "name": "", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "START", "payloadType": "str", "x": 110, "y": 40, "wires": [ [ "302cfb99.eb6ad4" ] ] }, { "id": "87b98e47.b188c", "type": "debug", "z": "e3c81493.d9d2f8", "name": "TIMER TRIGGERED", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 580, "y": 120, "wires": [] }, { "id": "6f03d8e2.43ef98", "type": "inject", "z": "e3c81493.d9d2f8", "name": "", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "STOP", "payloadType": "str", "x": 110, "y": 80, "wires": [ [ "302cfb99.eb6ad4" ] ] }, { "id": "80765310.41236", "type": "inject", "z": "e3c81493.d9d2f8", "name": "", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "RESET", "payloadType": "str", "x": 110, "y": 120, "wires": [ [ "302cfb99.eb6ad4" ] ] }, { "id": "8efa6f10.34b82", "type": "inject", "z": "e3c81493.d9d2f8", "name": "", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "PAUSE", "payloadType": "str", "x": 110, "y": 160, "wires": [ [ "302cfb99.eb6ad4" ] ] }, { "id": "dc1a826a.162c", "type": "inject", "z": "e3c81493.d9d2f8", "name": "CONTINUE", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "CONTINUE", "payloadType": "str", "x": 130, "y": 200, "wires": [ [ "302cfb99.eb6ad4" ] ] }, { "id": "4452e395.eca39c", "type": "debug", "z": "e3c81493.d9d2f8", "name": "TIMER HALTED", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 560, "y": 160, "wires": [] }, { "id": "3df24239.0889fe", "type": "inject", "z": "e3c81493.d9d2f8", "name": "", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "UNKNOWN1", "payloadType": "str", "x": 130, "y": 240, "wires": [ [ "302cfb99.eb6ad4" ] ] }, { "id": "302cfb99.eb6ad4", "type": "controltimer", "z": "e3c81493.d9d2f8", "name": "", "timerType": "delay", "timerDurationUnit": "second", "timerDurationType": "num", "timerDuration": "5", "isConsecutiveStartActionTimerResetAllowed": false, "isRunningTimerProgressVisible": false, "outputReceivedMessageOnTimerTrigger": true, "outputReceivedMessageOnTimerHalt": true, "startTimerOnReceivalOfUnknownMessage": false, "resetTimerOnReceivalOfUnknownMessage": false, "isStartActionEnabled": true, "isResetActionEnabled": true, "isStopActionEnabled": true, "isPauseActionEnabled": true, "isContinueActionEnabled": true, "isDebugModeEnabled": false, "actionPropertyNameType": "msg", "actionPropertyName": "payload", "startActionName": "START", "resetActionName": "RESET", "pauseActionName": "PAUSE", "continueActionName": "CONTINUE", "stopActionName": "STOP", "x": 360, "y": 140, "wires": [ [ "87b98e47.b188c" ], [ "4452e395.eca39c" ] ] }, { "id": "903e22bf.49913", "type": "inject", "z": "e3c81493.d9d2f8", "name": "UNKNOWN2", "props": [ { "p": "unknown", "v": "UNKNOWN2", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "x": 130, "y": 280, "wires": [ [ "302cfb99.eb6ad4" ] ] } ]
Current TODO list for node-red-contrib-controltimer:
- Timeout for looping behaviour after which the timer is stopped.
- Max loops for looping behaviour after which timer is stopped.
- Allow configuring timer type (loop or delay) and duration (amount and unit) via received message.
- Improve the node configuration view.
Let me know if you find it useful or lacking of some functionality or if there's something I could have done better. And is there anything because of what you prefer to use some other general timer node (looptimer, stoptimer, etc.) instead of node-red-contrib-controltimer?