Node-red-contrib-enocean

I am using the above mentioned Node-red Flow and have some problems with a rocker 4 switch.
How can I calculate the time between button pressed and button released.
Actually I am not able to identify the resulting messages as coming from the same button.
Any help appreciated.

regards

Hello,
First of did you teach in the rocker switch in an actor node?
From the actor node you get a parsed object which contains all the necessary information.
You can sort the messages coming from the actor node based on the msg.meta.senderId property which will include the unique id of each enocean device you saved.
So use a switch node after the actor node to sort based on this property. Which button was pressed is represented by the msg.payload.R1.value property of the message.

  • 0 is upper left
  • 1 is lower left
  • 2 is upper right
  • 3 is lower right

so this way you can sort which button of the rocker was pressed.
Pressed and released can be found in the msg.payload.EB.description property.
To find the time between those two events you can use a simple function node which contains the following:

switch (msg.payload.EB.description) {
    case "pressed":
        context.set("pressed",Date.now());
        break;
    case "released":
        const diff = Date.now() - context.get("pressed");
        node.send({payload:diff});
}
return null;

which will give you a message which has the time difference as a msg.payload.
Hope this helps.

Johannes

Hi Johannes,

many thanks for the quick response.
I tried what you said before but it does not work.
msg.payload.R1.value is not the same for the press and the release message.
msg.payload.R1.value is always 0 for the release message where as msg.payload.R1.value for the pressed message is as you mentioned 0 - 3.
Due this situation it is not possible to bring these to mesages together and calculate the time difference.
Could there be a problem in the actor SW?

regards Johannes (same name :slightly_smiling_face:)

You are right. I hadn’t noticed that...
But as the released message always comes after a pressed and that has the information you could do something like this:

[{"id":"e31a6805.59a838","type":"switch","z":"fbd0452.6a05538","name":"senderId","property":"meta.senderId","propertyType":"msg","rules":[{"t":"eq","v":"fef9093c","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":240,"y":860,"wires":[["45597fe8.90d"]]},{"id":"76962ba3.f6dad4","type":"switch","z":"fbd0452.6a05538","name":"whichButton","property":"payload.R1.value","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"},{"t":"eq","v":"3","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":650,"y":800,"wires":[["a3ea5442.76bf1"],["1f514644.87a692"],["47908b5.dd86ef4"],["c37fb8f9.2fe508"]]},{"id":"a3ea5442.76bf1","type":"function","z":"fbd0452.6a05538","name":"interval","func":"switch (msg.payload.EB.description) {\n    case \"pressed\":\n        context.set(\"pressed\",Date.now());\n        break;\n    case \"released\":\n        const pressed = context.get(\"pressed\") || false;\n        if (!pressed) {\n            break;\n        } else {\n            const diff = Date.now() - context.get(\"pressed\");\n            node.send({payload:diff,topic:0});\n            flow.set(\"pressed\", false);\n            break;\n        }\n}\nreturn null;","outputs":1,"noerr":0,"x":860,"y":800,"wires":[["edc1496a.315e6"]]},{"id":"45597fe8.90d","type":"switch","z":"fbd0452.6a05538","name":"pressed/released","property":"payload.EB.description","propertyType":"msg","rules":[{"t":"eq","v":"pressed","vt":"str"},{"t":"eq","v":"released","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":430,"y":860,"wires":[["76962ba3.f6dad4"],["a3ea5442.76bf1","1f514644.87a692","47908b5.dd86ef4","c37fb8f9.2fe508"]]},{"id":"1f514644.87a692","type":"function","z":"fbd0452.6a05538","name":"interval","func":"switch (msg.payload.EB.description) {\n    case \"pressed\":\n        context.set(\"pressed\",Date.now());\n        break;\n    case \"released\":\n        const pressed = context.get(\"pressed\") || false;\n        if (!pressed) {\n            break;\n        } else {\n            const diff = Date.now() - context.get(\"pressed\");\n            node.send({payload:diff,topic:1});\n            flow.set(\"pressed\", false);\n            break;\n        }\n}\nreturn null;","outputs":1,"noerr":0,"x":860,"y":840,"wires":[["edc1496a.315e6"]]},{"id":"47908b5.dd86ef4","type":"function","z":"fbd0452.6a05538","name":"interval","func":"switch (msg.payload.EB.description) {\n    case \"pressed\":\n        context.set(\"pressed\",Date.now());\n        break;\n    case \"released\":\n        const pressed = context.get(\"pressed\") || false;\n        if (!pressed) {\n            break;\n        } else {\n            const diff = Date.now() - context.get(\"pressed\");\n            node.send({payload:diff,topic:2});\n            flow.set(\"pressed\", false);\n            break;\n        }\n}\nreturn null;","outputs":1,"noerr":0,"x":860,"y":880,"wires":[["edc1496a.315e6"]]},{"id":"c37fb8f9.2fe508","type":"function","z":"fbd0452.6a05538","name":"interval","func":"switch (msg.payload.EB.description) {\n    case \"pressed\":\n        context.set(\"pressed\",Date.now());\n        break;\n    case \"released\":\n        const pressed = context.get(\"pressed\") || false;\n        if (!pressed) {\n            break;\n        } else {\n            const diff = Date.now() - context.get(\"pressed\");\n            node.send({payload:diff,topic:3});\n            flow.set(\"pressed\", false);\n            break;\n        }\n}\nreturn null;","outputs":1,"noerr":0,"x":860,"y":920,"wires":[["edc1496a.315e6"]]},{"id":"edc1496a.315e6","type":"debug","z":"fbd0452.6a05538","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1090,"y":860,"wires":[]}]

which sends the pressed only to the function for each button but sends the released msg to all four. Each function checks if it was pressed/saved a timestamp and only acts if this is true. If true it sends the measured delay and resets its context to false:

switch (msg.payload.EB.description) {
    case "pressed":
        context.set("pressed",Date.now());
        break;
    case "released":
        const pressed = context.get("pressed") || false;
        if (!pressed) {
            break;
        } else {
            const diff = Date.now() - context.get("pressed");
            node.send({payload:diff,topic:0});
            flow.set("pressed", false);
            break;
        }
}
return null;

This of course right now only works as long as you dont press multiple buttons on the rocker switch at the same time as it expects that a released message belongs to the last pressed button.
Maybe this could be a workaround that works for you. You could wrap it into a nice reusable subflow that uses an enviroment variable for the sender Id. That way it would take up less space and would be easily reusable for each rocker.

Johannes :wink:

Hallo Johannes,

I need your help.
I would like to move a slider as a funtion of the time I press a rocker button.
Every 500 ms +10 to the input of a slider. (0-100)
this means 5 sec = 100%. (should drive a dimmer).
One rocker button up an the rocker other button down.
How to program a delay in js?

regards Johannes

Hello,
sorry for taking so long but I had a busy week.

[{"id":"e31a6805.59a838","type":"switch","z":"fbd0452.6a05538","name":"senderId","property":"meta.senderId","propertyType":"msg","rules":[{"t":"eq","v":"fef9093c","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":460,"y":1020,"wires":[["45597fe8.90d"]]},{"id":"76962ba3.f6dad4","type":"switch","z":"fbd0452.6a05538","name":"whichButton","property":"payload.R1.value","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"},{"t":"eq","v":"3","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":870,"y":960,"wires":[["a3ea5442.76bf1"],["1f514644.87a692"],["47908b5.dd86ef4"],["c37fb8f9.2fe508"]]},{"id":"a3ea5442.76bf1","type":"function","z":"fbd0452.6a05538","name":"left down","func":"switch (msg.payload.EB.description) {\n    case \"pressed\":\n        context.set(\"pressed\",true);\n        let rounds = 0;\n        const repeat = setInterval(()=>{\n            if (context.get(\"pressed\") === false || rounds === 10) { clearInterval(repeat); }\n            node.send({payload:\"pressed\",topic:\"down\"})\n            rounds += 1;\n        },500)\n        break;\n    case \"released\":\n        const pressed = context.get(\"pressed\") || false;\n        if (!pressed) {\n            break;\n        } else {\n            context.set(\"pressed\", false);\n            break;\n        }\n}\nreturn null;","outputs":1,"noerr":0,"x":1080,"y":960,"wires":[["8b78ed6.ec25d1"]]},{"id":"45597fe8.90d","type":"switch","z":"fbd0452.6a05538","name":"pressed/released","property":"payload.EB.description","propertyType":"msg","rules":[{"t":"eq","v":"pressed","vt":"str"},{"t":"eq","v":"released","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":650,"y":1020,"wires":[["76962ba3.f6dad4"],["a3ea5442.76bf1","1f514644.87a692","47908b5.dd86ef4","c37fb8f9.2fe508"]]},{"id":"1f514644.87a692","type":"function","z":"fbd0452.6a05538","name":"left up","func":"switch (msg.payload.EB.description) {\n    case \"pressed\":\n        context.set(\"pressed\",true);\n        let rounds = 0;\n        const repeat = setInterval(()=>{\n            if (context.get(\"pressed\") === false || rounds === 10) { clearInterval(repeat); }\n            node.send({payload:\"pressed\",topic:\"up\"})\n            rounds += 1;\n        },500)\n        break;\n    case \"released\":\n        const pressed = context.get(\"pressed\") || false;\n        if (!pressed) {\n            break;\n        } else {\n            context.set(\"pressed\", false);\n            break;\n        }\n}\nreturn null;","outputs":1,"noerr":0,"x":1070,"y":1000,"wires":[["8b78ed6.ec25d1"]]},{"id":"47908b5.dd86ef4","type":"function","z":"fbd0452.6a05538","name":"right down","func":"switch (msg.payload.EB.description) {\n    case \"pressed\":\n        context.set(\"pressed\",true);\n        let rounds = 0;\n        const repeat = setInterval(()=>{\n            if (context.get(\"pressed\") === false || rounds === 10) { clearInterval(repeat); }\n            node.send({payload:\"pressed\",topic:\"down\"})\n            rounds += 1;\n        },500)\n        break;\n    case \"released\":\n        const pressed = context.get(\"pressed\") || false;\n        if (!pressed) {\n            break;\n        } else {\n            context.set(\"pressed\", false);\n            break;\n        }\n}\nreturn null;","outputs":1,"noerr":0,"x":1090,"y":1040,"wires":[["feefbd4e.0bb268"]]},{"id":"c37fb8f9.2fe508","type":"function","z":"fbd0452.6a05538","name":"right up","func":"switch (msg.payload.EB.description) {\n    case \"pressed\":\n        context.set(\"pressed\",true);\n        let rounds = 0;\n        const repeat = setInterval(()=>{\n            if (context.get(\"pressed\") === false || rounds === 10) { clearInterval(repeat); }\n            node.send({payload:\"pressed\",topic:\"up\"})\n            rounds += 1;\n        },500)\n        break;\n    case \"released\":\n        const pressed = context.get(\"pressed\") || false;\n        if (!pressed) {\n            break;\n        } else {\n            context.set(\"pressed\", false);\n            break;\n        }\n}\nreturn null;","outputs":1,"noerr":0,"x":1080,"y":1080,"wires":[["feefbd4e.0bb268"]]},{"id":"edc1496a.315e6","type":"debug","z":"fbd0452.6a05538","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1470,"y":1060,"wires":[]},{"id":"feefbd4e.0bb268","type":"function","z":"fbd0452.6a05538","name":"right state","func":"let state = flow.get(\"Rocker1RightState\") || 0;\nswitch (msg.topic) {\n    case \"up\":\n        if (state < 100) {\n            state += 10;\n            node.send({payload:state});\n        }\n        break;\n    case \"down\":\n        if (state > 0) {\n            state -= 10;\n            node.send({payload:state});\n        }\n        break;\n}\nflow.set(\"Rocker1RightState\", state);\nreturn null;","outputs":1,"noerr":0,"x":1300,"y":1060,"wires":[["edc1496a.315e6"]]},{"id":"f201122b.77f9a8","type":"debug","z":"fbd0452.6a05538","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1470,"y":980,"wires":[]},{"id":"8b78ed6.ec25d1","type":"function","z":"fbd0452.6a05538","name":"left state","func":"let state = flow.get(\"Rocker1LeftState\") || 0;\nswitch (msg.topic) {\n    case \"up\":\n        if (state < 100) {\n            state += 10;\n            node.send({payload:state});\n        }\n        break;\n    case \"down\":\n        if (state > 0) {\n            state -= 10;\n            node.send({payload:state});\n        }\n        break;\n}\nflow.set(\"Rocker1LeftState\", state);\nreturn null;","outputs":1,"noerr":0,"x":1300,"y":980,"wires":[["f201122b.77f9a8"]]}]

This should do what you want.
I changed the first function node for each button to repeat a message every 500ms using the javascript setInterval() method as long as its pressed with the method from the previous flow i posted.
I added a second function node for each side of the switch. This gets the state of the lamp which it controls which is saved as a flow variable. if the message is up it increments that variable by 10 and sends the result as long as less than 100. Opposite happens for down.
So you an connect a slider to this to show the result.
For it to properly work use a change node after the slider set to the same flow.var that the function before uses to keep state and loop the slider back into itself.
Set the slider to set its value from the input and not pass through.
Hope this helps.

Johannes

Hi Johannes,

very smart. It works like a charm! I am impressed!
I actualy increased the rounds to 20 and decreased the interval to 250 ms which makes it even better.
many thanks

Hannes (shorter :wink:)

1 Like