Git Product home page Git Product logo

dxdc / node-red-contrib-join-wait Goto Github PK

View Code? Open in Web Editor NEW
7.0 5.0 0.0 642 KB

Node-RED module to wait for incoming messages from different input paths to arrive within a fixed time window.

Home Page: https://flows.nodered.org/node/node-red-contrib-join-wait

License: MIT License

JavaScript 82.71% HTML 17.29%
node-red nodered wait join home-automation homebridge merge timeout time parallel

node-red-contrib-join-wait's Introduction

Node RED join-wait

mit license npm npm Donate

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:

  1. As a string, set to the path to check, e.g., msg.paths = "path_1";
  2. 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+$"] 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 1

Flow
[
    {
        "id": "7382168d.c47858",
        "type": "inject",
        "z": "fb783323.7e308",
        "name": "",
        "topic": "topic1",
        "payload": "{\"brightness\":\"20\"}",
        "payloadType": "json",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "x": 950,
        "y": 1460,
        "wires": [["93c1545b.dca6f8"]]
    },
    {
        "id": "3b8f6807.956d78",
        "type": "debug",
        "z": "fb783323.7e308",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "complete": "true",
        "x": 1610,
        "y": 1320,
        "wires": []
    },
    {
        "id": "5866d421.7eb66c",
        "type": "inject",
        "z": "fb783323.7e308",
        "name": "",
        "topic": "topic1",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "x": 960,
        "y": 1380,
        "wires": [["8d0b69cc.b2b228"]]
    },
    {
        "id": "337256a2.04446a",
        "type": "debug",
        "z": "fb783323.7e308",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1610,
        "y": 1480,
        "wires": []
    },
    {
        "id": "8d0b69cc.b2b228",
        "type": "change",
        "z": "fb783323.7e308",
        "name": "Set path_1",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_1", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1210,
        "y": 1380,
        "wires": [["959a4717.0b5138"]]
    },
    {
        "id": "93c1545b.dca6f8",
        "type": "change",
        "z": "fb783323.7e308",
        "name": "Set path_2",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_2", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1210,
        "y": 1460,
        "wires": [["959a4717.0b5138"]]
    },
    {
        "id": "959a4717.0b5138",
        "type": "join-wait",
        "z": "fb783323.7e308",
        "name": "",
        "paths": "[\"path_1\", \"path_2\"]",
        "pathsToExpire": "",
        "ignoreUnmatched": false,
        "pathTopic": "paths",
        "pathTopicType": "msg",
        "correlationTopic": "",
        "correlationTopicType": "msg",
        "timeout": "5",
        "timeoutUnits": "1000",
        "exactOrder": "false",
        "firstMsg": "true",
        "mapPayload": "true",
        "disableComplete": false,
        "x": 1420,
        "y": 1400,
        "wires": [["3b8f6807.956d78"], ["337256a2.04446a"]]
    },
    {
        "id": "6ae4802.e40238",
        "type": "comment",
        "z": "fb783323.7e308",
        "name": "(optional) expired messages",
        "info": "",
        "x": 1660,
        "y": 1520,
        "wires": []
    }
]

Example 2: Wait 5 seconds for input from a split flow (in any order); one message does not arrive in time

  • _msgid is used as the Correlation topic, so that flows from split queues can be tracked.

Example 2

Flow
[
    {
        "id": "c5aae6a2.78f4d8",
        "type": "debug",
        "z": "fb783323.7e308",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "complete": "true",
        "x": 1590,
        "y": 1440,
        "wires": []
    },
    {
        "id": "4644d839.170ac8",
        "type": "inject",
        "z": "fb783323.7e308",
        "name": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "x": 800,
        "y": 1500,
        "wires": [["f785671e.2f1ac8", "2869e698.5a1daa", "373d1571.a4d5fa"]]
    },
    {
        "id": "3ed2d37b.3a852c",
        "type": "debug",
        "z": "fb783323.7e308",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1590,
        "y": 1600,
        "wires": []
    },
    {
        "id": "f785671e.2f1ac8",
        "type": "change",
        "z": "fb783323.7e308",
        "name": "Set path_1",
        "rules": [
            { "t": "set", "p": "paths", "pt": "msg", "to": "path_1", "tot": "str" },
            { "t": "set", "p": "payload", "pt": "msg", "to": "true", "tot": "bool" }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1190,
        "y": 1500,
        "wires": [["c492296e.f80428"]]
    },
    {
        "id": "84493c9a.b98f9",
        "type": "change",
        "z": "fb783323.7e308",
        "name": "Set path_2",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_2", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1190,
        "y": 1580,
        "wires": [["c492296e.f80428"]]
    },
    {
        "id": "c492296e.f80428",
        "type": "join-wait",
        "z": "fb783323.7e308",
        "name": "",
        "paths": "[\"path_1\", \"path_2\"]",
        "pathsToExpire": "",
        "pathTopic": "paths",
        "pathTopicType": "msg",
        "correlationTopic": "_msgid",
        "correlationTopicType": "msg",
        "timeout": "5",
        "timeoutUnits": "1000",
        "exactOrder": "false",
        "firstMsg": "true",
        "mapPayload": "true",
        "x": 1400,
        "y": 1520,
        "wires": [["c5aae6a2.78f4d8"], ["3ed2d37b.3a852c"]]
    },
    {
        "id": "a73abdd0.1bd6",
        "type": "comment",
        "z": "fb783323.7e308",
        "name": "(optional) expired messages",
        "info": "",
        "x": 1640,
        "y": 1640,
        "wires": []
    },
    {
        "id": "2869e698.5a1daa",
        "type": "delay",
        "z": "fb783323.7e308",
        "name": "",
        "pauseType": "delay",
        "timeout": "4",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 1000,
        "y": 1580,
        "wires": [["84493c9a.b98f9"]]
    },
    {
        "id": "373d1571.a4d5fa",
        "type": "delay",
        "z": "fb783323.7e308",
        "name": "",
        "pauseType": "delay",
        "timeout": "7",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 1000,
        "y": 1640,
        "wires": [["84493c9a.b98f9"]]
    }
]

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
  • If Event 3A is received, reset queue

Example 3

Flow
[
    {
        "id": "ecf4478b.5bcf28",
        "type": "change",
        "z": "ee7b2f38.64383",
        "name": "Set event_1B",
        "rules": [{ "t": "set", "p": "name", "pt": "msg", "to": "event_1B", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 760,
        "y": 740,
        "wires": [["fb17fdab.13bc6"]]
    },
    {
        "id": "fb17fdab.13bc6",
        "type": "join-wait",
        "z": "ee7b2f38.64383",
        "name": "",
        "paths": "[\"event_1A\", \"event_1B\"]",
        "pathsToExpire": "",
        "ignoreUnmatched": false,
        "pathTopic": "name",
        "pathTopicType": "msg",
        "correlationTopic": "",
        "correlationTopicType": "msg",
        "timeout": "5",
        "timeoutUnits": "1000",
        "exactOrder": "false",
        "firstMsg": "true",
        "mapPayload": "true",
        "disableComplete": false,
        "x": 960,
        "y": 680,
        "wires": [["8d4ce0e0.362b7"], []]
    },
    {
        "id": "c264c765.36e3c8",
        "type": "change",
        "z": "ee7b2f38.64383",
        "name": "Set event_1A",
        "rules": [{ "t": "set", "p": "name", "pt": "msg", "to": "event_1A", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 750,
        "y": 660,
        "wires": [["fb17fdab.13bc6"]]
    },
    {
        "id": "6a032c55.883394",
        "type": "delay",
        "z": "ee7b2f38.64383",
        "name": "",
        "pauseType": "delay",
        "timeout": "2",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 560,
        "y": 740,
        "wires": [["ecf4478b.5bcf28"]]
    },
    {
        "id": "8d4ce0e0.362b7",
        "type": "join-wait",
        "z": "ee7b2f38.64383",
        "name": "",
        "paths": "[\"event_1A\", \"event_1B\", \"event_2A\", \"event_2B\"]",
        "pathsToExpire": "[\"event_3A\"]",
        "ignoreUnmatched": false,
        "pathTopic": "name",
        "pathTopicType": "msg",
        "correlationTopic": "",
        "correlationTopicType": "msg",
        "timeout": "1",
        "timeoutUnits": "60000",
        "exactOrder": "false",
        "firstMsg": "true",
        "mapPayload": "false",
        "disableComplete": false,
        "x": 1200,
        "y": 800,
        "wires": [["f4c5e7c1.831528"], ["830ebf9c.f1588"]]
    },
    {
        "id": "2830e00c.06bde",
        "type": "inject",
        "z": "ee7b2f38.64383",
        "name": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "x": 300,
        "y": 780,
        "wires": [["4213bd84.2c68b4", "6a032c55.883394", "c47ba83d.c17548", "d2839a03.b24e98"]]
    },
    {
        "id": "7e51b1f.75d755",
        "type": "change",
        "z": "ee7b2f38.64383",
        "name": "Set event_2B",
        "rules": [{ "t": "set", "p": "name", "pt": "msg", "to": "event_2B", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 760,
        "y": 900,
        "wires": [["4d466044.9e7ba"]]
    },
    {
        "id": "4213bd84.2c68b4",
        "type": "change",
        "z": "ee7b2f38.64383",
        "name": "Set event_2A",
        "rules": [{ "t": "set", "p": "name", "pt": "msg", "to": "event_2A", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 750,
        "y": 840,
        "wires": [["4d466044.9e7ba"]]
    },
    {
        "id": "c47ba83d.c17548",
        "type": "delay",
        "z": "ee7b2f38.64383",
        "name": "",
        "pauseType": "delay",
        "timeout": "4",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 560,
        "y": 900,
        "wires": [["7e51b1f.75d755"]]
    },
    {
        "id": "4d466044.9e7ba",
        "type": "join-wait",
        "z": "ee7b2f38.64383",
        "name": "",
        "paths": "[\"event_2A\", \"event_2B\"]",
        "pathsToExpire": "",
        "ignoreUnmatched": false,
        "pathTopic": "name",
        "pathTopicType": "msg",
        "correlationTopic": "",
        "correlationTopicType": "msg",
        "timeout": "5",
        "timeoutUnits": "1000",
        "exactOrder": "false",
        "firstMsg": "true",
        "mapPayload": "true",
        "disableComplete": false,
        "x": 940,
        "y": 860,
        "wires": [["89331b9.e9fbce8"], []]
    },
    {
        "id": "a335f9be.14d698",
        "type": "change",
        "z": "ee7b2f38.64383",
        "name": "Set event_3A",
        "rules": [{ "t": "set", "p": "name", "pt": "msg", "to": "event_3A", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 950,
        "y": 1040,
        "wires": [["8d4ce0e0.362b7"]]
    },
    {
        "id": "b3d43a9c.4f0558",
        "type": "inject",
        "z": "ee7b2f38.64383",
        "name": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "x": 780,
        "y": 1040,
        "wires": [["a335f9be.14d698"]]
    },
    {
        "id": "830ebf9c.f1588",
        "type": "debug",
        "z": "ee7b2f38.64383",
        "name": "Expired",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "x": 1360,
        "y": 840,
        "wires": []
    },
    {
        "id": "f4c5e7c1.831528",
        "type": "debug",
        "z": "ee7b2f38.64383",
        "name": "Success",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 1360,
        "y": 760,
        "wires": []
    },
    {
        "id": "89331b9.e9fbce8",
        "type": "delay",
        "z": "ee7b2f38.64383",
        "name": "",
        "pauseType": "delay",
        "timeout": "10",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 1000,
        "y": 800,
        "wires": [["8d4ce0e0.362b7"]]
    },
    {
        "id": "d2839a03.b24e98",
        "type": "delay",
        "z": "ee7b2f38.64383",
        "name": "",
        "pauseType": "delay",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 560,
        "y": 660,
        "wires": [["c264c765.36e3c8"]]
    },
    {
        "id": "69bf4156.8d7b8",
        "type": "comment",
        "z": "ee7b2f38.64383",
        "name": "Expire all messages with event_3A",
        "info": "",
        "x": 860,
        "y": 1000,
        "wires": []
    }
]

Example 4: Wait 10 seconds for Event 1 to fire 3 times, followed by Event 3. Must be in this exact order.

  • Shows an example of repeated path names
  • Shows an example of setting multiple paths by a single event

Example 4

Flow
[
    {
        "id": "cc9d6391.878ea",
        "type": "debug",
        "z": "d21c3caf.1c4a6",
        "name": "success",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 120,
        "wires": []
    },
    {
        "id": "98108d1f.bc6aa",
        "type": "join-wait",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "paths": "[\"path_1\",\"path_1\",\"path_1\",\"path_3\"]",
        "pathsToExpire": "",
        "useRegex": false,
        "warnUnmatched": false,
        "pathTopic": "paths",
        "pathTopicType": "msg",
        "correlationTopic": "",
        "correlationTopicType": "undefined",
        "timeout": "10",
        "timeoutUnits": "1000",
        "exactOrder": "true",
        "firstMsg": "true",
        "mapPayload": "true",
        "disableComplete": false,
        "x": 600,
        "y": 180,
        "wires": [["cc9d6391.878ea"], ["38e19f0c.ff2a9"]]
    },
    {
        "id": "38e19f0c.ff2a9",
        "type": "debug",
        "z": "d21c3caf.1c4a6",
        "name": "expired",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 260,
        "wires": []
    },
    {
        "id": "9d4f0eed.15eb3",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_1 and path_3",
        "rules": [
            { "t": "set", "p": "paths", "pt": "msg", "to": "{\"path_1\": true, \"path_3\":true}", "tot": "json" }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 360,
        "y": 260,
        "wires": [["98108d1f.bc6aa"]]
    },
    {
        "id": "c1809b24.8990f8",
        "type": "delay",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "pauseType": "delay",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 160,
        "y": 260,
        "wires": [["9d4f0eed.15eb3"]]
    },
    {
        "id": "b69f3131.98969",
        "type": "inject",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 140,
        "y": 120,
        "wires": [["bb0b9bc5.c65ee8", "c1809b24.8990f8", "8969e7ba.e36038"]]
    },
    {
        "id": "bb0b9bc5.c65ee8",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_1",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_1", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 330,
        "y": 120,
        "wires": [["98108d1f.bc6aa"]]
    },
    {
        "id": "8969e7ba.e36038",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_1",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_1", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 330,
        "y": 180,
        "wires": [["98108d1f.bc6aa"]]
    }
]

Example 5: Wait 10 seconds for the exact event order "path_1", "path_2", "path_1", "path_2".

  • Shows an example of repeated path names
  • Shows an example of an unexpected path name being observed. This can be caught by another node, if desired.

Example 5

Flow
[
    {
        "id": "cc9d6391.878ea",
        "type": "debug",
        "z": "d21c3caf.1c4a6",
        "name": "success",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 120,
        "wires": []
    },
    {
        "id": "98108d1f.bc6aa",
        "type": "join-wait",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "paths": "[\"path_1\",\"path_2\",\"path_1\",\"path_2\"]",
        "pathsToExpire": "",
        "useRegex": false,
        "warnUnmatched": true,
        "pathTopic": "paths",
        "pathTopicType": "msg",
        "correlationTopic": "",
        "correlationTopicType": "undefined",
        "timeout": "10",
        "timeoutUnits": "1000",
        "exactOrder": "true",
        "firstMsg": "true",
        "mapPayload": "true",
        "disableComplete": false,
        "x": 640,
        "y": 160,
        "wires": [["cc9d6391.878ea"], ["38e19f0c.ff2a9"]]
    },
    {
        "id": "38e19f0c.ff2a9",
        "type": "debug",
        "z": "d21c3caf.1c4a6",
        "name": "expired",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 240,
        "wires": []
    },
    {
        "id": "c1809b24.8990f8",
        "type": "delay",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "pauseType": "delay",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 160,
        "y": 200,
        "wires": [["bb0b9bc5.c65ee8", "2f5d90da.fabdf", "77c09e21.8cb11"]]
    },
    {
        "id": "b69f3131.98969",
        "type": "inject",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 140,
        "y": 120,
        "wires": [["bb0b9bc5.c65ee8", "2f5d90da.fabdf", "c1809b24.8990f8"]]
    },
    {
        "id": "bb0b9bc5.c65ee8",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_1",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_1", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 430,
        "y": 100,
        "wires": [["98108d1f.bc6aa"]]
    },
    {
        "id": "8969e7ba.e36038",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_2",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_2", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 470,
        "y": 220,
        "wires": [["98108d1f.bc6aa"]]
    },
    {
        "id": "2f5d90da.fabdf",
        "type": "delay",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "pauseType": "delay",
        "timeout": "100",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 430,
        "y": 160,
        "wires": [["8969e7ba.e36038"]]
    },
    {
        "id": "77c09e21.8cb11",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_3",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_3", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 470,
        "y": 260,
        "wires": [["98108d1f.bc6aa"]]
    }
]

Example 6: Wait 10 seconds for two "path_1" events and one "path_2" event in any order.

Example 6

Flow
[
    {
        "id": "cc9d6391.878ea",
        "type": "debug",
        "z": "d21c3caf.1c4a6",
        "name": "success",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 120,
        "wires": []
    },
    {
        "id": "98108d1f.bc6aa",
        "type": "join-wait",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "paths": "[\"path_1\",\"path_2\",\"path_1\"]",
        "pathsToExpire": "",
        "useRegex": false,
        "warnUnmatched": true,
        "pathTopic": "paths",
        "pathTopicType": "msg",
        "correlationTopic": "",
        "correlationTopicType": "undefined",
        "timeout": "10",
        "timeoutUnits": "1000",
        "exactOrder": "false",
        "firstMsg": "true",
        "mapPayload": "true",
        "disableComplete": false,
        "x": 640,
        "y": 160,
        "wires": [["cc9d6391.878ea"], ["38e19f0c.ff2a9"]]
    },
    {
        "id": "38e19f0c.ff2a9",
        "type": "debug",
        "z": "d21c3caf.1c4a6",
        "name": "expired",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 240,
        "wires": []
    },
    {
        "id": "b69f3131.98969",
        "type": "inject",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 140,
        "y": 180,
        "wires": [["1546292e.21d097", "25f3441b.c9fd9c", "3c1f3edc.6a53c2"]]
    },
    {
        "id": "bb0b9bc5.c65ee8",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_1",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_1", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 450,
        "y": 140,
        "wires": [["98108d1f.bc6aa"]]
    },
    {
        "id": "8969e7ba.e36038",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_1",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_1", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 450,
        "y": 180,
        "wires": [["98108d1f.bc6aa"]]
    },
    {
        "id": "77c09e21.8cb11",
        "type": "change",
        "z": "d21c3caf.1c4a6",
        "name": "Set path_2",
        "rules": [{ "t": "set", "p": "paths", "pt": "msg", "to": "path_2", "tot": "str" }],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 450,
        "y": 220,
        "wires": [["98108d1f.bc6aa"]]
    },
    {
        "id": "25f3441b.c9fd9c",
        "type": "delay",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "pauseType": "random",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "25",
        "randomUnits": "milliseconds",
        "drop": false,
        "x": 300,
        "y": 140,
        "wires": [["bb0b9bc5.c65ee8"]]
    },
    {
        "id": "1546292e.21d097",
        "type": "delay",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "pauseType": "random",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "25",
        "randomUnits": "milliseconds",
        "drop": false,
        "x": 300,
        "y": 180,
        "wires": [["8969e7ba.e36038"]]
    },
    {
        "id": "3c1f3edc.6a53c2",
        "type": "delay",
        "z": "d21c3caf.1c4a6",
        "name": "",
        "pauseType": "random",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "25",
        "randomUnits": "milliseconds",
        "drop": false,
        "x": 300,
        "y": 220,
        "wires": [["77c09e21.8cb11"]]
    }
]

โ“ Get Help

For bug reports and feature requests, open issues. ๐Ÿ›

Installation

First of all, install Node-RED

# 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 ๐Ÿš€
  • PayPal PayPalโ€” You can make one-time donations via PayPal.
  • Venmoโ€” You can make one-time donations via Venmo. Venmo QR Code
  • Bitcoinโ€” You can send me Bitcoin at this address: 33sT6xw3tZWAdP2oL4ygbH5TVpVMfk9VW7

Credits

MIT License

node-red-contrib-join-wait's People

Contributors

dxdc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

node-red-contrib-join-wait's Issues

Correlation topic doesn't persist on edit

Correlation topic doesn't persist on edit. To reproduce the issue:

  • Edit the join-wait node
  • Write something in the Correlation Topic (msg.payload.xxx)
  • Click on Done
  • Edit the join-wait node
  • -> Correlation Topic is empty

Exact order failed in case of incorrect order

Hello,

First thanks for your node it seems to be really what I'm looking for.

But it seems the exact order is not working correctly.
In case of this Paths (Wait):
["path_1", "path_2"]
And if this arrive:
["path_2", "path_1", "path_2"]

The second part is not detected and I get 3 times the timeout.

With the following code (sending ["path_1", "path_2", "path_2", "path_1", "path_2"]) I detect the first "path_1", "path_2" but not the second:
[{"id":"95381dc9.c8b9c","type":"inject","z":"1cc55bbe.9f4cd4","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":"","x":100,"y":600,"wires":[["6121961b.964748","4d403e03.16926","5e3a1179.8b5bc","8bb9d125.33826","740a74e2.9c761c"]]},{"id":"c2c874bd.a96468","type":"join-wait","z":"1cc55bbe.9f4cd4","name":"","paths":"[\"event_1A\", \"event_1B\"]","pathsToExpire":"","ignoreUnmatched":false,"pathTopic":"name","pathTopicType":"msg","correlationTopic":"","correlationTopicType":"msg","timeout":"10","timeoutUnits":"1000","exactOrder":"true","firstMsg":"true","mapPayload":"true","disableComplete":false,"x":820,"y":600,"wires":[["1b4b893c.2987a7"],["6adcdcde.84df34"]]},{"id":"49734310.67eb8c","type":"change","z":"1cc55bbe.9f4cd4","name":"Set event_1A","rules":[{"t":"set","p":"name","pt":"msg","to":"event_1A","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":600,"wires":[["c2c874bd.a96468"]]},{"id":"fb85239f.3a70c","type":"change","z":"1cc55bbe.9f4cd4","name":"Set event_1B","rules":[{"t":"set","p":"name","pt":"msg","to":"event_1B","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":660,"wires":[["c2c874bd.a96468"]]},{"id":"1b4b893c.2987a7","type":"debug","z":"1cc55bbe.9f4cd4","name":"Success","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1060,"y":580,"wires":[]},{"id":"6adcdcde.84df34","type":"debug","z":"1cc55bbe.9f4cd4","name":"Expired","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","x":1060,"y":640,"wires":[]},{"id":"6121961b.964748","type":"delay","z":"1cc55bbe.9f4cd4","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":400,"y":600,"wires":[["49734310.67eb8c"]]},{"id":"4d403e03.16926","type":"delay","z":"1cc55bbe.9f4cd4","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":400,"y":680,"wires":[["fb85239f.3a70c"]]},{"id":"5e3a1179.8b5bc","type":"delay","z":"1cc55bbe.9f4cd4","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":400,"y":720,"wires":[["fb85239f.3a70c"]]},{"id":"8bb9d125.33826","type":"delay","z":"1cc55bbe.9f4cd4","name":"","pauseType":"delay","timeout":"4","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":400,"y":640,"wires":[["49734310.67eb8c"]]},{"id":"740a74e2.9c761c","type":"delay","z":"1cc55bbe.9f4cd4","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":400,"y":760,"wires":[["fb85239f.3a70c"]]}]

When one msg timeouts, all the messages go to the 'expired' output

How is it supposed to work? I have a simplest setup and it does not work as if: when the delayed message expires, both messages go to the "expired" output.

image

[{"id":"34367e56.7509c2","type":"join-wait","z":"cf34b7cb.9183b8","name":"","paths":"[\"path_1\", \"path_2\"]","pathsToExpire":"","ignoreUnmatched":false,"pathTopic":"paths","pathTopicType":"msg","correlationTopic":"_msgid","correlationTopicType":"msg","timeout":"3000","timeoutUnits":1,"exactOrder":"false","firstMsg":"true","mapPayload":"true","disableComplete":false,"x":600,"y":220,"wires":[["dbb5dc6f.0524"],["2c925d4f.8f424a"]]},{"id":"35386928.fb21de","type":"inject","z":"cf34b7cb.9183b8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":240,"wires":[["1c9f51ea.ab8536","d584d77b.bb42e8"]]},{"id":"1c9f51ea.ab8536","type":"change","z":"cf34b7cb.9183b8","name":"v1","rules":[{"t":"set","p":"paths","pt":"msg","to":"path_1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":290,"y":220,"wires":[["34367e56.7509c2"]]},{"id":"9363809b.0165f8","type":"change","z":"cf34b7cb.9183b8","name":"v2","rules":[{"t":"set","p":"paths","pt":"msg","to":"path_2","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":300,"wires":[["34367e56.7509c2"]]},{"id":"dbb5dc6f.0524","type":"debug","z":"cf34b7cb.9183b8","name":"on_time","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"paths","targetType":"msg","statusVal":"","statusType":"auto","x":800,"y":160,"wires":[]},{"id":"2c925d4f.8f424a","type":"debug","z":"cf34b7cb.9183b8","name":"expired","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"paths","targetType":"msg","statusVal":"","statusType":"auto","x":800,"y":280,"wires":[]},{"id":"d584d77b.bb42e8","type":"delay","z":"cf34b7cb.9183b8","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":300,"y":300,"wires":[["9363809b.0165f8"]]}]

Feature request: combine all input messages

First off: thanks for this node. I saw your discussion on the node-red forum and I think you're right. This should be a standard node.

I think this node could solve even more problems if there were an option to combine all incoming messages and send the resulting object out when all paths are received.

Say I have { 'topic': 'weight', 'weight':80 } and {'topic': 'impodence', 'impodence': 500}. The join-wait node waits for ['weight', 'impodence'] paths. When both messages are received, the output would be { 'topic': 'impodence', 'weight': 80, 'impodence': 500 }. Notice the topic could come from the first or the last message, depending on the already existing configuration.

Expire earlier for 'any order'

Consider the case for waitPath: ["p1", "p1", "p2", "p2"] in any order.

If ["p1", "p1", "p1"] is received, the first "p1" could be expired.

This gets more complicated in scenarios like:
waitPath: ["p1", "p1", "p2", "p2", "p3"] (any order)

["p3", "p2", "p1", "p2", "p2"] is received, because in this case, we shouldn't expire the "p3" because if the next rec'd item is "p1" it would satisfy the conditions.

Support for duplicate paths

Based on #1, add support for duplicate paths. E.g. ["1", "1", "2"]. Or, ["1", "2", "3", "2"].

Need to think through how to manage this very carefully/thoroughly since intermediate paths can become quite tricky. For example, how should ["1", "2", "1", "3", "2"] be handled.

Missing option: "And After Every Subsequent"

Hi, just stumbled upon your node. Looks great at first glance, but I'm missing the option "And After Every Subsequent" available in node-red's core join node.

Here's my use case:
I store options for several flows in MQTT. Let's say I have a custom timer with the options name and active.
The topic looks like timer/timername/optionname, so 2 different timers have these 4 topics:

  • timer/timer1/name
  • timer/timer1/active
  • timer/timer2/name
  • timer/timer2/active

To be able to initialize a timer, I need all options from that timer together, so I use a join-wait node with Paths (wait) set to:
["^timer/[^/]+/name$", "^timer/[^/]+/active$"]
Furthermore I need to tell the node that messages with the same timername belongs together. So I set Correlation topic to:
$split( msg.topic, '/' )[1]
This works great, but when the timer is now turned on/off, only the timer/timername/active topic is triggered again and the join-wait node runs into timeout.
Any idea how to achieve this with your node?

One other (related) thing:
Let's imagine this incoming message order:

timer/timer1/active = false
timer/timer1/active = true
timer/timer1/name = "working day"

After the third message arrives (within timeout), this object will be send to success output as expected:
{ "timer/timer1/active": true, "timer/timer1/name": "working day" }
However, immediately after the second message arrives, the expired output is triggered with the value from the first message (false). The object of that message has the same format as a timeout message, so I see no way to determine if the message is a timeout message (=> error) or a duplicate message (=> conventional).
I suggest to either provide a way to turn the duplicate messages of (favored) ot at least to make them distinguishable by adding some kind of "type" property.

Cheers
Putzeimer

Example flow:
[
    {
        "id": "51b4898c1305055e",
        "type": "join-wait",
        "z": "a2b23fab59d842d2",
        "name": "",
        "paths": "[\"^timer/[^/]+/name$\", \"^timer/[^/]+/active$\"]",
        "pathsToExpire": "",
        "useRegex": true,
        "warnUnmatched": false,
        "pathTopic": "topic",
        "pathTopicType": "msg",
        "correlationTopic": "$split( msg.topic, '/' )[1]",
        "correlationTopicType": "jsonata",
        "timeout": "5",
        "timeoutUnits": "1000",
        "exactOrder": "false",
        "firstMsg": "true",
        "mapPayload": "true",
        "disableComplete": false,
        "persistOnRestart": false,
        "x": 1200,
        "y": 1140,
        "wires": [
            [
                "e2e43594f7036dfc"
            ],
            [
                "2e213fc0dc7dd1d1"
            ]
        ]
    },
    {
        "id": "3d1e6f711c80c2f1",
        "type": "inject",
        "z": "a2b23fab59d842d2",
        "name": "",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            },
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "timer/timer1/name",
        "payload": "working day",
        "payloadType": "str",
        "x": 950,
        "y": 1020,
        "wires": [
            [
                "51b4898c1305055e"
            ]
        ]
    },
    {
        "id": "ece7ee6536a75c1f",
        "type": "inject",
        "z": "a2b23fab59d842d2",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "timer/timer1/active",
        "payload": "true",
        "payloadType": "bool",
        "x": 920,
        "y": 1060,
        "wires": [
            [
                "51b4898c1305055e"
            ]
        ]
    },
    {
        "id": "a6ebf4bc12dfde68",
        "type": "inject",
        "z": "a2b23fab59d842d2",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "timer/timer1/active",
        "payload": "false",
        "payloadType": "bool",
        "x": 920,
        "y": 1100,
        "wires": [
            [
                "51b4898c1305055e"
            ]
        ]
    },
    {
        "id": "4604c00887309857",
        "type": "inject",
        "z": "a2b23fab59d842d2",
        "name": "",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            },
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "timer/timer2/name",
        "payload": "weekend",
        "payloadType": "str",
        "x": 940,
        "y": 1180,
        "wires": [
            [
                "51b4898c1305055e"
            ]
        ]
    },
    {
        "id": "37811ebd3d10abb4",
        "type": "inject",
        "z": "a2b23fab59d842d2",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "timer/timer2/active",
        "payload": "true",
        "payloadType": "bool",
        "x": 920,
        "y": 1220,
        "wires": [
            [
                "51b4898c1305055e"
            ]
        ]
    },
    {
        "id": "640ef0c3dd44399d",
        "type": "inject",
        "z": "a2b23fab59d842d2",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "timer/timer2/active",
        "payload": "false",
        "payloadType": "bool",
        "x": 920,
        "y": 1260,
        "wires": [
            [
                "51b4898c1305055e"
            ]
        ]
    },
    {
        "id": "e2e43594f7036dfc",
        "type": "debug",
        "z": "a2b23fab59d842d2",
        "name": "success",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1380,
        "y": 1120,
        "wires": []
    },
    {
        "id": "2e213fc0dc7dd1d1",
        "type": "debug",
        "z": "a2b23fab59d842d2",
        "name": "expired",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1380,
        "y": 1160,
        "wires": []
    }
]

feature request: retain state after restart

First, this node is great and Iโ€™ve been using it a bunch in my home automation projects.

With my use case I have several timeouts that are hours long while it waits for a second event. If I am futzing with node red (as I tend to be) and restart the instance I will lose my waits. Iโ€™d love to have it pick back up where it left off upon reboot.

the stoptimer-varidelay node has a useful interface for this feature.
https://flows.nodered.org/node/node-red-contrib-stoptimer-varidelay

thanks for considering!

So smart

This package is soooo smart and simple at the same time . Thanks a lot ! @dxdc

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.