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'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
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
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:
Then once the switch is clicked, it will wait for an input msg:
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.
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.