Would someone like to have a "squiz" at this flow I just made?

I hope this isn't seen as trying to prove anything to anyone.

I shall upload it soon to the library, but I would like to be sure of this after a few other recent uploads.

This flow (which would be super great if I could make a sub-flow) is for buttons on dashboards.
But I think there is a problem setting the time in the trigger node.

I am going through re-designing and writing a lot of my stuff as I have got better.
But a lot of my dashboards were just "over run" with buttons, and it was getting worse.

One flaw I have is "protecting" buttons from accidental pressing. I therefore have an ENABLE button which allows the buttons to then be pressed.

But even that was taking up way too much real estate. So, I got adventurous with the button node and have written a few different things with buttons.

I have also made a press button flow so when the button is pressed, it indicates the press by changing colour, text and/or image.

Anyway, that lead to this: The integration of those two functions and a bit more.
Rather than having 3 buttons: "enable" "option 1" and "option 2", you have one!

At "rest" but button shows what is selected/active.
Pressing it once, it becomes active.
Pressing it again - within a time limit - it toggles to the second value.
Then, after the time, it becomes inactive.

I am sure there may be other ways of doing this, but I have put a lot of hours into it and shot myself in the foot so many times, I am luck to have any toes left.

It has a READ ME node in it.

[{"id":"ed9234b8.2f122","type":"function","z":"df652827.d02c3","name":"Push Button","func":"var state = context.get(\"STATE\")||0;\nvar enabled = context.get(\"ENABLED\")||0;\n\n//  Look for a !X message to get 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.colour = msg.colourA;\n    msg.fontclr = msg.txtclrA;\n    return msg;\n}\n\n//      Now on to the real stuff.\n//if (msg.payload === true)\nif (msg.payload == \"X\")\n{\n    //node.waran(\"X detected\");\n    //  Insert here code to enable other stuff.\n//    if (context.get(\"ENABLED\") === 0)\n    if (enabled === 0)\n    {\n        //node.waran(\"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        return msg;\n    }\n\n    state = (state + 1)% 2;\n    //node.waran(state);\n    context.set(\"STATE\",state);\n// close loop\n\n    if (context.get(\"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.waran(\"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,"x":3120,"y":280,"wires":[["e01f15d7.afae28","e380fd5d.7618b8"]]},{"id":"e01f15d7.afae28","type":"ui_button","z":"df652827.d02c3","name":"28 June","group":"373c4fb2.a22078","order":5,"width":"3","height":"1","passthru":false,"label":"{{msg.txt}}","tooltip":"","color":"{{msg.fontclr}}","bgcolor":"{{msg.colour}}","icon":"","payload":"X","payloadType":"str","topic":"","x":3110,"y":230,"wires":[["ed9234b8.2f122","356bd2e0.9a44fe"]]},{"id":"584e530b.bfda9c","type":"inject","z":"df652827.d02c3","name":"Inject","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"3","x":3100,"y":140,"wires":[["5bc8465e.969d08"]]},{"id":"5bc8465e.969d08","type":"function","z":"df652827.d02c3","name":"Setup","func":"msg = {\n    \"topic\":\"SETUP\",\n    \"disabledColour\":\"brown\",\n    \"colourA\": \"yellow\",\n    \"colourB\": \"green\",\n    \"txtA\": \"Option 1\",\n    \"txtB\": \"Option 2\",\n    \"txtclrA\": \"black\",\n    \"txtclrB\": \"black\",\n    \"payloadA\": 0,\n    \"payloadB\": 1,\n    \"topicSET\": \"CONTROL\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":3100,"y":190,"wires":[["ed9234b8.2f122"]]},{"id":"7adca369.70a604","type":"comment","z":"df652827.d02c3","name":"Read me","info":"Variables needing to be set in the **setup** node:\n\"disabledColour\":\"brown\",\n\"colourA\": \"yellow\",\n\"colourB\": \"green\",\n\"txtA\": \"Option 1\",\n\"txtB\": \"Option 2\",\n\"txtclrA\": \"black\",\n\"txtclrB\": \"black\",\n\"payloadA\": 0,\n\"payloadB\": 1,\n\"topicSET\": \"CONTROL\"\n\nDisabledColour - this is the colour shown if the\nbutton is inactive.\ncolourA - this is the colour of the button when\noption A is selected.\ncolourB - (as above but for option B)\ntxtA - this is the text shown when option A\nis selected.\ntxtB - (as above but for option B)\ntxtclrA - the font colour for option A\ntxtclrB - the font colour for option B\npayloadA - what is sent out when option A is\nselected.\npayloadB - (as above but for option B)\ntopicSET - the topic of the payload sent\n\nAdjust the time the button accepts input by\nediting the `trigger` node.\n\nThe output is AFTER the `switch` node.\nThis will need to be edited if the `topic` is \nnot \"CONTROL\".\nThis could be worked around with flow.context\nvariables, but I don't want to make too many\nchanges to people's flows.  But by all means,\nchange if it suits you.\n\n","x":3100,"y":100,"wires":[]},{"id":"356bd2e0.9a44fe","type":"trigger","z":"df652827.d02c3","op1":"","op2":"Z","op1type":"nul","op2type":"str","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":3110,"y":320,"wires":[["ed9234b8.2f122"]]},{"id":"e2b7cb62.3cec68","type":"debug","z":"df652827.d02c3","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":3320,"y":360,"wires":[]},{"id":"e380fd5d.7618b8","type":"switch","z":"df652827.d02c3","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"CONTROL","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":3270,"y":280,"wires":[["e2b7cb62.3cec68"]]},{"id":"373c4fb2.a22078","type":"ui_group","name":"Group 1","tab":"bca4b6a6.5ee09","order":1,"disp":true,"width":6},{"id":"bca4b6a6.5ee09","type":"ui_tab","z":"","name":"Pushbutton","icon":"dashboard","order":44,"disabled":false,"hidden":false}]

HI,
so on start it is like this
image
click once and wait for timeout it goes to
image
so the label now says option2 ? surely it should revert back to initial state ?
Then when I click It shows
image
So is yellow Option 1 ? or Option2 ?

Once back to Red, I click it again now - it goes yellow - and once yellow I click again - it stays yellow, click another time it goes green and click again it goes yellow.

  • Not sure why I need to click it twice when it's yellow ?
  • First click (to yellow) there is no debug output, second click sends some output.
  • Why does it go back to yellow - should it go back to red ? (I don't know... maybe not)
1 Like

Hmmm....

That's interesting.

On mine, I see the "Option 1" and I press the button.

It goes from brown colour to yellow. I don't do anything. After a few seconds it goes back to "Option 1".

Pressing it again - after it goes brown - it goes yellow. I click it and it then turns to "Option 2".

I don't think it could be a problem but the initial "setup" needs to be done. But that's a given as you are getting the correct text on the button.

The idea is:

It is brown colour with "Option 1".
You press it once and the button turns yellow. (Set by the setup node)
Quickly pressing it again the text changes to "Option 2" and the colour turns green.
Then, after a short time the button goes back to brown colour indicating it is unable to change form "Option 1" to "Option 2".

Though I have to concur that after getting it to "Option 2" single clicking the button it goes from "Option 2" to "Option 1".

The second click - (when it turns yellow, or green) is what is sent to the flow to indicate an action is required.

Seems I am not as smart as I thought.

Thanks.

I just realised why the "Option 2" changes to "Option 1" after a correct cycle.

The code I wrote for setting the "enabled button" reads the option 1 settings, rather than the state value.

Ok. Thanks.

Ok.

Weird.

I did (hand on heart) test it before uploading.

Found another problem I mentioned and so had another crack at it.

This time I tested it with all 4 possibilities:
Option 1 single press.
Option 1 double press.
Option 2 single press.
Option 2 double press.

Seems to work now.

To clarify:
The button is "brown". Showing "Option 1".
Pressing the button it turns "yellow". If you don't do anything, it will time out.
If you press the button while it is "yellow", it will change to "Option 2".
This will output a 1 to the now included text node.

After a while (yeah, 5 seconds) it will turn "brown" again and retain the "Option 2" text.
Pressing the button now, it will turn "green". Doing nothing it will time out and go back to "brown".
Pressing the button while it is "green" it will turn "yellow" and the text change back to "Option 1" and a 0 will be displayed in the text field/node.

Sanity check that is now what you see.

It does this so you can't just accidentaly press the button and it change.

You need to press it twice to action the change.

[{"id":"ed9234b8.2f122","type":"function","z":"df652827.d02c3","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,"x":3120,"y":280,"wires":[["e01f15d7.afae28","e380fd5d.7618b8","2313dbca.3746cc"]]},{"id":"e01f15d7.afae28","type":"ui_button","z":"df652827.d02c3","name":"28 June","group":"373c4fb2.a22078","order":5,"width":"3","height":"1","passthru":false,"label":"{{msg.txt}}","tooltip":"","color":"{{msg.fontclr}}","bgcolor":"{{msg.colour}}","icon":"","payload":"X","payloadType":"str","topic":"","x":3110,"y":230,"wires":[["ed9234b8.2f122","356bd2e0.9a44fe"]]},{"id":"584e530b.bfda9c","type":"inject","z":"df652827.d02c3","name":"Inject","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"3","x":3100,"y":140,"wires":[["5bc8465e.969d08"]]},{"id":"5bc8465e.969d08","type":"function","z":"df652827.d02c3","name":"Setup","func":"msg = {\n    \"topic\":\"SETUP\",\n    \"disabledColour\":\"brown\",\n    \"colourA\": \"yellow\",\n    \"colourB\": \"green\",\n    \"txtA\": \"Option 1\",\n    \"txtB\": \"Option 2\",\n    \"txtclrA\": \"black\",\n    \"txtclrB\": \"black\",\n    \"payloadA\": 0,\n    \"payloadB\": 1,\n    \"topicSET\": \"CONTROL\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":3100,"y":190,"wires":[["ed9234b8.2f122"]]},{"id":"356bd2e0.9a44fe","type":"trigger","z":"df652827.d02c3","op1":"","op2":"Z","op1type":"nul","op2type":"str","duration":"5","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":3110,"y":320,"wires":[["ed9234b8.2f122"]]},{"id":"e380fd5d.7618b8","type":"switch","z":"df652827.d02c3","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"CONTROL","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":3270,"y":280,"wires":[["e2b7cb62.3cec68","150610bb.fcd347"]]},{"id":"e2b7cb62.3cec68","type":"debug","z":"df652827.d02c3","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":3320,"y":360,"wires":[]},{"id":"150610bb.fcd347","type":"ui_text","z":"df652827.d02c3","group":"373c4fb2.a22078","order":7,"width":"3","height":"1","name":"","label":"output","format":"{{msg.payload}}","layout":"row-spread","x":3320,"y":400,"wires":[]},{"id":"373c4fb2.a22078","type":"ui_group","name":"Group 1","tab":"bca4b6a6.5ee09","order":1,"disp":true,"width":6},{"id":"bca4b6a6.5ee09","type":"ui_tab","z":"","name":"Pushbutton","icon":"dashboard","order":44,"disabled":false,"hidden":false}]