-
-
Notifications
You must be signed in to change notification settings - Fork 103
'Wait for trigger'-like node #335
Replies: 1 comment · 10 replies
-
You did all the hard work not just move it into a subflow and you're set. But yes seems like a good addition. |
Beta Was this translation helpful? Give feedback.
All reactions
-
Added the per message timeout capability. Pretty simple actually, just forks the input send the same message into the function node and a delay node. When the message comes out of the delay node it looks for a message with the same [{"id":"4d396c71.b4f074","type":"subflow","name":"","info":"","category":"","in":[{"x":148,"y":136,"wires":[{"id":"db7c1a8a.a4c848"},{"id":"d61f373.c59fb48"}]}],"out":[{"x":740,"y":100,"wires":[{"id":"db7c1a8a.a4c848","port":0}]},{"x":740,"y":160,"wires":[{"id":"db7c1a8a.a4c848","port":1}]}],"env":[{"name":"event","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"store","type":"str","value":"all","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"all messages"},"v":"all"},{"l":{"en-US":"first message"},"v":"first"},{"l":{"en-US":"last message"},"v":"last"}]}}},{"name":"property","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"coniditonal","type":"str","value":"is","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"is"},"v":"is"},{"l":{"en-US":"is not"},"v":"is not"},{"l":{"en-US":"<"},"v":"lt"},{"l":{"en-US":">"},"v":"gt"},{"l":{"en-US":"<="},"v":"lte"},{"l":{"en-US":">="},"v":"gte"}]}}},{"name":"value","type":"str","value":"","ui":{"type":"input","opts":{"types":["str","num","bool","json"]}}},{"name":"timeout","type":"num","value":"","ui":{"label":{"en-US":"Timeout (seconds)"},"type":"input","opts":{"types":["num","env"]}}}],"color":"#DDAA99","outputLabels":["triggered","timeout"],"status":{"x":384,"y":232,"wires":[{"id":"ffd3933d.17153","port":0}]}},{"id":"304357a7.cbefd","type":"server-events","z":"4d396c71.b4f074","name":"","server":"cc03735a.94933","event_type":"${event}","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":true,"x":260,"y":180,"wires":[["429a750.65ff88c"]]},{"id":"429a750.65ff88c","type":"change","z":"4d396c71.b4f074","name":"Set flush","rules":[{"t":"set","p":"flush","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":430,"y":180,"wires":[["db7c1a8a.a4c848"]]},{"id":"db7c1a8a.a4c848","type":"function","z":"4d396c71.b4f074","name":"","func":"let messages = context.get(\"messages\") || [];\n\nif(msg.flush === true) {\n const data = msg.payload.event;\n const property = env.get(\"property\");\n const conditional = env.get(\"conditional\");\n const value = env.get(\"value\");\n \n if(property.length) {\n const p = getProperty(property, data);\n if(!p || !isConditionValid(conditional, p, value)) {\n return;\n }\n }\n \n context.set(\"messages\", null);\n node.status({text: \"flushed\"});\n return [messages, null];\n}\n\nif(msg.timeout === true) {\n let id = msg._msgid;\n for(let i in messages){\n let message = messages[i];\n if(id === message._msgid){\n return [null, messages.splice(i, 1)];\n }\n }\n}\n\nconst store = env.get(\"store\");\nif(store === \"first\" && messages.length === 0) {\n messages = [msg];\n} else if (store === 'last') {\n messages = [msg];\n} else {\n messages = [...messages, msg];\n}\n\nnode.status({text: messages.length});\ncontext.set(\"messages\", messages);\n\nfunction getProperty(property, data) {\n const keys = property.replace(/\\[([\"'])(\\w+)\\1\\]/g, '.$2').replace(/^\\./, '').split('.');\n for (let i = 0, n = keys.length; i < n; ++i) {\n const k = keys[i];\n if (k in data) {\n data = data[k];\n } else {\n return;\n }\n }\n return data;\n}\nfunction isConditionValid(conditional, val1, val2) {\n switch(conditional) {\n case \"isnot\":\n return val1 != val2;\n case \"lt\":\n return val1 < val2;\n case \"gt\":\n return val1 > val2;\n case \"lte\":\n return val1 <= val2;\n case \"gte\":\n return val1 >= val2;\n case \"is\":\n default:\n return val1 == val2;\n }\n}","outputs":2,"noerr":0,"initialize":"","finalize":"","x":568,"y":136,"wires":[[],[]]},{"id":"ffd3933d.17153","type":"status","z":"4d396c71.b4f074","name":"","scope":["db7c1a8a.a4c848"],"x":248,"y":232,"wires":[[]]},{"id":"d61f373.c59fb48","type":"delay","z":"4d396c71.b4f074","name":"Timeout","pauseType":"delay","timeout":"${timeout}","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":280,"y":100,"wires":[["fe74a7f2.91e298"]]},{"id":"fe74a7f2.91e298","type":"change","z":"4d396c71.b4f074","name":"Timeout","rules":[{"t":"set","p":"timeout","pt":"msg","to":"true","tot":"bool"},{"t":"delete","p":"flush","pt":"msg"},{"t":"delete","p":"reset","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":100,"wires":[["db7c1a8a.a4c848"]]},{"id":"cbe06712.0b862","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"b","payloadType":"str","x":1510,"y":280,"wires":[["fad0180c.f71308"]]},{"id":"6df64c6a.c62d64","type":"debug","z":"dc93c609.7a6e5","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1950,"y":240,"wires":[]},{"id":"f662c516.342ba","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1520,"y":360,"wires":[["619a2628.12c0a8"]]},{"id":"619a2628.12c0a8","type":"ha-fire-event","z":"dc93c609.7a6e5","name":"fire my_test_event","server":"cc03735a.94933","event":"my_test_event","data":"","dataType":"json","x":1694,"y":360,"wires":[[]]},{"id":"fad0180c.f71308","type":"subflow:4d396c71.b4f074","z":"dc93c609.7a6e5","name":"","env":[{"name":"event","value":"my_test_event","type":"str"},{"name":"property","value":"test.abc","type":"str"},{"name":"value","value":"123","type":"num"},{"name":"timeout","value":"5","type":"num"}],"x":1714,"y":280,"wires":[["6df64c6a.c62d64"],["f1956950.f67728"]]},{"id":"720bd362.94919c","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"a","payloadType":"str","x":1510,"y":248,"wires":[["fad0180c.f71308"]]},{"id":"362c48a2.ceff08","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"c","payloadType":"str","x":1510,"y":312,"wires":[["fad0180c.f71308"]]},{"id":"44516250.2b330c","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1520,"y":408,"wires":[["50254bca.eb6494"]]},{"id":"50254bca.eb6494","type":"ha-fire-event","z":"dc93c609.7a6e5","name":"fire my_test_event with data","server":"cc03735a.94933","event":"my_test_event","data":"{\"test\": {\"abc\": 123}}","dataType":"json","x":1724,"y":408,"wires":[[]]},{"id":"f1956950.f67728","type":"debug","z":"dc93c609.7a6e5","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1950,"y":300,"wires":[]},{"id":"cc03735a.94933","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}] Man this is great, there's so many places I can use this. Thanks for your help @zachowj ! |
Beta Was this translation helpful? Give feedback.
All reactions
-
Added JSON matching just to finish it out. If you provide JSON in the [{"id":"4d396c71.b4f074","type":"subflow","name":"Wait for event","info":"Messages wait for an event of type `event` to be received before being allowed to proceed. Can choose whether to queue all received messages or just the first or last.\n\nEvents received can filtered further in two ways:\n * Provide a conditional to evaluate against event data in the form of `<property>` `<conditional>` `<value>`. Property can be a nested reference\n * Provide a JSON object in `value` to compare against the event data. Filter will pass the JSON is a subset of the event data (same value in all fields)\n\nA `timeout` can be provided in seconds limiting how long each message can wait in the queue. Timeout is missing or not greater then 0 then messages queue indefinitely. Timed out messages go to the second output.","category":"","in":[{"x":148,"y":136,"wires":[{"id":"46ef85e4.6c860c"},{"id":"3302b6fe.b663da"}]}],"out":[{"x":840,"y":100,"wires":[{"id":"db7c1a8a.a4c848","port":0}]},{"x":840,"y":160,"wires":[{"id":"db7c1a8a.a4c848","port":1}]}],"env":[{"name":"event","type":"str","value":"","ui":{"label":{"en-US":"Event type"},"type":"input","opts":{"types":["str"]}}},{"name":"store","type":"str","value":"all","ui":{"label":{"en-US":"Store"},"type":"select","opts":{"opts":[{"l":{"en-US":"all messages"},"v":"all"},{"l":{"en-US":"first message"},"v":"first"},{"l":{"en-US":"last message"},"v":"last"}]}}},{"name":"property","type":"str","value":"","ui":{"label":{"en-US":"Property"},"type":"input","opts":{"types":["str"]}}},{"name":"conditional","type":"str","value":"is","ui":{"label":{"en-US":"Conditional"},"type":"select","opts":{"opts":[{"l":{"en-US":"is"},"v":"is"},{"l":{"en-US":"is not"},"v":"is not"},{"l":{"en-US":"<"},"v":"lt"},{"l":{"en-US":">"},"v":"gt"},{"l":{"en-US":"<="},"v":"lte"},{"l":{"en-US":">="},"v":"gte"}]}}},{"name":"value","type":"str","value":"","ui":{"label":{"en-US":"Value"},"type":"input","opts":{"types":["str","num","bool","json"]}}},{"name":"timeout","type":"num","value":"","ui":{"label":{"en-US":"Timeout (seconds)"},"type":"input","opts":{"types":["num","env"]}}}],"color":"#DDAA99","outputLabels":["triggered","timeout"],"status":{"x":384,"y":252,"wires":[{"id":"ffd3933d.17153","port":0}]}},{"id":"304357a7.cbefd","type":"server-events","z":"4d396c71.b4f074","name":"","server":"cc03735a.94933","event_type":"${event}","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":true,"x":260,"y":200,"wires":[["3cca7dba.9babea"]]},{"id":"db7c1a8a.a4c848","type":"function","z":"4d396c71.b4f074","name":"Queue","func":"let messages = context.get(\"messages\") || [];\n\nif(msg.hasOwnProperty(\"flush\")) {\n context.set(\"messages\", null);\n node.status({text: \"flushed\"});\n return [messages, null];\n}\n\nif(msg.hasOwnProperty(\"reset\")){\n context.set(\"messages\", null);\n node.status({text: \"reset\"});\n return null;\n}\n\nif(msg.timeout === true) {\n let id = msg._msgid;\n for(let i in messages){\n let message = messages[i];\n if(id === message._msgid){\n if(messages.length - 1 > 0){\n node.status({\n fill:\"blue\",shape:\"dot\",\n text: messages.length - 1\n });\n }\n else{\n node.status({});\n }\n return [null, messages.splice(i, 1)];\n }\n }\n}\n\nconst store = env.get(\"store\");\nif(store === \"first\" && messages.length === 0) {\n messages = [msg];\n} else if (store === 'last') {\n messages = [msg];\n} else {\n messages = [...messages, msg];\n}\n\nnode.status({\n fill:\"blue\",shape:\"dot\",\n text: messages.length\n});\ncontext.set(\"messages\", messages);","outputs":2,"noerr":0,"initialize":"","finalize":"","x":658,"y":136,"wires":[[],[]]},{"id":"ffd3933d.17153","type":"status","z":"4d396c71.b4f074","name":"","scope":["db7c1a8a.a4c848"],"x":248,"y":252,"wires":[[]]},{"id":"d61f373.c59fb48","type":"delay","z":"4d396c71.b4f074","name":"Timeout","pauseType":"delay","timeout":"${timeout}","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":375,"y":100,"wires":[["fe74a7f2.91e298"]],"l":false},{"id":"fe74a7f2.91e298","type":"change","z":"4d396c71.b4f074","name":"Set timeout","rules":[{"t":"set","p":"timeout","pt":"msg","to":"true","tot":"bool"},{"t":"delete","p":"flush","pt":"msg"},{"t":"delete","p":"reset","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":100,"wires":[["db7c1a8a.a4c848"]]},{"id":"46ef85e4.6c860c","type":"switch","z":"4d396c71.b4f074","name":"Timeout >0","property":"timeout","propertyType":"env","rules":[{"t":"gt","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":270,"y":100,"wires":[["d61f373.c59fb48"]]},{"id":"3cca7dba.9babea","type":"function","z":"4d396c71.b4f074","name":"Filter","func":"const data = msg.payload.event;\nconst property = env.get(\"property\");\nconst conditional = env.get(\"conditional\");\nconst value = env.get(\"value\");\n\n\nif(property.length){\n const p = getProperty(property, data);\n if(!p || !isConditionValid(conditional, p, value)) {\n return;\n }\n}\nelse if(typeof value == 'object'){\n if(!objectComparison(value, data)){\n return;\n }\n}\n\nreturn {\"flush\": true};\n\n\nfunction objectComparison(comparatorObj, targetObj){\n for(let key in comparatorObj){\n if (key === '_msgid'){ continue; }\n \n let field = comparatorObj[key];\n let targetField = targetObj[key];\n \n if (typeof field == 'object' && \n !(typeof targetField == 'object' && objectComparison(field, targetField)))\n {\n return false;\n }\n else if (typeof field != 'object' && field !== targetField){\n return false;\n }\n }\n return true;\n}\n\nfunction getProperty(property, data) {\n const keys = property.replace(/\\[([\"'])(\\w+)\\1\\]/g, '.$2').replace(/^\\./, '').split('.');\n for (let i = 0, n = keys.length; i < n; ++i) {\n const k = keys[i];\n if (k in data) {\n data = data[k];\n } else {\n return;\n }\n }\n return data;\n}\nfunction isConditionValid(conditional, val1, val2) {\n switch(conditional) {\n case \"isnot\":\n return val1 != val2;\n case \"lt\":\n return val1 < val2;\n case \"gt\":\n return val1 > val2;\n case \"lte\":\n return val1 <= val2;\n case \"gte\":\n return val1 >= val2;\n case \"is\":\n default:\n return val1 == val2;\n }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":430,"y":200,"wires":[["db7c1a8a.a4c848"]]},{"id":"3302b6fe.b663da","type":"change","z":"4d396c71.b4f074","name":"No timeout","rules":[{"t":"delete","p":"timeout","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":270,"y":140,"wires":[["db7c1a8a.a4c848"]]},{"id":"cbe06712.0b862","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"b","payloadType":"str","x":1510,"y":280,"wires":[["fad0180c.f71308"]]},{"id":"6df64c6a.c62d64","type":"debug","z":"dc93c609.7a6e5","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1950,"y":240,"wires":[]},{"id":"f662c516.342ba","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1520,"y":360,"wires":[["619a2628.12c0a8"]]},{"id":"619a2628.12c0a8","type":"ha-fire-event","z":"dc93c609.7a6e5","name":"fire my_test_event","server":"cc03735a.94933","event":"my_test_event","data":"{\"test\": \"no\"}","dataType":"json","x":1694,"y":360,"wires":[[]]},{"id":"fad0180c.f71308","type":"subflow:4d396c71.b4f074","z":"dc93c609.7a6e5","name":"","env":[{"name":"event","value":"my_test_event","type":"str"},{"name":"value","value":"{\"test\":{\"abc\":[123, 456]}}","type":"json"},{"name":"timeout","value":"5","type":"num"}],"x":1684,"y":280,"wires":[["6df64c6a.c62d64"],["f1956950.f67728"]]},{"id":"720bd362.94919c","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"a","payloadType":"str","x":1510,"y":248,"wires":[["fad0180c.f71308"]]},{"id":"362c48a2.ceff08","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"c","payloadType":"str","x":1510,"y":312,"wires":[["fad0180c.f71308"]]},{"id":"44516250.2b330c","type":"inject","z":"dc93c609.7a6e5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1520,"y":408,"wires":[["50254bca.eb6494"]]},{"id":"50254bca.eb6494","type":"ha-fire-event","z":"dc93c609.7a6e5","name":"fire my_test_event with data","server":"cc03735a.94933","event":"my_test_event","data":"{\"test\": {\"abc\": [123, 456]}}","dataType":"json","x":1724,"y":408,"wires":[[]]},{"id":"f1956950.f67728","type":"debug","z":"dc93c609.7a6e5","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1950,"y":300,"wires":[]},{"id":"cc03735a.94933","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}] |
Beta Was this translation helpful? Give feedback.
All reactions
-
Here is my version 3 that I forgot to post based on your previous one. It's not really tested
edit: when using a timeout and only saving the first or last message, definitely needs a fix |
Beta Was this translation helpful? Give feedback.
All reactions
-
v3.1
|
Beta Was this translation helpful? Give feedback.
All reactions
-
So I noticed in your In addition to that change I added a few more comparator options ( I haven't tested everything yet but I tested all the different options individually so I feel pretty good about it. Going to start replacing some unnecessary complexity out of my flows with these. [{"id":"34f5b813.356ad8","type":"subflow","name":"Wait for state","info":"Messages are either allowed through or blocked based on whether the state of the entity specified by `entity_id` is in `states`. `states` can be one value or multiple comma-separated values.\n\nCan also provide a more complex conditional on state by providing a conditional of the form `<property>``<conditional>``<value`. This conditional will be run against the `data` field of the output of an `events: state` node and messages will only be allowed if it also evaluates to true.\n\nLike a `traffic` node you can choose whether to `store unsent` messages when the entity is not in the correct state and or drop any blocked messages. If `store unsent` is `true` then a `timeout` can be provided in seconds limiting how long each message can wait in the queue. Timed out messages are released to the second output. If `timeout` is 0 then messages queue indefinitely.\n\nIf using Node RED > 0.19, gate state can be saved to a [context store](https://nodered.org/docs/api/context/) besides the default if you would like it to persist over restarts. To use this, specify a value for `gate context store`. Will use the default if left blank.","category":"","in":[{"x":60,"y":80,"wires":[{"id":"c4c7268f.c54a88"}]}],"out":[{"x":660,"y":40,"wires":[{"id":"c4c7268f.c54a88","port":0}]},{"x":660,"y":100,"wires":[{"id":"c4c7268f.c54a88","port":1}]}],"env":[{"name":"entity_id","type":"str","value":"","ui":{"label":{"en-US":"Entity"},"type":"input","opts":{"types":["str","env"]}}},{"name":"states","type":"str","value":"","ui":{"label":{"en-US":"States (comma-separated)"},"type":"input","opts":{"types":["str","env"]}}},{"name":"property","type":"str","value":"","ui":{"label":{"en-US":"Property"},"type":"input","opts":{"types":["str","env"]}}},{"name":"conditional","type":"str","value":"none","ui":{"label":{"en-US":"Conditional"},"type":"select","opts":{"opts":[{"l":{"en-US":"none"},"v":"none"},{"l":{"en-US":"=="},"v":"eq"},{"l":{"en-US":"!="},"v":"neq"},{"l":{"en-US":"<"},"v":"lt"},{"l":{"en-US":">"},"v":"gt"},{"l":{"en-US":"<="},"v":"lte"},{"l":{"en-US":">="},"v":"gte"},{"l":{"en-US":"in"},"v":"in"},{"l":{"en-US":"not in"},"v":"nin"},{"l":{"en-US":"matches"},"v":"matches"},{"l":{"en-US":"not matches"},"v":"nmatches"},{"l":{"en-US":"compare state data to value"},"v":"compareObjects"}]}}},{"name":"value","type":"str","value":"","ui":{"label":{"en-US":"Value"}}},{"name":"timeout","type":"num","value":"0","ui":{"label":{"en-US":"Timeout (seconds)"},"type":"input","opts":{"types":["num","env"]}}},{"name":"gate_context_store","type":"str","value":"","ui":{"label":{"en-US":"Gate context store"},"type":"input","opts":{"types":["str","env"]}}},{"name":"state_must_change","type":"bool","value":"true","ui":{"label":{"en-US":"Ignore events if current state = previous state"},"type":"checkbox"}},{"name":"store_unsent","type":"bool","value":"true","ui":{"label":{"en-US":"Store unsent"},"type":"checkbox"}}],"color":"#DDAA99","outputLabels":["Released","Timed out"],"status":{"x":660,"y":160,"wires":[{"id":"db12ffbf.e81e28","port":0}]}},{"id":"db12ffbf.e81e28","type":"status","z":"34f5b813.356ad8","name":"","scope":["c4c7268f.c54a88"],"x":520,"y":160,"wires":[[]]},{"id":"a4f2a060.d641d8","type":"subflow:fdf07536.0c98e","z":"34f5b813.356ad8","name":"","env":[{"name":"property","value":"property","type":"env"},{"name":"conditional","value":"conditional","type":"env"},{"name":"value","value":"value","type":"env"},{"name":"pass_msg","value":"{\"_gate_open\":true}","type":"json"},{"name":"fail_msg","value":"{\"_gate_open\":false}","type":"json"},{"name":"property_context","value":"data.event","type":"str"}],"x":330,"y":140,"wires":[["c4c7268f.c54a88"],["c4c7268f.c54a88"]]},{"id":"c4c7268f.c54a88","type":"function","z":"34f5b813.356ad8","name":"Traffic","func":"let messages = context.get(\"messages\") || [];\nconst timeoutIds = context.get(\"timeoutIds\") || [];\nconst timeout = env.get(\"timeout\") || 0;\nconst gate_store = env.get(\"gate_context_store\") || undefined;\n\nif(msg._gate_open === true) {\n clearTimeouts();\n context.set(\"messages\", null);\n context.set(\"timeoutIds\", null);\n flow.set(\"gate_open\", true, gate_store);\n node.status({fill:\"green\",shape:\"dot\",text: \"open\"});\n return [messages, null];\n}\n\nif(msg._gate_open === false){\n flow.set(\"gate_open\", false, gate_store);\n node.status({fill:\"red\",shape:\"dot\",text:messages.length || 'closed'});\n return;\n}\n\nif(flow.get(\"gate_open\", gate_store)){\n return [msg, null];\n}\n\nif(env.get(\"store_unsent\")){\n messages = [...messages, msg];\n \n if(timeout) {\n const timeoutId = setTimeout(() => {\n removeMessage(msg._msgid);\n }, timeout * 1000);\n timeoutIds.push(timeoutId);\n context.set(\"timeoutIds\", timeoutIds); \n }\n \n node.status({fill:\"red\",shape:\"dot\",text:messages.length});\n context.set(\"messages\", messages);\n}\n\nfunction clearTimeouts() {\n timeoutIds.forEach(id => clearTimeout(id));\n}\n\nfunction removeMessage(id) {\n const msgs = context.get(\"messages\");\n const index = msgs.findIndex(m => m._msgid = id);\n if(index !== -1){\n node.send([null, msgs.splice(index, 1)]);\n context.set(\"messages\", msgs);\n node.status({fill:\"red\",shape:\"dot\",text: msgs.length || 'closed'});\n }\n}","outputs":2,"noerr":0,"initialize":"","finalize":"","x":530,"y":80,"wires":[[],[]],"outputLabels":["triggered","timed out"]},{"id":"f425f356.9fb5c","type":"change","z":"34f5b813.356ad8","name":"Close gate","rules":[{"t":"set","p":"_gate_open","pt":"msg","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":180,"wires":[["c4c7268f.c54a88"]]},{"id":"de30f988.4a27f","type":"trigger-state","z":"34f5b813.356ad8","name":"${entity_id} changed","server":"cc03735a.94933","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"${entity_id}","entityidfiltertype":"exact","debugenabled":false,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"current_state","comparatorType":"is_not","comparatorValueDatatype":"jsonata","comparatorValue":"$env(\"state_must_change\") ? $prevEntity().state : {} ","propertyValue":"new_state.state"}],"outputs":4,"customoutputs":[{"messageType":"default","messageValue":"","messageValueType":"json","comparatorPropertyType":"current_state","comparatorType":"includes","comparatorValue":"${states}","comparatorValueDataType":"list","comparatorPropertyValue":"new_state.state"},{"messageType":"default","messageValue":"","messageValueType":"json","comparatorPropertyType":"current_state","comparatorType":"does_not_include","comparatorValue":"${states}","comparatorValueDataType":"list","comparatorPropertyValue":"new_state.state"}],"outputinitially":false,"state_type":"str","x":120,"y":160,"wires":[[],[],["a4f2a060.d641d8"],["f425f356.9fb5c"]],"outputLabels":["","","In states","Not in states"]},{"id":"fdf07536.0c98e","type":"subflow","name":"Apply filter","info":"Messages received can filtered in two ways:\n * Provide a conditional to evaluate against event data in the form of `<property>` `<comparator>` `<value>`. Property can be a nested reference\n * Provide a JSON object in `value` to compare against the event data. Filter will pass the JSON is a subset of the event data (same value in all fields)\n\nIf the filter passes, `pass message` (or original message if not provided) will be sent to the first output. If the filter fails then `fail message` (or original message) will be sent to the second output.\n\nIf the comparison is to be run within a specific context within the message, provide a field within the message to start from to `property context`.","category":"","in":[{"x":60,"y":60,"wires":[{"id":"a1ccfe22.9d6ac"}]}],"out":[{"x":320,"y":40,"wires":[{"id":"a1ccfe22.9d6ac","port":0}]},{"x":320,"y":100,"wires":[{"id":"a1ccfe22.9d6ac","port":1}]}],"env":[{"name":"property","type":"str","value":"","ui":{"label":{"en-US":"Property"},"type":"input","opts":{"types":["str","env"]}}},{"name":"conditional","type":"str","value":"none","ui":{"label":{"en-US":"Conditional"},"type":"input","opts":{"types":["str","env"]}}},{"name":"value","type":"str","value":"","ui":{"label":{"en-US":"Value"}}},{"name":"pass_msg","type":"json","value":"null","ui":{"label":{"en-US":"Pass message"},"type":"input","opts":{"types":["json","env"]}}},{"name":"fail_msg","type":"json","value":"null","ui":{"label":{"en-US":"Fail message"},"type":"input","opts":{"types":["json","env"]}}},{"name":"property_context","type":"str","value":"","ui":{"label":{"en-US":"Property context"},"type":"input","opts":{"types":["str","env"]}}}],"color":"#DDAA99","outputLabels":["Passed","Failed"],"status":{"x":240,"y":160,"wires":[{"id":"16403a10.0dd41e","port":0}]}},{"id":"a1ccfe22.9d6ac","type":"function","z":"fdf07536.0c98e","name":"Filter","func":"const property_context = env.get(\"property_context\");\nconst data = property_context.length ? getProperty(property_context, msg) : msg;\nconst property = env.get(\"property\");\nconst conditional = env.get(\"conditional\");\nconst value = env.get(\"value\");\nconst pass_msg = env.get(\"pass_msg\") || msg;\nconst fail_msg = env.get(\"fail_msg\") || msg;\n\n\nif(conditional !== 'none'){\n const p = property.length ? getProperty(property, data) : data;\n if(!p || !isConditionValid(conditional, p, value)) {\n node.status({fill:\"red\",shape:\"dot\",text:\"failed\"});\n return [null, fail_msg];\n }\n}\n\nnode.status({fill:\"green\",shape:\"dot\",text:\"passed\"});\nreturn [pass_msg, null];\n\nfunction getProperty(property, data) {\n const keys = property.replace(/\\[([\"'])(\\w+)\\1\\]/g, '.$2').replace(/^\\./, '').split('.');\n for (let i = 0, n = keys.length; i < n; ++i) {\n const k = keys[i];\n if (k in data) {\n data = data[k];\n } else {\n return;\n }\n }\n return data;\n}\nfunction isConditionValid(conditional, left, right) {\n switch(conditional) {\n case \"compareObjects\":\n return compareObjects(left, right);\n case \"neq\":\n return left !== right;\n case \"lt\":\n return left < right;\n case \"gt\":\n return left > right;\n case \"lte\":\n return left <= right;\n case \"gte\":\n return left >= right;\n case \"in\":\n return right.split(/\\s*,\\s*/).includes(left);\n case \"nin\":\n return !right.split(/\\s*,\\s*/).includes(left);\n case \"matches\":\n return left.match(right);\n case \"nmatches\":\n return !left.match(right);\n case \"eq\":\n default:\n return left === right;\n }\n}\n\nfunction compareObjects(whole, subset) {\n if (whole === subset) return true;\n\n if (typeof whole != 'object' || typeof subset != 'object' || whole == null || subset == null) return false;\n\n const keysWhole = Object.keys(whole);\n const keysSubset = Object.keys(subset);\n\n if (keysWhole.length < keysSubset.length) return false;\n\n for (let key of keysSubset) {\n if(key === '_msgid') continue;\n \n if (!keysWhole.includes(key)) return false;\n\n if (!compareObjects(whole[key], subset[key])) return false;\n }\n\n return true;\n}","outputs":2,"noerr":0,"initialize":"","finalize":"","x":170,"y":60,"wires":[[],[]],"outputLabels":["passed","failed"]},{"id":"16403a10.0dd41e","type":"status","z":"fdf07536.0c98e","name":"","scope":["a1ccfe22.9d6ac"],"x":120,"y":160,"wires":[[]]},{"id":"4d396c71.b4f074","type":"subflow","name":"Wait for trigger v4","info":"Messages wait for an event of type `event` to be received before being allowed to proceed. Can choose whether to queue all received messages or just the first or last.\n\nEvents received can filtered further in two ways:\n * Provide a conditional to evaluate against event data in the form of `<property>` `<comparator>` `<value>`. Property can be a nested reference\n * Provide a JSON object in `value` to compare against the event data. Filter will pass the JSON is a subset of the event data (same value in all fields)\n\nA `timeout` can be provided in seconds limiting how long each message can wait in the queue. Timed out messages are released to the second output. If `timeout` is 0 then messages queue indefinitely.","category":"","in":[{"x":100,"y":80,"wires":[{"id":"34eaf0ce.2653f"}]}],"out":[{"x":440,"y":40,"wires":[{"id":"34eaf0ce.2653f","port":0}]},{"x":440,"y":100,"wires":[{"id":"34eaf0ce.2653f","port":1}]}],"env":[{"name":"event","type":"str","value":"","ui":{"label":{"en-US":"Event type"},"type":"input","opts":{"types":["str"]}}},{"name":"store","type":"str","value":"all","ui":{"label":{"en-US":"Store"},"type":"select","opts":{"opts":[{"l":{"en-US":"all messages"},"v":"all"},{"l":{"en-US":"first message"},"v":"first"},{"l":{"en-US":"last message"},"v":"last"}]}}},{"name":"property","type":"str","value":"","ui":{"label":{"en-US":"Property"},"type":"input","opts":{"types":["str"]}}},{"name":"conditional","type":"str","value":"none","ui":{"label":{"en-US":"Conditional"},"type":"select","opts":{"opts":[{"l":{"en-US":"none"},"v":"none"},{"l":{"en-US":"=="},"v":"eq"},{"l":{"en-US":"!="},"v":"neq"},{"l":{"en-US":"<"},"v":"lt"},{"l":{"en-US":">"},"v":"gt"},{"l":{"en-US":"<="},"v":"lte"},{"l":{"en-US":">="},"v":"gte"},{"l":{"en-US":"in"},"v":"in"},{"l":{"en-US":"not in"},"v":"nin"},{"l":{"en-US":"matches"},"v":"matches"},{"l":{"en-US":"not matches"},"v":"nmatches"},{"l":{"en-US":"compare event data to value"},"v":"compareObjects"}]}}},{"name":"value","type":"str","value":"","ui":{"label":{"en-US":"Value"},"type":"input","opts":{"types":["str","num","bool","json"]}}},{"name":"timeout","type":"num","value":"","ui":{"label":{"en-US":"Timeout (seconds)"},"type":"input","opts":{"types":["num","env"]}}}],"color":"#DDAA99","outputLabels":["triggered","timed out"],"status":{"x":296,"y":220,"wires":[{"id":"ffd3933d.17153","port":0}]}},{"id":"304357a7.cbefd","type":"server-events","z":"4d396c71.b4f074","name":"","server":"cc03735a.94933","event_type":"${event}","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":true,"x":120,"y":140,"wires":[["971aec1d.2e"]]},{"id":"ffd3933d.17153","type":"status","z":"4d396c71.b4f074","name":"","scope":["34eaf0ce.2653f"],"x":160,"y":220,"wires":[[]]},{"id":"971aec1d.2e","type":"subflow:fdf07536.0c98e","z":"4d396c71.b4f074","name":"","env":[{"name":"property","value":"property","type":"env"},{"name":"conditional","value":"conditional","type":"env"},{"name":"value","value":"value","type":"env"},{"name":"pass_msg","value":"{\"flush\":true}","type":"json"},{"name":"property_context","value":"payload.event","type":"str"},{"name":"msg_field","value":"payload.event","type":"str"}],"x":290,"y":140,"wires":[["34eaf0ce.2653f"],[]]},{"id":"34eaf0ce.2653f","type":"function","z":"4d396c71.b4f074","name":"Queue","func":"let messages = context.get(\"messages\") || [];\nconst timeoutIds = context.get(\"timeoutIds\") || [];\nlet timeout = env.get(\"timeout\") || 0;\n\nif(msg.hasOwnProperty(\"flush\")) {\n clearTimeouts();\n context.set(\"messages\", null);\n context.set(\"timeoutIds\", null);\n node.status({text: \"flushed\"});\n return [messages, null];\n}\n\nif(msg.hasOwnProperty(\"reset\")){\n clearTimeouts();\n context.set(\"messages\", null);\n context.set(\"timeoutIds\", null);\n node.status({text: \"reset\"});\n return;\n}\n\nconst store = env.get(\"store\");\nif(store === \"first\") {\n if(messages.length === 0) {\n messages = [msg];\n } else {\n timeout = 0;\n }\n} else if (store === 'last') {\n messages = [msg];\n clearTimeouts();\n} else {\n messages = [...messages, msg];\n}\n\nif(timeout) {\n const timeoutId = setTimeout(() => {\n removeMessage(msg._msgid);\n }, timeout * 1000);\n timeoutIds.push(timeoutId);\n context.set(\"timeoutIds\", timeoutIds);\n}\n\nnode.status({fill:\"blue\",shape:\"dot\",text: messages.length});\ncontext.set(\"messages\", messages);\n\nfunction clearTimeouts() {\n timeoutIds.forEach(id => clearTimeout(id));\n}\n\nfunction removeMessage(id) {\n const msgs = context.get(\"messages\");\n const index = msgs.findIndex(m => m._msgid = id);\n if(index !== -1){\n node.send([null, msgs.splice(index, 1)]);\n context.set(\"messages\", msgs);\n if(msgs.length){\n node.status({fill:\"blue\",shape:\"dot\",text: msgs.length});\n }\n else{\n node.status({});\n }\n \n }\n}","outputs":2,"noerr":0,"initialize":"","finalize":"","x":310,"y":80,"wires":[[],[]],"outputLabels":["triggered","timed out"]},{"id":"d6c7f79.98cc808","type":"inject","z":"cf25e3ff.a9bd78","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"b","payloadType":"str","x":110,"y":100,"wires":[["237e09a3.6c848e"]]},{"id":"3bc4dbeb.15e7d4","type":"debug","z":"cf25e3ff.a9bd78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":550,"y":60,"wires":[]},{"id":"e9c1e97d.7fec3","type":"inject","z":"cf25e3ff.a9bd78","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":180,"wires":[["d26381e6.0896d"]]},{"id":"d26381e6.0896d","type":"ha-fire-event","z":"cf25e3ff.a9bd78","name":"fire my_test_event","server":"cc03735a.94933","event":"my_test_event","data":"{\"test\": \"no\"}","dataType":"json","x":294,"y":180,"wires":[[]]},{"id":"237e09a3.6c848e","type":"subflow:4d396c71.b4f074","z":"cf25e3ff.a9bd78","name":"","env":[{"name":"event","value":"my_test_event","type":"str"},{"name":"property","value":"test","type":"str"},{"name":"conditional","value":"compareObjects","type":"str"},{"name":"value","value":"{\"abc\":[123, 456]}","type":"json"},{"name":"timeout","value":"60","type":"num"}],"x":290,"y":100,"wires":[["3bc4dbeb.15e7d4"],["ea478410.196a78"]]},{"id":"3f2be27a.0d094e","type":"inject","z":"cf25e3ff.a9bd78","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"a","payloadType":"str","x":110,"y":68,"wires":[["237e09a3.6c848e"]]},{"id":"ca4c40a5.02437","type":"inject","z":"cf25e3ff.a9bd78","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"c","payloadType":"str","x":110,"y":132,"wires":[["237e09a3.6c848e"]]},{"id":"c4d236f6.12e948","type":"inject","z":"cf25e3ff.a9bd78","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":228,"wires":[["298f09c9.4973de"]]},{"id":"298f09c9.4973de","type":"ha-fire-event","z":"cf25e3ff.a9bd78","name":"fire my_test_event with data","server":"cc03735a.94933","event":"my_test_event","data":"{\"test\": {\"abc\": [123, 456], \"other\": \"other\"}}","dataType":"json","x":324,"y":228,"wires":[[]]},{"id":"ea478410.196a78","type":"debug","z":"cf25e3ff.a9bd78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":550,"y":120,"wires":[]},{"id":"44506bd5.bcb9ac","type":"inject","z":"cf25e3ff.a9bd78","name":"passes","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"test\":{\"abc\":\"123\",\"extra_data\":\"ignore\",\"extra_array\":[\"ignore\",\"no\"]}}","payloadType":"json","x":870,"y":100,"wires":[["80c4937a.79351"]]},{"id":"3514a1cc.dbeb76","type":"debug","z":"cf25e3ff.a9bd78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1210,"y":100,"wires":[]},{"id":"ab31527b.7af5d","type":"debug","z":"cf25e3ff.a9bd78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1210,"y":160,"wires":[]},{"id":"80c4937a.79351","type":"subflow:fdf07536.0c98e","z":"cf25e3ff.a9bd78","name":"test","env":[{"name":"property","value":"test","type":"str"},{"name":"conditional","value":"compareObjects","type":"str"},{"name":"value","value":"{\"abc\":\"123\"}","type":"json"},{"name":"pass_msg","value":"{\"passed\": true}","type":"json"},{"name":"fail_msg","value":"{\"passed\": false}","type":"json"},{"name":"property_context","value":"payload","type":"str"}],"x":1030,"y":120,"wires":[["3514a1cc.dbeb76"],["ab31527b.7af5d"]]},{"id":"450f3e18.ec04c","type":"inject","z":"cf25e3ff.a9bd78","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"b","payloadType":"str","x":870,"y":300,"wires":[["9243999d.48ff3"]]},{"id":"eb41b297.ad827","type":"debug","z":"cf25e3ff.a9bd78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1250,"y":280,"wires":[]},{"id":"160b96ec.fa5521","type":"inject","z":"cf25e3ff.a9bd78","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"a","payloadType":"str","x":870,"y":268,"wires":[["9243999d.48ff3"]]},{"id":"1966d3e9.0c608c","type":"inject","z":"cf25e3ff.a9bd78","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"c","payloadType":"str","x":870,"y":332,"wires":[["9243999d.48ff3"]]},{"id":"b9d7c3c2.a54498","type":"debug","z":"cf25e3ff.a9bd78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1250,"y":340,"wires":[]},{"id":"9243999d.48ff3","type":"subflow:34f5b813.356ad8","z":"cf25e3ff.a9bd78","name":"","env":[{"name":"entity_id","value":"sensor.testing_sensor","type":"str"},{"name":"states","value":"great, good, yes","type":"str"},{"name":"state_must_change","type":"bool","value":"false"},{"name":"property","value":"new_state.attributes.an_attribute","type":"str"},{"name":"conditional","value":"nin","type":"str"},{"name":"value","value":"bad, no","type":"str"},{"name":"gate_context_store","value":"file","type":"str"}],"x":1050,"y":300,"wires":[["eb41b297.ad827"],["b9d7c3c2.a54498"]]},{"id":"f1464a40.8c3b8","type":"inject","z":"cf25e3ff.a9bd78","name":"fails","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"other","v":"no","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"test\":{\"extra_data\":\"ignore\",\"extra_array\":[\"ignore\",\"no\"]}}","payloadType":"json","x":870,"y":140,"wires":[["80c4937a.79351"]]},{"id":"356f8d60.800c52","type":"inject","z":"cf25e3ff.a9bd78","name":"Open","props":[{"p":"state","v":"yes","vt":"str"},{"p":"attribute","v":"yes","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":870,"y":400,"wires":[["bcf21baa.f65f6"]]},{"id":"dafb0e65.b79278","type":"inject","z":"cf25e3ff.a9bd78","name":"State fail","props":[{"p":"state","v":"no","vt":"str"},{"p":"attribute","v":"yes","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":880,"y":440,"wires":[["bcf21baa.f65f6"]]},{"id":"bcf21baa.f65f6","type":"ha-entity","z":"cf25e3ff.a9bd78","name":"Testing sensor","server":"cc03735a.94933","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Testing sensor"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"state","stateType":"msg","attributes":[{"property":"an_attribute","value":"attribute","valueType":"msg"}],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1100,"y":440,"wires":[[]]},{"id":"49a90d11.168804","type":"inject","z":"cf25e3ff.a9bd78","name":"Attribute fail","props":[{"p":"state","v":"yes","vt":"str"},{"p":"attribute","v":"no","vt":"str"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"str","x":890,"y":480,"wires":[["bcf21baa.f65f6"]]},{"id":"cc03735a.94933","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}] EDIT: Oh right, one other thing. I changed the |
Beta Was this translation helpful? Give feedback.
-
I've been admiring the power of the 'wait for trigger' node in HA scripts and wishing I could use it in my Node RED flows. You can kind of do it with a delay node but its awkward. To replicate a
wait_for_trigger
of typeevent
you'd have to do something like this:Code to import
This works but it adds complexity to flows (more if you need to filter out events based on their data). Would be really cool if there was a
wait_for_event
node.Or alternatively the
wait_until
node could be updated to support this use case and allow users to choose whether they are waiting on state or an event. Would also need to add an option to thewait_until
node to queue messages though, right now it only passes on the last received message.Beta Was this translation helpful? Give feedback.
All reactions