Button State node - is something similar available for Dashboard 2?

I've created: Switch: Button Type · Issue #1292 · FlowFuse/node-red-dashboard · GitHub

To capture this feature request, also having come up elsewhere. We would support this in the UI Switch.

I just wrote a really carefully thought through feature request, took about an hour, then I went to get a pint (I'm in a pub!) and came back then finished the feature request and pressed submit, and it failed to send, hit back, the form was empty :cry::cry:

Oh man, sorry to hear that. For what it's worth, it doesnt need to be too formal, dump top level thoughts in there to capture something and we can always work on details later

Nice! I like it :grinning:
Just a couple of observations though...

There is no indication if the switch is actually on or off, as the background color remains static.

On a laptop, the button is pressed, and the loading spinning circle awaits confirmation (as expected), but if the same dashboard is then viewed on another device - ie a phone, the spinning circle is not visible (but remains spinning on the laptop until confirmed). In other words, the visual queue is not replicated on other devices viewing the dashboard.

You would surely have to wire in some interactivity with Node-RED? Not only to send notifications back but also to broadcast notifications to all connected clients - and take care of caching as well.

If you look at @hotNipi's demo, the 'interaction' is faked with feedback provided by a trigger node. In practice, that 'feedback' would come from, for example a shelly MQTT msg confirming it's current relay state (on/off).

My first usable implementation.
Blink - function available
icon - not yet

[
    {
        "id": "cdc19dcf50907703",
        "type": "ui-button",
        "z": "99366da2301717ce",
        "group": "d2ada84cc7beaf41",
        "name": "",
        "label": "btn1",
        "order": 1,
        "width": "1",
        "height": "1",
        "emulateClick": false,
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "iconPosition": "left",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "buttonColor": "green",
        "textColor": "white",
        "iconColor": "",
        "x": 630,
        "y": 360,
        "wires": [
            []
        ]
    },
    {
        "id": "d363987354b7c11e",
        "type": "debug",
        "z": "99366da2301717ce",
        "name": "debug 2",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 640,
        "y": 320,
        "wires": []
    },
    {
        "id": "4b007b52ceaa2b7d",
        "type": "inject",
        "z": "99366da2301717ce",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "btn",
        "payload": "grey",
        "payloadType": "str",
        "x": 240,
        "y": 300,
        "wires": [
            [
                "8da43418d62cac46"
            ]
        ]
    },
    {
        "id": "cc30c8ae72af2e01",
        "type": "inject",
        "z": "99366da2301717ce",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "btn",
        "payload": "green",
        "payloadType": "str",
        "x": 240,
        "y": 340,
        "wires": [
            [
                "8da43418d62cac46"
            ]
        ]
    },
    {
        "id": "8da43418d62cac46",
        "type": "function",
        "z": "99366da2301717ce",
        "name": "btn setup",
        "func": "var top = msg.topic;\nvar val = msg.payload;\nvar msg1 = {};\nvar ui_update = {};\nvar bc = context.get(\"bc\") || \"blue\";   // buttonColor\nvar tc = context.get(\"tc\") || \"white\";  // textColor\nvar lb = context.get(\"lb\") || \"btn1\";   // button label\nvar bcblink = context.get(\"bcblink\") || \"yellow\"; // buttonColor in blink state\nvar tcblink = context.get(\"tcblink\") || \"blue\"  // textCoor in blink state\nvar bs = context.get(\"blinkstate\") || 0;  // blinkstate\nvar blinkenable = context.get(\"blinkenable\") || 0;    // enables or disables blinking\n\nif (top === \"sbon\") {   // slow blinking\n    bs = 1;\n    context.set(\"blinkstate\",bs);\n}\nelse if (top === \"sboff\") {\n    bs = 0;\n    context.set(\"blinkstate\",bs);\n}\nelse if (top === \"blinkenable\") {\n    blinkenable = val;\n    context.set (\"blinkenable\",blinkenable);\n}\nelse if (top === \"btn\") {\n    bc = val;\n    context.set(\"bc\",bc);\n}\nelse if (top === \"btn_blink\") {\n    bcblink = val;\n    context.set(\"bcblink\",bcblink);\n}\nelse if (top === \"txt\") {\n    tc = val;\n    context.set(\"tc\",tc);\n}\nelse if (top === \"txt_blink\") {\n    tcblink = val;\n    context.set(\"tcblink\",tcblink);\n}\nelse if (top === \"lab\") {\n    lb = val;\n    context.set(\"lb\",lb);\n}\nelse if (top === \"init\") {\n    bc = \"blue\";            // button color\n    tc = \"white\";           // text color\n    lb = \"Button\";          // label\n    bcblink = \"yellow\";     // button blink color\n    tcblink = \"blue\";       // text blink color\n    context.set(\"bc\",bc);\n    context.set(\"tc\",tc);\n    context.set(\"lb\",lb);\n    context.set(\"bcblink\",bcblink);\n    context.set(\"tcblink\",tcblink);\n    context.set (\"blinkenable\",0);\n}\n\nif (blinkenable === 0) {\n    msg1 = {\n        payload: \"\",\n        ui_update: {\n            buttonColor: bc,\n            textColor: tc,\n            label: lb,\n        },\n    }\n}\nif (blinkenable === 1) {\n    if (bs === 0) {\n        msg1 = {\n            payload: \"\",\n            ui_update: {\n                buttonColor: bc,\n                textColor: tc,\n                label: lb,\n            },\n        }\n    }\n    else {\n        msg1 = {\n            payload: \"\",\n            ui_update: {\n                buttonColor: bcblink,\n                textColor: tcblink,\n                label: lb,\n            },\n        }\n    }\n}\nreturn msg1;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 460,
        "y": 360,
        "wires": [
            [
                "cdc19dcf50907703",
                "d363987354b7c11e"
            ]
        ]
    },
    {
        "id": "e66a5e736d15ab21",
        "type": "inject",
        "z": "99366da2301717ce",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "lab",
        "payload": "Btn1",
        "payloadType": "str",
        "x": 240,
        "y": 380,
        "wires": [
            [
                "8da43418d62cac46"
            ]
        ]
    },
    {
        "id": "7b00ba7e3a4fa7f4",
        "type": "inject",
        "z": "99366da2301717ce",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "lab",
        "payload": "Btn2",
        "payloadType": "str",
        "x": 240,
        "y": 420,
        "wires": [
            [
                "8da43418d62cac46"
            ]
        ]
    },
    {
        "id": "2f7f32273dd5d448",
        "type": "inject",
        "z": "99366da2301717ce",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": "0.5",
        "topic": "init",
        "payload": "",
        "payloadType": "str",
        "x": 230,
        "y": 260,
        "wires": [
            [
                "8da43418d62cac46"
            ]
        ]
    },
    {
        "id": "0adee22ae0d1364f",
        "type": "inject",
        "z": "99366da2301717ce",
        "name": "slow blink clock",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "0.8",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 270,
        "y": 120,
        "wires": [
            [
                "24036f7c90f3b35e"
            ]
        ]
    },
    {
        "id": "24036f7c90f3b35e",
        "type": "function",
        "z": "99366da2301717ce",
        "name": "sb msg former",
        "func": "var state = context.get(\"state\") || 0;\nif (state === 0) {\n    state = 1;\n    msg.topic = \"sbon\";   // slowblink on\n}\nelse {\n    state = 0;\n    msg.topic = \"sboff\";  // slowblink off\n}\ncontext.set(\"state\",state);\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 460,
        "y": 120,
        "wires": [
            [
                "90ebc57dcf8defb6",
                "13770ede68d700c5"
            ]
        ]
    },
    {
        "id": "90ebc57dcf8defb6",
        "type": "debug",
        "z": "99366da2301717ce",
        "name": "debug 2481",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 690,
        "y": 120,
        "wires": []
    },
    {
        "id": "a49affeb1b4f26ea",
        "type": "inject",
        "z": "99366da2301717ce",
        "name": "sb on",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "blinkenable",
        "payload": "1",
        "payloadType": "num",
        "x": 230,
        "y": 460,
        "wires": [
            [
                "8da43418d62cac46"
            ]
        ]
    },
    {
        "id": "1622e504778276e5",
        "type": "inject",
        "z": "99366da2301717ce",
        "name": "sb off",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "blinkenable",
        "payload": "0",
        "payloadType": "num",
        "x": 230,
        "y": 500,
        "wires": [
            [
                "8da43418d62cac46"
            ]
        ]
    },
    {
        "id": "13770ede68d700c5",
        "type": "link out",
        "z": "99366da2301717ce",
        "name": "tx slowblink",
        "mode": "link",
        "links": [
            "141c624a70b7b4c0"
        ],
        "x": 585,
        "y": 160,
        "wires": []
    },
    {
        "id": "141c624a70b7b4c0",
        "type": "link in",
        "z": "99366da2301717ce",
        "name": "rx slowblink",
        "links": [
            "13770ede68d700c5"
        ],
        "x": 265,
        "y": 220,
        "wires": [
            [
                "8da43418d62cac46"
            ]
        ]
    },
    {
        "id": "2d97df2ef256c7ae",
        "type": "comment",
        "z": "99366da2301717ce",
        "name": "available commands",
        "info": "** funcktion **     ** context **   ** payload **\ninit                init            --\nbutton color        btn             <color>\nbutton blink_color  btn_blink       <color>\ntext color          txt             <color>\ntext blink_color    txt_blink       <color>\nbutton label        lbl             <string>      \nenable blinking     blinkenable     1\ndisable blinking    blinkenable     0\nblinkstate on       sbon            --\nblinkstate off      sboff           --\n\ncurrently only slow blinking is realized, fast \nblinking may be added.\n\ncustomize the button:\nadjust lines 46 - 50 to your needs",
        "x": 490,
        "y": 420,
        "wires": []
    },
    {
        "id": "d2ada84cc7beaf41",
        "type": "ui-group",
        "name": "g1",
        "page": "a753d3c3ec5c9991",
        "width": "6",
        "height": "1",
        "order": 1,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "a753d3c3ec5c9991",
        "type": "ui-page",
        "name": "p1",
        "ui": "fdd5060deaa38d04",
        "path": "/page1",
        "icon": "home",
        "layout": "grid",
        "theme": "ea314d4cabcf2177",
        "order": 1,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "fdd5060deaa38d04",
        "type": "ui-base",
        "name": "UI Name",
        "path": "/dashboard",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "showPageTitle": true,
        "navigationStyle": "default",
        "titleBarStyle": "default"
    },
    {
        "id": "ea314d4cabcf2177",
        "type": "ui-theme",
        "name": "Default Theme",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094CE",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px",
            "density": "default"
        }
    }
]

Feel free to use and modify it!

That is indeed nice. It looks quite similar to the ui-switch node, when you use this option:

image

Then once the switch is clicked, it will wait for an input msg:

switch_progress

2 Likes

Yes! that's what we need in the button node!
We can't rely upon assuming that an external device has changed it's status just because of a dashboard button press. It's too easy to get out of sync.

I will have a look at that this week.

BTW before I will start implementing this, I will first wait for another feature request to be solved. Because it 'look' to me that it is conflicting with this one. But I might be mistaken...

We have two active threads on this same topic (the other being this one)

Documenting here (as I have in the other too), that despite being tempted to add this into core button node, I think we should be going down the button-state as a third-party node route.

2 Likes

Bless on that. Keep basic widgets clean and clear thus those are not only the nodes to use but also examples how to make stuff.

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