Trigger at specific date-time

I feel like this is really easy and I am just missing it.

I want to provide a datetime as an input and wait in a flow until that time occurs.

Everything I look at appears to only want a brief interval or a time of day and it fires the next time. I want to provide an actual datetime, with a date portion. Inject is like cron, repeats on day of week, I want date.

Have I just not found the right node? Or not calling one correctly?

Basically "Wait until 2019-07-15 23:12" or whatever format it wants for time.

Possible?

Thanks, Linwood

PS. I can simulate this with a complicated loop that waits, say, 12 hours at a time until the remaining time is under 12 hours, then waits that long. But that's ugly.

Inject that outputs a timestamp as seconds since epoch, and a function node that checks if the timestamp is greater than/equals to the specified data and if not drops the message, then drops all messages after passing through the message at the correct time? Doesn't sound like a very clean solution to me, but I guess it should work.

You could use the node-red-contrib--cron-pkjq node to trigger at specific dates.

@afelix, yes, I can loop and check and loop and check. Hoping for elegant.

@bakman2 I need to feed the date-time as an input to the node, and this node does not appear to permit anything but hard-coded info.

Thanks both.

I cannot find any node that handles actual date scheduling.

What you could try is the node-red-contrib-moment (for date/time formatting) and use an inject node with interval (eg. every 30 secs) into that node. And add another node inject node for your date/time schedule (possibly best to set flow variables) and compare if the date/time matches, if yes, trigger whatever you like.

If you don't mind needing Internet connectivity, you could always use Google Calendar.

Perhaps node-red-contrib-calendar-trigger (node) - Node-RED?

A relatively easy way is to do some simple maths

Lets say i want to set something to go off tomorrow at 7AM

I would get the time and date as at now, then using one of the other nodes (such as moment) perform maths to see how far away that time is when i want the alarm (in minutes) - i would then feed that to the mytimeout node by Neil Chery - essentially you can feed this timeout node the amount of time you want it to wait (not sure of the maximum) and it will at the end of the time send out something for you - you could just take this output through the switch node - and essentially invert it - i.e.mytimeout is counting down - when it finishes counting down it will send an off/finish - you take this into the switch node and test what it is getting as input and then act on that

Craig

Here's what I ended up doing.

I have the "until" time stored in a flow context variable.

In a function node I grab it and check if it is expired, and if so exit to output 1 (expired).

If not, I compare the date portion (only) with today, and if not the same (i.e. until is later) I emit from output 2 a "00:00" for midnight, and fall into the schedex node (which I'm using elsewhere also).

If on the other hand the until is the same date, I emit the time portion in output 2 the same way.

Then I loop back to the same node from the schedex output.

The result is that the timer fires once a day at midnight, until the last day, it fires on the until time.

Finally on the output 1 path I feed back to schedex a blank on/off time, which cancels any timer still running.

It is a bit messy but it seems easiest, most of the code is just pulling apart javascript date/times and formatting them.

It occurs to me I might be able to just do all this in a function node with settimeout, but was not at all sure how such a timeout would work with node-red's structure.

Sounds like a pretty clean solution to me, from a logic point of view that is. Nice job!

This seems like the cleanest option to me. However, if node-red is restarted, the timeout will not continue from where it left off correct? The easiest way around that would just be to store the event time and just re-calculate at node-red start but I wanted to avoid having to do that if the timeout is persistent after the service is restarted. Thanks!!

No and if it did it would be incorrect as i was stating that you would at the start load the amount of time to countdown into mytimeout - as such if you stopped NR etc then that would be incorrect.

The only way i could see to handle a restart elegantly would be to store the finish time (i.e. when it was meant to fire) in a context variable. - Do this when you set it at the dashboard and set it as a Linux EPOCH value so it handles dates and times etc,

When you startup then perform the same calculation as the original one as part of your initialisation and load in the new timeout value to the MyTimeout node. i.e. convert current time into EPOCH time, subtract from required time to trigger EPOCH (handle a negative value (i.e. time to trigger has passed) and then convert the remaining EPOCH value into whatever Mytimeout takes (i think it is seconds)

Craig

Yup, that's what I was saying would be the only way to handle it. Which wouldn't be all that complicated to do. And I could just launch all recalcs from one inject node. If you have to gave a one-time only schedule I think this is the only way to do it.

1 Like

I'll throw my hat into this.

Option:

text input node. Set to input date format.

Sorry. Just saw you can't do that.

Send that through a node that will convert that to a timestamp value.

Use a change node to set flow context of this value. (Say flow.wait_until)

Next part:
inject node spitting out a timestamp every.... second. Given you want second accuracy.

That goes into a switch node. This is configured to say:
if (msg.payload == flow.get(wait_until)

So only when the timestamp matches the flow context does it let the packet through.

You could maybe /1000 to make it real seconds, as I think the millisecond resolution is just a bit too much to ask.

Ok, not worded the best, but do you understand the gist of what I am saying?

I think only one extra node is required. I think it is the moment node.
Sorry I can't name it exactly.

But anyway, that's my idea/thought/suggestion.

Idea in flow format:

Needed to do:
The inject node needs to be set to inject every second.

[{"id":"b66769cb.37ea1","type":"ui_form","z":"d103f472.19f3c8","name":"","label":"DATE","group":"ac199624.cb655","order":2,"width":"6","height":"1","options":[{"label":"Date","value":"Date","type":"date","required":true,"rows":null},{"label":"Time","value":"time","type":"text","required":true,"rows":null}],"formValue":{"Date":"","time":""},"payload":"","submit":"submit","cancel":"cancel","topic":"","x":130,"y":2250,"wires":[["de99d9c8.432e5"]]},{"id":"91292cb4.d7058","type":"change","z":"d103f472.19f3c8","name":"Store","rules":[{"t":"set","p":"wait_until","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":680,"y":2250,"wires":[[]]},{"id":"2dd24339.d37be4","type":"switch","z":"d103f472.19f3c8","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"wait_until","vt":"flow"}],"checkall":"true","repair":false,"outputs":1,"x":510,"y":2310,"wires":[["7bdac84.c763d38"]]},{"id":"29e4423f.e7dc76","type":"inject","z":"d103f472.19f3c8","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":2310,"wires":[["221f2e95.87dbaa"]]},{"id":"7bdac84.c763d38","type":"debug","z":"d103f472.19f3c8","name":"ACTION HERE!","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":680,"y":2310,"wires":[]},{"id":"221f2e95.87dbaa","type":"moment","z":"d103f472.19f3c8","name":"","topic":"","input":"","inputType":"msg","inTz":"","adjAmount":0,"adjType":"days","adjDir":"add","format":"","locale":"","output":"","outputType":"msg","outTz":"","x":330,"y":2310,"wires":[["2dd24339.d37be4"]]},{"id":"de99d9c8.432e5","type":"string","z":"d103f472.19f3c8","name":"","methods":[{"name":"delRightMost","params":[{"type":"str","value":"T"}]}],"prop":"payload.Date","propout":"payload.Date","object":"msg","objectout":"msg","x":270,"y":2250,"wires":[["cb43b445.aa9d48"]]},{"id":"cb43b445.aa9d48","type":"template","z":"d103f472.19f3c8","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.Date}}T{{payload.time}}","output":"str","x":430,"y":2250,"wires":[["91292cb4.d7058"]]},{"id":"ac199624.cb655","type":"ui_group","name":"Group 6","tab":"de5134a7.f0a0d","order":6,"disp":true,"width":6},{"id":"de5134a7.f0a0d","type":"ui_tab","name":"Tab 6","icon":"dashboard","order":5}]

You may need to tweak the moment node.

But I hope you get the idea.