I admit I was bored and I agree with @Trying_to_learn that if @lalo wants to continue down this path who are we to stop him. @Steve-Mcl I often build new solutions just for the fun of it even if the problem has already been solved by others.
So here we go (https://flows.nodered.org/node/node-red-node-ui-table needs to be installed):
[{"id":"8233c164.1bcb58","type":"function","z":"f954564f.03e718","name":"check command","func":"const time = new Date(msg.payload);\nconst hour = time.getHours();\nconst minute = time.getMinutes();\nlet timef = \"\";\nif(minute<10){\n if(hour>9){\n timef = String(hour) + \":0\" + String(minute);\n } else {\n timef = \"0\"+ String(hour) + \":0\" + String(minute);\n }\n} else {\n if(hour>9){\n timef = String(hour) + \":\" + String(minute);\n } else {\n timef = \"0\"+ String(hour) + \":\" + String(minute);\n }\n}\nconst schedule = flow.get(\"schedule\");\nschedule.forEach(element => {\n if(element.time == timef) node.send({payload:element.command,item:element.item});\n});\nnode.done();\nreturn;","outputs":1,"noerr":0,"x":470,"y":3660,"wires":[["2af56f10.1de678","fdd91332.9b43"]]},{"id":"ef2b9f11.6427a","type":"inject","z":"f954564f.03e718","name":"","topic":"","payload":"","payloadType":"date","repeat":"60","crontab":"","once":false,"onceDelay":0.1,"x":260,"y":3660,"wires":[["8233c164.1bcb58"]]},{"id":"37d3efaa.0c2018","type":"ui_text","z":"f954564f.03e718","group":"5b810075.4590d","order":1,"width":0,"height":0,"name":"","label":"Pump","format":"{{msg.payload}}","layout":"row-spread","x":850,"y":3640,"wires":[]},{"id":"69efc588.ee6c0c","type":"ui_form","z":"f954564f.03e718","name":"","label":"","group":"7d6a9a85.b4af24","order":1,"width":0,"height":0,"options":[{"label":"Item","value":"item","type":"text","required":true,"rows":null},{"label":"Command","value":"command","type":"text","required":true,"rows":null},{"label":"Time","value":"time","type":"text","required":true,"rows":null}],"formValue":{"item":"","command":"","time":""},"payload":"","submit":"Add","cancel":"","topic":"","x":430,"y":3520,"wires":[["d81b69c7.453cd8","6f55d1dd.163138"]]},{"id":"d81b69c7.453cd8","type":"change","z":"f954564f.03e718","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"payload.time","pt":"msg","to":"enter a time in the hh:mm format","tot":"str"},{"t":"set","p":"payload.command","pt":"msg","to":"enter a command","tot":"str"},{"t":"set","p":"payload.item","pt":"msg","to":"enter the item to switch","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":3520,"wires":[["69efc588.ee6c0c"]]},{"id":"27cb3d9b.1c51b2","type":"ui_table","z":"f954564f.03e718","group":"7d6a9a85.b4af24","name":"","order":2,"width":"6","height":"6","columns":[],"outputs":1,"cts":true,"x":770,"y":3520,"wires":[["41b7de7e.3e51f8"]]},{"id":"6f55d1dd.163138","type":"function","z":"f954564f.03e718","name":"add to schedule","func":"let schedule = flow.get(\"schedule\") || [];\nlet command = msg.payload;\nlet newindex = null;\nif(schedule.length > 0){\n for(i=0;i<schedule.length-1;i++){\n if(command.time >= schedule[i].time && command.time < schedule[i+1].time){\n newindex = i+1;\n }\n }\n if(newindex !== null){\n schedule.splice(newindex,0,command);\n } else if (command.time < schedule[0].time){\n schedule.splice(0,0,command);\n } else {\n schedule.push(command);\n }\n} else {\n schedule.push(command);\n}\nflow.set(\"schedule\", schedule);\nmsg.payload = schedule;\nreturn msg;","outputs":1,"noerr":0,"x":600,"y":3520,"wires":[["27cb3d9b.1c51b2","c4a381a3.dace88"]]},{"id":"e962955b.b0359","type":"function","z":"f954564f.03e718","name":"remove from schedule","func":"if (msg.payload == \"Cancel\") return null;\nlet schedule = flow.get(\"schedule\");\nschedule.splice(msg.row, 1);\nflow.set(\"schedule\", schedule);\nmsg.payload = schedule;\nreturn msg;","outputs":1,"noerr":0,"x":1360,"y":3520,"wires":[["27cb3d9b.1c51b2","c4a381a3.dace88"]]},{"id":"eec5a4b.3af5bd8","type":"ui_toast","z":"f954564f.03e718","position":"dialog","displayTime":"3","highlight":"","sendall":true,"outputs":1,"ok":"OK","cancel":"Cancel","raw":false,"topic":"","name":"","x":1150,"y":3520,"wires":[["e962955b.b0359"]]},{"id":"41b7de7e.3e51f8","type":"change","z":"f954564f.03e718","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"content","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"Delete this schedule?","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"Delete","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":960,"y":3520,"wires":[["eec5a4b.3af5bd8"]]},{"id":"c4a381a3.dace88","type":"delay","z":"f954564f.03e718","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":780,"y":3460,"wires":[["ef3518ad.80b7e8"]]},{"id":"59f1e488.99455c","type":"ui_ui_control","z":"f954564f.03e718","name":"","events":"all","x":1140,"y":3460,"wires":[[]]},{"id":"ef3518ad.80b7e8","type":"change","z":"f954564f.03e718","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"tab\":\"\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":960,"y":3460,"wires":[["59f1e488.99455c"]]},{"id":"2af56f10.1de678","type":"switch","z":"f954564f.03e718","name":"which item","property":"item","propertyType":"msg","rules":[{"t":"eq","v":"Pump","vt":"str"},{"t":"eq","v":"Irrigation","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":670,"y":3660,"wires":[["37d3efaa.0c2018"],["e2210cd1.e8f83"]]},{"id":"e2210cd1.e8f83","type":"ui_text","z":"f954564f.03e718","group":"5b810075.4590d","order":2,"width":0,"height":0,"name":"","label":"Irrigation","format":"{{msg.payload}}","layout":"row-spread","x":860,"y":3680,"wires":[]},{"id":"fdd91332.9b43","type":"debug","z":"f954564f.03e718","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":650,"y":3780,"wires":[]},{"id":"c54ebfc9.b3594","type":"inject","z":"f954564f.03e718","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":250,"y":3460,"wires":[["d81b69c7.453cd8"]]},{"id":"5b810075.4590d","type":"ui_group","z":"","name":"Items","tab":"b83efc1a.370b88","order":1,"disp":true,"width":"6","collapse":false},{"id":"7d6a9a85.b4af24","type":"ui_group","z":"","name":"Scheduler","tab":"b83efc1a.370b88","order":2,"disp":true,"width":"6","collapse":false},{"id":"b83efc1a.370b88","type":"ui_tab","z":"","name":"Scheduler","icon":"call_split","order":2,"disabled":false,"hidden":false}]
This is an evolution of the last post and kind of an intermediate step to something like using the cron-plus.
Instead of saving each time to a variable we save one object for each time to an array variable.
This object includes An item to be switched, a command to be executed and a time to execute this command.
Because this is quite simplistic we have to input those vars in the correct format. we use the ui form node for this. The item name has to be the exact item name! Same for command. The time needs to be in the hh:mm format for this to work. eg "11:30".
We than in the following function node add the object that the form node outputs once you click add (something like this:
{"item":"Pump","command":"ON","time":"12:14"}
) to the flow.schedule var. We do do something else, we sort the added object according to the time into this var. So the times will always be in chronological order.
We also return the schedule array to the table node to display our schedule.
If you click one of the entered schedules you can also delete it from the flow.schedule array.
I changed the function node that previously checked for the on&off vars every minute to instead check for the time property of each object in the flow.schedule array.
So it now checks for the hh:mm format.
It also adds item property to the message so we can use a simple switch node to sort the commands to the correct items.
You can add and delete as many time schedules as you want and they will always be sorted chronologically.
Have fun playing around and I hope you can learn something from this.
Be aware that this is a very rough prototype I threw together in half an hour and havent tested it extensively for errors.
Johannes
PS I hope this makes some sense and i added a check if the time is previous to the first time in the collumn or generallly the first