[ANNOUNCE] Ultimate (Swiss-Army-Knife) Node-Red Timer based flow control

Hallo,

I would like to introduce my node collection node-red-contrib-sun-position.

The name is unfortunately misleading here and describes only a very small fraction of the possibilities of this package. Over the years, the possibilities have grown very strongly and in the meantime this package has reached a stable state.

This package contains everything that is required for timing for node red.

You could start a flow by time:
image

You could control a flow by time:

You could compare, parse, reformat times:
image

You could calculate time-spans:

The origin of the package is of course still there. This is how the sun position or moon position and there times can be determined:


For more complex scenarios exists a clock timer or a blind control node:
image
image

All time depending has a huge configuration possibility.

A lot of sun-times are supported:

Time Description SunBH
astronomicalDawn night ends (morning astronomical twilight starts) 18
amateurDawn amateur astronomical dawn (sun at 12° before sunrise) 15
nauticalDawn nautical dawn (morning nautical twilight starts) 12
blueHourDawnStart blue Hour start (time for special photography photos starts) 8
civilDawn dawn (morning nautical twilight ends, morning civil twilight starts) 6
blueHourDawnEnd blue Hour end (time for special photography photos end) 4
goldenHourDawnStart morning golden hour (soft light, best time for photography) starts -1
sunrise sunrise (top edge of the sun appears on the horizon) 0.833
sunriseEnd sunrise ends (bottom edge of the sun touches the horizon) 0.3
goldenHourDawnEnd morning golden hour (soft light, best time for photography) ends -6
solarNoon solar noon (sun is in the highest position)
goldenHourDuskStart evening golden hour (soft light, best time for photography) starts -6
sunsetStart sunset starts (bottom edge of the sun touches the horizon) 0.3
sunset sunset (sun disappears below the horizon, evening civil twilight starts) 0.833
goldenHourDuskEnd evening golden hour (soft light, best time for photography) ends 1
blueHourDuskStart blue Hour start (time for special photography photos starts) 4
civilDusk dusk (evening nautical twilight starts) 6
blueHourDuskEnd blue Hour end (time for special photography photos end) 8
nauticalDusk nautical dusk end (evening astronomical twilight starts) 12
amateurDusk amateur astronomical dusk (sun at 12° after sunrise) 15
astronomicalDusk night starts (dark enough for astronomical observations) 18
nadir nadir (darkest moment of the night, sun is in the lowest position)

(SunBH is the angle of the sun below the horizon)

The greatest strength is that all nodes have a lot of possibilities. This goes until then that the JSONATA function has been expanded with additional functions.

4 Likes

Wow, thanks for sharing!
That library is huge...I am still trying to comprehend all options and parameters available and how to use them.

Also, the idea of naming it the "Swiss Army Knife" of Timers is well deserved and, as it looks, well thought of :rofl: :blush:

Quick question, as this is what I am looking for ATM: Is there a way to generate a given number of timer events between sunrise and sunset each day, at equidistant intervals. Would this be easily possible with this knife?

keep up the good work!
regards,
hominidae

That's quite a specific need to say the least. :smile:

Yes, a far call, I agree...but specifically made tools is what a swiss army knife is made of, isn't it?

Isn't a Swiss army knife more like a general tool suitable for most tasks but not very specialized ones? :slightly_smiling_face:

I would approach the problem by:

  1. Finding a way to get the times for both events (may or may not be possible with existing nodes(?))
  2. Calculate the difference and divide it by the X times required, then
  3. a) send an event X times using the result as an interval or
    b) create an array of event times by adding the result interval to the start time (sunrise) X times, and then set timers to fire up during the times in the array

...nope, that is only if you are Angus "Mac" MacGuyver, but this includes carrying a pair of matches, a chewing gum, shoe strings and this: https://www.victorinox.com/global/en/Products/Swiss-Army-Knives/Small-Pocket-Knives/Midnite-Manager/p/0.6366

....this is for normal people and definitely not generic :rofl: :joy:
https://www.victorinox.com/global/en/Products/Swiss-Army-Knives/Medium-Pocket-Knives/Swiss-Champ-XAVT/p/1.6795.XAVT.

Thanks for the hints...I thought into the same direction, maybe using schedex to configure the events by means of feeding it with them,. once I found out how to identify them.

1 Like

Yes, the Inject node of this package can do this.
It can be configured to have a start and an end time (fixed time, sun tine, moon time,...) and an intervall where the Payload should be send.

1 Like

Just tested it! and afterwards deleted all other astro and sunevent nodes :grinning:
Really impressive!

...thank for answering, that's great info!
I'll give it a try asap. I actually browsed the docs but wasn't able to find the information regarding that feature.

If I understood correctly this is close to what @hominidae requested but not quite. The hope was to define a start and end time, during which an event would trigger X times at equal intervals (defined by the start/end time and the given repetitions).

If you'd ask from me, I'd say it'd be too obscure to implement as a reusable feature. :slightly_smiling_face: But I might have misinterpreted the question also!

Yes, @ristomatti did understand correctly.
I investigated the library and it is able to accept a repeating interval for triggering in between start-&end-times. However, if these interval framing times would change over the year (like sunrise and sunset), the number of iterations between these times would change.
What I would like to see is quite the opposite, keeping the number of iterations fixed, even if the interval length changes over the time of year (OK, and as a big, big extra bonus also submitting the counter of this time injection incident (number of iteration occured ) with the message).

Background to this idea/my request is, that I have access to a certain service API, where the number of calls allowed is limited to a certain number per day. I would like to maximize these request-calls to take place in between a certain time of day

:grin: I need to explain a little more:

The inject node of this package has different configuration posibiities.

  1. is only manual trigger of the inject.
    The advantage of the build in Inject node is then that the Node has much more option of the payload:

There is the possibility to set an additional property of the message object (or a context) with additional payload:


Einer der ursprünglichen Anwendungsfälle bestand darin, zusammen mit einem Einschaltsignal die Zeit für das Ausschalten mitzugeben. Das ist aber sehr flexibel gestaltet für beliebig andere Anwendungsfälle.

  1. beside the manual trigger the node can be configured to send in a fixed interval the payload
    image

  2. The node can send the payload on a fixed timestamp:

  3. the Node can send in an interval between two timestamps:

All timestamps could be a fixed time, a sun-time or moon-time.

However, the time between sending a message is a fixed time. This changes the number of iterations between the specified times, as these change over the year. Maybe at some point I could still implement the use case that the number is fixed.

...OK, here is a first demo-flow that can do what I want (generate a given number of timer events between sunrise and sunset each day, at equidistant intervals).
I am using the suncalc node to get get the start/end-times, then calculate the interval in a change node..
The iterations are injected using a dsm node with an interval config (from the dsm-node wiki, https://github.com/cflurin/node-red-contrib-dsm/wiki/Interval) and start/stop events are fired from the inject nodes at sunrise/sunset..

[{"id":"1fd8cac4.8f5445","type":"tab","label":"Flow 3","disabled":false,"info":""},{"id":"313aadae.e6d532","type":"sun-position","z":"1fd8cac4.8f5445","name":"suncalc","positionConfig":"8c7609ce.dd5798","rules":[],"onlyOnChange":"true","topic":"interval","outputs":1,"start":"sunrise","startType":"pdsTime","startOffset":0,"startOffsetType":"none","startOffsetMultiplier":60000,"end":"sunset","endType":"pdsTime","endOffset":0,"endOffsetType":"none","endOffsetMultiplier":60000,"x":601,"y":120,"wires":[["cc99eed2.f5748"]]},{"id":"cc99eed2.f5748","type":"change","z":"1fd8cac4.8f5445","name":"set interval","rules":[{"t":"set","p":"iterations","pt":"msg","to":"20","tot":"num"},{"t":"set","p":"intervalLength","pt":"msg","to":"payload.endTime - payload.startTime","tot":"jsonata"},{"t":"set","p":"interval","pt":"msg","to":"$ceil(intervalLength / (iterations -1)\t)","tot":"jsonata"},{"t":"move","p":"interval","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":814,"y":120,"wires":[["98f9356d.380198"]]},{"id":"231aedc8.aa7d62","type":"inject","z":"1fd8cac4.8f5445","name":"start","topic":"start","payload":"my payload","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":670,"y":340,"wires":[["98f9356d.380198"]]},{"id":"d8bb28c.2b81fd8","type":"debug","z":"1fd8cac4.8f5445","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1208,"y":240,"wires":[]},{"id":"98f9356d.380198","type":"dsm","z":"1fd8cac4.8f5445","name":"interval","sm_config":"{\n    \"stateOutput\": \"state\",\n    \"currentState\": \"stopped\",\n    \"states\": {\n        \"stopped\": {\n            \"start\": \"started\"\n        },\n        \"started\": {\n            \"run\": \"running\",\n            \"stop\": \"stopped\"\n        },\n        \"running\": {\n            \"run\": \"running\",\n            \"stop\": \"stopped\"\n        }\n    },\n    \"data\": {\n        \"interval\": 2000\n    },\n    \"methods\": {\n        \"interval\": {\n            \"name\": \"setData\"\n        },\n        \"start\":  [\n            \"if (sm.currentState === 'started') {\",\n            \"   node.send(msg);\",\n            \"   resume('run',msg);\",\n            \"}\"\n        ],\n        \"run\": [\n            \"timeout.interval = setTimeout(function() {\",\n            \"   node.send(msg);\",\n            \"   resume('run',msg);\",\n            \"}, sm.data.interval);\"\n        ],\n        \"stop\": [\n            \"if (timeout.interval) {\",\n            \"   clearTimeout(timeout.interval);\",\n            \"}\"\n        ],\n        \"onAfterTransition\": \"output = false;\",\n        \"status\": {\n            \"fill\": {\n                \"get\": \"sm.currentState === 'running' ? 'green' : 'grey'\"\n            },\n            \"shape\": \"dot\",\n            \"text\": {\n                \"get\": \"sm.currentState === 'running' ? 'interval ' + sm.data.interval : sm.currentState\"\n            }\n        }\n    }\n}","x":1018,"y":240,"wires":[["d8bb28c.2b81fd8"]]},{"id":"b39dce4e.2a689","type":"inject","z":"1fd8cac4.8f5445","name":"stop","topic":"stop","payload":"stopped","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":670,"y":382,"wires":[["98f9356d.380198"]]},{"id":"4cea86cf.cfe658","type":"inject","z":"1fd8cac4.8f5445","name":"","topic":"interval","payload":"5000","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":690,"y":464,"wires":[["98f9356d.380198"]]},{"id":"5551575d.3a2058","type":"time-inject","z":"1fd8cac4.8f5445","name":"","nameInt":"⏲ Sonnenaufgang Begin = Zeitpunkt","positionConfig":"8c7609ce.dd5798","payload":"","payloadType":"date","payloadTimeFormat":0,"payloadOffset":0,"payloadOffsetType":"none","payloadOffsetMultiplier":60000,"topic":"start","injectTypeSelect":"time","intervalCount":1,"intervalCountType":"num","intervalCountMultiplier":60000,"time":"sunrise","timeType":"pdsTime","offset":0,"offsetType":"none","offsetMultiplier":60000,"timeEnd":"","timeEndType":"entered","timeEndOffset":0,"timeEndOffsetType":"none","timeEndOffsetMultiplier":60000,"timeDays":"*","timeOnlyOddDays":false,"timeOnlyEvenDays":false,"timeMonths":"*","timedatestart":"","timedateend":"","property":"","propertyType":"none","propertyCompare":"true","propertyThreshold":"","propertyThresholdType":"num","timeAlt":"","timeAltType":"entered","timeAltDays":"*","timeAltOnlyOddDays":false,"timeAltOnlyEvenDays":false,"timeAltMonths":"*","timeAltOffset":0,"timeAltOffsetType":"none","timeAltOffsetMultiplier":60000,"once":false,"onceDelay":0.1,"addPayload1":"","addPayload1Type":"none","addPayload1Value":"","addPayload1ValueType":"date","addPayload1Format":"0","addPayload1Offset":0,"addPayload1OffsetType":"none","addPayload1OffsetMultiplier":60000,"addPayload1Next":true,"addPayload1Days":"*","addPayload2":"","addPayload2Type":"none","addPayload2Value":"","addPayload2ValueType":"date","addPayload2Format":"0","addPayload2Offset":0,"addPayload2OffsetType":"none","addPayload2OffsetMultiplier":60000,"addPayload2Next":true,"addPayload2Days":"*","addPayload3":"","addPayload3Type":"none","addPayload3Value":"","addPayload3ValueType":"date","addPayload3Format":"0","addPayload3Offset":0,"addPayload3OffsetType":"none","addPayload3OffsetMultiplier":60000,"addPayload3Next":true,"addPayload3Days":"*","recalcTime":2,"x":270,"y":200,"wires":[["313aadae.e6d532","cbc61aa9.459e58"]]},{"id":"9729d616.48af08","type":"time-inject","z":"1fd8cac4.8f5445","name":"","nameInt":"⏲ Sonnenuntergang Ende = Zeitpunkt","positionConfig":"8c7609ce.dd5798","payload":"","payloadType":"date","payloadTimeFormat":0,"payloadOffset":0,"payloadOffsetType":"none","payloadOffsetMultiplier":60000,"topic":"stop","injectTypeSelect":"time","intervalCount":1,"intervalCountType":"num","intervalCountMultiplier":60000,"time":"sunset","timeType":"pdsTime","offset":0,"offsetType":"none","offsetMultiplier":60000,"timeEnd":"","timeEndType":"entered","timeEndOffset":0,"timeEndOffsetType":"none","timeEndOffsetMultiplier":60000,"timeDays":"*","timeOnlyOddDays":false,"timeOnlyEvenDays":false,"timeMonths":"*","timedatestart":"","timedateend":"","property":"","propertyType":"none","propertyCompare":"true","propertyThreshold":"","propertyThresholdType":"num","timeAlt":"","timeAltType":"entered","timeAltDays":"*","timeAltOnlyOddDays":false,"timeAltOnlyEvenDays":false,"timeAltMonths":"*","timeAltOffset":0,"timeAltOffsetType":"none","timeAltOffsetMultiplier":60000,"once":false,"onceDelay":0.1,"addPayload1":"","addPayload1Type":"none","addPayload1Value":"","addPayload1ValueType":"date","addPayload1Format":"0","addPayload1Offset":0,"addPayload1OffsetType":"none","addPayload1OffsetMultiplier":60000,"addPayload1Next":true,"addPayload1Days":"*","addPayload2":"","addPayload2Type":"none","addPayload2Value":"","addPayload2ValueType":"date","addPayload2Format":"0","addPayload2Offset":0,"addPayload2OffsetType":"none","addPayload2OffsetMultiplier":60000,"addPayload2Next":true,"addPayload2Days":"*","addPayload3":"","addPayload3Type":"none","addPayload3Value":"","addPayload3ValueType":"date","addPayload3Format":"0","addPayload3Offset":0,"addPayload3OffsetType":"none","addPayload3OffsetMultiplier":60000,"addPayload3Next":true,"addPayload3Days":"*","recalcTime":2,"x":270,"y":300,"wires":[["cbc61aa9.459e58","313aadae.e6d532"]]},{"id":"e83dc62e.ada438","type":"inject","z":"1fd8cac4.8f5445","name":"","topic":"interval","payload":"1000","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":690,"y":424,"wires":[["98f9356d.380198"]]},{"id":"cbc61aa9.459e58","type":"delay","z":"1fd8cac4.8f5445","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":660,"y":240,"wires":[["98f9356d.380198"]]},{"id":"5b62f0eb.a59f","type":"inject","z":"1fd8cac4.8f5445","name":"","topic":"inject","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":200,"y":120,"wires":[["313aadae.e6d532"]]},{"id":"8c7609ce.dd5798","type":"position-config","z":"","name":"DACH-1","isValide":"true","longitude":"0","latitude":"0","angleType":"deg","timeZoneOffset":"99","timeZoneDST":"0","stateTimeFormat":"3","stateDateFormat":"12"}]