Button node bug report. (Look at bottom)

This was working.

Not too old version of NR.

[{"id":"5dcb15fb.24d17c","type":"inject","z":"39ea4ac5.b46c1e","name":"Inject","repeat":"","crontab":"","once":true,"onceDelay":"3","topic":"","payload":"","payloadType":"str","x":420,"y":860,"wires":[["6272e4a0.8faa44"]]},{"id":"6272e4a0.8faa44","type":"function","z":"39ea4ac5.b46c1e","name":"Setup","func":"msg = {\n    \"topic\":\"SETUP\",\n    \"disabledColour\":\"brown\",\n    \"colourA\": \"lime\",\n    \"colourB\": \"green\",\n    \"txtA\": \"Log\",\n    \"txtB\": \"Log Stop\",\n    \"txtclrA\": \"black\",\n    \"txtclrB\": \"black\",\n    \"payloadA\": \"GO\",\n    \"payloadB\": \"STOP\",\n    \"topicSET\": \"CONTROL\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":420,"y":900,"wires":[["93f710a2.69e118"]]},{"id":"a999cdd7.d7fdc","type":"ui_button","z":"39ea4ac5.b46c1e","name":"Error Logging","group":"d057989d.1f3368","order":3,"width":"2","height":"1","passthru":false,"label":"{{msg.txt}}","tooltip":"","color":"{{msg.fontclr}}","bgcolor":"{{msg.colour}}","icon":"","payload":"X","payloadType":"str","topic":"","x":630,"y":860,"wires":[["93f710a2.69e118","763a7526.22a8f4"]]},{"id":"93f710a2.69e118","type":"function","z":"39ea4ac5.b46c1e","name":"Push Button","func":"//  working\nvar state = context.get(\"STATE\")||0;\nvar enabled = context.get(\"ENABLED\")||0;\n\n//  Look for a message with topic set to SETUP to set values.\nif (msg.topic == \"SETUP\")     //Do this if the message is NOT \"X\"\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    //  Now do text.\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.\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    msg.txt = msg.txtA;\n    msg.colour = msg.disabledColour;\n    msg.fontclr = msg.txtclrA;\n    return msg;\n}\n\n//      Now on to the real stuff.\nif (msg.payload == \"X\")\n{\n    //node.warn(\"X detected\");\n    //  Insert here code to enable other stuff.\n//    if (context.get(\"ENABLED\") === 0)\n    if (enabled === 0)\n    {\n        //\n        //  Old code.\n        //\n        //node.warn(\"Setting enable\");\n//        context.set(\"ENABLED\",1);\n//        msg.txt = context.get(\"Atxt\");\n//        msg.colour = context.get(\"ABGC\");\n//        msg.fontclr = context.get(\"AFC\");\n\n        //  New code.\n        \n        //node.warn(\"State = \" + state);\n\n        if (state === 0)\n        {\n            //\n            //  Set things for state 0\n            //\n            //node.warn(\"State 0 detected\");\n            msg.payload = context.get(\"PayloadA\");\n            msg.colour = context.get(\"ABGC\");\n            msg.txt = context.get(\"Atxt\");\n            msg.fontclr = context.get(\"AFC\");\n        }\n        else if (state === 1)\n        {\n            //\n            //  Set things for state 1\n            //\n            //node.warn(\"State 1 detected\");\n            msg.payload = context.get(\"PayloadB\");\n            msg.colour = context.get(\"BBGC\");\n            msg.txt = context.get(\"Btxt\");\n            msg.fontclr = context.get(\"BFC\");\n        }\n        context.set(\"ENABLED\",1);\n        return msg;\n    }\n\n//    if (context.get(\"ENABLED\") === 1)\n    state = (state + 1)% 2;\n    //node.warn(state);\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            msg.colour = context.get(\"ABGC\");\n            msg.txt = context.get(\"Atxt\");\n            msg.fontclr = context.get(\"AFC\");\n        } else\n        if (state === 1)\n        {\n            //  Condition B\n            msg.payload = context.get(\"PayloadB\");\n            msg.colour = context.get(\"BBGC\");\n            msg.txt = context.get(\"Btxt\");\n            msg.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;\n}\nif (msg.payload == \"Z\")\n{\n    //\n    ////node.warn(\"Timed out\");\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.colour = context.get(\"DISABLEDCLR\");\n        msg.txt = context.get(\"Atxt\");\n        msg.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.colour = context.get(\"DISABLEDCLR\");\n        msg.txt = context.get(\"Btxt\");\n        msg.fontclr = context.get(\"BFC\");\n    }\n    return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":620,"y":900,"wires":[["a999cdd7.d7fdc","1ddaae04.be6602"]]},{"id":"763a7526.22a8f4","type":"trigger","z":"39ea4ac5.b46c1e","name":"","op1":"","op2":"Z","op1type":"nul","op2type":"str","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","outputs":1,"x":610,"y":940,"wires":[["93f710a2.69e118"]]},{"id":"d057989d.1f3368","type":"ui_group","name":"Errors","tab":"41ad2f9a.ed0df","order":2,"disp":true,"width":"6","collapse":false},{"id":"41ad2f9a.ed0df","type":"ui_tab","name":"Logging","icon":"list","order":5,"disabled":false,"hidden":false}]

I updated the dashboard recently and things went awry.
Button versions: 2.26.2 and 2.28.1

Walk through of the code:

There is a button and it toggles between two messages indicating the mode.

The inject node is run at the start to set up the context of the function node (push button).

Break down of what I suspect:
The msg.topic is some how kept at setup when the button is pressed.
Though it is set to NOT pass through the message.

This code gets around the problem:

[{"id":"c5ccf203.8fff9","type":"inject","z":"39ea4ac5.b46c1e","name":"Inject","repeat":"","crontab":"","once":true,"onceDelay":"3","topic":"","payload":"","payloadType":"str","x":290,"y":440,"wires":[["a95c95ac.a0ab6"]]},{"id":"a95c95ac.a0ab6","type":"function","z":"39ea4ac5.b46c1e","name":"Setup","func":"msg = {\n    \"topic\":\"SETUP\",\n    \"disabledColour\":\"brown\",\n    \"colourA\": \"lime\",\n    \"colourB\": \"green\",\n    \"txtA\": \"Display\",\n    \"txtB\": \"Display Stop\",\n    \"txtclrA\": \"black\",\n    \"txtclrB\": \"black\",\n    \"payloadA\": \"GO\",\n    \"payloadB\": \"STOP\",\n    \"topicSET\": \"CONTROL\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":290,"y":480,"wires":[["e0d476a7.3e5e7"]]},{"id":"1d77a37e.a76b95","type":"ui_button","z":"39ea4ac5.b46c1e","name":"Commands RX List","group":"1baf0833.3ae918","order":1,"width":"2","height":"1","passthru":false,"label":"{{msg.txt}}","tooltip":"","color":"{{msg.fontclr}}","bgcolor":"{{msg.colour}}","icon":"","payload":"X","payloadType":"str","topic":"blah","topicType":"str","x":510,"y":440,"wires":[["e0d476a7.3e5e7","aa338cfc.ca1fd"]]},{"id":"e0d476a7.3e5e7","type":"function","z":"39ea4ac5.b46c1e","name":"Push Button","func":"var state = context.get(\"STATE\")||0;\nvar enabled = context.get(\"ENABLED\")||0;\n\n//  Look for a message with topic set to SETUP to set values.\nif (msg.topic == \"SETUP\")     //Do this if the message is NOT \"X\"\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    //  Now do text.\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.\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    msg.txt = msg.txtA;\n    msg.colour = msg.disabledColour;\n    msg.fontclr = msg.txtclrA;\n    return msg;\n}\n\n//      Now on to the real stuff.\nif (msg.payload == \"X\")\n{\n    //node.warn(\"X detected\");\n    //  Insert here code to enable other stuff.\n//    if (context.get(\"ENABLED\") === 0)\n    if (enabled === 0)\n    {\n        //\n        //  Old code.\n        //\n        //node.warn(\"Setting enable\");\n//        context.set(\"ENABLED\",1);\n//        msg.txt = context.get(\"Atxt\");\n//        msg.colour = context.get(\"ABGC\");\n//        msg.fontclr = context.get(\"AFC\");\n\n        //  New code.\n        \n        //node.warn(\"State = \" + state);\n\n        if (state === 0)\n        {\n            //\n            //  Set things for state 0\n            //\n            //node.warn(\"State 0 detected\");\n            msg.payload = context.get(\"PayloadA\");\n            msg.colour = context.get(\"ABGC\");\n            msg.txt = context.get(\"Atxt\");\n            msg.fontclr = context.get(\"AFC\");\n        }\n        else if (state === 1)\n        {\n            //\n            //  Set things for state 1\n            //\n            //node.warn(\"State 1 detected\");\n            msg.payload = context.get(\"PayloadB\");\n            msg.colour = context.get(\"BBGC\");\n            msg.txt = context.get(\"Btxt\");\n            msg.fontclr = context.get(\"BFC\");\n        }\n        context.set(\"ENABLED\",1);\n        return msg;\n    }\n\n//    if (context.get(\"ENABLED\") === 1)\n    state = (state + 1)% 2;\n    //node.warn(state);\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            msg.colour = context.get(\"ABGC\");\n            msg.txt = context.get(\"Atxt\");\n            msg.fontclr = context.get(\"AFC\");\n        } else\n        if (state === 1)\n        {\n            //  Condition B\n            msg.payload = context.get(\"PayloadB\");\n            msg.colour = context.get(\"BBGC\");\n            msg.txt = context.get(\"Btxt\");\n            msg.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;\n}\nif (msg.payload == \"Z\")\n{\n    //\n    ////node.warn(\"Timed out\");\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.colour = context.get(\"DISABLEDCLR\");\n        msg.txt = context.get(\"Atxt\");\n        msg.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.colour = context.get(\"DISABLEDCLR\");\n        msg.txt = context.get(\"Btxt\");\n        msg.fontclr = context.get(\"BFC\");\n    }\n    return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":490,"y":480,"wires":[["1d77a37e.a76b95","217a2e14.0dbb4a"]]},{"id":"aa338cfc.ca1fd","type":"trigger","z":"39ea4ac5.b46c1e","name":"","op1":"","op2":"Z","op1type":"nul","op2type":"str","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","outputs":1,"x":480,"y":520,"wires":[["e0d476a7.3e5e7"]]},{"id":"1baf0833.3ae918","type":"ui_group","name":"Cmds Received","tab":"41ad2f9a.ed0df","order":1,"disp":true,"width":"6","collapse":false},{"id":"41ad2f9a.ed0df","type":"ui_tab","name":"Logging","icon":"list","order":5,"disabled":false,"hidden":false}]

Note the topic is set in the button node.
Seemingly it didn't used to be needed to be set.

This seems to be something happening with the button node.

Add debug nodes showing what is going into and out of the button in order to see if that supposition is correct. We don't need a large flow, all we need is the debug node data and the config of the button node, once you have shown that this is happening.

Ah!

I now realise this isn't quite as simple as I said it is/was.

All other things being good, things are ok.

Here is a screen shot.

However, if I edit the button and give it a msg.topic set to something else, it works.

Then if I go and delete the msg.topic part of the button and DEPLOY it works.
Yeah, because (I suspect) it (the button/node) keeps the previous topic.

It didn't used to

What caught me is I edited the button node and set the topic.
So when I went to demonstrate the problem, it was working.
(Though weirdly the topic wasn't set.)
You can see that as the first message on the screen shot.
(Update)
This may be because I had the topic field set to blank and it .... Honestly I am not sure what is happening there. Subsequent pressings I get a topic shown as NOT SETUP.

So I had to invoke the inject node (the set up) and press the button again.

Here is the best walk through I can give at this stage to see the problem:

With the latest button version....
(hang on)

Load the "this code gets around the problem" code.

Edit the button node and delete the msg.topic field. Make it blank.
Deploy.
Press the inject to set things up.
Go to the GUI and press the button. It will just go blank when you press it.

Now, edit the button node, and put something in the msg.topic field.
(I did blah.)

Press the inject node again.

Go to the GUI and press the button.
If - all being good - it will turn lime and allow you to press it again and the text will change.

All because the button node sends the previously received topic if the field is blank.

We don't need screenshots and explanations just show us the debug output.

They are on the last screen shot showing both outputs with the changing topic.

{"payload":"X","topic":"SETUP","event":{"clientX":547,"clientY":148,"bbox":[498,172,599,124]},"socketid":"ynhNe8jm9wAcU6ReAAAL","_msgid":"f5a78fa7.53fc5"}
{"payload":"X","topic":"blah","event":{"clientX":548,"clientY":153,"bbox":[498,172,599,124]},"socketid":"ynhNe8jm9wAcU6ReAAAL","_msgid":"6ff26b0d.6c4584"}

You haven't shown us what is going into the button, or is nothing going in at this time?

Actually, you may be right. Is the button in your flow configured exactly as in the one you posted at the start? With the output topic set to empty string?

Correct.

Until the latest version if the button was pressed (after receiving a message with topic set to SETUP the topic was blank.

Now it is retaining the previous one.

Ok, so create a test case with an Inject node, a button node and a debug node with instructions on how to show the problem and submit an issue against the dashboard node.

Ok, the definitive bug report:

Flow/code:

[{"id":"feced108.12695","type":"ui_button","z":"39ea4ac5.b46c1e","name":"","group":"d20ab961.4f8e68","order":3,"width":"3","height":"1","passthru":false,"label":"Press me","tooltip":"","color":"","bgcolor":"","icon":"","payload":"Button pressed","payloadType":"str","topic":"topic","topicType":"msg","x":620,"y":3430,"wires":[["d66390c7.30c458"]]},{"id":"ce4918b2.2f33b","type":"inject","z":"39ea4ac5.b46c1e","name":"setup","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"LOOK-FOR-THIS","payload":"blah","payloadType":"str","x":470,"y":3480,"wires":[["feced108.12695","d66390c7.30c458"]]},{"id":"d66390c7.30c458","type":"debug","z":"39ea4ac5.b46c1e","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":760,"y":3480,"wires":[]},{"id":"d20ab961.4f8e68","type":"ui_group","name":"Group 3","tab":"9979cb8a.2a3238","order":3,"disp":true,"width":6},{"id":"9979cb8a.2a3238","type":"ui_tab","name":"TEST","icon":"dashboard","order":20,"disabled":false,"hidden":false}]

Why is the msg.topic set when the button is pressed?
It didn't used to do this.

Now, in the button node, you have told it to send with the topic set to msg.topic from the input message so that is what it is doing.
Better to use two debug nodes rather than one, and give them names, so they can be identified more easily in the output.

I think the payload explains what is what.

The message when the button is pressed is CLEARLY marked as "BUTTON PRESSED"

ARGH!

(&($%&*(!

So now the button structure has changed.

Originally it was you entered the text for the msg.topic.

Now you select what is sent.

Yes, I need to learn to read.

But I feel this is sneaky how it was done.

This is now closed.

I'm stupid - that's a given.

But that has just caused me 2 hours of grief.

Yes, but look at the button node config, you have the send topic set to msg.topic which is telling it to send the topic from the last message passed in, which is exactly what it is doing, so in your test case it is working as it should. The test case should have the button send topic set to an empty string, that is the failing case.
There is a bug when the send topic is set to an empty string, but your test case is not demonstrating that bug.

Press the button a second and third and fourth time.

I give up.

As said: I'm stupid.

I have wasted 2 hours because I didn't notice the subtle change on how the msg.topic is now set in the latest version.

Why? All you have to do is (in your test case) change the send topic to an empty string and you have correctly shown that there is a bug in the button node.

Like this

[{"id":"feced108.12695","type":"ui_button","z":"37f5b818.697af8","name":"","group":"d20ab961.4f8e68","order":3,"width":"3","height":"1","passthru":false,"label":"Press me","tooltip":"","color":"","bgcolor":"","icon":"","payload":"Button pressed","payloadType":"str","topic":"","topicType":"str","x":240,"y":800,"wires":[["d66390c7.30c458"]]},{"id":"ce4918b2.2f33b","type":"inject","z":"37f5b818.697af8","name":"setup","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"LOOK-FOR-THIS","payload":"blah","payloadType":"str","x":90,"y":850,"wires":[["feced108.12695","5c402c08.50161c"]]},{"id":"d66390c7.30c458","type":"debug","z":"37f5b818.697af8","name":"Button output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":380,"y":850,"wires":[]},{"id":"5c402c08.50161c","type":"debug","z":"37f5b818.697af8","name":"Injected messge","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":260,"y":920,"wires":[]},{"id":"d20ab961.4f8e68","type":"ui_group","name":"Group 3","tab":"9979cb8a.2a3238","order":3,"disp":true,"width":6},{"id":"9979cb8a.2a3238","type":"ui_tab","name":"TEST","icon":"dashboard","order":20,"disabled":false,"hidden":false}]

Yeah, I kinda worked that out when I saw how the topic is now set compared to the older way.

Problem is gone.

No you haven't, you have found a regression and worked out how to replicate it.

If I could read better, I would not have needed to waste 2 hours messing around.

(note to self)
I have to learn to read.

Are you going to submit a bug report?