Waits for incoming messages from different input paths to arrive within a fixed time window.
Usage no npm install needed!
<script type="module">
import nodeRedContribJoinWait from 'https://cdn.skypack.dev/node-red-contrib-join-wait';
</script>
README
Node RED join-wait
This Node-RED module waits for incoming messages from different input paths to arrive within a fixed time window.
Node-RED is a tool for wiring together hardware devices, APIs and online services in new and interesting ways.
Description
This node waits for messages from all items in the Paths (Wait) array, which must be received inside of a designated time window.
If all of the messages are received in that interval, a merged output is sent to the success output. Otherwise, any expired messages are sent to the timeout output. Either output can be optionally connected for further processing.
In the event of multiple messages, the time window is adjusted as needed to continue evaluation on subsequent messages. This node has several potential applications, including home automation. For instance, to handle a case where the light turning on/off is also triggering a motion sensor: IF a) light turned OFF, b) motion sensor activated, c) light turned ON all occur within 10 seconds, then turn light OFF.
Memory is managed to delete objects after they reach the Timeout.
Configuration
Each item in the Paths (Wait) array corresponds with an input path to wait for. E.g., ["path_1", "path_2", "other_path"]. Each path item must have a unique name.
This can also be configured at runtime by passing an array using msg.pathsToWait.
Each item in the Paths (Expire) array corresponds with an input path that will immediately expire all messages in the queue without further processing. This acts as a reset. Each path item must have a unique name.
This can also be configured at runtime by passing an array using msg.pathsToExpire.
If the Use regex option is enabled, each item in the Paths array will be treated as a regular expression.
This can also be configured at runtime by passing msg.useRegex as a boolean.
Paths topic must be set to a msg property, which is used to check each flow to see if all of the elements in Paths (Wait) are matched. This can be msg.topic, msg.paths, etc. If this is not specified, msg.paths is the default.
Note that Paths topic can be set in one of two ways:
As a string, set to the path to check, e.g., msg.paths = "path_1";
As an object, set to any value (e.g., msg.paths["path_1"] = {"example": "data"}; or msg.paths["path_1"] = 42;).
If the object format is used, multiple paths can be specified. For example, msg.paths = {"path_1": true, "path_2": true}; This can be useful if one flow needs to trigger multiple paths.
Correlation topic can be set, if desired, to ensure that only related messages are grouped. E.g., msg._msgid can be used to ensure that only messages from a single split flow are grouped together.
If left blank, all messages will be assumed to be related.
Timeout is required to designate the time window to receive all of the messages from Paths (Wait).
Sequence order defines the criteria to evaluate the received messages. An exact match can be specified, otherwise, it will match them in any order.
To determine the order, the timestamp on the latest valid Paths (Wait) is used, even if multiple messages arrived earlier. In this case of waiting for ["path_1", "path_2", "path_3"], the * indicates which messages are used: ["path_1", "path_2", "path_1"*, "path_2"*, "path_3"*].
Base message defines which message object should be returned as the base message. Either the first message in a sequence or the last.
Merged data defines how the data from msg.paths (or, another designed Paths topic) will be returned. Either, it can be merged in its original form, or, it can be overwritten with each respective msg.payload. This merged data is then appended to the Base message.
In the event that multiple messages arrive in this time interval with the same Paths (Wait), only the data from the latest item is returned. For instance, if Paths (Wait) = ["path_1", "path_2", "path_3"], the * indicates which messages are used in this sequence: ["path_1", "path_2", "path_1", "path_2", "path_1"*, "path_2"*, "path_3"*]. These additional messages (not starred) will be expired.
Notes and Caveats
There is support for repeated paths. For example, ["path_1", "path_2", "path_1", "path_2"].
If any order is used, Paths (Wait) is evaluated to determine the count for repeated paths. If regex is used, paths will be counted in a greedy fashion from left to right. For example, ["path_[12]", "path_2"] would never complete because all instances of "path_1" and "path_2" would be counted for the first path.
If exact order is used, note that unexpected paths would still be tolerated.
In the case of duplicate paths, only the data from the latest path(s) will be used.
If the regex option is enabled, each path will be treated as a regular expression. So, ["^path\d+
quot;] would match any path1, path2, path3, etc. Note that ^$ are not required, and if omitted, would just perform a partial match. For example ["path\d+"] would match "my_path1_test". This property can also be set at runtime by passing msg.useRegex.
If the msg.complete property is set, the message queue will be evaluated for completion, and then any remaining items in the queue will be immediately expired. This feature can be disabled in the settings, if desired.
All values within Paths topic must be contained by either Paths (Wait) or Paths (Expire), or an error will be thrown. The Unmatched paths error notification can be disabled within the settings.
If msg.pathsToWait is used instead of setting Paths (Wait), note that each successive msg.pathsToWait will overwrite the previously stored global value. Due to the nature of the timeout, Paths (Wait) needs to be evaluated even after a message has arrived. Changing the value of msg.pathsToWait between messages may cause unexpected behavior.
Timeout should be padded with a small amount of overhead (i.e., ~5-10 ms or so) for the time it takes to evaluate all of the messages and conditions. This may become critical under very short timeouts.
Example 1: Wait 5 seconds for input from 2 flows (in any order)
Example 3: Wait 5 seconds for input from Events 1A and 1B; Wait 5 seconds for input from Events 2A and 2B; Wait 1 minute for both event groups to complete.
Shows an example of how multiple join-wait nodes can be chained
# Then open the user data directory `~/.node-red` and install the package
$ cd ~/.node-red
$ npm install node-red-contrib-join-wait
Or search for join-wait in the manage palette menu
How to contribute
Have an idea? Found a bug? Contributions and pull requests are welcome.
Support my projects
I try to reply to everyone needing help using these projects. Obviously, this takes time. However, if you get some profit from this or just want to encourage me to continue creating stuff, there are few ways you can do it:
Starring and sharing the projects you like :rocket:
PayPal— You can make one-time donations via PayPal.
Venmo— You can make one-time donations via Venmo.
Bitcoin— You can send me Bitcoin at this address: 33sT6xw3tZWAdP2oL4ygbH5TVpVMfk9VW7