Status of a dashboard button

Hello everyone,
I integrated buttons into my dashboard.
The default state of the button if I use a boolean is :

  • a click on button sends an output "true" for example and a "false" output when you release the click

Can we obtain the following situation :

  • a click on the button sends a "true" output and remains "true" when I release the click. When I press the same button again, it changes to "false" and so on...

Merci d'avance pour votre aide.

What button widget did you use?

My understanding of the default button widget, dashboard v1 and v2, is that it sends a message when it is released. Nothing on click.

I use the button to cut off power to a pump.
Capture
The button must be in "true" by default for the pump to work and I can switch it to "false" so that the pump stops in order to intervene on the circuit for an indefinite time.

Maybe use a ui-switch node rather than a button?

Yes, that's the solution, I didn't know if it was possible with the button node to configure it differently.

You could write code to store the current status in a context variable and toggle it whenever the button sends a message.
Either a function node or a couple of change nodes should work.

I think I found something on the link below :

https://nodered.org/docs/creating-nodes/appearance

Can we make it so that the switch node can go to the on state by default when starting nodered ?

Connect an inject node firing on startup to put it in that state.

Thanks, it works well :+1:

Just if you are interested....

I wrote a subflow to do something like that.

[{"id":"ce274e69.c6f778","type":"subflow","name":"Button toggle with enable","info":"Update 2024 06 08\n======\n\nEdited so you can set the start mode.\nA/B\nHUGE rewrite to get code working correctly.\n\nsend \"RESET\" as `msg.payload` and the `startOn`\nsetting will be reloaded.\nsend \"RELOAD\" as `msg.payload` and the state of\nthe node will be resent to the `button` node.\n(NO output sent)\n\nUpdate 2023 09 03\n------\n\nNow fixed.\n`trigger` node not set to accept `msg.delay`\n\n\nUpdate 2022 02 21\n------\n\nTo initialise the node send a message of `Z` into the input.\n\nIf you want a specific ouptut:\n`A` sets the mode to what the `a` named messages indicate.\n\n`B` sets the mode to what the `b` named messages indicate.\n\nThe output from the `button` node must be `X` to toggle the state, and the button must NOT pass the input onto the output!\n\nYou MUST set the `environment` variables listed below or it won't work.\n(Example)\n```\nmode: (0/1) (see below)\nStartOn:  either A or B (the two conditions)\ndisabledColour: brown\ndisabledTXT:  something\ncolourA: lime\ncolourB: green\ntxtA: Log\ntxtB: Stop\ntxtclrA: black\ntxtclrB: black\npayloadA: GO\npayloadB: STOP\ntopicSET: CONTROL\ndelay: 800\n```\n```\nmode - toggle mode or single mode (0/1).\nThis means in toggle mode you get 2 output messages.\nSingle mode you only get one output message.\n```\n```\ndelay - (optional)  millisecond delay for time button is active.\n```\n```\ndisabledColour - the colour the button is when disabled.\n```\n```\ndisabledTXT - This is used when the `mode` is set to `1`.  The text is displayed by default.\n```\n```\ncolourA - the background colour if condition `A` is selected.  (Temporary)\n```\n```\ncolourB - the background colour if condition `B` is selected.  (Temporary)\n```\n```\ntxtA - The text to display if condition `A` is selected.\n```\n```\ntxtB - The text to display if condition `B` is selected.\n```\n```\ntxtclrA - the colour of the text if condition `A` is selected.\n```\n```\ntxtclrB - the colour of the text if condtion `B` is selected.\n```\n```\npayloadA - the text sent to the output if condtion `A` is selected.\n```\n```\npayloadB - the text sent to the output if condition `B` is selected.\n```\n```\nThese payloads can then be used to set context values or used to control (external node) `gate`\n```\n```\ntopicSET - the message topic which is sent to the `gate`.\n(this is needed if/when used to control the afore mentioned `gate` nodes.)\n```\n\nThe *temporary* meaning is that the button will show that colour for a few seconds\nthen it will turn to the `disabled` colour.\n\nThe active time is `3` seconds (adjustable via the `delay` value) to press/toggle the button once initially pressed.\nNow: if you keep pressing the button, it will *wait* until you finish pressing it.\n\nThe background colours (and text colours) apply to the `button` node (or other) that is pressed.\nThat node must be configured to allow inputs of `{{msg.txt}}`, `{{msg.colour}}` and `{{mdg.fontclr}}`.\n\n****\nFoot note:\n`msg.payload = \"0/1\"` `msg.toic = \"D\"`\nToggles debug mode.","category":"","in":[{"x":190,"y":260,"wires":[{"id":"c43c865d57f36958"},{"id":"e8e0b354f6fd8938"}]}],"out":[{"x":930,"y":220,"wires":[{"id":"c43c865d57f36958","port":0}]},{"x":950,"y":300,"wires":[{"id":"c43c865d57f36958","port":1}]}],"env":[{"name":"delay","type":"num","value":"","ui":{"type":"input","opts":{"types":["num"]}}},{"name":"StartOn","type":"str","value":"","ui":{"label":{"en-US":"StartCond"},"type":"input","opts":{"types":["str"]}}},{"name":"mode","type":"num","value":""},{"name":"disabledColour","type":"str","value":""},{"name":"disabledTXT","type":"str","value":""},{"name":"colourA","type":"str","value":""},{"name":"colourB","type":"str","value":""},{"name":"txtA","type":"str","value":""},{"name":"txtB","type":"str","value":""},{"name":"txtclrA","type":"str","value":""},{"name":"txtclrB","type":"str","value":""},{"name":"payloadA","type":"str","value":""},{"name":"payloadB","type":"str","value":""},{"name":"topicSET","type":"str","value":""}],"meta":{},"color":"#3FADB5","outputLabels":["To the `GATE` node","To the `BUTTON` node"],"icon":"node-red-dashboard/ui_switch.png","status":{"x":860,"y":380,"wires":[{"id":"4d8b7aa6.6af80c","port":0}]}},{"id":"4d8b7aa6.6af80c","type":"status","z":"ce274e69.c6f778","name":"","scope":["c43c865d57f36958"],"x":590,"y":380,"wires":[[]]},{"id":"c43c865d57f36958","type":"function","z":"ce274e69.c6f778","name":"Push Button","func":"//  ----    Assign variable names to ENV variables.\n//  all future use of variables is by their names below.\n//  These are the userdefined variables from ENV\nconst INPUT = msg.payload;\n//var mode = env.get(\"mode\");\nvar mode = parseInt(env.get(\"mode\"));\nconst Disabledcolour = env.get(\"disabledColour\");\nconst disabledTXT = env.get(\"disabledTXT\");\nconst colourA = env.get(\"colourA\");\nconst colourB = env.get(\"colourB\");\nconst txtA = env.get(\"txtA\");\nconst txtB = env.get(\"txtB\");\nconst txtclrA = env.get(\"txtclrA\");\nconst txtclrB = env.get(\"txtclrB\");\nconst payloadA = env.get(\"payloadA\");\nconst payloadB = env.get(\"payloadB\");\nlet topic = env.get(\"topicSET\");\nif (topic === undefined)\n    topic = \"\";\n\n//  These are other variables\nlet state = context.get(\"STATE\")||0;\nlet enabled = context.get(\"ENABLED\")||0;\nconst msg1 = {};\n\n\n//--------------------------------------------\n\n\nif (msg.topic === \"D\")\n{\n    context.set(\"DEBUG\",msg.payload);\n    //  Show env \n    node.warn(\"Disabled colour \" + Disabledcolour);\n    node.warn(\"Disabled text \" + disabledTXT);\n    node.warn(\"colourA \" + colourA);\n    node.warn(\"colourB \" + colourB); \n    node.warn(\"txtA \" + txtA);\n    node.warn(\"txtB \" + txtB);\n    node.warn(\"txtclrA \" + txtclrA);\n    node.warn(\"txtclrB \" + txtclrB);\n    node.warn(\"payloadA \" + payloadA);\n    node.warn(\"payloadB \" + payloadB);\n    node.warn(\"topic \" + topic);\n    return;\n}\n\nlet debug = context.get(\"DEBUG\") || 0;\n\nif (debug === 1)\n{\n    node.warn(\"INPUT \" + INPUT);\n    node.warn(\"Disabled colour \" + Disabledcolour);\n    node.warn(\"Disabled text \" + disabledTXT);\n    node.warn(\"colourA \" + colourA);\n    node.warn(\"colourB \" + colourB); \n    node.warn(\"txtA \" + txtA);\n    node.warn(\"txtB \" + txtB);\n    node.warn(\"txtclrA \" + txtclrA);\n    node.warn(\"txtclrB \" + txtclrB);\n    node.warn(\"payloadA \" + payloadA);\n    node.warn(\"payloadB \" + payloadB);\n    node.warn(\"topic \" + topic);\n}\n//--------------------------------------------\n\n//  Reload desired state\nif (INPUT == \"RESET\")\n{\n    // load startOn value.\n    msg.payload = env.get(\"StartOn\")\n}\n\nif (INPUT == \"RELOAD\")\n{\n    //  force redisplay for `button` node.\n    if (state == 0)\n    {\n        //\n        msg1.txt = txtA;\n        msg1.colour = Disabledcolour;\n        msg1.fontclr = txtclrA;\n        node.status({ fill: \"yellow\", text: \"A\" });\n    } else\n    if (state == 1)\n    {\n        //\n        msg1.txt = txtB;\n        msg1.colour = Disabledcolour;\n        msg1.fontclr = txtclrB;\n        node.status({ fill: \"red\", text: \"B\" });\n\n    }\n    return [null,msg1];\n}\n\n//  =========================================\n//  Set condition if the message is either A or B\n\nif (msg.payload === \"A\")\n{\n    msg.payload = payloadA;\n    msg.topic = topic;\n\n    msg1.txt = txtA;\n    msg1.colour = Disabledcolour;\n    msg1.fontclr = txtclrA;\n    node.status({ fill: \"yellow\", text: \"A\" });\n    \n    context.set(\"STATE\",0);\n\n    return [msg,msg1];\n}\n\nif (msg.payload === \"B\")\n{\n    msg.payload = payloadB;\n    msg.topic = topic;\n\n    msg1.txt = txtB;\n    msg1.colour = Disabledcolour;\n    msg1.fontclr = txtclrB;\n    node.status({ fill: \"red\", text: \"B\" });\n    \n    context.set(\"STATE\",1);\n\n    return [msg,msg1];\n}\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n//      Main routine below.\n//-------------------------------------\n//      Now on to the real stuff.\nif (msg.payload === \"X\")\n{\n    //\n    //  Button pressed.\n    //\n    node.status({fill: \"green\",text: \"Pressed\"});\n    if (enabled === undefined)\n    {\n        node.status({text:\"Button_Toggle_Enable_Context_Not_Set\"});\n        node.warn(\"Button toggle enable context not set\");\n        return [null,null];\n    }\n    if (enabled === 0)\n    {\n        //\n        node.status({ fill: \"blue\", text: \"enabled\" });\n        context.set(\"ENABLED\", 1);\n        if (state === 0)\n        {\n            //\n            //  Set things for state 0\n            //\n            msg1.colour = colourA;\n            msg1.txt = txtA;\n            msg1.fontclr = txtclrA;\n            //node.status({ fill: \"yellow\", text: \"A\" });\n        }\n        else \n        if (state === 1)\n        {\n            //\n            //  Set things for state 1\n            //\n            msg1.colour = colourB;\n            msg1.txt = txtB;\n            msg1.fontclr = txtclrB;\n            //node.status({ fill: \"red\", text: \"B\" });\n        }\n        return [null,msg1];\n    }\n    //  To here `enabled` === 0.  Now set to 1.\n    //-------------------------------------\n    //      ENABLED from here down.\n    if (enabled === 1)\n    {\n\n        state = (state + 1)% 2;\n        context.set(\"STATE\",state);\n\n        if (mode === 0)\n        {\n            //\n            //  Condition A\n            //\n            node.status({ fill: \"yellow\", text: \"A\" });\n            msg.payload = payloadA;\n            msg1.colour = colourA;\n            msg1.txt = txtA;\n            msg1.fontclr = txtclrA;\n        }   //  END FOR MODE === 0\n        //-------------------------------------\n        //  Code here for MODE === 1\n        if (mode === 1)\n        {\n            if (state === 0)\n            {\n                //\n                //  Condition A\n                //\n                node.status({fill: \"yellow\",text: \"A\"});\n                msg.payload = payloadA;\n                msg1.colour = colourA;\n                msg1.txt = txtA;\n                msg1.fontclr = txtclrA;\n            } else\n            if (state === 1)\n            {\n                //\n                //  Condition B\n                //\n                node.status({fill: \"red\",text: \"B\"});\n                msg.payload = payloadB;\n                msg1.colour = colourB;\n                msg1.txt = txtB;\n                msg1.fontclr = txtclrB;\n            }\n        }   //  END FOR MODE === 1\n    }\n    //-------------------------------------\n    msg.topic = topic;\n    return [msg,msg1];\n}\n//-------------------------------------\n\n//-------------------------------------\nif (msg.payload === \"Z\")\n{\n    //\n    //      Timed out\n    ////node.warn(\"Timed out\");\n    //\n    //-------------------------------------\n    context.set(\"ENABLED\",0);\n    if (mode === 0) {\n        //\n        //  Condition A\n        //\n        node.status({ text: \"\" });\n        context.set(\"STATE\", 0);\n        msg1.colour = Disabledcolour;\n        msg1.txt = disabledTXT;\n    }\n    //-------------------------------------\n\n    //-------------------------------------\n    if (mode === 1)\n    {\n        //node.status({text: \"\"});\n        if (payloadA === undefined)\n        {\n            //  This needs work.   Throw error?\n            return [null,null];\n        }\n        if (state === 0)\n        {\n            //\n            //  Set things for state 0\n            //\n            msg.payload = payloadA;\n            msg.topic = topic;\n            msg1.colour = Disabledcolour;\n            msg1.txt = txtA;\n            msg1.fontclr = txtclrA;\n            node.status({ fill: \"yellow\", text: \"A\" });\n        }\n        else if (state === 1)\n        {\n            //\n            //  Set things for state 1\n            //\n            msg.payload = payloadB;\n            msg.topic = topic;\n            msg1.colour = Disabledcolour;\n            msg1.txt = txtB;\n            msg1.fontclr = txtclrB;\n            node.status({ fill: \"red\", text: \"B\" });\n        }\n    }\n    //-------------------------------------\n    return [null,msg1];\n}\n//-------------------------------------\n","outputs":2,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\n\ncontext.set(\"ABGC\", env.get(\"colourA\"));\ncontext.set(\"BBGC\", env.get(\"colourB\"));\n//\n//  Disabled button background colour.\n//\ncontext.set(\"DISABLEDCLR\",env.get(\"disabledColour\"));\n//\n//  Now do text.\n//\ncontext.set(\"Atxt\", env.get(\"txtA\"));\ncontext.set(\"Btxt\", env.get(\"txtB\"));\n//\n//  Font colours.\n//\ncontext.set(\"AFC\",env.get(\"txtclrA\"));\ncontext.set(\"BFC\",env.get(\"txtclrB\"));\n//\n//  Payloads.\n//\ncontext.set(\"PayloadA\", env.get(\"payloadA\"));\ncontext.set(\"PayloadB\", env.get(\"payloadB\"));\n\n","finalize":"","libs":[],"x":600,"y":260,"wires":[[],[]],"outputLabels":["To gate","To button"]},{"id":"ce88ca05dfbfc987","type":"trigger","z":"ce274e69.c6f778","name":"","op1":"","op2":"Z","op1type":"nul","op2type":"str","duration":"3","extend":true,"overrideDelay":true,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":425,"y":370,"wires":[["c43c865d57f36958"]],"l":false},{"id":"e8e0b354f6fd8938","type":"switch","z":"ce274e69.c6f778","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"X","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":305,"y":370,"wires":[["f3f9aaf11f719403"]],"l":false},{"id":"f3f9aaf11f719403","type":"function","z":"ce274e69.c6f778","name":"set msg.delay","func":"msg.delay = env.get(\"delay\") || 1000;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":365,"y":370,"wires":[["ce88ca05dfbfc987"]],"l":false},{"id":"c906d5b6e5da1f26","type":"inject","z":"ce274e69.c6f778","name":"Selected","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"StartOn","payloadType":"env","x":350,"y":170,"wires":[["c43c865d57f36958","f4758814ab1ca9b8"]]},{"id":"f4758814ab1ca9b8","type":"switch","z":"ce274e69.c6f778","name":"","property":"mode","propertyType":"env","rules":[{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":305,"y":330,"wires":[["f3f9aaf11f719403"]],"l":false},{"id":"7cca560378a25633","type":"subflow:ce274e69.c6f778","z":"60d0e3e966d484ae","name":"","x":450,"y":100,"wires":[[],[]]}]

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