there are indeed any wormholes built into the fabric of Node-RED just waiting to be fallen through.
:sigh: yes, I've fallen through many of those over the years - appearing hours later with no knowledge of how I got there! Never yet fallen through one of the reverse time holes though sadly.
Nice, just saw it implemented, works fine so far, just tested a sunrise with offset
How do I get rid of the AM/PM notations and only show a 24h clock, currently it is inconsistent too.
Great job!
Many thanks for sharing.
regards Hannes
loading initially many schedules (about 50) from a CSV-file into cron+ which are maintained in ms-excel.
[{"id":"efa48538.e03fb8","type":"ui_text","z":"9dbb8104.3f78f","group":"eb699215.f94c3","order":1,"width":"16","height":"2","name":"CRON Description","label":"Expression Description (updates as you type)...","format":"{{msg.payload.result.description}}","layout":"col-center","x":790,"y":1060,"wires":[]},{"id":"73736609.869518","type":"cronplus","z":"9dbb8104.3f78f","name":"","outputField":"payload","timeZone":"","options":[],"x":500,"y":1060,"wires":[["efa48538.e03fb8"]]},{"id":"8b1ee630.0777e8","type":"function","z":"9dbb8104.3f78f","name":"describe cmd","func":"msg.payload = {\n \"command\": \"describe\",\n \"expression\": msg.payload\n}\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":1060,"wires":[["73736609.869518"]]},{"id":"7c4a2308.d3744c","type":"change","z":"9dbb8104.3f78f","name":"","rules":[{"t":"set","p":"ui_add_schedule_name","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":940,"wires":[[]]},{"id":"24c40de1.fb53e2","type":"change","z":"9dbb8104.3f78f","name":"","rules":[{"t":"set","p":"ui_add_schedule_payload","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":980,"wires":[[]]},{"id":"195ca11c.006d9f","type":"change","z":"9dbb8104.3f78f","name":"","rules":[{"t":"set","p":"ui_add_schedule_expression","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":1020,"wires":[[]]},{"id":"5cf184c3.757c5c","type":"change","z":"9dbb8104.3f78f","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"payload.payload","pt":"msg","to":"ui_add_schedule_payload","tot":"flow"},{"t":"set","p":"payload.name","pt":"msg","to":"ui_add_schedule_name","tot":"flow"},{"t":"set","p":"payload.expression","pt":"msg","to":"ui_add_schedule_expression","tot":"flow"},{"t":"set","p":"payload.command","pt":"msg","to":"add","tot":"str"},{"t":"set","p":"payload.type","pt":"msg","to":"str","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":1140,"wires":[["6340224e.770a7c","f8d064b9.bd8388"]]},{"id":"6340224e.770a7c","type":"cronplus","z":"9dbb8104.3f78f","name":"","outputField":"payload","timeZone":"","options":[],"x":660,"y":1140,"wires":[["57a74f77.23a51","4c79ac4b.e71ec4"]]},{"id":"8fdabd61.462d9","type":"ui_toast","z":"9dbb8104.3f78f","position":"top right","displayTime":"3","highlight":"","sendall":true,"outputs":0,"ok":"OK","cancel":"","topic":"","name":"","x":610,"y":1220,"wires":[]},{"id":"57a74f77.23a51","type":"switch","z":"9dbb8104.3f78f","name":"1=Cron Event 2=List Results ","property":"cronplus.triggerTimestamp","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":340,"y":1240,"wires":[["8fdabd61.462d9"],["962192b0.5772c"]]},{"id":"f8d064b9.bd8388","type":"ui_button","z":"9dbb8104.3f78f","name":"Refresh","group":"eb699215.f94c3","order":6,"width":"1","height":"1","passthru":true,"label":"","tooltip":"Get status of jobs","color":"","bgcolor":"","icon":"fa-refresh","payload":"{\"command\":\"list-all\"}","payloadType":"json","topic":"","x":500,"y":1160,"wires":[["6340224e.770a7c"]]},{"id":"7ff3a55d.ab656c","type":"ui_text_input","z":"9dbb8104.3f78f","name":"","label":"Expression","tooltip":"CRON expression or date/csv list of dates","group":"eb699215.f94c3","order":3,"width":"4","height":"1","passthru":true,"mode":"text","delay":"100","topic":"","x":130,"y":1020,"wires":[["8b1ee630.0777e8","195ca11c.006d9f"]]},{"id":"993691e.584377","type":"ui_text_input","z":"9dbb8104.3f78f","name":"","label":"Name","tooltip":"Schedule Name","group":"eb699215.f94c3","order":2,"width":"4","height":"1","passthru":true,"mode":"text","delay":"100","topic":"","x":110,"y":940,"wires":[["7c4a2308.d3744c"]]},{"id":"e8bbc13d.cdb0d","type":"ui_button","z":"9dbb8104.3f78f","name":"","group":"eb699215.f94c3","order":5,"width":"3","height":"1","passthru":false,"label":"Add","tooltip":"Add or update named schedule","color":"","bgcolor":"","icon":"send","payload":"","payloadType":"str","topic":"","x":110,"y":1140,"wires":[["5cf184c3.757c5c"]]},{"id":"fb09de34.47039","type":"ui_text_input","z":"9dbb8104.3f78f","name":"","label":"Payload","tooltip":"Payload to send when schedule fires","group":"eb699215.f94c3","order":4,"width":"4","height":"1","passthru":true,"mode":"text","delay":"100","topic":"","x":120,"y":980,"wires":[["24c40de1.fb53e2"]]},{"id":"3adee653.9f028a","type":"ui_template","z":"9dbb8104.3f78f","group":"eb699215.f94c3","name":"","order":7,"width":"16","height":"5","format":"<style type=\"text/css\">\n.t1 {border-collapse:collapse;border-spacing:0;border-color:#ccc;}\n.t1 td{font-family:Arial, sans-serif;font-size:14px;padding:8px 3px;border-style:solid;border-width:0px;overflow:hidden;word-break:normal;border-top-width:1px;border-bottom-width:1px;border-color:#ccc;color:#333;background-color:#fff;}\n.t1 th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#ccc;color:#333;background-color:#f0f0f0;}\n.t1 .t1-36r9{background-color:#000000;color:#ffffff;text-align:left;vertical-align:top}\n.t1 .t1-x2zo{background-color:#c0c0c0;font-size:small;text-align:left;vertical-align:top}\n.t1 .t1-o73e{background-color:#c0c0c0;font-size:small;text-align:center;vertical-align:top}\n.t1 .t1-5qt9{font-size:small;text-align:left;vertical-align:top}\n.t1 .t1-5qta{font-size:small;text-align:center;vertical-align:middle}\n</style>\n<table class=\"t1\">\n <tr>\n <th class=\"t1-36r9\" colspan=\"9\">CRON Schedules</th>\n </tr>\n <tr>\n <td class=\"t1-x2zo\">Name</td>\n <td class=\"t1-x2zo\">Expression</td>\n <td class=\"t1-x2zo\">Payload</td>\n <td class=\"t1-x2zo\">Description</td>\n <td class=\"t1-x2zo\">Next run</td>\n <td class=\"t1-x2zo\">State</td>\n <td class=\"t1-o73e\">Delete</td>\n <td class=\"t1-o73e\">Pause</td>\n <td class=\"t1-o73e\">Resume</td>\n </tr>\n <tr ng-repeat=\"item in msg.payload\">\n <td class=\"t1-5qt9\">{{item.config.name}}</td>\n <td class=\"t1-5qt9\" style=\"white-space: nowrap\" nowrap>{{item.config.expression}}</td>\n <td class=\"t1-5qt9\">{{item.config.payload}}</td>\n <td class=\"t1-5qt9\">{{item.status.description}}</td>\n <td class=\"t1-5qt9\">{{item.status.nextDescription}}</td>\n <td class=\"t1-5qta\"><i class=\"fa fa-{{item.status.isRunning ? 'play' : 'pause'}}\"> </i></td>\n\n <td class=\"t1-5qta\">\n <md-button class=\"md-raised\"\n ng-click=\"send([[{payload:{command:'remove', name: item.config.name}}, {payload:{command:'list-all'}}]]);\"> <i class=\"fa fa-trash\"> </i></md-button>\n </td>\n <td class=\"t1-5qta\">\n <md-button class=\"button\" \n ng-click=\"send([[{payload:{command:'pause', name: item.config.name}}, {payload:{command:'list-all'}}]]);\"> <i class=\"fa fa-pause\"> </i></md-button>\n </td>\n <td class=\"t1-5qta\">\n <md-button class=\"button\" \n ng-click=\"send([[{payload:{command:'start', name: item.config.name}}, {payload:{command:'list-all'}}]]);\"> <i class=\"fa fa-play\"> </i></md-button>\n </td>\n\n </tr>\n\n </tbody>\n</table>\n\n<!--<table id=\"table\" class=\"table table-striped table-responsive-md btn-table\" >-->\n<!-- <tr>-->\n<!-- <th>Name</th> -->\n<!-- <th>Expression</th> -->\n<!-- <th>Payload</th> -->\n<!-- <th>Description</th>-->\n<!-- <th>Next run</th>-->\n<!-- <th>State</th>-->\n<!-- <th>Delete</th>-->\n<!-- <th>Pause</th>-->\n<!-- <th>Resume</th>-->\n<!-- </tr>-->\n<!-- <tbody>-->\n<!-- <tr ng-repeat=\"item in msg.payload\">-->\n<!-- <td >{{item.config.name}}</td>-->\n<!-- <td style=\"white-space: nowrap\" nowrap>{{item.config.expression}}</td>-->\n<!-- <td >{{item.config.payload}}</td>-->\n<!-- <td >{{item.status.description}}</td>-->\n<!-- <td >{{item.status.nextDescription}}</td>-->\n<!-- <td >{{item.status.isRunning ? 'Running' : 'Paused'}}</td>-->\n<!-- <td>-->\n<!-- <md-button class=\"md-raised\"-->\n<!-- ng-click=\"send([[{payload:{command:'remove', name: item.config.name}}, {payload:{command:'list-all'}}]]);\"> <i class=\"fa fa-trash\"> </i></md-button>-->\n<!-- </td>-->\n<!-- <td>-->\n<!-- <md-button class=\"button\" -->\n<!-- ng-click=\"send([[{payload:{command:'pause', name: item.config.name}}, {payload:{command:'list-all'}}]]);\"> <i class=\"fa fa-pause\"> </i></md-button>-->\n<!-- </td>-->\n<!-- <td>-->\n<!-- <md-button class=\"button\" -->\n<!-- ng-click=\"send([[{payload:{command:'start', name: item.config.name}}, {payload:{command:'list-all'}}]]);\"> <i class=\"fa fa-play\"> </i></md-button>-->\n<!-- </td>-->\n<!-- </tr>-->\n<!-- </tbody>-->\n<!--</table>-->\n\n","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":760,"y":1260,"wires":[["e62f3011.047d1"]]},{"id":"962192b0.5772c","type":"function","z":"9dbb8104.3f78f","name":"Make table data","func":"if(!msg.payload || !msg.payload.result || !msg.payload.result.length){\n msg.payload = [];\n return msg;\n}\n\nmsg.payload = msg.payload.result;\nreturn msg;","outputs":1,"noerr":0,"x":600,"y":1260,"wires":[["3adee653.9f028a"]]},{"id":"e62f3011.047d1","type":"link out","z":"9dbb8104.3f78f","name":"","links":["b9b9e3e3.d4933","1ce54dd0.8fa932"],"x":875,"y":1260,"wires":[]},{"id":"1d1c4707.745b09","type":"ui_template","z":"9dbb8104.3f78f","group":"eb699215.f94c3","name":"CRON Info","order":8,"width":"16","height":"12","format":"<div>\n<pre>CRON Format...\n\n s m h md m wd y\n | | | | | | |\n * * * * * * * Field Allowed values Special symbols\n | | | | | | | ----------------- --------------- ---------------\n `--|--|--|--|--|--|-> Second (optional) 0-59 * / , -\n `--|--|--|--|--|-> Minute 0-59 * / , -\n `--|--|--|--|-> Hour 0-23 * / , -\n `--|--|--|-> Day of Month 1-31 * / , - L W\n `--|--|-> Month 1-12 or JAN-DEC * / , -\n `--|-> Day of Week 0-7 or SUN-SAT * / , - L #\n `-> Year (optional) 1970-2099 * / , -\n \n</pre> \n</div>\n\n<style type=\"text/css\">\n.t2 {border-collapse:collapse;border-spacing:0;border-color:#ccc;}\n.t2 td{font-family:Arial, sans-serif;font-size:14px;padding:2px 2px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#ccc;color:#333;background-color:#fff;}\n.t2 th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#ccc;color:#333;background-color:#f0f0f0;}\n.t2 .t2-dg6o{background-color:#000000;color:#ffffff;text-align:left;vertical-align:top}\n.t2 .t2-6e8n{font-weight:bold;background-color:#c0c0c0;border-color:inherit;text-align:left;vertical-align:top}\n.t2 .t2-0pky{border-color:inherit;text-align:left;vertical-align:top}\n</style>\n<table class=\"t2\">\n <tr>\n <th class=\"t2-dg6o\" colspan=\"2\">Example CRON Expressions</th>\n </tr>\n <tr>\n <td class=\"t2-6e8n\">Expression</td>\n <td class=\"t2-6e8n\">Description</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">* * * * * *</td>\n <td class=\"t2-0pky\">Every Second</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 * * * * *</td>\n <td class=\"t2-0pky\">Every minute</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 */10 * * * *</td>\n <td class=\"t2-0pky\">Every 10 minutes</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 */20 1 * * *</td>\n <td class=\"t2-0pky\">Every 20 minutes, between 01:00 AM and 01:59 AM</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 15,30,45 * * * *</td>\n <td class=\"t2-0pky\">At 15, 30, and 45 minutes past the hour</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 0 12 * * *</td>\n <td class=\"t2-0pky\">Every day at noon - 12pm</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 0 2 29 FEB * 2020-2040</td>\n <td class=\"t2-0pky\">At 02:00 AM, on day 29 of the month, only in February, every 4 years, 2020 through 2040</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 0 7 * *</td>\n <td class=\"t2-0pky\">MON#1 * At 07:00 AM, on the first Monday of the month</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 0 12 * JAN,FEB,MAR,APR *</td>\n <td class=\"t2-0pky\">Every day at noon in January, February, March and April</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">* * 1W * *</td>\n <td class=\"t2-0pky\">Every minute, on the first weekday of the month</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">* * * * Tue#3</td>\n <td class=\"t2-0pky\">Every minute, on the third Tuesday of the month</td>\n </tr>\n <tr>\n <td class=\"t2-0pky\">0 12 * * MONL</td>\n <td class=\"t2-0pky\">At 12:00 PM, on the last Monday of the month</td>\n </tr>\n</table>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":770,"y":1320,"wires":[[]]},{"id":"1ce54dd0.8fa932","type":"link in","z":"9dbb8104.3f78f","name":"","links":["e62f3011.047d1","dde0b2cf.76d48"],"x":455,"y":1120,"wires":[["6340224e.770a7c"]]},{"id":"42726643.0a62b8","type":"debug","z":"9dbb8104.3f78f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1110,"y":1140,"wires":[]},{"id":"2f79e063.bec1d","type":"file in","z":"9dbb8104.3f78f","name":"","filename":"/home/pi/Temp_Tabelle/temp_tabelle.CSV","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":400,"y":780,"wires":[["c8b1ad17.6f756"]]},{"id":"c8b1ad17.6f756","type":"csv","z":"9dbb8104.3f78f","name":"","sep":";","hdrin":false,"hdrout":"","multi":"one","ret":"\\n","temp":"","skip":"1","strings":true,"x":630,"y":780,"wires":[["fdc6a389.39d7d"]]},{"id":"305a2daf.f3cbe2","type":"inject","z":"9dbb8104.3f78f","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":780,"wires":[["2f79e063.bec1d"]]},{"id":"15ac52fa.b84e3d","type":"function","z":"9dbb8104.3f78f","name":"","func":"msg.payload = \"1\";\nreturn msg;","outputs":1,"noerr":0,"x":450,"y":880,"wires":[["a07d068f.7e6048"]]},{"id":"ce45a3bb.f168d","type":"link in","z":"9dbb8104.3f78f","name":"","links":["a07d068f.7e6048"],"x":135,"y":1180,"wires":[["5cf184c3.757c5c"]]},{"id":"a07d068f.7e6048","type":"link out","z":"9dbb8104.3f78f","name":"testload","links":["ce45a3bb.f168d"],"x":535,"y":880,"wires":[]},{"id":"2e8c3a79.1939c6","type":"delay","z":"9dbb8104.3f78f","name":"","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":310,"y":880,"wires":[["15ac52fa.b84e3d"]]},{"id":"3a6693c5.59391c","type":"function","z":"9dbb8104.3f78f","name":"","func":"var name = msg.payload.col1;\nvar expression = msg.payload.col2;\nvar pload = msg.payload.col3;\nreturn [\n {payload:name},\n {payload:expression},\n {payload:pload}\n ];","outputs":3,"noerr":0,"x":110,"y":880,"wires":[["7c4a2308.d3744c","2e8c3a79.1939c6"],["195ca11c.006d9f"],["24c40de1.fb53e2"]]},{"id":"fdc6a389.39d7d","type":"delay","z":"9dbb8104.3f78f","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":770,"y":780,"wires":[["3a6693c5.59391c"]]},{"id":"4c79ac4b.e71ec4","type":"switch","z":"9dbb8104.3f78f","name":"","property":"payload","propertyType":"msg","rules":[{"t":"istype","v":"string","vt":"string"}],"checkall":"true","repair":false,"outputs":1,"x":850,"y":1140,"wires":[["a4fc2226.fbaf"]]},{"id":"a4fc2226.fbaf","type":"json","z":"9dbb8104.3f78f","name":"","property":"payload","action":"","pretty":false,"x":970,"y":1140,"wires":[["42726643.0a62b8"]]},{"id":"eb699215.f94c3","type":"ui_group","z":"","name":"Default","tab":"98aadccf.4b3e1","disp":false,"width":"16","collapse":false},{"id":"98aadccf.4b3e1","type":"ui_tab","z":"","name":"CRON","icon":"dashboard","order":2,"disabled":false,"hidden":false}]
Hi @bakman2 the library that describes the CRON expression is a separate entity and (i dont think) it can be affected unfortunately - i will look into it.
Update time (pre-release - git only for now)
First a gif (to paint many thousands of words)...
So, some of the changes may or may not suit everyone's exact requirement regarding the scheduling of sunrise / sunset but I tried to take into account users requirements - and - structure it in a manor that was both easy to use and provide as MUCH flexibility* as possible.
- Example: Separate offset for sunrise and sunset
- Solution: Add 2 entries, 1 for sunrise, 1 for sunset - enter different offsets.
-
Example: Status of day/night state in the output message
-
Solution: Internally, the node scans backwards and forwards past the solar event to determine actual solar state. Not just day and night, but also if its twilight (astronomical, nautical, civil), if the sun is rising (post solar midnight) or falling (post solar noon). The properties outputed, when combined, give you lots of granularity & options.
Ouput of the describe command...
- Example: Get sun state and solar event times for any date and time
- Solution: Send a
describe
command withlocation
andtime
- get solar state and event times in the msg.
*Granted - flexibility and ease of use are often mutually exclusive so here are some them "ease" features...
- Added a combo drop down on the cron expression input box - to provide a bunch of "starter" example expressions. This should give the user somewhere to start (as it will popup the expression tooltip that also links to the help!)
- I added a link to the help info in the tooltip - hopefully prompting those who are blissfully unaware of node-red nodes having built in help information
- Added a second output to split scheduled events from command responses simplifying dynamic setups
- Added a map picker to simplify entering coordinates (100% loaded on demand & external CDN - so no internet - no map - only a help message telling how to get coordinates)
- New and updated examples demonstrating most of the functionality
Many other considerations have been made and tested (to a degree) like.
- extreme latitudes where there is no day or no night for many weeks
- where a schedule is setup with a solar event that has passed but the offset means the event time is in the future
With so many changes and wanting to get to a V1 release at some point in its life, it was time for the V1 stamp (V1.0.0-beta.0)
So i would greatly appreciate feedback.
NOTE:
Installation is currently only possible direct from github until tested.
npm install Steve-Mcl/node-red-contrib-cron-plus
I've yet to try this but it looks nothing short of amazing. I can't imagine how many hours of work you'd have to have put into this! I'm not too much of a beta tester type but this node will sure be part of my big NR home automation refactoring I'm planning.
Great work Steve. I can't recall the number of times that I've written a cron schedule wrongly, but this makes it so easy to use & get right every time.
Thank you for the great work !! Being a unix/linux guy for 25 years, I can't live without cron
Initially it was the lack of cron in home-assistant that put me into NR!!
Something that I am missing (more than sun related stuff -sorry-) would be the ability to do something similar to the inject node. When nodered is started, being able to start the flow after X seconds. The thing being that if I have a cron running eg every two hours and nodered is restarted, I'll have to wait up to 1:59 for the flow to be started by cron.
So I often end up with an inject node in addition to cron, just for that purpose. No big deal though, but "cleaner" without it.
Hope this makes sense.
GV
This looks like the ultimate scheduler node, awesome work @Steve-Mcl
It has crossed my mind, but how / where to put this is tricky.
Until I have one of these > < moments, its gonna have to be a separate inject for initialisation.
Thanks for the kind words everyone.
What not a tick box in the cron node + a delay, same stuff as the basic inject node.
I know it is easier to write it than it is doing it. Sorry.
GV
Thinking further (may become convoluted - just thoughts): could a separate output per schedule be a possibility ?
/ducks.
haha - this crossed my mind 2 days ago but i dropped it due to the lingering thought "what to do with dynamic entries?"
Its actually not too difficult to provide separate outputs.
How about adding an index property in the msg to the related schedule line so that it can be used in a switch node if needed? Optionally I would say.
Its more the implementation (I didnt want to get into it - but as you ask)
Do you have
- per node?
or - per crontab entry?
RE: option 1 - what do we send? Add a new payload option to the main ui part?
RE: option 2 - this is less problematic - but does it make sense to have multiple send on starts?
or just keep it clean and just do (fantastic) cron stuff, and let the inject do inject at start stuff...