Join/Wait Node: Timeout Feature request

I still think that a DSM would be the best way, I haven't used those nodes enough to knock off the solution in 5 minutes. I imagine that @cflurin would come up with a solution in no time at all if he were to have a few minutes to look at it.

1 Like

I haven't read the thread yet but this might help, otherwise I'll have a deaper look.

How can you get another door close event without an open in between?

@cflurin this flow is cool for state tracking, but it doesn't seem to track timing. E.g., both events need to happen within a specific timeframe.

@Colin I realize this is non-ideal, but it has to do with the sensor. Sometimes - esp. depending on speed of movement and sensitivity - the open event may not fire. These sensors are all battery powered, so the latency is non-zero.

Understood. An RBE on the way in might be the easiest way to sanitise that rather than complicating the later logic.

@Colin Yeah, good thought but it's still problematic though -- for instance -- if a door is rapidly open/closed, it will send the "close" event again, but RBE would block it.

Do you mean that if you get a motion event, then miss the door open, then door close that the RBE would hide that? In which case yes I think you are right, the RBE node is not what you want.

On the DSM I think the example posted was not supposed to be a complete solution but a starting point. The timer would need to be added in.

Do you mean that if you get a motion event, then miss the door open, then door close that the RBE would hide that? In which case yes I think you are right, the RBE node is not what you want.

Exactly.

I get that, but after reading over the documentation for it (multiple times), I'm still somewhat confused by how this works or how it would even be possible to modify it to work with a timer. While I understand the code in the example (I think), there are a number of undocumented options. For example:

  • The difference in labeling between states and transition names should be more clear. I don't find this intuitive that idle and opened are state names where as open is a transition name. It gets confusing especially when nearly identical names are chosen for state/transition.
    "states": {
        "idle": {
            "open": "opened",
            "detect": "detected"
        },
    },
  • What is a preState?
  • The description of what these do was not provided: triggerInput , stateOutput , preStateOutput , globalOutput and flowOutput
  • setData and getData examples were not extremely clear, and neither were the timer/watchdog.
  • The use of before/on/after transition isn't entirely obvious. I guess, before/after make sense, but not sure about on.
  • output = true/false seems like an undocumented feature?

Maybe using a trigger and outputting the intermediate states there is some hope but I'm not really sure how it would work.

Here is a first approach corresponding to your specs but I think it needs some more improvements.

[{"id":"2243fd98.bc6bf2","type":"inject","z":"aff5350e.4a1208","name":"Motion true","topic":"motion","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":220,"y":140,"wires":[["de2779d0.7beb48"]]},{"id":"db2b3f24.f8ab2","type":"inject","z":"aff5350e.4a1208","name":"Door true","topic":"door","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":220,"y":240,"wires":[["de2779d0.7beb48"]]},{"id":"6d2bb831.b0f508","type":"inject","z":"aff5350e.4a1208","name":"Door false","topic":"door","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":220,"y":280,"wires":[["de2779d0.7beb48"]]},{"id":"7b3b3552.650bdc","type":"inject","z":"aff5350e.4a1208","name":"Motion false","topic":"motion","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":180,"wires":[["de2779d0.7beb48"]]},{"id":"de2779d0.7beb48","type":"dsm","z":"aff5350e.4a1208","name":"light control","sm_config":"{\n    \"stateOutput\": \"payload\",\n    \"currentState\": \"idle\",\n    \"data\": {\n        \"motion\": \"init\",\n        \"door\": \"init\",\n        \"timeover\": false,\n        \"timeout\": 10\n    },\n    \"methods\": {\n        \"motion\": [\n            \"sm.data.motion = msg.payload;\",\n            \"sm.data.timeover = false;\",\n            \"clearTimeout(timeout.id);\",\n            \"timeout.id = setTimeout(function() {\",\n                \"sm.data.timeover = true;\",\n            \"}, sm.data.timeout * 1000);\"\n        ],\n        \"door\": [\n            \"sm.data.door = msg.payload;\"\n        ],\n        \"onTransition\": [\n            \"if (typeof sm.data.motion !== 'init' && typeof sm.data.door !== 'init') {\",\n                \"if (sm.data.motion && !sm.data.door && !sm.data.timeover) {\",\n                    \"msg.topic = 'light';\",\n                    \"msg.payload = true;\",\n                    \"node.send(msg);\",\n                \"};\",\n            \"};\"\n        ],\n        \"status\": {\n            \"fill\": {\n                \"get\": \"'green';\"\n            },\n            \"shape\": \"dot\",\n            \"text\": {\n                \"get\": \"'motion: ' + sm.data.motion + ' door: ' + sm.data.door;\"\n            }\n        }\n    }\n}\n","x":510,"y":200,"wires":[["2606da5f.12e926"]]},{"id":"2606da5f.12e926","type":"debug","z":"aff5350e.4a1208","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":690,"y":200,"wires":[]}]

In case you missed it the detailed spec is in post 17

I know, the doc should be updated.
I'm working on a new project so a Pull Request for the dsm-documentation is welcome.

Note: there are several examples in the Wiki that might help.

Would consider it if I understood how it works a bit better :slight_smile:
It seems quite powerful once you master all the options.

Interesting. I'm not sure I understand the init state here, but it does seem to work somewhat. I get repeated outputs if motion:true is continually sent though. And, if door:false then motion:true will continue to send events without regard for the elapsed time.

I changed init to null and typeof to boolean. The purpose is to allow evaluation after both inputs are set.

{
    "stateOutput": "payload",
    "currentState": "idle",
    "data": {
        "motion": null,
        "door": null,
        "timeover": false,
        "timeout": 10
    },
    "methods": {
        "motion": [
            "sm.data.motion = msg.payload;",
            "sm.data.timeover = false;",
            "clearTimeout(timeout.id);",
            "timeout.id = setTimeout(function() {",
                "sm.data.timeover = true;",
            "}, sm.data.timeout * 1000);"
        ],
        "door": [
            "sm.data.door = msg.payload;"
        ],
        "onTransition": [
            "if (typeof sm.data.motion === 'boolean' && typeof sm.data.door === 'boolean') {",
                "if (sm.data.motion && !sm.data.door && !sm.data.timeover) {",
                    "msg.topic = 'light';",
                    "msg.payload = true;",
                    "node.send(msg);",
                "};",
            "};"
        ],
        "status": {
            "fill": {
                "get": "'green';"
            },
            "shape": "dot",
            "text": {
                "get": "'motion: ' + sm.data.motion + ' door: ' + sm.data.door;"
            }
        }
    }
}

Regarding the function I'll have a look tomorrow.

@dxdc: my point of view:

  1. You have built a contrib-node because you think you can't do it with the core-nodes, that's ok just use your node.

  2. Howerver I'm quite sure this can be achieved with the core nodes. If you want an one-node solution have a look at the function node or use the dsm node, just start with a simple example. You don't need to understand all the features and options.

  3. I only use a few contrib-nodes (less installtion and most important less maintenance). With the core-nodes (they should remain simple to use) and some contrib-nodes (2 of 8 are my nodes) I can almost do all what I need.

1 Like

I generally agree that simpler is better. There is some functionality that I feel would be really valuable in the context of core nodes though that isn't there. It's "possible" to add it using elaborate function nodes, but at that point, it's cleaner to just make it a separate contrib node for maintenance reasons in my opinion... esp. since you can add unit tests for those.

I think the core nodes would benefit tremendously from enhanced boolean logic gates/state tracking, as well as having that happen within a fix time window, rather than trying to reinvent the wheel. I think these problems are ubiquitous enough that making core nodes with them would be very beneficial.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.