# Another subflow I made for use with \`button\` nodes

**URL:** <https://discourse.nodered.org/t/another-subflow-i-made-for-use-with-button-nodes/46955>\
**Category:** Share Your Nodes\
**Created:** [10 June 2021 01:53 UTC](https://discourse.nodered.org/t/another-subflow-i-made-for-use-with-button-nodes/46955 "2021-06-10T01:53:38Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)\
**Post date:** [10 June 2021 01:53 UTC](https://discourse.nodered.org/t/another-subflow-i-made-for-use-with-button-nodes/46955/1 "2021-06-10T01:53:38Z")

</div>

This is another subflow to use with `button` nodes. Though you could use other ones, I am sticking to the basic idea of a _button_ and accidentally pressing it.

The _button_ has two states: ON and OFF.  
For me that is used to control a `gate` node to stop / allow messages to pass.

Rather than having TWO buttons, I have one.

It has **3** states.  
1 - idle / disabled.  
2 - on / disabled.  
3 - off / disabled.

Though it has a couple of extra intermediate states too.

Starting at _Square 1_:  
It is either ON or OFF.  
You want to change it.

You press the button.  
It changes colour (background).  
Within 3 seconds you press it again and the text and background colour change, indicating the new state.  
After 3 seconds it goes back to the original background colour but the text has changed.

Meanwhile a message was sent to control (in my usage case) the state of the `gate` node.

It needs to be configured / set up at boot.  
This is done by sending a _special_ message with the `topic` set to `SETUP`.

The structure is described in the documentation of the node.

````auto
[{"id":"ce274e69.c6f778","type":"subflow","name":"Button toggle with enable","info":"/ **\n* Used to help toggle `button` node state to give a nicer look to the `button`.\n* \n* @version 0.1.0\n* @auther Andrew\n*/\n\n/** \n* Before use the node needs a `setup` message sent to it to configure things.\n* The structure is shown below.\n*/\n\n/**\n* At the end there is a bit on how to use the node.\n*/\n\nStructure (eg):\n```\nmsg = {\n \"topic\":\"SETUP\",\n \"disabledColour\":\"brown\",\n \"colourA\": \"lime\",\n \"txtA\": \"Log\",\n \"txtclrA\": \"black\",\n \"payloadA\": \"GO\",\n \"colourB\": \"green\",\n \"txtB\": \"Stop\",\n \"txtclrB\": \"black\",\n \"payloadB\": \"STOP\",\n \"topicSET\": \"CONTROL\"\n}\nreturn msg;\n```\n\nBreakdown of lines:\n\n```\ndisabledColour - the colour the button is when disabled.\n```\nThis is the background colour of the button which will be seen the most.\nThis is when you have selected the state you want and the button is *disabled*\n\n```\ncolourA - the background colour if condition `A` is selected. (Temporary)\n```\nThis colour is shown at the background colour when option `A` is the one selected.\n\n```\ncolourB - the background colour if condition `B` is selected. (Temporary)\n```\nThis colour is shown at the background colour when option `B` is the one selected.\n\n```\ntxtA - The text to display if condition `A` is selected.\n```\nThis is the text shown when option `A` is selected.\n\n```\ntxtB - The text to display if condition `B` is selected.\n```\nThis is the text shown when option `B` is selected.\n\n```\ntxtclrA - the colour of the text if condition `A` is selected.\n```\nThis is the text colour used when option `A` is selected.\n\n```\ntxtclrB - the colour of the text if condtion `B` is selected.\n```\nThis is the text colour used when option `B` is selected.\n\n```\npayloadA - the text sent to the `gate` if condtion `A` is selected.\n```\nThis is the message output to the flow when option `A` is selected.\n\n```\npayloadB - the text sent to the `gate` if condition `B` is selected.\n```\nThis is the message output to the flow when option `B` is selected.\n\n```\ntopicSET - the message topic which is sent to the `gate`.\n```\nThis is needed if you are sending the message to a `gate` node as they need a\nspecific `topic` to be set to indicate the message is for them.\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 to press/toggle the button once initially pressed.\n\n/**\n* **USING THE NODE:** \n* \n* **INPUT** \n* The input is connected to the `button`'s output. (Note: The button must send `X` when pressed, and not send the input to the ouput.)\n* The `button` node must be configured as so:\n* `Label` set to `{{msg.txt}}`\n* `Colour` set to `{{msg.fontclr}}`\n* `Background` set to `{{msg.colour}}`\n* `Payload` set to `X`\n* `if msg arrives on input, emulate a button click` NOT selected.\n* \n* **OUTPUTS** \n* The first one is used to control what is happening in the flow.\n* I use it to control `gate` nodes. (`node-red-contrib-simple-gate`)\n* \n* The second one goes back to the `button` input.\n*/\n","category":"","in":[{"x":190,"y":120,"wires":[{"id":"761936f2.605b3"},{"id":"475a3d05.9bbc34"}]}],"out":[{"x":560,"y":80,"wires":[{"id":"475a3d05.9bbc34","port":0}]},{"x":560,"y":160,"wires":[{"id":"475a3d05.9bbc34","port":1}]}],"env":[],"color":"#3FADB5","outputLabels":["To the `GATE` node. This is what gets things done.","To the `BUTTON` node"],"icon":"node-red-dashboard/ui_switch.png","status":{"x":560,"y":240,"wires":[{"id":"59a2a371.c4ee5c","port":0}]}},{"id":"475a3d05.9bbc34","type":"function","z":"ce274e69.c6f778","name":"Push Button","func":"// 2021 06 08 tidied up a lot of mess. Working now.\n// Rewriting this for subflow usability.\nmsg1 = {};\nvar state = context.get(\"STATE\")||0;\nvar enabled = context.get(\"ENABLED\")||0;\n\n// Use message with `topic` set to `SETUP` to set up values.\nif (msg.topic == \"SETUP\")\n{\n //\n // Background colours first.\n //\n context.set(\"ABGC\", msg.colourA);\n context.set(\"BBGC\", msg.colourB);\n //\n // Disabled button background colour.\n //\n context.set(\"DISABLEDCLR\",msg.disabledColour);\n //\n // Text to be displayed / used.\n //\n context.set(\"Atxt\", msg.txtA);\n context.set(\"Btxt\", msg.txtB);\n //\n // Font colours.\n //\n context.set(\"AFC\",msg.txtclrA);\n context.set(\"BFC\",msg.txtclrB);\n //\n // Payloads. (Used to get things done outside the subflow)\n //\n context.set(\"PayloadA\", msg.payloadA);\n context.set(\"PayloadB\", msg.payloadB);\n //\n // Topic.\n //\n if (msg.topicSET !== null)\n {\n context.set(\"Topic\",msg.topicSET);\n } else\n {\n context.set(\"Topic\",\"~\");\n }\n // To control the state of the `gate` node.\n msg.payload = context.get(\"PayloadA\");\n msg.topic = context.get(\"Topic\");\n // To set the `button` colour/text/etc.\n msg1.txt = context.get(\"Atxt\");\n msg1.colour = context.get(\"DISABLEDCLR\");\n msg1.fontclr = context.get(\"AFC\");\n\n return [msg,msg1];\n}\n\n// Normal operation of the node.\nif (msg.payload == \"X\")\n{\n // Abort if context values are not set.\n if (context.get(\"PayloadA\") == undefined)\n {\n node.status({text:\"Button_Toggle_Enable_Context_Not_Set\"});\n return [null,null];\n }\n //node.warn(\"X detected\");\n // Insert here code to enable other stuff.\n if (enabled === 0)\n {\n if (state === 0)\n {\n //\n // Set things for state 0\n //\n msg.payload = context.get(\"PayloadA\");\n msg.topic = context.get(\"Topic\");\n msg1.colour = context.get(\"ABGC\");\n msg1.txt = context.get(\"Atxt\");\n msg1.fontclr = context.get(\"AFC\");\n }\n else if (state === 1)\n {\n //\n // Set things for state 1\n //\n msg.payload = context.get(\"PayloadB\");\n msg.topic = context.get(\"Topic\");\n msg1.colour = context.get(\"BBGC\");\n msg1.txt = context.get(\"Btxt\");\n msg1.fontclr = context.get(\"BFC\");\n }\n context.set(\"ENABLED\",1);\n return [null,msg1];\n }\n\n state = (state + 1)% 2;\n context.set(\"STATE\",state);\n if (enabled === 1)\n {\n if (state === 0)\n {\n // Condition A\n msg.payload = context.get(\"PayloadA\");\n msg1.colour = context.get(\"ABGC\");\n msg1.txt = context.get(\"Atxt\");\n msg1.fontclr = context.get(\"AFC\");\n } else\n if (state === 1)\n {\n // Condition B\n msg.payload = context.get(\"PayloadB\");\n msg1.colour = context.get(\"BBGC\");\n msg1.txt = context.get(\"Btxt\");\n msg1.fontclr = context.get(\"BFC\");\n }\n }\n \n if (context.get(\"Topic\") == \"~\")\n {\n msg.topic = \"\";\n } else\n {\n msg.topic = context.get(\"Topic\");\n }\n return [msg,msg1];\n}\nif (msg.payload == \"Z\")\n{\n // Abort if context values are not set.\n if (context.get(\"PayloadA\") == undefined)\n {\n return [null,null];\n }\n context.set(\"ENABLED\",0);\n if (state === 0)\n {\n //\n // Set things for state 1\n //\n msg.payload = context.get(\"PayloadA\");\n msg.topic = context.get(\"Topic\");\n msg1.colour = context.get(\"DISABLEDCLR\");\n msg1.txt = context.get(\"Atxt\");\n msg1.fontclr = context.get(\"AFC\");\n }\n else if (state === 1)\n {\n //\n // Set things for state 2\n //\n msg.payload = context.get(\"PayloadB\");\n msg.topic = context.get(\"Topic\");\n msg1.colour = context.get(\"DISABLEDCLR\");\n msg1.txt = context.get(\"Btxt\");\n msg1.fontclr = context.get(\"BFC\");\n }\n return [null,msg1];\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","x":380,"y":120,"wires":[[],[]],"outputLabels":["To gate","To button"]},{"id":"4b9bf99.eb5f688","type":"trigger","z":"ce274e69.c6f778","name":"","op1":"","op2":"Z","op1type":"nul","op2type":"str","duration":"3","extend":false,"overrideDelay":false,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":445,"y":170,"wires":[["475a3d05.9bbc34"]],"l":false},{"id":"761936f2.605b3","type":"switch","z":"ce274e69.c6f778","name":"Block SETUP messages","property":"topic","propertyType":"msg","rules":[{"t":"neq","v":"SETUP","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":280,"y":170,"wires":[["4b9bf99.eb5f688"]]},{"id":"59a2a371.c4ee5c","type":"status","z":"ce274e69.c6f778","name":"","scope":["475a3d05.9bbc34"],"x":410,"y":240,"wires":[[]]},{"id":"9f3a3dc4.7e43e8","type":"subflow:ce274e69.c6f778","z":"7879609.4fb06a","name":"","env":[],"x":640,"y":110,"wires":[[],[]]}]

````

---

<div class="post-metadata">

**Author:** ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)\
**Post date:** [10 June 2021 06:35 UTC](https://discourse.nodered.org/t/another-subflow-i-made-for-use-with-button-nodes/46955/2 "2021-06-10T06:35:25Z")

</div>

Nice idea, that saves a lot of Dashboard space compared to 2 different buttons. 👍

Regarding the setup message: You could make these obsolete and use [subflow instance properties](https://nodered.org/blog/2019/03/12/version-0-20-released#subflow-instance-properties) instead. Those are available to your subflow as environment variables and you can configure these settings beforehand on each subflow instance. There's also a nice UI for them since NR 1.0, so subflows can be configured almost like normal nodes. 🤓

---

<div class="post-metadata">

**Author:** ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)\
**Post date:** [10 June 2021 09:42 UTC](https://discourse.nodered.org/t/another-subflow-i-made-for-use-with-button-nodes/46955/3 "2021-06-10T09:42:53Z")

</div>

The only _Problem_ with that is that the node needs an initial message anyway.

As is, when you send the _setup_ message, it sets up the `button` node to show the correct state too.

Doing it the way you suggest, there is no initial _message_ and so things aren't set.

Yeah, ok, you could just inject an `X` at boot anyway. But I can't see much benefit to using `env` variables to a _setup_ message.

---

<div class="post-metadata">

**Author:** ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)\
**Post date:** [10 June 2021 10:02 UTC](https://discourse.nodered.org/t/another-subflow-i-made-for-use-with-button-nodes/46955/4 "2021-06-10T10:02:43Z")

</div>

It was just a suggestion. 😉

Of course, an initial message with the current state is required, most likely that would originate from a retained mqtt message or something similar. But everything else that is more or less static could be done in the properties.

---

<div class="post-metadata">

**Author:** ![Trying\_to\_learn](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/trying_to_learn/32/28400_2.png) [@Trying\_to\_learn](https://discourse.nodered.org/u/Trying_to_learn)\
**Post date:** [10 June 2021 10:06 UTC](https://discourse.nodered.org/t/another-subflow-i-made-for-use-with-button-nodes/46955/5 "2021-06-10T10:06:25Z")

</div>

No worries.

I am still at the shallow end of the learning curve and when I was learning programming, that sort of thing didn't exist.

So I wrote it the only way I know.

I am trying to do it, but it isn't quite working.

Well, the _original_ message is/could be what is preferred. So when you `deploy` the flow, it gets what you want as the default.

Basically the `A` options are the one to be used as the default.

The other thing which is tripping me is the initial message doesn't get the _disabled_ message/colour coming through.
