The conversation began here https://discourse.nodered.org/t/led-icon-changed/656/16?u=ozpos
I have made significant progress but still have a couple of problems.
[
{
"id": "77b9551a682cccf9",
"type": "tab",
"label": "Flow 3",
"disabled": false,
"info": ""
},
{
"id": "7e1c80b7bacaa1eb",
"type": "debug",
"z": "77b9551a682cccf9",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 530,
"y": 160,
"wires": []
},
{
"id": "edb3ddb6cd354130",
"type": "ui_template",
"z": "77b9551a682cccf9",
"group": "879c5e97.07fff",
"name": "LED Array",
"order": 13,
"width": "0",
"height": "0",
"format": "<script>\n(function($scope) {\n // Inspired by h t t p s://flows.nodered.org/user/Hugobox\n let led_count = 32\n let label = \"GPIO\"\n let initialised = false\n var bargraph = new Array(led_count).fill(\"#000000\")\n\n //From @Hotnip: cause a small delay while things load\n //ideally this would be an init event or on all parts of document loaded\n //(may not be necessary!)\n setTimeout(function() {\n //debugger\n $scope.init();\n },100);\n\n /**\n * Inform controller of browser refresh or nr server restart or deploy.\n */\n $scope.init = function () {\n //debugger\n console.log(\"$scope.init called.\");\n \n if(initialised == false){\n //debugger\n console.log(\"Sending _init_ msg\");\n $scope.send({payload: bargraph, topic: \"_init_\"});\n }\n };\n\n $scope.$watch('msg', function() {\n \n if ($scope.msg){\n if ($scope.msg.hasOwnProperty('payload') &&\n typeof $scope.msg.payload == \"object\" &&\n Array.isArray( $scope.msg.payload ) &&\n $scope.msg.payload.length <= led_count && \n $scope.msg.payload.length > 0 ){\n\n console.log(\"msg.payload[0]=\" + String($scope.msg.payload[0]) + \" typeof \" + typeof $scope.msg.payload + \" isArray \" + Array.isArray($scope.msg.payload) + \" length \" + $scope.msg.payload.length + \" typeof \" + typeof $scope.msg.payload[0])\n $scope.msg.label = label\n for(let i=0; i<led_count && i<$scope.msg.payload.length; i++){\n if ( typeof $scope.msg.payload[i] == 'string'){\n bargraph[i]=$scope.msg.payload[i]\n }\n }\n $scope.msg.bargraph = bargraph.reverse()\n $scope.msg.bargraph = bargraph.reverse()\n }else if (typeof $scope.msg.payload !== \"number\"){\n $scope.msg = {\"bargraph\":[...bargraph], \"payload\": 0, \"label\":label}\n } \n }else{\n $scope.msg = {\"bargraph\":[...bargraph], \"payload\": 0, \"label\":label}\n }\n });\n})(scope);\n</script>\n\n<style>\n.bargraph {\n float: right;\n padding: 3px;\n width: 3px;\n height: 10px;\n margin: 4px 2px 8px 0px;\n border-radius: 0%;\n}\n</style>\n\n<div>{{msg.label}}\n<div>\n <span ng-repeat=\"led in msg.payload track by $index\">\n <span class=\"bargraph\" style=\"background-color: {{msg.payload[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black 0 -1px 4px, {{msg.payload[$index]}} 0 3px 15px;\"></span>\n </span>\n</div>\n</div>\n",
"storeOutMessages": false,
"fwdInMessages": false,
"resendOnRefresh": false,
"templateScope": "local",
"x": 370,
"y": 160,
"wires": [
[
"7e1c80b7bacaa1eb",
"52ab717f225a0b77"
]
]
},
{
"id": "29bb58bf97a78ce9",
"type": "inject",
"z": "77b9551a682cccf9",
"name": "32 colours",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "[\"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\",\"#00ff00\", \"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\",\"#00ff00\",\"#0000ff\",\"#ff0000\"]",
"payloadType": "jsonata",
"x": 180,
"y": 120,
"wires": [
[
"edb3ddb6cd354130",
"09efd2d2113522b6"
]
]
},
{
"id": "81e0d7df3c97b312",
"type": "inject",
"z": "77b9551a682cccf9",
"name": "3 colours",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "[\"#ff0000\",\"#00ff00\",\"#0000ff\"]",
"payloadType": "jsonata",
"x": 180,
"y": 80,
"wires": [
[
"edb3ddb6cd354130",
"09efd2d2113522b6"
]
]
},
{
"id": "c3c3ef63ebd223ce",
"type": "inject",
"z": "77b9551a682cccf9",
"name": "1 colour",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "[\"#ffff00\"]",
"payloadType": "jsonata",
"x": 190,
"y": 40,
"wires": [
[
"edb3ddb6cd354130"
]
]
},
{
"id": "9d69baab914b9193",
"type": "inject",
"z": "77b9551a682cccf9",
"name": "empty array",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "[]",
"payloadType": "jsonata",
"x": 390,
"y": 40,
"wires": [
[
"edb3ddb6cd354130"
]
]
},
{
"id": "af5b84708f88cb03",
"type": "comment",
"z": "77b9551a682cccf9",
"name": "sending empty array deleted the leds.",
"info": "",
"x": 430,
"y": 280,
"wires": []
},
{
"id": "52ab717f225a0b77",
"type": "function",
"z": "77b9551a682cccf9",
"name": "gpio",
"func": "let gpio = flow.get(node.name);\nlet refresh_ui = false;\nlet cmd = String(msg.topic).split(\" \");\n\nswitch (cmd[0]){\n case \"_init_\":\n if (JSON.stringify(gpio.payload) !== JSON.stringify(msg.payload)) {\n refresh_ui = true;\n }\n break;\n\n case \"w\":\n let led = parseInt(msg.payload);\n if (led >= 0 && led < 32){\n gpio.payload[led] = cmd[1];\n flow.set(node.name, gpio);\n refresh_ui = true;\n }\n\n}\nif ( refresh_ui ){\n msg.topic = \"_init_\";\n msg.payload = gpio.payload;\n return msg;\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nlet gpio = flow.get(node.name);\nif ( gpio === undefined){\n gpio = {\n payload: [\"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\"],\n topic: \"_init_\"\n }\n flow.set(node.name, gpio);\n}\n",
"finalize": "",
"libs": [],
"x": 370,
"y": 200,
"wires": [
[
"edb3ddb6cd354130",
"d81a5f772e875be5"
]
]
},
{
"id": "ff467ed83e025341",
"type": "inject",
"z": "77b9551a682cccf9",
"name": "w #ffff00 to 2",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "w #ffff00",
"payload": "2",
"payloadType": "num",
"x": 170,
"y": 180,
"wires": [
[
"52ab717f225a0b77"
]
]
},
{
"id": "d81a5f772e875be5",
"type": "debug",
"z": "77b9551a682cccf9",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 530,
"y": 200,
"wires": []
},
{
"id": "11f35c798c27084f",
"type": "comment",
"z": "77b9551a682cccf9",
"name": "sending array length of 1 shows only one led leds.",
"info": "",
"x": 420,
"y": 320,
"wires": []
},
{
"id": "95f023d4c0c7aa7b",
"type": "inject",
"z": "77b9551a682cccf9",
"name": "w #ffff00 to 31",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "w #ffff00",
"payload": "31",
"payloadType": "num",
"x": 170,
"y": 220,
"wires": [
[
"52ab717f225a0b77"
]
]
},
{
"id": "20b47688438693c9",
"type": "comment",
"z": "77b9551a682cccf9",
"name": "Outstanding Problems",
"info": "",
"x": 450,
"y": 240,
"wires": []
},
{
"id": "09efd2d2113522b6",
"type": "ui_template",
"z": "77b9551a682cccf9",
"group": "879c5e97.07fff",
"name": "LED Array 2",
"order": 13,
"width": "0",
"height": "0",
"format": "<script>\n(function($scope) {\n // Inspired by h t t p s://flows.nodered.org/user/Hugobox\n let led_count = 32\n let label = \"GPIO\"\n let initialised = false\n var bargraph = new Array(led_count).fill(\"#000000\")\n\n //From @Hotnip: cause a small delay while things load\n //ideally this would be an init event or on all parts of document loaded\n //(may not be necessary!)\n setTimeout(function() {\n //debugger\n $scope.init();\n },100);\n\n /**\n * Inform controller of browser refresh or nr server restart or deploy.\n */\n $scope.init = function () {\n //debugger\n console.log(\"$scope.init called.\");\n \n if(initialised == false){\n //debugger\n console.log(\"Sending _init_ msg\");\n $scope.send({payload: bargraph, topic: \"_init_\"});\n }\n };\n\n $scope.$watch('msg', function() {\n \n if ($scope.msg){\n if ($scope.msg.hasOwnProperty('payload') &&\n typeof $scope.msg.payload == \"object\" &&\n Array.isArray( $scope.msg.payload ) &&\n $scope.msg.payload.length <= led_count && \n $scope.msg.payload.length > 0 ){\n\n console.log(\"msg.payload[0]=\" + String($scope.msg.payload[0]) + \" typeof \" + typeof $scope.msg.payload + \" isArray \" + Array.isArray($scope.msg.payload) + \" length \" + $scope.msg.payload.length + \" typeof \" + typeof $scope.msg.payload[0])\n $scope.msg.label = label\n for(let i=0; i<led_count && i<$scope.msg.payload.length; i++){\n if ( typeof $scope.msg.payload[i] == 'string'){\n bargraph[i]=$scope.msg.payload[i]\n }\n }\n $scope.msg.bargraph = bargraph.reverse()\n $scope.msg.bargraph = bargraph.reverse()\n }else if (typeof $scope.msg.payload !== \"number\"){\n $scope.msg = {\"bargraph\":[...bargraph], \"payload\": 0, \"label\":label}\n } \n }else{\n $scope.msg = {\"bargraph\":[...bargraph], \"payload\": 0, \"label\":label}\n }\n });\n})(scope);\n</script>\n\n<style>\n.bargraph {\n float: right;\n padding: 3px;\n width: 3px;\n height: 10px;\n margin: 4px 2px 8px 0px;\n border-radius: 0%;\n}\n</style>\n\n<div>{{msg.label}}\n<div>\n <span ng-repeat=\"led in msg.payload track by $index\">\n <span class=\"bargraph\" style=\"background-color: {{msg.payload[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black 0 -1px 4px, {{msg.payload[$index]}} 0 3px 15px;\"></span>\n </span>\n</div>\n</div>\n",
"storeOutMessages": false,
"fwdInMessages": false,
"resendOnRefresh": false,
"templateScope": "local",
"x": 590,
"y": 100,
"wires": [
[
"a0343d6543eb0cf8",
"c8a91fd27e9606f1"
]
]
},
{
"id": "73a3d4698afcfc82",
"type": "inject",
"z": "77b9551a682cccf9",
"name": "w #ffff00 to 0",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "w #ffff00",
"payload": "0",
"payloadType": "num",
"x": 610,
"y": 20,
"wires": [
[
"09efd2d2113522b6"
]
]
},
{
"id": "aa74d58c7c373f63",
"type": "inject",
"z": "77b9551a682cccf9",
"name": "w #ffff00 to 30",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "w #ffff00",
"payload": "30",
"payloadType": "num",
"x": 610,
"y": 60,
"wires": [
[
"09efd2d2113522b6"
]
]
},
{
"id": "a0343d6543eb0cf8",
"type": "debug",
"z": "77b9551a682cccf9",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 750,
"y": 140,
"wires": []
},
{
"id": "c8a91fd27e9606f1",
"type": "function",
"z": "77b9551a682cccf9",
"name": "gpio2",
"func": "let gpio = flow.get(node.name);\nlet refresh_ui = false;\nlet cmd = String(msg.topic).split(\" \");\n\nswitch (cmd[0]){\n case \"_init_\":\n if (JSON.stringify(gpio.payload) !== JSON.stringify(msg.payload)) {\n refresh_ui = true;\n }\n break;\n\n case \"w\":\n let led = parseInt(msg.payload);\n if (led >= 0 && led < 32){\n gpio.payload[led] = cmd[1];\n flow.set(node.name, gpio);\n refresh_ui = true;\n }\n\n}\nif ( refresh_ui ){\n msg.topic = \"_init_\";\n msg.payload = gpio.payload;\n return msg;\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nlet gpio = flow.get(node.name);\nif ( gpio === undefined){\n gpio = {\n payload: [\"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\", \"#00ff00\", \"#0000ff\", \"#ff0000\"],\n topic: \"_init_\"\n }\n flow.set(node.name, gpio);\n}\n",
"finalize": "",
"libs": [],
"x": 690,
"y": 200,
"wires": [
[
"09efd2d2113522b6"
]
]
},
{
"id": "7c2c748c90daf304",
"type": "comment",
"z": "77b9551a682cccf9",
"name": "How to use more than one led array template ?",
"info": "",
"x": 420,
"y": 360,
"wires": []
},
{
"id": "879c5e97.07fff",
"type": "ui_group",
"name": "n:14.17.5 r:2.0.5 d:20.30.0",
"tab": "105c5e70.b644f2",
"order": 4,
"disp": true,
"width": "8",
"collapse": true
},
{
"id": "105c5e70.b644f2",
"type": "ui_tab",
"name": "dashboard template",
"icon": "dashboard",
"order": 1,
"disabled": false,
"hidden": false
}
]
The list of problems I now have are:
- get http://127.0.0.1:1893/ui/loading.html 404 (Not Found)
- I cannot seem to protect the template from spurious array sizes in msg.payload.
- What has to change to allow multiple independent led array templates on the same flow.
Many thanks in advance.