How to detect multiple presses on a single button

With reference to this thread:
Single button multiple presses

Have you ever wanted to allow multiple presses from a button do multiple things?

This flow allows that.

One "problem" the use of a flow. variable.

If you are going to use multiple versions on the one flow, you need to edit the name used in the flow.set node and the count presses node.

Oh, and you will/may need to install this node:
node-red-contrib-counter

[{"id":"47f8333.7595f4c","type":"change","z":"710ca09a.8302a8","name":"Reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"foo","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":1000,"wires":[["baa481f7.8c92f"]]},{"id":"46bb072c.9ab548","type":"inject","z":"710ca09a.8302a8","name":"Reset","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"0.5","x":400,"y":1040,"wires":[["47f8333.7595f4c"]]},{"id":"6419695d.f444a8","type":"debug","z":"710ca09a.8302a8","name":"Four presses","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1170,"y":1120,"wires":[]},{"id":"9a9ece0e.e21968","type":"inject","z":"710ca09a.8302a8","name":"Start","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":403.33331298828125,"y":951.111083984375,"wires":[["baa481f7.8c92f","d4d7fd43.e18b5"]]},{"id":"baa481f7.8c92f","type":"counter","z":"710ca09a.8302a8","name":"","init":"0","step":"1","lower":null,"upper":null,"mode":"increment","outputs":"1","x":590,"y":950,"wires":[["eeab3859.a0a81","1ccfa267.6709d6"]]},{"id":"cdc2f3f7.8cd668","type":"switch","z":"710ca09a.8302a8","name":"count presses","property":"count","propertyType":"flow","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"eq","v":"4","vt":"num"}],"checkall":"true","repair":false,"outputs":4,"x":790,"y":1060,"wires":[["c3a6c0e7.e7824"],["1939c1b3.49b2c6"],["7bfb6bfb.a555f4"],["c75d22c1.43a18"]],"info":"Just expand the flow.count to how ever many\npresses you want/need."},{"id":"d4d7fd43.e18b5","type":"trigger","z":"710ca09a.8302a8","op1":"","op2":"0","op1type":"nul","op2type":"str","duration":"6","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":410,"y":1000,"wires":[["47f8333.7595f4c"]]},{"id":"1ccfa267.6709d6","type":"change","z":"710ca09a.8302a8","name":"Flow set","rules":[{"t":"set","p":"count","pt":"flow","to":"count","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":910,"wires":[[]]},{"id":"d5ec0e6d.65fe68","type":"debug","z":"710ca09a.8302a8","name":"Tripple press","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1170,"y":1080,"wires":[]},{"id":"a4900536.188a4","type":"debug","z":"710ca09a.8302a8","name":"Double press","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1170,"y":1040,"wires":[]},{"id":"f7ea3f92.56f1b","type":"delay","z":"710ca09a.8302a8","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":770,"y":1000,"wires":[["cdc2f3f7.8cd668"]]},{"id":"eaa4f15.17e7a9","type":"debug","z":"710ca09a.8302a8","name":"Single Press","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1170,"y":1000,"wires":[]},{"id":"eeab3859.a0a81","type":"switch","z":"710ca09a.8302a8","name":"","property":"count","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":760,"y":950,"wires":[["f7ea3f92.56f1b"]]},{"id":"c3a6c0e7.e7824","type":"change","z":"710ca09a.8302a8","name":"Single Press","rules":[{"t":"set","p":"payload","pt":"msg","to":"Single Press","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":990,"y":1000,"wires":[["eaa4f15.17e7a9"]]},{"id":"1939c1b3.49b2c6","type":"change","z":"710ca09a.8302a8","name":"Double Press","rules":[{"t":"set","p":"payload","pt":"msg","to":"Double Press","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1000,"y":1040,"wires":[["a4900536.188a4"]]},{"id":"7bfb6bfb.a555f4","type":"change","z":"710ca09a.8302a8","name":"Tripple Press","rules":[{"t":"set","p":"payload","pt":"msg","to":"Tripple Press","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":990,"y":1080,"wires":[["d5ec0e6d.65fe68"]]},{"id":"c75d22c1.43a18","type":"change","z":"710ca09a.8302a8","name":"Four Press","rules":[{"t":"set","p":"payload","pt":"msg","to":"Four Press","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":990,"y":1120,"wires":[["6419695d.f444a8"]]},{"id":"c0dd4310.43d0a8","type":"comment","z":"710ca09a.8302a8","name":"DELAY - Readme","info":"The DELAY time has to be a bit longer than how\nlong it takes you to press the button the\nmaximum number of times.\nRead information in the SWITCH node too!","x":790,"y":870,"wires":[]},{"id":"8caf97b8.187508","type":"comment","z":"710ca09a.8302a8","name":"Input","info":"","x":400,"y":910,"wires":[]},{"id":"70b7384.c5ce6c8","type":"comment","z":"710ca09a.8302a8","name":"Outputs","info":"Debug nodes are here now, but just connect\nthem to what ever you want.\nThe messages sent are in the nodes just before\nthe debug nodes.\n","x":1150,"y":960,"wires":[]}]
2 Likes

I've re-written the code to optimise how it works and for how long you can be pressing the button.

The old flow limits you to 6 seconds. Granted that is a long time, but it is limited.

I re-wrote how it works which allows unlimited pressing of the button.

Also with the old way you had to wait 6 seconds between sequences, which is also a bit long.

The new one takes that down to 1 second.

This new way the reset signal is kept from being sent because the button has been pressed again with an interval of less than 1 second.

This is 4 examples.
I pressed the inject node 1, 2,3 and 4 times, and got those 4 messages.
Sorry too: I haven't updated an of the comment nodes.

I was a bit over come with excitement that I got the re-write done and wanted to share.
(Yeah, I know. Not really professional.)

[{"id":"1139a03d.d1ca","type":"change","z":"184dc884.7aba5f","name":"Reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"foo","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":2270,"wires":[["fcb3cb17.693a9"]]},{"id":"900577c3.9deb4","type":"inject","z":"184dc884.7aba5f","name":"Reset","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"0.5","x":430,"y":2230,"wires":[["1139a03d.d1ca"]]},{"id":"820bd696.fbc028","type":"debug","z":"184dc884.7aba5f","name":"Four presses","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1180,"y":2370,"wires":[]},{"id":"525e3ec9.3bb6b8","type":"inject","z":"184dc884.7aba5f","name":"Start","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":273.33331298828125,"y":2201.111083984375,"wires":[["fcb3cb17.693a9","ba72e20d.299b8"]]},{"id":"fcb3cb17.693a9","type":"counter","z":"184dc884.7aba5f","name":"","init":"0","step":"1","lower":null,"upper":null,"mode":"increment","outputs":"1","x":620,"y":2200,"wires":[["9faf97df.4ce4a"]]},{"id":"4189a6d1.44073","type":"switch","z":"184dc884.7aba5f","name":"count presses","property":"count","propertyType":"flow","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"eq","v":"4","vt":"num"}],"checkall":"true","repair":false,"outputs":4,"x":790,"y":2310,"wires":[["83d02113.4743b8"],["fbfe53e5.4fcae8"],["e22efc97.c6b018"],["d9a249bd.1f82a8"]],"info":"Just expand the flow.count to how ever many\npresses you want/need."},{"id":"ba72e20d.299b8","type":"trigger","z":"184dc884.7aba5f","op1":"","op2":"0","op1type":"nul","op2type":"str","duration":"1","extend":true,"units":"s","reset":"","bytopic":"all","name":"","x":440,"y":2310,"wires":[["62860129.ec7bd","4189a6d1.44073"]]},{"id":"9faf97df.4ce4a","type":"change","z":"184dc884.7aba5f","name":"Flow set","rules":[{"t":"set","p":"count","pt":"flow","to":"count","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":2200,"wires":[["a018a094.13d14"]]},{"id":"ddd0ab58.0a3e58","type":"debug","z":"184dc884.7aba5f","name":"Tripple press","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1180,"y":2330,"wires":[]},{"id":"ed9739c.0628148","type":"debug","z":"184dc884.7aba5f","name":"Double press","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1180,"y":2290,"wires":[]},{"id":"8082f0.4ba02d1","type":"debug","z":"184dc884.7aba5f","name":"Single Press","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1180,"y":2250,"wires":[]},{"id":"83d02113.4743b8","type":"change","z":"184dc884.7aba5f","name":"Single Press","rules":[{"t":"set","p":"payload","pt":"msg","to":"Single Press","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1000,"y":2250,"wires":[["8082f0.4ba02d1"]]},{"id":"fbfe53e5.4fcae8","type":"change","z":"184dc884.7aba5f","name":"Double Press","rules":[{"t":"set","p":"payload","pt":"msg","to":"Double Press","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":2290,"wires":[["ed9739c.0628148"]]},{"id":"e22efc97.c6b018","type":"change","z":"184dc884.7aba5f","name":"Tripple Press","rules":[{"t":"set","p":"payload","pt":"msg","to":"Tripple Press","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1000,"y":2330,"wires":[["ddd0ab58.0a3e58"]]},{"id":"d9a249bd.1f82a8","type":"change","z":"184dc884.7aba5f","name":"Four Press","rules":[{"t":"set","p":"payload","pt":"msg","to":"Four Press","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1000,"y":2370,"wires":[["820bd696.fbc028"]]},{"id":"a1783324.3f9f","type":"comment","z":"184dc884.7aba5f","name":"DELAY - Readme","info":"The DELAY time has to be a bit longer than how\nlong it takes you to press the button the\nmaximum number of times.\nRead information in the SWITCH node too!","x":820,"y":2120,"wires":[]},{"id":"660d35d0.b41aa4","type":"comment","z":"184dc884.7aba5f","name":"Input","info":"","x":430,"y":2160,"wires":[]},{"id":"f91932b.cacfb5","type":"comment","z":"184dc884.7aba5f","name":"Outputs","info":"Debug nodes are here now, but just connect\nthem to what ever you want.\nThe messages sent are in the nodes just before\nthe debug nodes.\n","x":1160,"y":2210,"wires":[]},{"id":"a018a094.13d14","type":"debug","z":"184dc884.7aba5f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"count","targetType":"msg","x":1000,"y":2200,"wires":[]},{"id":"62860129.ec7bd","type":"delay","z":"184dc884.7aba5f","name":"Delay","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":430,"y":2270,"wires":[["1139a03d.d1ca"]]}]
3 Likes

This is an excellent flow, I've been looking for something similar for my garage. On two occasions the garage has opened and i wasn't sure why. I feel like if i put the garage switch on a double press it should eliminate that problem.

Makes me want to add secret double press and triple presses to all my room light switches now.

Hi everyone

I'm looking to something very similar as your solution, but would like to detect also long presses for dimming while the button is pressed.

  • sigle cick --> toggle
  • double click / three time click --> special action like activate a szene
  • long press --> dimming while button is pressed

With some google search I got to this article and also found the folowing one.
https://groups.google.com/g/node-red/c/WcHYquUvLjE?pli=1

With the "node-red-contrib-timed-counter" node it looks to me as a very simple solution. But with my sketch and also with the one from the link above I get the folowing error out of the "timed-counter" node.

"Creating handler for ....."

Do you have a Idea what that means and how I can fix it?

I use Node-Red V1.1.2
And the node-red-contrib-timed-counter is the V0.0.4

Thanks for your help.

Hi everyone

First I would like to thank “Trying_to_learn”, because this was very helpful for me too. After some trail and error and a lot of fine tuning I found a solution that works fine for me also with dimming. So I would like to share it with you. My solution builds up on the solution from “Trying_to_learn”. Because of that I share my code in this post.

Function:

My flow is designed to get inputs from a MQTT message that comes from a shelly device and outputs some values for a device that is programmed by my selves. For other uses the flow should be relatively easy to adapt. If not, just ask.

One click, Multiple clicks --> programmable action like toggle a lamp

Long press --> dimming of main output

The clicks are recognized on the falling edges. With that it is possible to detect a long press bevor a single click happens. The single click that would happen when you release the button is suppressed after a dimming action.

Also the time for multiple clicks will be reset after each click. With that the reset delay time counts between the clicks, not fix for all clicks together. This is a bit more useful to be able to click several times, because the delay time gets renewed every click.

Optimization potential:

The dimming holds the value without caring about if the light was turned ON or OFF befor starting dimming with a long press. So if the light is OFF and you hold down the button, it could start with a bright light and then start dimming down.

If someone has ideas how to solve this, I would be thankful.

Used additional nodes:

node-red-contrib-time-based-dimmer

[{"id":"b05aa0d1.fec8b","type":"function","z":"d9cf9e97.6745a","name":"store old states","func":"global.set(msg.topic, msg.payload); // store data in context\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":380,"y":960,"wires":[[]]},{"id":"1c03a867.85dc38","type":"mqtt in","z":"d9cf9e97.6745a","name":"all MQTT topics","topic":"#","qos":"2","datatype":"auto","broker":"b496b411.fe5358","x":140,"y":960,"wires":[["b05aa0d1.fec8b"]]},{"id":"5c465ea2.9fe8a","type":"comment","z":"d9cf9e97.6745a","name":"store states","info":"store states for toggeling outputs","x":150,"y":920,"wires":[]},{"id":"cdd00358.59912","type":"mqtt in","z":"d9cf9e97.6745a","name":"","topic":"shellies/shellyrgbw2-6D11B1/input/0","qos":"2","datatype":"auto","broker":"b496b411.fe5358","x":200,"y":1180,"wires":[["547a44be.7c04bc","e910a7af.637cc8"]]},{"id":"43ff6d40.885d24","type":"counter","z":"d9cf9e97.6745a","name":"button counter","init":"0","step":"1","lower":"","upper":"","mode":"increment","outputs":1,"x":1120,"y":1120,"wires":[["ca30ec30.3ba32"]]},{"id":"91cd0240.3289b","type":"change","z":"d9cf9e97.6745a","name":"Reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"foo","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":1180,"wires":[["43ff6d40.885d24"]]},{"id":"ca30ec30.3ba32","type":"function","z":"d9cf9e97.6745a","name":"click action","func":"var newMsg = {payload: null, topic: null};\nconst outTopic_main = \"/office/woodlamp4/\"; // topic that should perform a action out of the clicks\nconst outTopic_doubleClick = \"/office/woodlamp3/\";\nconst outTopic_threeClick = \"/office/woodlamp2/\";\n\nconst dimmingTopic = \"dimming\";             // string of topic for detecting dimming\nconst minONValue = 10;                      // button state is set to ON or OFF with this limit\n\nif(msg.topic == dimmingTopic)\n{\n    // dimming action\n    newMsg.topic = outTopic_main;\n    newMsg.payload = msg.payload;\n    \n    // store sate of dimmer for click-action use\n    if(newMsg.payload > minONValue)\n        context.set(dimmingTopic, msg.payload);     \n    else\n        context.set(dimmingTopic, minONValue+1);\n}\nelse\n{\n    // click action\n    switch(msg.count)\n    {\n        case 0: //do nothing after reset the counter to zero\n            break;\n            \n        case 1: // single click action\n            if(global.get(outTopic_main) < minONValue)          // light is OFF and will be turned ON\n            {\n                newMsg.topic = outTopic_main;\n                newMsg.payload = context.get(dimmingTopic);\n            }\n            else                                                // light is ON and will be turned OFF\n            {\n                newMsg.topic = outTopic_main;\n                newMsg.payload = 0;\n            }\n            break;\n        \n        case 2: // double click action\n            if(global.get(outTopic_doubleClick) < minONValue)    // light is OFF and will be turned ON\n            {\n                newMsg.topic = outTopic_doubleClick;\n                newMsg.payload = 200;\n            }\n            else                                                 // light is ON and will be turned OFF\n            {\n                newMsg.topic = outTopic_doubleClick;\n                newMsg.payload = 0;\n            }\n            break;\n        \n        case 3: // three clicks action\n            if(global.get(outTopic_threeClick) < minONValue)    // light is OFF and will be turned ON\n            {\n                newMsg.topic = outTopic_threeClick;\n                newMsg.payload = 200;\n            }\n            else                                                // light is ON and will be turned OFF\n            {\n                newMsg.topic = outTopic_threeClick;\n                newMsg.payload = 0;\n            }\n            break;\n        \n        default: // more clicks action\n            break;\n    }\n}\n\nif(newMsg.topic !== null){          // send if a action should perform\n    return newMsg;\n}","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\nconst dimmingTopic = \"dimming\";\ncontext.set(dimmingTopic, 200); ","finalize":"","x":1310,"y":1120,"wires":[["a5bc6ffc.dd9c"]]},{"id":"a5bc6ffc.dd9c","type":"mqtt out","z":"d9cf9e97.6745a","name":"","topic":"","qos":"","retain":"","broker":"b496b411.fe5358","x":1470,"y":1120,"wires":[]},{"id":"eec4f702.a1c148","type":"comment","z":"d9cf9e97.6745a","name":"Filter dimming","info":"","x":470,"y":1060,"wires":[]},{"id":"372252f9.7ebcae","type":"comment","z":"d9cf9e97.6745a","name":"Reset","info":"Resets the counter of clicks after a fix given time.","x":950,"y":1060,"wires":[]},{"id":"b535aed9.f19a","type":"comment","z":"d9cf9e97.6745a","name":"counter","info":"counts the number of clicks until it is reseted from the reset mechanism.\n\nmsg.count: shows the count value\nmsg.payload: input value of this node","x":1110,"y":1060,"wires":[]},{"id":"32618161.ba173e","type":"comment","z":"d9cf9e97.6745a","name":"click action","info":"defines the action that should be performed when the button is clicked.","x":1300,"y":1060,"wires":[]},{"id":"bf124070.cd469","type":"trigger","z":"d9cf9e97.6745a","name":"delay","op1":"","op2":"reset","op1type":"nul","op2type":"str","duration":"500","extend":true,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":870,"y":1180,"wires":[["91cd0240.3289b"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"81a4be1a.2cce7","type":"comment","z":"d9cf9e97.6745a","name":"Signal Inputs","info":"","x":230,"y":1060,"wires":[]},{"id":"e910a7af.637cc8","type":"trigger","z":"d9cf9e97.6745a","name":"start dimming delay","op1":"","op2":"start dimming","op1type":"nul","op2type":"str","duration":"500","extend":true,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":410,"y":1240,"wires":[["547a44be.7c04bc"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"65418864.bdae38","type":"change","z":"d9cf9e97.6745a","name":"dimm prepair","rules":[{"t":"set","p":"topic","pt":"msg","to":"dimming","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":1240,"wires":[["ca30ec30.3ba32"]]},{"id":"547a44be.7c04bc","type":"function","z":"d9cf9e97.6745a","name":"start dimming?","func":"var newMsg = {payload: null, topic: null};\nconst lastButtonAction = \"lastButtonAction\";\n\n\nif(msg.payload == \"start dimming\")\n{\n    // \"start dimming\" delay is over and we can check if the button is still pressed\n    \n    if(context.get(lastButtonAction) == 1)\n    {\n        // button is still pressed and we can start dimming\n        newMsg.payload = msg.payload;\n        \n    }\n}\nelse\n{\n    // button action that is not \"start dimming\" --> rising edge (1) or falling edge (0)\n    \n    context.set(lastButtonAction, msg.payload); // store if the button was last on a faling (0), rising edge (1) or \"start dimming\"\n    newMsg.payload = msg.payload; // gives button state to the next node\n}\n\n\nif(newMsg.payload !== null){          // send if a action should perform\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":560,"y":1180,"wires":[["8fc6262c.8f9868","edf4006c.a22a"]]},{"id":"8fc6262c.8f9868","type":"function","z":"d9cf9e97.6745a","name":"faling edge if not dimming","func":"var newMsg = {payload: null, topic: null};\nconst lastMsg = \"lastMsg\"\n\nif(context.get(lastMsg) != \"start dimming\")\n{\n    // dimming is not active\n    if (msg.payload == \"0\")\n    {\n        newMsg.payload = msg.payload;   // just forward faling edges\n    }\n    \n}\n\ncontext.set(lastMsg, msg.payload);      // store msg as lastMsg\n\nif(newMsg.payload !== null)\n{\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":770,"y":1120,"wires":[["43ff6d40.885d24","bf124070.cd469"]]},{"id":"edf4006c.a22a","type":"one-button-dimmer","z":"d9cf9e97.6745a","name":"","interval":"20","step":"1","minValue":0,"maxValue":"255","startCommand":"start dimming","stopCommand":"0","x":760,"y":1240,"wires":[["65418864.bdae38"]]},{"id":"b496b411.fe5358","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]
2 Likes

That sounds great!

I will see if I can find time to play with it, as this may have a use for me.

I don't have any of those devices. Would it be too much for you to make a flow which emulates them?

That way I can see the messages come in (etc).

So how I am reading it:

  • single/multiple clicks selects the lamp.

  • long clicks adjust the brightness.

But what do you do to simply turn the selected light on/off?

Say, I want to turn on "light 2" (given it is now off)

What do I do?

click, click. pause click?

Shelly to Shelly

Today I have adapted the flow for a flow with just shelly deviced (input and output "shelly"). This could help some more folk, because the shelly devices are quit popular these days.

function clearification

  • Single click: turns on/off a specific lamp, or what ever you programm in the "click action" node e specific light.
  • multible clicks: also free programmable, maybe prefered for light scene activations
  • long clicks: dimms the "single click light" up or down (changes each time if you press the button long). The action of the dimming can be defined also in the "click action" node.

So after copy the flow, you need to adjust the input to your needs (in my case a MQTT node) that sends 1 (pressed) and 0 (released) as a payload. The output behaver you can adjust in the "click action" node. If you do not use MQTT, you can also split the informations afterwards by the topics.

I hope it helps to understand the function. If not, pleas ask.

[{"id":"b05aa0d1.fec8b","type":"function","z":"d9cf9e97.6745a","name":"store old states","func":"global.set(msg.topic, msg.payload); // store data in context\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":380,"y":960,"wires":[[]]},{"id":"1c03a867.85dc38","type":"mqtt in","z":"d9cf9e97.6745a","name":"all MQTT topics","topic":"#","qos":"2","datatype":"auto","broker":"b496b411.fe5358","x":140,"y":960,"wires":[["b05aa0d1.fec8b"]]},{"id":"5c465ea2.9fe8a","type":"comment","z":"d9cf9e97.6745a","name":"store states","info":"store states for toggeling outputs","x":150,"y":920,"wires":[]},{"id":"cdd00358.59912","type":"mqtt in","z":"d9cf9e97.6745a","name":"","topic":"shellies/shellyrgbw2-6D11B1/input/0","qos":"2","datatype":"auto","broker":"b496b411.fe5358","x":200,"y":1180,"wires":[["547a44be.7c04bc","e910a7af.637cc8"]]},{"id":"43ff6d40.885d24","type":"counter","z":"d9cf9e97.6745a","name":"button counter","init":"0","step":"1","lower":"","upper":"","mode":"increment","outputs":1,"x":1120,"y":1120,"wires":[["ca30ec30.3ba32"]]},{"id":"91cd0240.3289b","type":"change","z":"d9cf9e97.6745a","name":"Reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"foo","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":1180,"wires":[["43ff6d40.885d24"]]},{"id":"ca30ec30.3ba32","type":"function","z":"d9cf9e97.6745a","name":"click action","func":"var newMsg = {payload: null, topic: null};\nconst outTopic_main = \"shellies/shellyrgbw2-6D11B1/white/0/command\"; // topic that should perform a action out of the clicks\nconst outTopic_dim = \"shellies/shellyrgbw2-6D11B1/white/0/set\";\nconst inTopic_main = \"shellies/shellyrgbw2-6D11B1/white/0\";\n\nconst dimmingTopic = \"dimming\";             // string of topic for detecting dimming\nconst minONValue = 10;                      // button state is set to ON or OFF with this limit\n\nif(msg.topic == dimmingTopic)\n{\n    // dimming action\n    newMsg.topic = outTopic_dim;\n    newMsg.payload = {\"brightness\": msg.payload, \"turn\": \"on\"};\n}\nelse\n{\n    // click action\n    switch(msg.count)\n    {\n        case 0: //do nothing after reset the counter to zero\n            break;\n            \n        case 1: // single click action\n            if(global.get(inTopic_main) == \"on\")    // light is OFF and will be turned ON\n            {\n                newMsg.topic = outTopic_main;\n                newMsg.payload = \"off\";\n            }\n            else                                    // light is ON and will be turned OFF\n            {\n                newMsg.topic = outTopic_main;\n                newMsg.payload = \"on\";\n                \n                if(JSON.parse(global.get(outTopic_dim)).brightness < minONValue)\n                {\n                    // shelly is dimmed down and will be set to the min value to be turned ON\n                    newMsg.topic = outTopic_dim;\n                    newMsg.payload = {\"brightness\": minONValue, \"turn\": \"on\"};\n                }\n            }\n            break;\n        \n        case 2: // double click action\n            break;\n        \n        case 3: // three clicks action\n            break;\n        \n        default: // more clicks action\n            break;\n    }\n}\n\nif(newMsg.topic !== null){          // send if a action should perform\n    return newMsg;\n}","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\nconst dimmingTopic = \"dimming\";\ncontext.set(dimmingTopic, 200); ","finalize":"","x":1310,"y":1120,"wires":[["a5bc6ffc.dd9c","1089ac96.5c7613"]]},{"id":"a5bc6ffc.dd9c","type":"mqtt out","z":"d9cf9e97.6745a","name":"","topic":"","qos":"","retain":"","broker":"b496b411.fe5358","x":1470,"y":1120,"wires":[]},{"id":"bf124070.cd469","type":"trigger","z":"d9cf9e97.6745a","name":"delay","op1":"","op2":"reset","op1type":"nul","op2type":"str","duration":"500","extend":true,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":870,"y":1180,"wires":[["91cd0240.3289b"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"e910a7af.637cc8","type":"trigger","z":"d9cf9e97.6745a","name":"start dimming delay","op1":"","op2":"start dimming","op1type":"nul","op2type":"str","duration":"500","extend":true,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":410,"y":1240,"wires":[["547a44be.7c04bc"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"65418864.bdae38","type":"change","z":"d9cf9e97.6745a","name":"dimm prepair","rules":[{"t":"set","p":"topic","pt":"msg","to":"dimming","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":1240,"wires":[["ca30ec30.3ba32"]]},{"id":"547a44be.7c04bc","type":"function","z":"d9cf9e97.6745a","name":"start dimming?","func":"var newMsg = {payload: null, topic: null};\nconst lastButtonAction = \"lastButtonAction\";\n\n\nif(msg.payload == \"start dimming\")\n{\n    // \"start dimming\" delay is over and we can check if the button is still pressed\n    \n    if(context.get(lastButtonAction) == 1)\n    {\n        // button is still pressed and we can start dimming\n        newMsg.payload = msg.payload;\n        \n    }\n}\nelse\n{\n    // button action that is not \"start dimming\" --> rising edge (1) or falling edge (0)\n    \n    context.set(lastButtonAction, msg.payload); // store if the button was last on a faling (0), rising edge (1) or \"start dimming\"\n    newMsg.payload = msg.payload; // gives button state to the next node\n}\n\n\nif(newMsg.payload !== null){          // send if a action should perform\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":560,"y":1180,"wires":[["8fc6262c.8f9868","edf4006c.a22a"]]},{"id":"8fc6262c.8f9868","type":"function","z":"d9cf9e97.6745a","name":"faling edge if not dimming","func":"var newMsg = {payload: null, topic: null};\nconst lastMsg = \"lastMsg\"\n\nif(context.get(lastMsg) != \"start dimming\")\n{\n    // dimming is not active\n    if (msg.payload == \"0\")\n    {\n        newMsg.payload = msg.payload;   // just forward faling edges\n    }\n    \n}\n\ncontext.set(lastMsg, msg.payload);      // store msg as lastMsg\n\nif(newMsg.payload !== null)\n{\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":770,"y":1120,"wires":[["43ff6d40.885d24","bf124070.cd469"]]},{"id":"edf4006c.a22a","type":"one-button-dimmer","z":"d9cf9e97.6745a","name":"","interval":"150","step":"3","minValue":0,"maxValue":"100","startCommand":"start dimming","stopCommand":"0","x":760,"y":1240,"wires":[["65418864.bdae38"]]},{"id":"65554949.9824e8","type":"comment","z":"d9cf9e97.6745a","name":"office LED band","info":"","x":140,"y":1120,"wires":[]},{"id":"eec4f702.a1c148","type":"comment","z":"d9cf9e97.6745a","name":"Filter dimming","info":"","x":470,"y":1060,"wires":[]},{"id":"372252f9.7ebcae","type":"comment","z":"d9cf9e97.6745a","name":"Reset","info":"Resets the counter of clicks after a fix given time.","x":950,"y":1060,"wires":[]},{"id":"b535aed9.f19a","type":"comment","z":"d9cf9e97.6745a","name":"counter","info":"counts the number of clicks until it is reseted from the reset mechanism.\n\nmsg.count: shows the count value\nmsg.payload: input value of this node","x":1110,"y":1060,"wires":[]},{"id":"32618161.ba173e","type":"comment","z":"d9cf9e97.6745a","name":"click action","info":"defines the action that should be performed when the button is clicked.","x":1300,"y":1060,"wires":[]},{"id":"81a4be1a.2cce7","type":"comment","z":"d9cf9e97.6745a","name":"Signal Inputs","info":"","x":230,"y":1060,"wires":[]},{"id":"1089ac96.5c7613","type":"debug","z":"d9cf9e97.6745a","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1450,"y":960,"wires":[]},{"id":"b496b411.fe5358","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

Generic

OK the generic flow is here. For that one I encresed the delay time for dimming and for the button clicks from 500ms to 1s. With that you can be fast enought to press "1" and "0" to simulate the button "press" and "release".

The button actions are now also generic just implemented as node.warn(), so you see the output in the debug window. What it should do for you, is now up to you.

[{"id":"a28d4492.11c098","type":"counter","z":"d9cf9e97.6745a","name":"button counter","init":"0","step":"1","lower":"","upper":"","mode":"increment","outputs":1,"x":1120,"y":2040,"wires":[["bd956e50.475df"]]},{"id":"371a19b8.322e86","type":"change","z":"d9cf9e97.6745a","name":"Reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"foo","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":2100,"wires":[["a28d4492.11c098"]]},{"id":"bd956e50.475df","type":"function","z":"d9cf9e97.6745a","name":"click action","func":"var newMsg = {payload: null, topic: null};\n\nconst dimmingTopic = \"dimming\";             // string of topic for detecting dimming\nconst minONValue = 10;                      // button state is set to ON or OFF with this limit\n\nif(msg.topic == dimmingTopic)\n{\n    // dimming action\n    node.warn({\"brightness\": msg.payload});\n\n}\nelse\n{\n    // click action\n    switch(msg.count)\n    {\n        case 0: //do nothing after reset the counter to zero\n            break;\n            \n        case 1: // single click action\n            node.warn(\"one click action\");\n            break;\n        \n        case 2: // double click action\n            node.warn(\"two click action\");\n            break;\n        \n        case 3: // three clicks action\n            node.warn(\"three click action\");\n            break;\n        \n        default: // more clicks action\n            break;\n    }\n}\n\nif(newMsg.topic !== null){          // send if a action should perform\n    return newMsg;\n}","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\nconst dimmingTopic = \"dimming\";\ncontext.set(dimmingTopic, 200); ","finalize":"","x":1310,"y":2040,"wires":[[]]},{"id":"e6160ee1.1eff5","type":"trigger","z":"d9cf9e97.6745a","name":"delay","op1":"","op2":"reset","op1type":"nul","op2type":"str","duration":"1000","extend":true,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":870,"y":2100,"wires":[["371a19b8.322e86"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"1b1515ac.eaa45a","type":"trigger","z":"d9cf9e97.6745a","name":"start dimming delay","op1":"","op2":"start dimming","op1type":"nul","op2type":"str","duration":"1000","extend":true,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":410,"y":2160,"wires":[["cf55bfbe.81adc"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"b6823ed.cb241c","type":"change","z":"d9cf9e97.6745a","name":"dimm prepair","rules":[{"t":"set","p":"topic","pt":"msg","to":"dimming","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":2160,"wires":[["bd956e50.475df"]]},{"id":"cf55bfbe.81adc","type":"function","z":"d9cf9e97.6745a","name":"start dimming?","func":"var newMsg = {payload: null, topic: null};\nconst lastButtonAction = \"lastButtonAction\";\n\n\nif(msg.payload == \"start dimming\")\n{\n    // \"start dimming\" delay is over and we can check if the button is still pressed\n    \n    if(context.get(lastButtonAction) == 1)\n    {\n        // button is still pressed and we can start dimming\n        newMsg.payload = msg.payload;\n        \n    }\n}\nelse\n{\n    // button action that is not \"start dimming\" --> rising edge (1) or falling edge (0)\n    \n    context.set(lastButtonAction, msg.payload); // store if the button was last on a faling (0), rising edge (1) or \"start dimming\"\n    newMsg.payload = msg.payload; // gives button state to the next node\n}\n\n\nif(newMsg.payload !== null){          // send if a action should perform\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":560,"y":2100,"wires":[["7869188.6f595e8","c971a203.7c5f"]]},{"id":"7869188.6f595e8","type":"function","z":"d9cf9e97.6745a","name":"faling edge if not dimming","func":"var newMsg = {payload: null, topic: null};\nconst lastMsg = \"lastMsg\"\n\nif(context.get(lastMsg) != \"start dimming\")\n{\n    // dimming is not active\n    if (msg.payload == \"0\")\n    {\n        newMsg.payload = msg.payload;   // just forward faling edges\n    }\n    \n}\n\ncontext.set(lastMsg, msg.payload);      // store msg as lastMsg\n\nif(newMsg.payload !== null)\n{\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":770,"y":2040,"wires":[["a28d4492.11c098","e6160ee1.1eff5"]]},{"id":"c971a203.7c5f","type":"one-button-dimmer","z":"d9cf9e97.6745a","name":"","interval":"150","step":"3","minValue":0,"maxValue":"100","startCommand":"start dimming","stopCommand":"0","x":760,"y":2160,"wires":[["b6823ed.cb241c"]]},{"id":"73f928bf.7b97f8","type":"comment","z":"d9cf9e97.6745a","name":"Filter dimming","info":"","x":470,"y":1980,"wires":[]},{"id":"211a729.2d1008e","type":"comment","z":"d9cf9e97.6745a","name":"Reset","info":"Resets the counter of clicks after a fix given time.","x":950,"y":1980,"wires":[]},{"id":"d4c8834a.6b9fd","type":"comment","z":"d9cf9e97.6745a","name":"counter","info":"counts the number of clicks until it is reseted from the reset mechanism.\n\nmsg.count: shows the count value\nmsg.payload: input value of this node","x":1110,"y":1980,"wires":[]},{"id":"7b6bb55b.ea890c","type":"comment","z":"d9cf9e97.6745a","name":"click action","info":"defines the action that should be performed when the button is clicked.","x":1300,"y":1980,"wires":[]},{"id":"f8a12eae.0bfdb","type":"comment","z":"d9cf9e97.6745a","name":"Signal Inputs","info":"","x":230,"y":1980,"wires":[]},{"id":"15c6305b.ddbbb","type":"inject","z":"d9cf9e97.6745a","name":"1 - button pressed","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"1","payloadType":"str","x":170,"y":2120,"wires":[["cf55bfbe.81adc","1b1515ac.eaa45a"]]},{"id":"470401ae.5ef24","type":"inject","z":"d9cf9e97.6745a","name":"0 - button release","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"0","payloadType":"str","x":160,"y":2160,"wires":[["cf55bfbe.81adc","1b1515ac.eaa45a"]]}]

Thanks.

(Dumb question) I see two posts from you.

One with function clarification and then a Generic one.

I'll try to look at them soon. Just now I am up to my chest with Python code and nodes.

one is for shelly devices specifig programmed. And the Generic one does no action right now but has the full logic and has inputs / outputs that makes it easyer for you to see how it works. So maybe if you do not use shelly devicec, you can start with the generic one. It should not be too complex. Then you should be able to implement actons what ever you like.

1 Like

I'd like to share one of my approaches. I think it's more intuitive, no offence! It's just a function node were essentially 2 properties are added to the msg, so you can make use of whatever property you need afterwards.

  1. How many times the button was pushed within specified time frame.
  2. Is this push down, or was this release a long press.
[{"id":"2e6bf7f1.4d376","type":"function","z":"cf56d87c.939b8","name":"short long times","func":"const pushed = true;        // define payload to be interpreted as push button pushed \nconst released = false;     // define payload to be interpreted as push button released\nconst awaitRetouch = 600;   // milliseconds to wait for a button state change before output\n\nclearTimeout(context.retouchTimer);\nmsg.timespushed = context.get(\"count\") || 0;\nif(msg.payload === pushed) context.set(\"count\", msg.timespushed +=1);\nelse if(msg.payload !== released) return null;\nif(context.get(\"lastlongpress\")) {  // long released\n    msg.timespushed = context.get(\"lastlongpress\");\n    context.set(\"lastlongpress\", 0);\n    msg.longpress = true;\n    return msg;\n}\ncontext.retouchTimer = setTimeout(function() {\n    context.set(\"count\", 0);\n    msg.longpress = msg.payload === pushed;\n    if(msg.longpress) context.set(\"lastlongpress\", msg.timespushed);\n    else{                           // short released\n        msg.payload = pushed;\n        // node.send(msg);             // uncomment to send a fake ...\n        // msg.payload = released;     // ... short released if needed\n    }\n    node.send(msg, false);\n}, awaitRetouch);\n","outputs":1,"noerr":0,"x":1400,"y":1260,"wires":[[]]}]

Usually I use subflows to do stuff, because that enables me to apply changes later on across all flows, while still being able to adjust things on a per subflow instance basis. Like what payload is to be interpreted as a button push or the timeframe, using environment variables, which makes it more generic. This here is like a raw example of what I mean with more intuitive:

[{"id":"e38dbb3a.cdd128","type":"subflow","name":"short long times","info":"","category":"","in":[{"x":40,"y":80,"wires":[{"id":"477f641c.1f309c"}]}],"out":[{"x":360,"y":80,"wires":[{"id":"477f641c.1f309c","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"477f641c.1f309c","type":"function","z":"e38dbb3a.cdd128","name":"short long times","func":"const pushed = env.get(\"pushed\");\nconst released = env.get(\"released\");\nclearTimeout(context.retouchTimer);\nmsg.timespushed = context.get(\"count\") || 0;\nif(msg.payload === pushed) context.set(\"count\", msg.timespushed +=1);\nelse if(msg.payload !== released) return null;\nif(!msg.timespushed) {\n    msg.timespushed = context.get(\"lastlongpress\");\n    msg.longpress = true;\n    return msg;\n}\ncontext.retouchTimer = setTimeout(function() {\n    context.set(\"count\", 0);\n    msg.longpress = msg.payload === pushed;\n    if(msg.longpress) context.set(\"lastlongpress\", msg.timespushed);\n    else msg.payload = pushed;\n    node.send(msg, false);\n}, env.get(\"awaitRetouch\") || 600);\n","outputs":1,"noerr":0,"x":190,"y":80,"wires":[[]],"outputLabels":["short"],"icon":"node-red/timer.svg"},{"id":"2e5e78ff.b68078","type":"subflow:e38dbb3a.cdd128","z":"a441fa9b.b97d","name":"","env":[{"name":"pushed","value":"On","type":"str"},{"name":"released","value":"Off","type":"str"},{"name":"awaitRetouch","value":"1500","type":"num"}],"x":540,"y":240,"wires":[["562cbfae.35a558"]]},{"id":"562cbfae.35a558","type":"switch","z":"a441fa9b.b97d","name":"last press long","property":"longpress","propertyType":"msg","rules":[{"t":"false"},{"t":"true"}],"checkall":"false","repair":false,"outputs":2,"x":830,"y":240,"wires":[["a7c9fba2.45b788"],["adb3ecc6.35bb6"]]},{"id":"a7c9fba2.45b788","type":"switch","z":"a441fa9b.b97d","name":"times pushed","property":"timespushed","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"gte","v":"3","vt":"num"}],"checkall":"false","repair":false,"outputs":3,"x":1070,"y":220,"wires":[["696615aa.957d14"],["d2d2fa87.3c9a5"],["3daa5317.2300fc"]]},{"id":"696615aa.957d14","type":"debug","z":"a441fa9b.b97d","name":"light 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1290,"y":200,"wires":[]},{"id":"d2d2fa87.3c9a5","type":"debug","z":"a441fa9b.b97d","name":"light 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1290,"y":260,"wires":[]},{"id":"3daa5317.2300fc","type":"debug","z":"a441fa9b.b97d","name":"light 3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1290,"y":320,"wires":[]},{"id":"adb3ecc6.35bb6","type":"switch","z":"a441fa9b.b97d","name":"off on release","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"Off","vt":"str"}],"checkall":"false","repair":false,"outputs":1,"x":1070,"y":300,"wires":[["696615aa.957d14","d2d2fa87.3c9a5","3daa5317.2300fc"]]},{"id":"fbfa15d4.f6ae78","type":"inject","z":"a441fa9b.b97d","name":"","topic":"","payload":"On","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":220,"wires":[["2e5e78ff.b68078"]]},{"id":"b5ce2302.ea1a28","type":"inject","z":"a441fa9b.b97d","name":"","topic":"","payload":"Off","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":260,"wires":[["2e5e78ff.b68078"]]},{"id":"b3fa0d12.a6508","type":"comment","z":"a441fa9b.b97d","name":"Button pressed","info":"","x":260,"y":180,"wires":[]},{"id":"81756938.29c72","type":"comment","z":"a441fa9b.b97d","name":"Button released","info":"","x":260,"y":300,"wires":[]},{"id":"4937a266.0773ec","type":"inject","z":"a441fa9b.b97d","name":"","topic":"","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":820,"wires":[["40a0f5fb.f00fb4"]]},{"id":"6069f026.2f3558","type":"inject","z":"a441fa9b.b97d","name":"","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":860,"wires":[["40a0f5fb.f00fb4"]]},{"id":"25c85e32.97bc6a","type":"switch","z":"a441fa9b.b97d","name":"times pushed","property":"timespushed","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"eq","v":"4","vt":"str"},{"t":"gte","v":"5","vt":"num"}],"checkall":"false","repair":false,"outputs":5,"x":810,"y":840,"wires":[["b540b4cb.e70238"],["6c64803.173d9"],["41944fb3.73fbb8"],["f1274306.5300f8"],["cebe7879.a9365"]]},{"id":"b540b4cb.e70238","type":"switch","z":"a441fa9b.b97d","name":"last press long","property":"longpress","propertyType":"msg","rules":[{"t":"false"},{"t":"true"}],"checkall":"false","repair":false,"outputs":2,"x":1220,"y":520,"wires":[["52567e69.1b91f8"],["7b8cde54.732bd"]]},{"id":"a46e2fac.fa3e48","type":"comment","z":"a441fa9b.b97d","name":"Button pressed","info":"","x":260,"y":780,"wires":[]},{"id":"5144ba53.e09ad4","type":"comment","z":"a441fa9b.b97d","name":"Button released","info":"","x":260,"y":900,"wires":[]},{"id":"41944fb3.73fbb8","type":"function","z":"a441fa9b.b97d","name":"toggle light","func":"if(msg.payload === 1) {\n    msg.payload = +!context.get(\"lastoutput\");\n    context.set(\"lastoutput\", msg.payload);\n    node.status(msg.payload ? {fill:\"yellow\",shape:\"dot\",text:\"ON\"} : {fill:\"grey\",shape:\"ring\",text:\"OFF\"});\n    return msg;\n}\n","outputs":1,"noerr":0,"x":1150,"y":840,"wires":[["85fd5008.7bc89"]]},{"id":"d841527c.7b5aa8","type":"debug","z":"a441fa9b.b97d","name":"switch on/off","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1650,"y":480,"wires":[]},{"id":"eb78febb.0b939","type":"debug","z":"a441fa9b.b97d","name":"dimm up / down","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1660,"y":540,"wires":[]},{"id":"cebe7879.a9365","type":"debug","z":"a441fa9b.b97d","name":"switch group on/off","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1220,"y":1140,"wires":[]},{"id":"6c64803.173d9","type":"switch","z":"a441fa9b.b97d","name":"last press long","property":"longpress","propertyType":"msg","rules":[{"t":"false"},{"t":"true"}],"checkall":"false","repair":false,"outputs":2,"x":1220,"y":660,"wires":[["f899971f.9d9318"],["f1d16ca0.c5ba4"]]},{"id":"f899971f.9d9318","type":"debug","z":"a441fa9b.b97d","name":"switch between rgb / color temperature","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1540,"y":620,"wires":[]},{"id":"f1d16ca0.c5ba4","type":"debug","z":"a441fa9b.b97d","name":"slide back & forth through color weel / temperature","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1580,"y":680,"wires":[]},{"id":"85fd5008.7bc89","type":"debug","z":"a441fa9b.b97d","name":"Room Light","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1330,"y":840,"wires":[]},{"id":"40a0f5fb.f00fb4","type":"subflow:e38dbb3a.cdd128","z":"a441fa9b.b97d","name":"","env":[{"name":"pushed","value":"1","type":"num"},{"name":"released","value":"0","type":"num"},{"name":"awaitRetouch","value":"1500","type":"num"}],"x":520,"y":840,"wires":[["25c85e32.97bc6a"]]},{"id":"be96b2f0.1f1398","type":"comment","z":"a441fa9b.b97d","name":"As subflow with environment variables","info":"","x":550,"y":200,"wires":[]},{"id":"7b8cde54.732bd","type":"function","z":"a441fa9b.b97d","name":"dimmer","func":"if(msg.payload) {\n    context.set(\"dim\", !context.get(\"dim\"));\n    msg.payload = context.get(\"dim\") ? \"decrement brightness\" : \"increment brightness\";\n}else msg.payload = \"stop dimming\";\nnode.status(msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":1430,"y":540,"wires":[["eb78febb.0b939"]]},{"id":"52567e69.1b91f8","type":"function","z":"a441fa9b.b97d","name":"toggle","func":"if(msg.payload) {\n    msg.payload = context.get(\"lastoutput\") === \"on\" ? \"off\" : \"on\";\n    context.set(\"lastoutput\", msg.payload);\n    node.status(msg.payload);\n    return msg;\n}\n","outputs":1,"noerr":0,"x":1430,"y":480,"wires":[["d841527c.7b5aa8"]]},{"id":"f1274306.5300f8","type":"switch","z":"a441fa9b.b97d","name":"last press long","property":"longpress","propertyType":"msg","rules":[{"t":"false"},{"t":"true"}],"checkall":"false","repair":false,"outputs":2,"x":1250,"y":1020,"wires":[["490283c5.8da614"],["e49df6fd.badbc"]]},{"id":"490283c5.8da614","type":"debug","z":"a441fa9b.b97d","name":"fan","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1690,"y":1020,"wires":[]},{"id":"e49df6fd.badbc","type":"switch","z":"a441fa9b.b97d","name":"off on release","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"}],"checkall":"false","repair":false,"outputs":1,"x":1470,"y":1060,"wires":[["490283c5.8da614"]]},{"id":"73605b11.897574","type":"comment","z":"a441fa9b.b97d","name":"LED stripe","info":"","x":1140,"y":600,"wires":[]},{"id":"fa24d5b.caf2a28","type":"comment","z":"a441fa9b.b97d","name":"different environment variables","info":"","x":530,"y":800,"wires":[]}]

For anybody reading this discussion, I recently announced node-red-contrib-button-events to detect different type of button presses. That might also be helpful in this kind of situations...
Bart

1 Like

Thanks, your approach is clean, however I can't figure out how to use it for holding the button down.
I am trying to:

  • Dim the light when holding button
  • Turn on/off on single press
  • Activate scenes with two and three presses

I don't want to start a fight but I'd suggest you look at @BartButenaers offering.

Me neither and @BartButenaers node clearly has its benefits, like the nicely integrated debounce, but it is also more limited. A debounce is sometimes obsolete when the hardware eg. Wifi Button has that already integrated, or when you integrate that into the hardware, like esp8266 or arduino, for performance reasons.

But the main limit is that you cannot increase the amount of outputs for each press, or differentiate between long and short, for each time pressed. For example:

1x short: Light1 On/Off

1x long: Light1 dimming

2x short: Light2 On/Off

...and here is where it ends...

2x long (1x short +1x long): Light2 dimming

3x short: Light3 On/Off

3x long: Light3 dimming

and so on...

What I shared is a different way that's more flexible I think, that is all.

Oh, and if you don't want to use the debounce in like the rpi node, or you want to let's say, filter out capacitive crosstalk, because you like to start different flows when multiple buttons are pressed on a let's say 4-way wall switch, then you can always do that in front of it, with something like this:

[{"id":"34367535.12f5b2","type":"function","z":"985f3f8f.b62cb8","name":"short long times","func":"const pushed = true;        // define payload to be interpreted as push button pushed \nconst released = false;     // define payload to be interpreted as push button released\nconst awaitRetouch = 600;   // milliseconds to wait for a button state change before output\n\nclearTimeout(context.retouchTimer);\nmsg.timespushed = context.get(\"count\") || 0;\nif(msg.payload === pushed) context.set(\"count\", msg.timespushed +=1);\nelse if(msg.payload !== released) return null;\nif(context.get(\"lastlongpress\")) {  // long released\n    msg.timespushed = context.get(\"lastlongpress\");\n    context.set(\"lastlongpress\", 0);\n    msg.longpress = true;\n    return msg;\n}\ncontext.retouchTimer = setTimeout(function() {\n    context.set(\"count\", 0);\n    msg.longpress = msg.payload === pushed;\n    if(msg.longpress) context.set(\"lastlongpress\", msg.timespushed);\n    else{                           // short released\n        msg.payload = pushed;\n        // node.send(msg);             // uncomment to send a fake ...\n        // msg.payload = released;     // ... short released if needed\n    }\n    node.send(msg, false);\n}, awaitRetouch);\n","outputs":1,"noerr":0,"x":600,"y":260,"wires":[[]]},{"id":"71ed9383.4fbd7c","type":"function","z":"985f3f8f.b62cb8","name":"filter","func":"clearTimeout(context.filter);\ncontext.filter = setTimeout(function() {\n    msg.payload = !msg.payload;     // invert because of pullup resistor\n    // this should filter out capacitive crosstalk between the wires inside a long cable, where multiple buttons are connected to, \n    // so no more false button released msg passing after debounce, when it hasn't actually been touched\n    if(msg.payload !== (context.get(\"lastoutput\") || false)) {  // || false so no Button released msg on restart (context undefined)\n        context.set(\"lastoutput\", msg.payload);\n        node.status(msg.payload ? {fill: \"blue\", shape: \"dot\", text: \"Button pressed\"} : {fill: \"grey\", shape: \"ring\", text: \"Button released\"});\n        node.send(msg, false);\n    }\n}, 80);     // debounce time    ~6ms= Wall switch bouncing, ~40ms= Blinds turn off under load interference, ~70ms= Lightning strike interferences so far\n","outputs":1,"noerr":0,"x":390,"y":260,"wires":[["34367535.12f5b2"]]},{"id":"7458d29c.cb347c","type":"arduino in","z":"985f3f8f.b62cb8","name":"","pin":"","state":"PULLUP","arduino":"b64b8b29.cc8b38","x":180,"y":260,"wires":[["71ed9383.4fbd7c"]]},{"id":"b64b8b29.cc8b38","type":"arduino-board","z":"","device":"/dev/ttyACM0"}]
1 Like

You don't really give me much info to help you here. Sorry...

Maybe it's on the input side, so what's your input? MQTT?, some wifi button?, a wall switch or a push-button?. Like how is it connected?

  1. Is the Input there and clean, like debounced and everything

  2. Does the node receive a button release after each button press?

  3. Have you configured what msg.payload is to be interpreted as pressed/released?

  4. Is the time span configured and adequately so, to count the presses within or output a long press if passed?

If your problem is on the output side of things, it depends on how you need to modify things, prepare things for the nodes, that talk to the hardware.

The examples I've given was just that, a raw example of how things can be approached so far, and configured, using environment variables for the subflow. The emphasis is on raw. I merely displayed possibilities. I didn't take the time to create a contrib node, (I don't know how) because it's just a few lines of code and I'm not even good at it, I'm a beginner.

How do you dim whatever? Like a 0-10V Dimmer, for a LED-Stripe Power Supply, controlled by some Relays connected to Node-Red somehow is a completely different story than an Hue Light Bulb for example. I don't know how to help you. Sorry

Sorry, to clarify: The input is a message from a Shelly dimmer 2 wired to a momentary switch, I get messages 1 when the button is down and 0 when the button is up (as well as it sometimes reports the current state 0/1, but I have code that checks if there is actual change but somehow I still get some messages through like there is a press, not sure if this is a Shelly problem or how I am reading messages or MQTT QoS related).

I kind of have this working now:

[{"id":"a28d4492.11c098","type":"counter","z":"396c09ba.0b87e6","name":"button counter","init":"0","step":"1","lower":null,"upper":null,"mode":"increment","outputs":1,"x":1180,"y":920,"wires":[["e7665c43.8e123"]]},{"id":"371a19b8.322e86","type":"change","z":"396c09ba.0b87e6","name":"Reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"foo","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1070,"y":980,"wires":[["a28d4492.11c098"]]},{"id":"bd956e50.475df","type":"function","z":"396c09ba.0b87e6","name":"click action","func":"var newMsg = {payload: null, topic: null};\n\nconst dimmingTopic = \"dimming\";             // string of topic for detecting dimming\nconst minONValue = 10;                      // button state is set to ON or OFF with this limit\n\nif(msg.topic == dimmingTopic)\n{\n    // dimming action\n    node.warn({\"brightness\": msg.payload});\n    var brightness = msg.payload;\n    msg.payload = { data: {\"brightness\":brightness, \"transition\": 1} };\n    return [msg, null, null, null, null]\n\n}\nelse\n{\n    // click action\n    switch(msg.count)\n    {\n        case 0: //do nothing after reset the counter to zero\n            break;\n            \n        case 1: // single click action\n            node.warn(\"one click action\");\n            return [null, msg, null, null, null]\n            break;\n        \n        case 2: // double click action\n            node.warn(\"two click action\");\n            return [null, null, msg, null, null]\n            break;\n        \n        case 3: // three clicks action\n            node.warn(\"three click action\");\n            return [null, null, null, msg, null]\n            break;\n        \n        default: // more clicks action\n            node.warn(\"more click action\");\n            return [null, null, null, null, msg]\n            break;\n    }\n}\n\nif(newMsg.topic !== null){          // send if a action should perform\n    return newMsg;\n}","outputs":5,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\nconst dimmingTopic = \"dimming\";\ncontext.set(dimmingTopic, 200); ","finalize":"","x":1510,"y":920,"wires":[["765b313c.43bc08","fa7e728a.8979f8"],["7ddeb090.4832d","b4661043.0a9ad8"],["695f21dc.05bc3","f1811a19.9f88c"],["17858cf5.3b6c13","ece917d.d876368"],["f3cdc9d1.036e18"]]},{"id":"e6160ee1.1eff5","type":"trigger","z":"396c09ba.0b87e6","name":"delay","op1":"","op2":"reset","op1type":"nul","op2type":"str","duration":"1000","extend":true,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":930,"y":980,"wires":[["371a19b8.322e86"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"1b1515ac.eaa45a","type":"trigger","z":"396c09ba.0b87e6","name":"start dimming delay","op1":"","op2":"start dimming","op1type":"nul","op2type":"str","duration":"600","extend":true,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":470,"y":1040,"wires":[["cf55bfbe.81adc"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"b6823ed.cb241c","type":"change","z":"396c09ba.0b87e6","name":"dimm prepair","rules":[{"t":"set","p":"topic","pt":"msg","to":"dimming","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1170,"y":1040,"wires":[["bd956e50.475df"]]},{"id":"cf55bfbe.81adc","type":"function","z":"396c09ba.0b87e6","name":"start dimming?","func":"var newMsg = {payload: null, topic: null};\nconst lastButtonAction = \"lastButtonAction\";\n\n\nif(msg.payload == \"start dimming\")\n{\n    // \"start dimming\" delay is over and we can check if the button is still pressed\n    \n    if(context.get(lastButtonAction) == 1)\n    {\n        // button is still pressed and we can start dimming\n        newMsg.payload = msg.payload;\n        \n    }\n}\nelse\n{\n    // button action that is not \"start dimming\" --> rising edge (1) or falling edge (0)\n    \n    context.set(lastButtonAction, msg.payload); // store if the button was last on a faling (0), rising edge (1) or \"start dimming\"\n    newMsg.payload = msg.payload; // gives button state to the next node\n}\n\n\nif(newMsg.payload !== null){          // send if a action should perform\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":620,"y":980,"wires":[["7869188.6f595e8","c971a203.7c5f"]]},{"id":"7869188.6f595e8","type":"function","z":"396c09ba.0b87e6","name":"faling edge if not dimming","func":"var newMsg = {payload: null, topic: null};\nconst lastMsg = \"lastMsg\"\n\nif(context.get(lastMsg) != \"start dimming\")\n{\n    // dimming is not active\n    if (msg.payload == \"0\")\n    {\n        newMsg.payload = msg.payload;   // just forward faling edges\n    }\n    \n}\n\ncontext.set(lastMsg, msg.payload);      // store msg as lastMsg\n\nif(newMsg.payload !== null)\n{\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":830,"y":920,"wires":[["a28d4492.11c098","e6160ee1.1eff5"]]},{"id":"c971a203.7c5f","type":"one-button-dimmer","z":"396c09ba.0b87e6","name":"","interval":"50","step":"1","minValue":"90","maxValue":"150","startCommand":"start dimming","stopCommand":"0","x":890,"y":1060,"wires":[["b6823ed.cb241c"]]},{"id":"73f928bf.7b97f8","type":"comment","z":"396c09ba.0b87e6","name":"Filter dimming","info":"","x":530,"y":860,"wires":[]},{"id":"211a729.2d1008e","type":"comment","z":"396c09ba.0b87e6","name":"Reset","info":"Resets the counter of clicks after a fix given time.","x":1010,"y":860,"wires":[]},{"id":"d4c8834a.6b9fd","type":"comment","z":"396c09ba.0b87e6","name":"counter","info":"counts the number of clicks until it is reseted from the reset mechanism.\n\nmsg.count: shows the count value\nmsg.payload: input value of this node","x":1170,"y":860,"wires":[]},{"id":"7b6bb55b.ea890c","type":"comment","z":"396c09ba.0b87e6","name":"click action","info":"defines the action that should be performed when the button is clicked.","x":1510,"y":860,"wires":[]},{"id":"f8a12eae.0bfdb","type":"comment","z":"396c09ba.0b87e6","name":"Signal Inputs","info":"","x":290,"y":860,"wires":[]},{"id":"15c6305b.ddbbb","type":"inject","z":"396c09ba.0b87e6","name":"1 - button pressed","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"1","payloadType":"str","x":230,"y":1000,"wires":[["cf55bfbe.81adc","1b1515ac.eaa45a"]]},{"id":"470401ae.5ef24","type":"inject","z":"396c09ba.0b87e6","name":"0 - button release","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"0","payloadType":"str","x":220,"y":1040,"wires":[["cf55bfbe.81adc","1b1515ac.eaa45a"]]},{"id":"3259bb14.25320c","type":"mqtt in","z":"396c09ba.0b87e6","name":"","topic":"shellies/shellydimmer2-/input/0","qos":"2","datatype":"auto","broker":"217472f.ad9218e","x":220,"y":900,"wires":[["399e959b.bb8c82"]]},{"id":"399e959b.bb8c82","type":"function","z":"396c09ba.0b87e6","name":"Check if new event","func":"local_event = context.get(\"living_room_ceiling_events\"); //to retrieve a variable  \nif (msg.payload != local_event) {\n    context.set(\"living_room_ceiling_events\",msg.payload);\n    return [msg, null]\n}\n//context.set(\"living_room_ceiling_events\",0);\nreturn [null, msg];","outputs":2,"noerr":0,"initialize":"","finalize":"","x":230,"y":960,"wires":[["cf55bfbe.81adc","1b1515ac.eaa45a"],[]]},{"id":"e7665c43.8e123","type":"function","z":"396c09ba.0b87e6","name":"delay","func":"const awaitRetouch = 600;   // milliseconds to wait for a button state change before output\n\nclearTimeout(context.retouchTimer);\nmsg.timespushed = context.get(\"count\") || 0;\ncontext.set(\"count\", msg.timespushed +=1);\ncontext.retouchTimer = setTimeout(function() {\n    context.set(\"count\", 0);\n    node.send(msg, false);\n}, awaitRetouch);\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1330,"y":920,"wires":[["bd956e50.475df"]]},{"id":"217472f.ad9218e","type":"mqtt-broker","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""}]

Issues are:

  1. Not getting brightness level before dimming so if last dimming went to 100% but brightness was updated some other way or light turned off, then the light jumps to 100% and starts dimming down. (In the future I would like to get the brightness before I start dimming, and if there is more than 1 minute since last dimming I would like it to go down if above 50% and up if below 50%, so you don't have the light at 95% and start dimming, and it just goes to 100%).
  2. I get a shadow press from the input, just a single press some time after using the switch.
  3. Dimming in a bit choppy, would like to figure out how to make it more smooth but not sure if that is possible.

Figured out how to get current brightness to prevent jumping, but now the light stops at minimum brightness when I start to hold the button and the light is off.

[{"id":"a28d4492.11c098","type":"counter","z":"396c09ba.0b87e6","name":"button counter","init":"0","step":"1","lower":null,"upper":null,"mode":"increment","outputs":1,"x":1180,"y":380,"wires":[["e7665c43.8e123"]]},{"id":"371a19b8.322e86","type":"change","z":"396c09ba.0b87e6","name":"Reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"foo","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1070,"y":440,"wires":[["a28d4492.11c098"]]},{"id":"bd956e50.475df","type":"function","z":"396c09ba.0b87e6","name":"click action","func":"var newMsg = {payload: null, topic: null};\n\nconst dimmingTopic = \"dimming\";             // string of topic for detecting dimming\nconst minONValue = 10;                      // button state is set to ON or OFF with this limit\n\nif(msg.topic == dimmingTopic)\n{\n    // dimming action\n    node.warn({\"brightness\": msg.payload});\n    var brightness = msg.payload;\n    msg.payload = { data: {\"brightness\":brightness, \"transition\": 1} };\n    return [msg, null, null, null, null]\n\n}\nelse\n{\n    // click action\n    switch(msg.count)\n    {\n        case 0: //do nothing after reset the counter to zero\n            break;\n            \n        case 1: // single click action\n            node.warn(\"one click action\");\n            return [null, msg, null, null, null]\n            break;\n        \n        case 2: // double click action\n            node.warn(\"two click action\");\n            return [null, null, msg, null, null]\n            break;\n        \n        case 3: // three clicks action\n            node.warn(\"three click action\");\n            return [null, null, null, msg, null]\n            break;\n        \n        default: // more clicks action\n            node.warn(\"more click action\");\n            return [null, null, null, null, msg]\n            break;\n    }\n}\n\nif(newMsg.topic !== null){          // send if a action should perform\n    return newMsg;\n}","outputs":5,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\nconst dimmingTopic = \"dimming\";\ncontext.set(dimmingTopic, 200); ","finalize":"","x":1510,"y":380,"wires":[["765b313c.43bc08","fa7e728a.8979f8"],["7ddeb090.4832d","b4661043.0a9ad8"],["695f21dc.05bc3","f1811a19.9f88c"],["17858cf5.3b6c13","ece917d.d876368"],["f3cdc9d1.036e18"]]},{"id":"e6160ee1.1eff5","type":"trigger","z":"396c09ba.0b87e6","name":"delay","op1":"","op2":"reset","op1type":"nul","op2type":"str","duration":"1000","extend":true,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":930,"y":440,"wires":[["371a19b8.322e86"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"1b1515ac.eaa45a","type":"trigger","z":"396c09ba.0b87e6","name":"start dimming delay","op1":"","op2":"start dimming","op1type":"nul","op2type":"str","duration":"600","extend":true,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":470,"y":500,"wires":[["cf55bfbe.81adc"]],"info":"The delay will be extended with every message / klick. With this behaver it is possible to detect also longer sequences of clicks."},{"id":"b6823ed.cb241c","type":"change","z":"396c09ba.0b87e6","name":"dimm prepair","rules":[{"t":"set","p":"topic","pt":"msg","to":"dimming","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1170,"y":500,"wires":[["bd956e50.475df"]]},{"id":"cf55bfbe.81adc","type":"function","z":"396c09ba.0b87e6","name":"start dimming?","func":"var newMsg = {payload: null, topic: null};\nconst lastButtonAction = \"lastButtonAction\";\n\n\nif(msg.payload == \"start dimming\")\n{\n    // \"start dimming\" delay is over and we can check if the button is still pressed\n    \n    if(context.get(lastButtonAction) == 1)\n    {\n        // button is still pressed and we can start dimming\n        newMsg.payload = msg.payload;\n        \n    }\n}\nelse\n{\n    // button action that is not \"start dimming\" --> rising edge (1) or falling edge (0)\n    \n    context.set(lastButtonAction, msg.payload); // store if the button was last on a faling (0), rising edge (1) or \"start dimming\"\n    newMsg.payload = msg.payload; // gives button state to the next node\n}\n\n\nif(newMsg.payload !== null){          // send if a action should perform\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":620,"y":440,"wires":[["7869188.6f595e8","c971a203.7c5f"]]},{"id":"7869188.6f595e8","type":"function","z":"396c09ba.0b87e6","name":"faling edge if not dimming","func":"var newMsg = {payload: null, topic: null};\nconst lastMsg = \"lastMsg\"\n\nif(context.get(lastMsg) != \"start dimming\")\n{\n    // dimming is not active\n    if (msg.payload == \"0\")\n    {\n        newMsg.payload = msg.payload;   // just forward faling edges\n    }\n    \n}\n\ncontext.set(lastMsg, msg.payload);      // store msg as lastMsg\n\nif(newMsg.payload !== null)\n{\n    return newMsg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":830,"y":380,"wires":[["a28d4492.11c098","e6160ee1.1eff5"]]},{"id":"c971a203.7c5f","type":"one-button-dimmer","z":"396c09ba.0b87e6","name":"","interval":"50","step":"1","minValue":"90","maxValue":"150","startCommand":"start dimming","stopCommand":"0","x":890,"y":520,"wires":[["b6823ed.cb241c"]]},{"id":"73f928bf.7b97f8","type":"comment","z":"396c09ba.0b87e6","name":"Filter dimming","info":"","x":530,"y":320,"wires":[]},{"id":"211a729.2d1008e","type":"comment","z":"396c09ba.0b87e6","name":"Reset","info":"Resets the counter of clicks after a fix given time.","x":1010,"y":320,"wires":[]},{"id":"d4c8834a.6b9fd","type":"comment","z":"396c09ba.0b87e6","name":"counter","info":"counts the number of clicks until it is reseted from the reset mechanism.\n\nmsg.count: shows the count value\nmsg.payload: input value of this node","x":1170,"y":320,"wires":[]},{"id":"7b6bb55b.ea890c","type":"comment","z":"396c09ba.0b87e6","name":"click action","info":"defines the action that should be performed when the button is clicked.","x":1510,"y":320,"wires":[]},{"id":"f8a12eae.0bfdb","type":"comment","z":"396c09ba.0b87e6","name":"Signal Inputs","info":"","x":290,"y":320,"wires":[]},{"id":"15c6305b.ddbbb","type":"inject","z":"396c09ba.0b87e6","name":"1 - button pressed","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"1","payloadType":"str","x":230,"y":460,"wires":[["cf55bfbe.81adc","1b1515ac.eaa45a"]]},{"id":"470401ae.5ef24","type":"inject","z":"396c09ba.0b87e6","name":"0 - button release","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"0","payloadType":"str","x":220,"y":500,"wires":[["cf55bfbe.81adc","1b1515ac.eaa45a"]]},{"id":"3259bb14.25320c","type":"mqtt in","z":"396c09ba.0b87e6","name":"","topic":"shellies/shellydimmer2-/input/0","qos":"2","datatype":"auto","broker":"217472f.ad9218e","x":220,"y":360,"wires":[["399e959b.bb8c82"]]},{"id":"399e959b.bb8c82","type":"function","z":"396c09ba.0b87e6","name":"Check if new event","func":"local_event = context.get(\"living_room_ceiling_events\"); //to retrieve a variable  \nif (msg.payload != local_event) {\n    context.set(\"living_room_ceiling_events\",msg.payload);\n    return [msg, null]\n}\n//context.set(\"living_room_ceiling_events\",0);\nreturn [null, msg];","outputs":2,"noerr":0,"initialize":"","finalize":"","x":230,"y":420,"wires":[["cf55bfbe.81adc","1b1515ac.eaa45a","67cf40b5.84524"],[]]},{"id":"e7665c43.8e123","type":"function","z":"396c09ba.0b87e6","name":"delay","func":"const awaitRetouch = 600;   // milliseconds to wait for a button state change before output\n\nclearTimeout(context.retouchTimer);\nmsg.timespushed = context.get(\"count\") || 0;\ncontext.set(\"count\", msg.timespushed +=1);\ncontext.retouchTimer = setTimeout(function() {\n    context.set(\"count\", 0);\n    node.send(msg, false);\n}, awaitRetouch);\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1330,"y":380,"wires":[["bd956e50.475df"]]},{"id":"765b313c.43bc08","type":"debug","z":"396c09ba.0b87e6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1750,"y":300,"wires":[]},{"id":"7ddeb090.4832d","type":"debug","z":"396c09ba.0b87e6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1750,"y":340,"wires":[]},{"id":"695f21dc.05bc3","type":"debug","z":"396c09ba.0b87e6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1750,"y":380,"wires":[]},{"id":"17858cf5.3b6c13","type":"debug","z":"396c09ba.0b87e6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1750,"y":420,"wires":[]},{"id":"f3cdc9d1.036e18","type":"debug","z":"396c09ba.0b87e6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1750,"y":460,"wires":[]},{"id":"67cf40b5.84524","type":"api-current-state","z":"396c09ba.0b87e6","name":"","server":"188ccb03.2ae3b5","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"light.living_room_ceiling_light","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":530,"y":600,"wires":[["eeb11aaf.a6e78"]]},{"id":"eeb11aaf.a6e78","type":"function","z":"396c09ba.0b87e6","name":"","func":"if (msg.payload == \"off\"){\n    msg.payload = 0;\n}\nelse{\n    brightness = msg.data.attributes.brightness;\n    if (brightness == null){\n        brightness = 0\n    }\n    msg.payload = brightness;\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":540,"wires":[["c971a203.7c5f"]]},{"id":"217472f.ad9218e","type":"mqtt-broker","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""},{"id":"188ccb03.2ae3b5","type":"server","name":"Home Assistant","addon":true}]

Forgive me, I'm a bit confused. You seem to reply to me when you seem to want to use another members approach, which is fine, but what are you trying to achieve? Have you looked at my approach on the second flow in my first comment? Maybe we're just talking past each other, so here is more in depth what my "concept" is about. Maybe I just wasn't clear enough. Maybe you can tell me at which step my thought process starts to deviate from yours, or if I got it all wrong. Maybe ask the other person about it, perhaps they can help you more.

It gets imported as a new flow...

[{"id":"e38dbb3a.cdd128","type":"subflow","name":"short long times","info":"","category":"","in":[{"x":40,"y":80,"wires":[{"id":"477f641c.1f309c"}]}],"out":[{"x":360,"y":80,"wires":[{"id":"477f641c.1f309c","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"477f641c.1f309c","type":"function","z":"e38dbb3a.cdd128","name":"short long times","func":"const pushed = env.get(\"pushed\");\nconst released = env.get(\"released\");\nclearTimeout(context.retouchTimer);\nmsg.timespushed = context.get(\"count\") || 0;\nif(msg.payload === pushed) context.set(\"count\", msg.timespushed +=1);\nelse if(msg.payload !== released) return null;\nif(!msg.timespushed) {\n    msg.timespushed = context.get(\"lastlongpress\");\n    msg.longpress = true;\n    return msg;\n}\ncontext.retouchTimer = setTimeout(function() {\n    context.set(\"count\", 0);\n    msg.longpress = msg.payload === pushed;\n    if(msg.longpress) context.set(\"lastlongpress\", msg.timespushed);\n    else msg.payload = pushed;\n    node.send(msg, false);\n}, env.get(\"awaitRetouch\") || 600);\n","outputs":1,"noerr":0,"x":190,"y":80,"wires":[[]],"outputLabels":["short"],"icon":"node-red/timer.svg"},{"id":"180442f7.70de1d","type":"tab","label":"As detailed as it gets","disabled":false,"info":""},{"id":"65be4757.a5206","type":"mqtt in","z":"180442f7.70de1d","name":"","topic":"shellies/shellydimmer2-/input/0","qos":"2","datatype":"auto","broker":"4665a0b7.9250b","x":250,"y":400,"wires":[["ea6965a5.f8cba8"]]},{"id":"c97f0f10.2106f","type":"comment","z":"180442f7.70de1d","name":"STEP 1 : Input and prepare for further processing","info":"","x":280,"y":240,"wires":[]},{"id":"47923019.b41a88","type":"comment","z":"180442f7.70de1d","name":"I don't have shelly products, so I don't know what it spits out","info":"","x":320,"y":340,"wires":[]},{"id":"57ef1e7.014166","type":"comment","z":"180442f7.70de1d","name":"Have a look at the full msg object with the debug node","info":"","x":320,"y":600,"wires":[]},{"id":"d4969161.69fd68","type":"comment","z":"180442f7.70de1d","name":"Check that the input is there and clean (debounced)","info":"","x":340,"y":640,"wires":[]},{"id":"f1cbc266.741fa","type":"comment","z":"180442f7.70de1d","name":"If its not like an mqtt node, see where the button state information is and what it looks like","info":"","x":420,"y":760,"wires":[]},{"id":"c6f218b9.a14268","type":"comment","z":"180442f7.70de1d","name":"If it's not in msg.payload move it there:","info":"","x":310,"y":800,"wires":[]},{"id":"53f0dcd5.1198f4","type":"comment","z":"180442f7.70de1d","name":"Maybe check how the response time looks like","info":"","x":330,"y":680,"wires":[]},{"id":"2b21bf45.c80fc8","type":"comment","z":"180442f7.70de1d","name":"STEP 2 : Filter the Input (optional) ","info":"","x":980,"y":240,"wires":[]},{"id":"69926259.abac04","type":"comment","z":"180442f7.70de1d","name":"Maybe change the input to your needs:","info":"","x":310,"y":920,"wires":[]},{"id":"ea6965a5.f8cba8","type":"function","z":"180442f7.70de1d","name":"debounce","func":"// basic debounce function\n// define time span in next line\nconst debounceTime = 80;    // in Milliseconds\n\nclearTimeout(context.debounce);\ncontext.debounce = setTimeout(function() {\n    node.send(msg, false);\n}, debounceTime);\n","outputs":1,"noerr":0,"x":950,"y":400,"wires":[["8e9fc4f6.e4e918"]]},{"id":"8e9fc4f6.e4e918","type":"rbe","z":"180442f7.70de1d","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":1120,"y":400,"wires":[["d1e7dd86.9c0a5"]]},{"id":"11036b37.b9d385","type":"comment","z":"180442f7.70de1d","name":"If the hardware doesn't do it or you can't config it in your input node","info":"","x":1130,"y":340,"wires":[]},{"id":"34190ef.9111372","type":"comment","z":"180442f7.70de1d","name":"google switch bouncing to know more","info":"","x":1010,"y":460,"wires":[]},{"id":"4c7d6b5e.ace0a4","type":"comment","z":"180442f7.70de1d","name":"STEP 3 : does the press counting within time frame or else  calls it a long press","info":"","x":1900,"y":240,"wires":[]},{"id":"d1e7dd86.9c0a5","type":"function","z":"180442f7.70de1d","name":"short long times","func":"const pushed = \"1\";        // define payload to be interpreted as push button pushed \nconst released = \"0\";     // define payload to be interpreted as push button released\nconst awaitRetouch = 600;   // milliseconds to wait for a button state change before output\n\nclearTimeout(context.retouchTimer);\nmsg.timespushed = context.get(\"count\") || 0;\nif(msg.payload === pushed) context.set(\"count\", msg.timespushed +=1);\nelse if(msg.payload !== released) return null;\nif(context.get(\"lastlongpress\")) {  // long released\n    msg.timespushed = context.get(\"lastlongpress\");\n    context.set(\"lastlongpress\", 0);\n    msg.longpress = true;\n    return msg;\n}\ncontext.retouchTimer = setTimeout(function() {\n    context.set(\"count\", 0);\n    msg.longpress = msg.payload === pushed;\n    if(msg.longpress) context.set(\"lastlongpress\", msg.timespushed);\n    else{                           // short released\n        msg.payload = pushed;\n        // node.send(msg);             // uncomment to send a fake ...\n        // msg.payload = released;     // ... short released if needed\n    }\n    node.send(msg, false);\n}, awaitRetouch);\n","outputs":1,"noerr":0,"x":1740,"y":400,"wires":[["88772d2.30ff55"]]},{"id":"f25035de.ed90e8","type":"comment","z":"180442f7.70de1d","name":"if you don't need it skip step 2 (remove them)","info":"","x":1030,"y":500,"wires":[]},{"id":"60fbae8a.c662","type":"comment","z":"180442f7.70de1d","name":"change the first 3 lines in the node to fit your input, thats it!","info":"","x":1840,"y":340,"wires":[]},{"id":"7dd14553.0157f4","type":"change","z":"180442f7.70de1d","name":"","rules":[{"t":"move","p":"deviceInfo.buttonState","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":710,"y":800,"wires":[["d47d7b2f.c8874"]]},{"id":"d47d7b2f.c8874","type":"switch","z":"180442f7.70de1d","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"my Finger is on the Button","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":600,"y":920,"wires":[["97d9c28a.bbb68","e284933b.0e90a"],["2ef9afc.a9055d","ddf6f8e4.be6b8"]]},{"id":"2ef9afc.a9055d","type":"change","z":"180442f7.70de1d","name":"pushed","rules":[{"t":"set","p":"payload","pt":"msg","to":"pushed","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":920,"wires":[[]]},{"id":"97d9c28a.bbb68","type":"change","z":"180442f7.70de1d","name":"released","rules":[{"t":"set","p":"payload","pt":"msg","to":"released","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":910,"y":960,"wires":[[]]},{"id":"566d835c.f8fc84","type":"comment","z":"180442f7.70de1d","name":"if you intend to reuse it in your flows you may alternatively use the subflow from my example:","info":"","x":1950,"y":640,"wires":[]},{"id":"f22604e5.e331c8","type":"subflow:e38dbb3a.cdd128","z":"180442f7.70de1d","name":"","env":[{"name":"pushed","value":"1","type":"num"},{"name":"released","value":"0","type":"num"},{"name":"awaitRetouch","value":"1500","type":"num"}],"x":2460,"y":640,"wires":[[]]},{"id":"4c47606c.435638","type":"comment","z":"180442f7.70de1d","name":"just double click  on it and click on Environment Variables to configure","info":"","x":1890,"y":700,"wires":[]},{"id":"895a0c16.1ab74","type":"comment","z":"180442f7.70de1d","name":"you said something about 1 and 0 and 1/0 ?","info":"","x":1810,"y":460,"wires":[]},{"id":"3280d6e5.50033a","type":"comment","z":"180442f7.70de1d","name":"If type string \"1\" '0' doesn't work try number 1 0","info":"","x":1850,"y":500,"wires":[]},{"id":"a5139eb3.b43a38","type":"comment","z":"180442f7.70de1d","name":"that will set it for this node instance","info":"","x":1800,"y":740,"wires":[]},{"id":"49aad3f.48c38ac","type":"comment","z":"180442f7.70de1d","name":"the benefit of this is you can change things on an per instance basis","info":"","x":1910,"y":780,"wires":[]},{"id":"b774d80.c3a59a8","type":"comment","z":"180442f7.70de1d","name":"but you can also change things for all subflows by editing the template e.g.:","info":"","x":1930,"y":880,"wires":[]},{"id":"68297932.c877e8","type":"comment","z":"180442f7.70de1d","name":"stuff step 2 in it if you always have the same inputs","info":"","x":1920,"y":920,"wires":[]},{"id":"9cb5b0cd.7b706","type":"comment","z":"180442f7.70de1d","name":"or step 4 if you always use the same nuber of outputs (presses)","info":"","x":1960,"y":960,"wires":[]},{"id":"e284933b.0e90a","type":"change","z":"180442f7.70de1d","name":"pushed","rules":[{"t":"set","p":"payload","pt":"msg","to":"pushed","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":840,"y":1000,"wires":[[]]},{"id":"ddf6f8e4.be6b8","type":"change","z":"180442f7.70de1d","name":"released","rules":[{"t":"set","p":"payload","pt":"msg","to":"released","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":950,"y":880,"wires":[[]]},{"id":"5971c70b.dc00b","type":"comment","z":"180442f7.70de1d","name":"or just set the time frame for all by writing it right into it","info":"","x":1930,"y":1000,"wires":[]},{"id":"ae8a11cc.39255","type":"comment","z":"180442f7.70de1d","name":"i.e. each subflow node - different settings","info":"","x":1880,"y":820,"wires":[]},{"id":"d831f658.61aea","type":"comment","z":"180442f7.70de1d","name":"STEP 4 : extract the info that the last node added to the msg object","info":"","x":2960,"y":240,"wires":[]},{"id":"88772d2.30ff55","type":"switch","z":"180442f7.70de1d","name":"last press long","property":"longpress","propertyType":"msg","rules":[{"t":"false"},{"t":"true"}],"checkall":"false","repair":false,"outputs":2,"x":2880,"y":400,"wires":[["eedd4628.abcbf8"],["93337500.ff1e68"]]},{"id":"54a8be14.34af28","type":"comment","z":"180442f7.70de1d","name":"was the last press a long one?","info":"","x":2880,"y":340,"wires":[]},{"id":"97586743.7333c","type":"comment","z":"180442f7.70de1d","name":"NO","info":"","x":3120,"y":400,"wires":[]},{"id":"26920a2b.16ca4e","type":"comment","z":"180442f7.70de1d","name":"YES","info":"","x":3020,"y":480,"wires":[]},{"id":"eedd4628.abcbf8","type":"switch","z":"180442f7.70de1d","name":"times pushed","property":"timespushed","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"eq","v":"4","vt":"str"},{"t":"gte","v":"5","vt":"num"}],"checkall":"false","repair":false,"outputs":5,"x":3770,"y":400,"wires":[["e6caf836.f914f8"],[],[],[],[]]},{"id":"93337500.ff1e68","type":"switch","z":"180442f7.70de1d","name":"times pushed","property":"timespushed","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"eq","v":"4","vt":"str"},{"t":"gte","v":"5","vt":"num"}],"checkall":"false","repair":false,"outputs":5,"x":3250,"y":640,"wires":[["bfb76ef7.ea8258"],[],[],[],[]]},{"id":"a48837d0.cde9f8","type":"comment","z":"180442f7.70de1d","name":"How many times was it pressed shortly","info":"","x":3850,"y":340,"wires":[]},{"id":"9070ec49.1eb5b","type":"comment","z":"180442f7.70de1d","name":"you can easy change the number of outputs here","info":"","x":3880,"y":460,"wires":[]},{"id":"b26f8d5a.4f374","type":"comment","z":"180442f7.70de1d","name":"How many times was it pressed before (including the last long one)","info":"","x":3420,"y":540,"wires":[]},{"id":"630156f4.836078","type":"comment","z":"180442f7.70de1d","name":"my point is, there is no fixed order and you can freely change things if you, like don't need stuff","info":"","x":3100,"y":740,"wires":[]},{"id":"1a8dc298.1f9415","type":"comment","z":"180442f7.70de1d","name":"do something on a long press here like dimming","info":"","x":2940,"y":520,"wires":[]},{"id":"ff751329.cdc9c8","type":"comment","z":"180442f7.70de1d","name":"do something on a short press here like switching on or off","info":"","x":3410,"y":400,"wires":[]},{"id":"961bc3e8.09e9a","type":"comment","z":"180442f7.70de1d","name":"you don't need that info? remove that node","info":"","x":3350,"y":580,"wires":[]},{"id":"42c2e925.710d1","type":"comment","z":"180442f7.70de1d","name":"quantic universe 101","info":"Don't take it too serious...","x":610,"y":980,"wires":[]},{"id":"a08efeb6.ca398","type":"comment","z":"180442f7.70de1d","name":"STEP 5 : Do stuff","info":"","x":4320,"y":220,"wires":[]},{"id":"8797d411.962be8","type":"comment","z":"180442f7.70de1d","name":"I already gave quite some raw examples of how one can approach this step","info":"","x":4500,"y":260,"wires":[]},{"id":"7c327edd.ed46d","type":"comment","z":"180442f7.70de1d","name":"but it ultimately depends on STEP 6 : Output","info":"","x":4490,"y":320,"wires":[]},{"id":"ecf0d416.b26ee","type":"comment","z":"180442f7.70de1d","name":"or more specifically, what the output expects to recive to make it work","info":"","x":4570,"y":360,"wires":[]},{"id":"1cb943aa.fd9dc4","type":"comment","z":"180442f7.70de1d","name":"I don't know that!","info":"","x":4440,"y":400,"wires":[]},{"id":"1aceddf8.5bd262","type":"function","z":"180442f7.70de1d","name":"what does it expect? this?","func":"node.status(msg.payload.toString());\nmsg.payload = {data: {\"brightness\": msg.payload, \"transition\": 1} };\nreturn msg;\n","outputs":1,"noerr":0,"x":4600,"y":860,"wires":[["c06d2fc1.90c598"]]},{"id":"e6caf836.f914f8","type":"function","z":"180442f7.70de1d","name":"toggle light","func":"if(msg.payload === \"1\") {\n    msg.payload = context.get(\"lastoutput\") === \"on\" ? \"off\" : \"on\";\n    context.set(\"lastoutput\", msg.payload);\n    node.status(msg.payload === \"on\" ? {fill:\"yellow\",shape:\"dot\",text:\"ON\"} : {fill:\"grey\",shape:\"ring\",text:\"OFF\"});\n    return msg;\n}\n","outputs":1,"noerr":0,"x":4290,"y":780,"wires":[["a038860f.85463"]]},{"id":"c06d2fc1.90c598","type":"debug","z":"180442f7.70de1d","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":4850,"y":820,"wires":[]},{"id":"bdb87bc7.828c7","type":"comment","z":"180442f7.70de1d","name":"pure guesswork here:","info":"","x":4030,"y":760,"wires":[]},{"id":"a038860f.85463","type":"function","z":"180442f7.70de1d","name":"what does it expect for on/off ?","func":"\n\nreturn msg;\n","outputs":1,"noerr":0,"x":4600,"y":780,"wires":[["c06d2fc1.90c598"]]},{"id":"bfb76ef7.ea8258","type":"function","z":"180442f7.70de1d","name":"whats your 50% value?","func":"const value = 120;  // ????\n\nif(msg.topic === \"brightness\") {\n    context.set(msg.topic, msg.payload);    // stores last brightness\n    return null;\n}\nif(msg.payload === \"1\") {   // pushed\n    if(context.get(\"brightness\")) {\n        msg.payload = context.get(\"brightness\") < value ? \"inc\" : \"dec\";\n    }else msg.payload = \"inc\";      // first dimming action\n}else msg.payload = \"stop\";\nreturn msg;\n","outputs":1,"noerr":0,"x":4050,"y":860,"wires":[["daa7d37d.e666a"]]},{"id":"17e9cb20.79db6d","type":"change","z":"180442f7.70de1d","name":"brightness","rules":[{"t":"set","p":"topic","pt":"msg","to":"brightness","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":4310,"y":940,"wires":[["bfb76ef7.ea8258"]]},{"id":"daa7d37d.e666a","type":"time-based-dimmer","z":"180442f7.70de1d","name":"","interval":"50","step":"1","minValue":"90","maxValue":"150","startIncCommand":"inc","stopIncCommand":"stop","startDecCommand":"dec","stopDecCommand":"stop","x":4290,"y":860,"wires":[["1aceddf8.5bd262","17e9cb20.79db6d"]]},{"id":"4665a0b7.9250b","type":"mqtt-broker","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""}]

Hello,

Very new to node red to be honest first flow.
This is the exact project i am looking to do.
I get the basics (i think) but i cannot figure out 2 thing.

  1. The code you all add at the bottom of your project, how do i use that or what is it for.
  2. I cannot figure out how to get the counter to work.

thank you if you are willing to revive this old tread to help me.