So been playing a bit with this great node. In the following example I wanted to create a scheduler that should
- send out "1" while sun is down
- send out "0" while sun is up
- having an offset of +/- 1 hour for both sunrise and sunset
- automatically update schedules since they will change every day
Doesn't sound as a very strange need? Especially if you for instance would like to automatically control outdoor lights (or anything else dependent on the sun state)
Well, how to solve this with the CRON+ node???
Below is one way. The code in the function node is calculating the sunrise/sunset times based on the injected location. Then it configures the necessary cron expressions (7 in total needed) and injects those to the CRON+ node. In this example this happens every minute in the function node but it could very well be done just once per day (hence the RBE node in the flow). The rest of the code is just to create a status text showing the current sunrise/sunset times
So if anyone would ever need such a scheduler, the flow is below
I can't avoid comparing this with what I'm currently using, the BigTimer node. Would the CRON+ simplify things? Well, one thing, you can reduce the number of nodes in the flow but with the cost of more complex code in function nodes. For more advanced needs, the complexity will be rather high. If we look at the code that is needed to define the cron expressions in this example it is rather obvious that you have to be extremely careful when editing those on top of having a very good understanding in how cron syntax works
EDIT: Nobody is perfect, found some bugs in my expressions. The problem appeared when adjusting the minutes, had to include a check that they did not "fall outside" of the allowed range 0-59. Updated expressions and flow below, this looks as if it is now working fine
let srh = times.sunrise.getHours();
let srm = times.sunrise.getMinutes();
let ssh = times.sunset.getHours();
let ssm = times.sunset.getMinutes();
let expr1 = '*/1 0-'+srh.toString()+' * * *';
let expr2 = '0-'+srm.toString()+'/1 '+(srh+1).toString()+' * * *';
let expr3 = '*/1 '+ssh.toString()+'-23'+' * * *';
let expr4 = ssm.toString()+'-59/1 '+(ssh-1).toString()+' * * *';
let expr5 = '*/1 '+(srh+2).toString()+'-'+(ssh-2).toString()+' * * *';
let expr6 = '';
if(srm<59){
expr6 = (srm+1).toString()+'-59/1 '+(srh+1).toString()+' * * *';
}
else{
expr6 = '0';
}
let expr7 = '';
if(ssm>0){
expr7 = '0-'+(ssm-1).toString()+'/1 '+(ssh-1).toString()+' * * *';
}
else{
expr7 = '0';
}
Will CRON+ help in improving visibility, what is happening and when? Partly I think. It's great that the next action is presented in the status text. It is also great with the "automated" descriptions like description: "Every 1 minutes, minutes 0 through 5 past the hour, between 08:00 AM and 08:59 AM"
In BigTimer the visibility is of course already very clear by default, just open the config dialog and you have it all in front of you
[{"id":"4d2c5558.05101c","type":"cronplus","z":"60f50465.20a53c","name":"","outputField":"payload","timeZone":"","options":[],"x":590,"y":1890,"wires":[["16db2d1.ccc4cd3"]]},{"id":"1f535f29.5da5d1","type":"inject","z":"60f50465.20a53c","name":"remove-all","topic":"","payload":"{\"command\":\"remove-all\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":310,"y":1860,"wires":[["4d2c5558.05101c"]]},{"id":"16db2d1.ccc4cd3","type":"debug","z":"60f50465.20a53c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":760,"y":1890,"wires":[]},{"id":"a8262ceb.6743f","type":"inject","z":"60f50465.20a53c","name":"status-all","topic":"","payload":"{\"command\":\"status-all\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":310,"y":1910,"wires":[["4d2c5558.05101c"]]},{"id":"cbe17617.b6c9a8","type":"function","z":"60f50465.20a53c","name":"SunRiseSet","func":"var SunCalc = global.get('SunCalc');\nvar loc = msg.payload.split(';');\nvar times = SunCalc.getTimes(new Date(), loc[0], loc[1]);\nvar sunriseStr = [times.sunrise.getHours().toString(), times.sunrise.getMinutes().toString()];\nvar sunsetStr = [times.sunset.getHours().toString(), times.sunset.getMinutes().toString()];\n\nfunction updateNodeStatus(txt) {\n node.status({\n \ttext : txt\n });\n}\n\nif (sunsetStr[0].length<2){\n sunsetStr[0]='0'+sunsetStr[0];\n}\nif (sunsetStr[1].length<2){\n sunsetStr[1]='0'+sunsetStr[1];\n}\nvar sunset = sunsetStr[0]+':'+sunsetStr[1];\n\nif (sunriseStr[0].length<2){\n sunriseStr[0]='0'+sunriseStr[0];\n}\nif (sunriseStr[1].length<2){\n sunriseStr[1]='0'+sunriseStr[1];\n}\nvar sunrise = sunriseStr[0]+':'+sunriseStr[1];\n\nlet info = 'sunUp:'+sunrise+' '+'sunDown:'+sunset;\nupdateNodeStatus(info);\n\nlet srh = times.sunrise.getHours();\nlet srm = times.sunrise.getMinutes();\nlet ssh = times.sunset.getHours();\nlet ssm = times.sunset.getMinutes();\n\nlet expr1 = '*/1 0-'+srh.toString()+' * * *';\nlet expr2 = '0-'+srm.toString()+'/1 '+(srh+1).toString()+' * * *';\nlet expr3 = '*/1 '+ssh.toString()+'-23'+' * * *';\nlet expr4 = ssm.toString()+'-59/1 '+(ssh-1).toString()+' * * *';\n\nlet expr5 = '*/1 '+(srh+2).toString()+'-'+(ssh-2).toString()+' * * *';\nlet expr6 = '';\nif(srm<59){\n expr6 = (srm+1).toString()+'-59/1 '+(srh+1).toString()+' * * *';\n}\nelse{\n expr6 = '0';\n}\nlet expr7 = '';\nif(ssm>0){\n expr7 = '0-'+(ssm-1).toString()+'/1 '+(ssh-1).toString()+' * * *';\n}\nelse{\n expr7 = '0';\n}\n\nmsg.payload = [\n {\n 'command': 'add',\n 'name': 'one',\n 'expression': expr1,\n 'payload': '1',\n 'type': 'num',\n },\n {\n 'command': 'add',\n 'name': 'two',\n 'expression': expr2,\n 'payload': '1',\n 'type': 'num',\n },\n {\n 'command': 'add',\n 'name': 'three',\n 'expression': expr3,\n 'payload': '1',\n 'type': 'num',\n },\n {\n 'command': 'add',\n 'name': 'four',\n 'expression': expr4,\n 'payload': '1',\n 'type': 'num',\n },\n {\n 'command': 'add',\n 'name': 'five',\n 'expression': expr5,\n 'payload': '0',\n 'type': 'num',\n },\n {\n 'command': 'add',\n 'name': 'six',\n 'expression': expr6,\n 'payload': '0',\n 'type': 'num',\n },\n {\n 'command': 'add',\n 'name': 'seven',\n 'expression': expr7,\n 'payload': '0',\n 'type': 'num',\n }\n]\n\nreturn msg;\n","outputs":"1","noerr":0,"x":600,"y":2080,"wires":[["38f04baa.dbf894"]]},{"id":"3ded6583.1a2eaa","type":"inject","z":"60f50465.20a53c","name":"","topic":"","payload":"59.4200;18.0000","payloadType":"str","repeat":"60","crontab":"","once":true,"onceDelay":"","x":340,"y":2080,"wires":[["cbe17617.b6c9a8"]]},{"id":"e9e43b93.b18398","type":"debug","z":"60f50465.20a53c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":760,"y":1990,"wires":[]},{"id":"38f04baa.dbf894","type":"rbe","z":"60f50465.20a53c","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":440,"y":1990,"wires":[["4d2c5558.05101c","e9e43b93.b18398"]]}]