Dashboard template led array problems

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.
image

[
    {
        "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:

  1. get http://127.0.0.1:1893/ui/loading.html 404 (Not Found)
  2. I cannot seem to protect the template from spurious array sizes in msg.payload.
  3. What has to change to allow multiple independent led array templates on the same flow.
    Many thanks in advance.

Sorry if I doubled up on this I hadn't realised that you had started a new topic.

Problem 1 : I do not get this one
Problem 3 : Just add another template plus GPIO function as you have shown

This solves problem 2

    (function($scope) {
        // Inspired by h t t p s://flows.nodered.org/user/Hugobox
        const led_count = 32
        const label = "GPIO"
        let initialised = false

        $scope.bargraph = new Array(led_count).fill("white")

        //From @Hotnip: cause a small delay while things load
        //ideally this would be an init event or on all parts of document loaded
        //(may not be necessary!)
        setTimeout(function() {
            //debugger
            $scope.init();
        }, 100);

        /**
        * Inform controller of browser refresh or nr server restart or deploy.
        */
        $scope.init = function () {
            //debugger
            console.log("$scope.init called.");
        
            if(initialised == false){
                //debugger
                console.log("Sending _init_ msg");
                $scope.send({payload: bargraph, topic: "_init_"});
            }
        };

        $scope.$watch('msg', function() {
        
            if ($scope.msg){
                if ($scope.msg.hasOwnProperty('payload') &&
                    typeof $scope.msg.payload == "object" &&
                    Array.isArray( $scope.msg.payload ) &&
                    $scope.msg.payload.length <= led_count && 
                    $scope.msg.payload.length > 0 ){

                    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])
                    
                    $scope.msg.label = label
                
                    for(let i = 0; i < $scope.msg.payload.length; i++){
                        if (typeof $scope.msg.payload[i] == 'string'){
                            $scope.bargraph[i] = $scope.msg.payload[i]
                        }
                    }
                    $scope.msg.bargraph = $scope.bargraph.reverse()
                    $scope.msg.bargraph = $scope.bargraph.reverse()

                } else if (typeof $scope.msg.payload !== "number") {
                    $scope.msg = {"bargraph": [...$scope.bargraph], "payload": 0, "label": label}

                } else if ($scope.msg.payload.length === 0) {
                    $scope.bargraph = new Array(led_count).fill("white")

                }

            } else {
                $scope.msg = {"bargraph": [...$scope.bargraph], "payload": 0, "label": label}

            }

        });

    })(scope);

</script>

<style>
.bargraph {
    float: right;
    padding: 3px;
    width: 3px;
    height: 10px;
    margin: 4px 2px 8px 0px;
    border-radius: 0%;
}
</style>

<div>{{msg.label}}

    <span ng-repeat="led in bargraph track by $index">
        <span class="bargraph" style="background-color: {{bargraph[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{bargraph[$index]}} 0 3px 15px;"></span>
    </span>

</div>
1 Like

@ozpos Again, I am not sure if I am understanding your actual required end result... But here is a simple way to inject a LED's position, colour and even a title, all with limited code needed.

Since you are unlikely to be dynamically changing the card size, just figure out the maximum needed string of LED's to fit and process the template and inject accordingly.

A blank LED is accomplished by making the "colour", "shell" & "glow" of a LED placeholder the same colour as the background (in my case "#333333").

image

image

image

[{"id":"96682096b9e10729","type":"inject","z":"2b9f58a274f446d8","name":"-RGB-","props":[{"p":"payload"},{"p":"title","v":"-RGB-","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"#333333\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#333333\"]","payloadType":"json","x":130,"y":120,"wires":[["aae3c27fbe18ee98"]]},{"id":"aae3c27fbe18ee98","type":"ui_template","z":"2b9f58a274f446d8","group":"45a28b30640ff9a5","name":"LED Bar","order":2,"width":6,"height":1,"format":"<style>\n.led-square {\n    float: right;\n    padding: 3px;\n    width: 24px;\n    height: 10px;\n    margin: 4px 2px 8px 0px;\n    border-radius: 0%;\n}\n</style>\n\n\n<div>{{msg.title}}\n<span class=\"led-square\" style=\"background-color: {{msg.payload[4]}}; box-shadow: {{msg.payload[4]}} 0 -1px 1px 0px, inset {{msg.payload[4]}}  0 -1px 4px, {{msg.payload[4]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[3]}}; box-shadow: {{msg.payload[3]}} 0 -1px 1px 0px, inset {{msg.payload[3]}}  0 -1px 4px, {{msg.payload[3]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[2]}}; box-shadow: {{msg.payload[2]}} 0 -1px 1px 0px, inset {{msg.payload[2]}}  0 -1px 4px, {{msg.payload[2]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[1]}}; box-shadow: {{msg.payload[1]}} 0 -1px 1px 0px, inset {{msg.payload[1]}}  0 -1px 4px, {{msg.payload[1]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[0]}}; box-shadow: {{msg.payload[0]}} 0 -1px 1px 0px, inset {{msg.payload[0]}}  0 -1px 4px, {{msg.payload[0]}} 0 3px 15px;\"></span>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":380,"y":120,"wires":[[]]},{"id":"83398054e405d2b2","type":"inject","z":"2b9f58a274f446d8","name":"R-G-B","props":[{"p":"payload"},{"p":"title","v":"R-G-B","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"#FF0000\",\"#333333\",\"#00FF00\",\"#333333\",\"#0000FF\"]","payloadType":"json","x":130,"y":200,"wires":[["a790ff625da48e9f"]]},{"id":"10470845386e3bf7","type":"inject","z":"2b9f58a274f446d8","name":"WRGBK","props":[{"p":"payload"},{"p":"title","v":"WRGBK","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#000000\"]","payloadType":"json","x":140,"y":160,"wires":[["0f5f43ae4f446fdc"]]},{"id":"0f5f43ae4f446fdc","type":"ui_template","z":"2b9f58a274f446d8","group":"45a28b30640ff9a5","name":"LED Bar","order":3,"width":6,"height":1,"format":"<style>\n.led-square {\n    float: right;\n    padding: 3px;\n    width: 24px;\n    height: 10px;\n    margin: 4px 2px 8px 0px;\n    border-radius: 0%;\n}\n</style>\n\n\n<div>{{msg.title}}\n<span class=\"led-square\" style=\"background-color: {{msg.payload[4]}}; box-shadow: {{msg.payload[4]}} 0 -1px 1px 0px, inset {{msg.payload[4]}}  0 -1px 4px, {{msg.payload[4]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[3]}}; box-shadow: {{msg.payload[3]}} 0 -1px 1px 0px, inset {{msg.payload[3]}}  0 -1px 4px, {{msg.payload[3]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[2]}}; box-shadow: {{msg.payload[2]}} 0 -1px 1px 0px, inset {{msg.payload[2]}}  0 -1px 4px, {{msg.payload[2]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[1]}}; box-shadow: {{msg.payload[1]}} 0 -1px 1px 0px, inset {{msg.payload[1]}}  0 -1px 4px, {{msg.payload[1]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[0]}}; box-shadow: {{msg.payload[0]}} 0 -1px 1px 0px, inset {{msg.payload[0]}}  0 -1px 4px, {{msg.payload[0]}} 0 3px 15px;\"></span>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":380,"y":160,"wires":[[]]},{"id":"a790ff625da48e9f","type":"ui_template","z":"2b9f58a274f446d8","group":"45a28b30640ff9a5","name":"LED Bar","order":4,"width":6,"height":1,"format":"<style>\n.led-square {\n    float: right;\n    padding: 3px;\n    width: 24px;\n    height: 10px;\n    margin: 4px 2px 8px 0px;\n    border-radius: 0%;\n}\n</style>\n\n\n<div>{{msg.title}}\n<span class=\"led-square\" style=\"background-color: {{msg.payload[4]}}; box-shadow: {{msg.payload[4]}} 0 -1px 1px 0px, inset {{msg.payload[4]}}  0 -1px 4px, {{msg.payload[4]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[3]}}; box-shadow: {{msg.payload[3]}} 0 -1px 1px 0px, inset {{msg.payload[3]}}  0 -1px 4px, {{msg.payload[3]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[2]}}; box-shadow: {{msg.payload[2]}} 0 -1px 1px 0px, inset {{msg.payload[2]}}  0 -1px 4px, {{msg.payload[2]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[1]}}; box-shadow: {{msg.payload[1]}} 0 -1px 1px 0px, inset {{msg.payload[1]}}  0 -1px 4px, {{msg.payload[1]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[0]}}; box-shadow: {{msg.payload[0]}} 0 -1px 1px 0px, inset {{msg.payload[0]}}  0 -1px 4px, {{msg.payload[0]}} 0 3px 15px;\"></span>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":380,"y":200,"wires":[[]]},{"id":"f878539454c0a219","type":"inject","z":"2b9f58a274f446d8","name":"Blank","props":[{"p":"payload"},{"p":"title","v":"Blank","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"[\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\"]","payloadType":"json","x":130,"y":80,"wires":[["980360b85c417cca","a790ff625da48e9f","aae3c27fbe18ee98","0f5f43ae4f446fdc"]]},{"id":"980360b85c417cca","type":"ui_template","z":"2b9f58a274f446d8","group":"45a28b30640ff9a5","name":"LED Bar","order":1,"width":6,"height":1,"format":"<style>\n.led-square {\n    float: right;\n    padding: 3px;\n    width: 24px;\n    height: 10px;\n    margin: 4px 2px 8px 0px;\n    border-radius: 0%;\n}\n</style>\n\n\n<div>{{msg.title}}\n<span class=\"led-square\" style=\"background-color: {{msg.payload[4]}}; box-shadow: {{msg.payload[4]}} 0 -1px 1px 0px, inset {{msg.payload[4]}}  0 -1px 4px, {{msg.payload[4]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[3]}}; box-shadow: {{msg.payload[3]}} 0 -1px 1px 0px, inset {{msg.payload[3]}}  0 -1px 4px, {{msg.payload[3]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[2]}}; box-shadow: {{msg.payload[2]}} 0 -1px 1px 0px, inset {{msg.payload[2]}}  0 -1px 4px, {{msg.payload[2]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[1]}}; box-shadow: {{msg.payload[1]}} 0 -1px 1px 0px, inset {{msg.payload[1]}}  0 -1px 4px, {{msg.payload[1]}} 0 3px 15px;\"></span>\n<span class=\"led-square\" style=\"background-color: {{msg.payload[0]}}; box-shadow: {{msg.payload[0]}} 0 -1px 1px 0px, inset {{msg.payload[0]}}  0 -1px 4px, {{msg.payload[0]}} 0 3px 15px;\"></span>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":380,"y":80,"wires":[[]]},{"id":"45a28b30640ff9a5","type":"ui_group","name":"LED Bar","tab":"2b177a1903e90f6f","order":17,"disp":true,"width":"6","collapse":false},{"id":"2b177a1903e90f6f","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]
1 Like

Hi @Gunner, Thank you for getting back to me. I am trying to show 32 leds and have a function maintain persistence over server restarts, browser reloads and nr deploys. The function node will also be able to change led colours on receipt of flow messages.

I am flagging a bit now and need to sleep. I will examine your flow in the morning. What I have so far is:


image

[
    {
        "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": 140,
        "wires": []
    },
    {
        "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": 160,
        "y": 120,
        "wires": [
            [
                "50c3809ef18339bf",
                "962284f73fc0a664"
            ]
        ]
    },
    {
        "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": 160,
        "y": 80,
        "wires": [
            [
                "50c3809ef18339bf",
                "962284f73fc0a664"
            ]
        ]
    },
    {
        "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": 510,
        "y": 40,
        "wires": [
            [
                "962284f73fc0a664"
            ]
        ]
    },
    {
        "id": "9d69baab914b9193",
        "type": "inject",
        "z": "77b9551a682cccf9",
        "name": "empty array",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[]",
        "payloadType": "jsonata",
        "x": 150,
        "y": 40,
        "wires": [
            [
                "962284f73fc0a664",
                "50c3809ef18339bf"
            ]
        ]
    },
    {
        "id": "52ab717f225a0b77",
        "type": "function",
        "z": "77b9551a682cccf9",
        "name": "gpio1",
        "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    case \"_save_\":\n        let a = JSON.stringify(gpio.payload);\n        let b = JSON.stringify(msg.payload);\n        if (a != b) {\n            let o = {};\n            o.payload = JSON.parse(b)\n            o.topic = cmd[0];\n            flow.set(node.name, o);\n            gpio.payload = o.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    default:\n}\nif ( refresh_ui ){\n    msg.topic = \"_refresh_\";\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": [
            [
                "d81a5f772e875be5",
                "50c3809ef18339bf"
            ]
        ]
    },
    {
        "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": 150,
        "y": 300,
        "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": 510,
        "y": 200,
        "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": 430,
        "y": 340,
        "wires": [
            [
                "52ab717f225a0b77"
            ]
        ]
    },
    {
        "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": 690,
        "y": 300,
        "wires": [
            [
                "506e043758776735"
            ]
        ]
    },
    {
        "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": 690,
        "y": 340,
        "wires": [
            [
                "506e043758776735"
            ]
        ]
    },
    {
        "id": "a0343d6543eb0cf8",
        "type": "debug",
        "z": "77b9551a682cccf9",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 690,
        "y": 60,
        "wires": []
    },
    {
        "id": "78f22f43f578c394",
        "type": "inject",
        "z": "77b9551a682cccf9",
        "name": "32 shifted colours",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "_refresh_",
        "payload": "[\"#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\",\"#0000ff\"]",
        "payloadType": "jsonata",
        "x": 140,
        "y": 160,
        "wires": [
            [
                "50c3809ef18339bf"
            ]
        ]
    },
    {
        "id": "e0f19e1943082fff",
        "type": "inject",
        "z": "77b9551a682cccf9",
        "name": "32 shifted colours t:_save_",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "_save_",
        "payload": "[\"#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\",\"#0000ff\"]",
        "payloadType": "jsonata",
        "x": 430,
        "y": 300,
        "wires": [
            [
                "52ab717f225a0b77"
            ]
        ]
    },
    {
        "id": "e4105e0c5c51be4e",
        "type": "comment",
        "z": "77b9551a682cccf9",
        "name": "Controller Verbs",
        "info": "",
        "x": 540,
        "y": 260,
        "wires": []
    },
    {
        "id": "c290d3642ea87e9a",
        "type": "inject",
        "z": "77b9551a682cccf9",
        "name": "w #0000ff to 2",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "w #0000ff",
        "payload": "2",
        "payloadType": "num",
        "x": 150,
        "y": 340,
        "wires": [
            [
                "52ab717f225a0b77"
            ]
        ]
    },
    {
        "id": "506e043758776735",
        "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    case \"_save_\":\n        let a = JSON.stringify(gpio.payload);\n        let b = JSON.stringify(msg.payload);\n        if (a != b) {\n            let o = {};\n            o.payload = JSON.parse(b)\n            o.topic = cmd[0];\n            flow.set(node.name, o);\n            gpio.payload = o.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    default:\n}\nif ( refresh_ui ){\n    msg.topic = \"_refresh_\";\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": 180,
        "wires": [
            [
                "962284f73fc0a664"
            ]
        ]
    },
    {
        "id": "50c3809ef18339bf",
        "type": "ui_template",
        "z": "77b9551a682cccf9",
        "group": "879c5e97.07fff",
        "name": "LED Array 1",
        "order": 7,
        "width": "0",
        "height": "0",
        "format": "<script>\n\n(function($scope) {\n\n    // Inspired by h t t p s://flows.nodered.org/user/Hugobox\n    const led_count = 32\n    const label = \"GPIO 1\"\n    let initialised = false\n\n    $scope.bargraph = new Array(led_count).fill(\"black\")\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: $scope.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 \"\n                    + Array.isArray($scope.msg.payload) + \" length \" + $scope.msg.payload.length + \" typeof \" + typeof\n                    $scope.msg.payload[0])\n\n                $scope.msg.label = label\n\n                for(let i = 0; i < $scope.msg.payload.length; i++){\n                    if (typeof $scope.msg.payload[i]=='string' ){\n                        $scope.bargraph[i]=$scope.msg.payload[i]\n                    } \n                }\n                $scope.msg.bargraph=$scope.bargraph.reverse()\n                $scope.msg.bargraph=$scope.bargraph.reverse()\n            } else if (typeof $scope.msg.payload !==\"number\" ) {\n                $scope.msg={\"bargraph\": [...$scope.bargraph], \"payload\" : 0, \"label\" : label} \n            } else if ($scope.msg.payload.length===0) {\n                $scope.bargraph=new Array(led_count).fill(\"black\") \n            } \n        } else {\n            $scope.msg={\"bargraph\": [...$scope.bargraph], \"payload\" : 0, \"label\" : label} \n        } \n    }); \n})(scope); \n\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\n    <span ng-repeat=\"led in bargraph track by $index\">\n<span class=\"bargraph\" style=\"background-color: {{bargraph[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{bargraph[$index]}} 0 3px 15px;\"></span>\n    </span>\n</div>\n",
        "storeOutMessages": false,
        "fwdInMessages": true,
        "resendOnRefresh": false,
        "templateScope": "local",
        "x": 370,
        "y": 140,
        "wires": [
            [
                "52ab717f225a0b77",
                "7e1c80b7bacaa1eb"
            ]
        ]
    },
    {
        "id": "962284f73fc0a664",
        "type": "ui_template",
        "z": "77b9551a682cccf9",
        "group": "879c5e97.07fff",
        "name": "LED Array 1",
        "order": 7,
        "width": "0",
        "height": "0",
        "format": "<script>\n\n(function($scope) {\n\n    // Inspired by h t t p s://flows.nodered.org/user/Hugobox\n    const led_count = 32\n    const label = \"GPIO 1\"\n    let initialised = false\n\n    $scope.bargraph = new Array(led_count).fill(\"black\")\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: $scope.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 \"\n                    + Array.isArray($scope.msg.payload) + \" length \" + $scope.msg.payload.length + \" typeof \" + typeof\n                    $scope.msg.payload[0])\n\n                $scope.msg.label = label\n\n                for(let i = 0; i < $scope.msg.payload.length; i++){\n                    if (typeof $scope.msg.payload[i]=='string' ){\n                        $scope.bargraph[i]=$scope.msg.payload[i]\n                    } \n                }\n                $scope.msg.bargraph=$scope.bargraph.reverse()\n                $scope.msg.bargraph=$scope.bargraph.reverse()\n            } else if (typeof $scope.msg.payload !==\"number\" ) {\n                $scope.msg={\"bargraph\": [...$scope.bargraph], \"payload\" : 0, \"label\" : label} \n            } else if ($scope.msg.payload.length===0) {\n                $scope.bargraph=new Array(led_count).fill(\"black\") \n            } \n        } else {\n            $scope.msg={\"bargraph\": [...$scope.bargraph], \"payload\" : 0, \"label\" : label} \n        } \n    }); \n})(scope); \n\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\n    <span ng-repeat=\"led in bargraph track by $index\">\n<span class=\"bargraph\" style=\"background-color: {{bargraph[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{bargraph[$index]}} 0 3px 15px;\"></span>\n    </span>\n</div>\n",
        "storeOutMessages": false,
        "fwdInMessages": true,
        "resendOnRefresh": false,
        "templateScope": "local",
        "x": 690,
        "y": 100,
        "wires": [
            [
                "a0343d6543eb0cf8",
                "506e043758776735"
            ]
        ]
    },
    {
        "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
    }
]

Thanks again.

OK, I realized that a lot of your code is probably for the persistence or the end results, and not the generating of LEDs and/or colors... so my two bits may not be of value. But at least I did figure out the code you were using to generate only the LEDs needed (based on length of JSON array) without needing to hardcode that in the template. It does display the JSON array from right to left, but I suspect there is a way of inverting that somehow??

EDIT: A preceding function node with...

let rev = msg.payload.reverse();
msg.payload = rev;
return msg;

...will do the trick. But I can't seem to get the same code to work within the template itself :thinking:


I did clean up my code a bit to demonstrate the injected JSON determines everything... # of LEDs, colour (or blank) & even placement. Perhaps having that msg.payload stored or recalled will help with persistence of the page?

image

image image

image image

image

[{"id":"96682096b9e10729","type":"inject","z":"2b9f58a274f446d8","name":"-RGB-     -RGB-","props":[{"p":"payload"},{"p":"title","v":"-RGB-     -RGB-","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"#444444\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#444444\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\"]","payloadType":"json","x":150,"y":160,"wires":[["980360b85c417cca"]]},{"id":"83398054e405d2b2","type":"inject","z":"2b9f58a274f446d8","name":"Colour Words","props":[{"p":"payload"},{"p":"title","v":"Colour Words","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]","payloadType":"json","x":150,"y":240,"wires":[["980360b85c417cca"]]},{"id":"10470845386e3bf7","type":"inject","z":"2b9f58a274f446d8","name":"WRGBWRGBW...","props":[{"p":"payload"},{"p":"title","v":"WRGBW...","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\"]","payloadType":"json","x":170,"y":200,"wires":[["980360b85c417cca"]]},{"id":"f878539454c0a219","type":"inject","z":"2b9f58a274f446d8","name":"16 \"blanks\" - ","props":[{"p":"payload"},{"p":"title","v":"16 Blanks","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\"]","payloadType":"json","x":150,"y":120,"wires":[["980360b85c417cca"]]},{"id":"980360b85c417cca","type":"ui_template","z":"2b9f58a274f446d8","group":"45a28b30640ff9a5","name":"LED Bar","order":1,"width":8,"height":1,"format":"<style>\n.led-square {\n    float: right;\n    padding: 3px;\n    width: 10px;\n    height: 24px;\n    margin: 4px 2px 8px 0px;\n    border-radius: 0%;\n}\n</style>\n\n\n<div>{{msg.title}}\n    <span ng-repeat=\"led in msg.payload track by $index\">\n        <span class=\"led-square\" style=\"background-color: {{msg.payload[$index]}}; box-shadow: {{msg.payload[$index]}} 0 -1px 1px 0px, inset {{msg.payload[$index]}}  0 -1px 4px, {{msg.payload[$index]}} 0 3px 15px;\"></span>\n    </span>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":500,"y":160,"wires":[[]]},{"id":"e5e84b3b8a884128","type":"inject","z":"2b9f58a274f446d8","name":"Clear","props":[{"p":"payload"},{"p":"title","v":"Clear","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"[\"#333333\"]","payloadType":"json","x":130,"y":80,"wires":[["980360b85c417cca"]]},{"id":"45a28b30640ff9a5","type":"ui_group","name":"LED Bar","tab":"2b177a1903e90f6f","order":17,"disp":true,"width":8,"collapse":false},{"id":"2b177a1903e90f6f","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]
1 Like

Hi @Gunner, Thank you very much for your response.

Your code works very well and I like the fact that led count, placement, clear are not fixed within the template.

I also like the simplicity a lot. Your code also preserves state on deploy and browser refresh, thank you.

I find it frustrating that because there are so many ways of doing this kind of thing it is hard to choose the most efficient path.

I will try and get rid of some controller bloat. For your template the controller would need to determine the surrounding background colour from the theme so that clear would work.

Many thanks, I will post back improvements if anyone is interested.

Hi @Buckskin, sorry for the delay in acknowledgement.

Thank you for your response it worked perfectly. Thanks for saying you do not get problem 1., as a result I suspect now that another flow is in conflict or has a problem somewhere other that this flow.

Hi @Gunner, I am trying to shrink the led size to get a row of 32. Is css inset is preventing this do you think ?

<style>
.led-square {
    float: right;
    padding: 3px;
    width: 2px;
    height: 6px;
/*    margin: 4px 2px 8px 0px;*/
    border-radius: 0%;
}
</style>

<div>{{msg.title}}
    <span ng-repeat="led in msg.payload track by $index">
        <span class="led-square" style="background-color: {{msg.payload[$index]}}; box-shadow: {{msg.payload[$index]}} 0 -1px 1px 0px, inset {{msg.payload[$index]}}  0 -1px 4px, {{msg.payload[$index]}} 0 3px 15px;"></span>
    </span>
</div>

These are never 2px by 6px.
image

Ok found the culprit, it was padding.
image
To get two rows closer presumably it would be simple to have msg.bank1 and msg.bank2 in the same template.

It would be truly marvellous if position and size were automatic so that two or more dashboard widget rows (one above the other) would produce an evenly spaced (vertically) seamless appearance !
image

[
    {
        "id": "e9d02814f49e8375",
        "type": "tab",
        "label": "Flow 5",
        "disabled": false,
        "info": ""
    },
    {
        "id": "3744daf31a555ed2",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "-RGB-     -RGB-",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "title",
                "v": "-RGB-     -RGB-",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\"#333333\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#444444\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\"]",
        "payloadType": "json",
        "x": 230,
        "y": 140,
        "wires": [
            [
                "fc63f59bcc9ea2ca"
            ]
        ]
    },
    {
        "id": "6e7e1ea619492a2f",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "32 Colour Words",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "title",
                "v": "gpio 1",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
        "payloadType": "json",
        "x": 240,
        "y": 220,
        "wires": [
            [
                "2b8f2f0e10996f17"
            ]
        ]
    },
    {
        "id": "aef55f20d90b683c",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "WRGBWRGBW...",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "title",
                "v": "WRGBW...",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\"]",
        "payloadType": "json",
        "x": 250,
        "y": 180,
        "wires": [
            [
                "fc63f59bcc9ea2ca"
            ]
        ]
    },
    {
        "id": "f905a72cc994a903",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "32 \"blanks\" - ",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "title",
                "v": "32 Blanks",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\"]",
        "payloadType": "json",
        "x": 230,
        "y": 100,
        "wires": [
            [
                "fc63f59bcc9ea2ca"
            ]
        ]
    },
    {
        "id": "fc63f59bcc9ea2ca",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 1,
        "width": "0",
        "height": "0",
        "format": "<style>\n.led-square {\n    float: right;\n    padding: 0px;\n    width: 9px;\n    height: 16px;\n    margin: 0px 2px 8px 0px;\n    border-radius: 0%;\n}\n</style>\n\n<div>{{msg.title}}\n    <span ng-repeat=\"led in msg.payload track by $index\">\n        <span class=\"led-square\" 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",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 500,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "3b481042da4d5d71",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "Clear",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "title",
                "v": "Clear",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "[\"#33ff33\"]",
        "payloadType": "json",
        "x": 210,
        "y": 60,
        "wires": [
            [
                "fc63f59bcc9ea2ca"
            ]
        ]
    },
    {
        "id": "a997fd73ae39a097",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "d": true,
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 1,
        "width": "0",
        "height": "0",
        "format": "<style>\n.led-square {\n    float: right;\n    padding: 3px;\n    width: 2px;\n    height: 6px;\n/*    margin: 4px 2px 8px 0px;*/\n    border-radius: 0%;\n}\n</style>\n\n<div>{{msg.title}}\n    <span ng-repeat=\"led in msg.payload track by $index\">\n        <span class=\"led-square\" style=\"background-color: {{msg.payload[$index]}}; box-shadow: {{msg.payload[$index]}} 0 -1px 1px 0px, inset {{msg.payload[$index]}}  0 -1px 4px, {{msg.payload[$index]}} 0 3px 15px;\"></span>\n    </span>\n</div>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 500,
        "y": 100,
        "wires": [
            []
        ]
    },
    {
        "id": "2b8f2f0e10996f17",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 1,
        "width": "0",
        "height": "0",
        "format": "<style>\n.led-square {\n    float: right;\n    padding: 0px;\n    width: 9px;\n    height: 16px;\n    margin: 0px 2px 8px 0px;\n    border-radius: 0%;\n}\n</style>\n\n<div>{{msg.title}}\n    <span ng-repeat=\"led in msg.payload track by $index\">\n        <span class=\"led-square\" 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",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 500,
        "y": 200,
        "wires": [
            []
        ]
    },
    {
        "id": "45a28b30640ff9a5",
        "type": "ui_group",
        "name": "LED Bar",
        "tab": "2b177a1903e90f6f",
        "order": 17,
        "disp": true,
        "width": "8",
        "collapse": false
    },
    {
        "id": "2b177a1903e90f6f",
        "type": "ui_tab",
        "name": "Home",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]

Hi @Gunner, I hope you do not mind if I ask another question.
As you can see I have managed to squash things up a bit:
image
image
The problem now is overflow. It display scrollbar sometimes:
image
Other times it is OK ?
image

Any ideas anyone ?

[
    {
        "id": "e9d02814f49e8375",
        "type": "tab",
        "label": "Flow 5",
        "disabled": false,
        "info": ""
    },
    {
        "id": "3744daf31a555ed2",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "-RGB-     -RGB-",
        "props": [
            {
                "p": "bank1",
                "v": "[\"#333333\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#444444\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "-RGB-     -RGB- 1",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"#333333\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#444444\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "-RGB-     -RGB- 2",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 230,
        "y": 140,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "6e7e1ea619492a2f",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "32 Colour Words",
        "props": [
            {
                "p": "bank1",
                "v": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "gpio 1",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "gpio 2",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 240,
        "y": 220,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "aef55f20d90b683c",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "WRGBWRGBW...",
        "props": [
            {
                "p": "bank1",
                "v": "[\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "WRGBW...1",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "WRGBW...2",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 250,
        "y": 180,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "f905a72cc994a903",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "32 \"blanks\" - ",
        "props": [
            {
                "p": "bank1",
                "v": "[\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "32 Blanks 1",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "32 Blanks 2",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 230,
        "y": 100,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "3b481042da4d5d71",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "Clear",
        "props": [
            {
                "p": "bank1",
                "v": "[\"#333333\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "Clear 1",
                "vt": "str"
            },
            {
                "p": "title2",
                "v": "Clear 2",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"#333333\"]",
                "vt": "json"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 210,
        "y": 60,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "a997fd73ae39a097",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "d": true,
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 3,
        "width": "0",
        "height": "0",
        "format": "<style>\n.led-square {\n    float: right;\n    padding: 3px;\n    width: 2px;\n    height: 6px;\n/*    margin: 4px 2px 8px 0px;*/\n    border-radius: 0%;\n}\n</style>\n\n<div>{{msg.title}}\n    <span ng-repeat=\"led in msg.payload track by $index\">\n        <span class=\"led-square\" style=\"background-color: {{msg.payload[$index]}}; box-shadow: {{msg.payload[$index]}} 0 -1px 1px 0px, inset {{msg.payload[$index]}}  0 -1px 4px, {{msg.payload[$index]}} 0 3px 15px;\"></span>\n    </span>\n</div>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 540,
        "y": 60,
        "wires": [
            []
        ]
    },
    {
        "id": "772a9052d2614525",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "32 bank1 + 32 bank2",
        "props": [
            {
                "p": "bank1",
                "v": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "gpio 2",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "gpio 1",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 280,
        "y": 280,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "d71dd936ba304424",
        "type": "ui_button",
        "z": "e9d02814f49e8375",
        "name": "",
        "group": "45a28b30640ff9a5",
        "order": 4,
        "width": "8",
        "height": "1",
        "passthru": false,
        "label": "button",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 530,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "b0b420044b7d5165",
        "type": "ui_button",
        "z": "e9d02814f49e8375",
        "name": "",
        "group": "45a28b30640ff9a5",
        "order": 6,
        "width": "8",
        "height": "1",
        "passthru": false,
        "label": "button",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 530,
        "y": 280,
        "wires": [
            []
        ]
    },
    {
        "id": "ede609a5f526f011",
        "type": "ui_button",
        "z": "e9d02814f49e8375",
        "name": "",
        "group": "45a28b30640ff9a5",
        "order": 9,
        "width": "8",
        "height": "1",
        "passthru": false,
        "label": "button",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 530,
        "y": 320,
        "wires": [
            []
        ]
    },
    {
        "id": "f03301c3b8671d1d",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 5,
        "width": "8",
        "height": "1",
        "format": "<style>\n.led-square {\n    overflow: hidden;\n    float: right;\n    padding: 0px;\n    width: 8px;\n    height: 20px;\n    margin: 0px 2px 0px 0px;\n    border-radius: 0%;\n}\n</style>\n\n<div style=\"width: 100%; overflow: hidden; position: absolute; top: 3px; left: 6px; padding: 0px;\">{{msg.title1}}\n    <div style=\"min-width: 0; position: relative; float:right; padding-right: 7px;\">\n    <span ng-repeat=\"led in msg.bank1 track by $index\" style=\"position: relative; float: right;\">\n        <span class=\"led-square\" style=\"background-color: {{msg.bank1[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.bank1[$index]}} 0 3px 20px;\"></span>\n    </span>\n    </div>\n</div>\n<div style=\"width: 100%; overflow: hidden; position: absolute; top: 27px; left: 6px; padding: 0px;\">{{msg.title2}}    \n    <div style=\"min-width: 0; position: relative; float:right; padding-right: 7px;\">\n    <span ng-repeat=\"led in msg.bank2 track by $index\" style=\"position: relative; float: right;\">\n        <span class=\"led-square\" style=\"background-color: {{msg.bank2[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.bank2[$index]}} 0 3px 20px;\"></span>\n    </span>\n    </div>\n</div>\n",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 540,
        "y": 200,
        "wires": [
            []
        ]
    },
    {
        "id": "a0cafa2e5bb52453",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 5,
        "width": "8",
        "height": "1",
        "format": "<style>\n.led-square {\n    overflow: hidden;\n    float: right;\n    padding: 0px;\n    width: 8px;\n    height: 20px;\n    margin: 0px 2px 0px 0px;\n    border-radius: 0%;\n}\n</style>\n\n<div style=\"width: 100%; overflow: hidden; position: absolute; top: 3px; left: 6px; padding: 0px;\">{{msg.title1}}\n    <div style=\"min-width: 0; position: relative; float:right; padding-right: 7px;\">\n    <span ng-repeat=\"led in msg.bank1 track by $index\" style=\"position: relative; float: right;\">\n        <span class=\"led-square\" style=\"background-color: {{msg.bank1[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.bank1[$index]}} 0 3px 20px;\"></span>\n    </span>\n    </div>\n</div>\n<div style=\"width: 100%; overflow: hidden; position: absolute; top: 27px; left: 6px; padding: 0px;\">{{msg.title2}}    \n    <div style=\"min-width: 0; position: relative; float:right; padding-right: 7px;\">\n    <span ng-repeat=\"led in msg.bank2 track by $index\" style=\"position: relative; float: right;\">\n        <span class=\"led-square\" style=\"background-color: {{msg.bank2[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.bank2[$index]}} 0 3px 20px;\"></span>\n    </span>\n    </div>\n</div>\n",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 540,
        "y": 240,
        "wires": [
            []
        ]
    },
    {
        "id": "45a28b30640ff9a5",
        "type": "ui_group",
        "name": "LED Bar",
        "tab": "2b177a1903e90f6f",
        "order": 17,
        "disp": true,
        "width": "8",
        "collapse": false
    },
    {
        "id": "2b177a1903e90f6f",
        "type": "ui_tab",
        "name": "Home",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]

No prob... just waking up at the moment :sleepy: Need coffee :coffee:

When a ui_element gets too close to the boarder of the card, the scroll bars appear... it is the nature of the browser. I suspect you may be adding one extra LED without being aware? Or just packing too close to card edge and the browser can be getting picky.

I found this will at least center the display within the allotted card space.

image

Thanks. Will try it after a dog walk.

I changed the html and css to use class="led-squarex" to make sure there was no interference from another definition but still the same random overflow.

What I cannot understand is how 1 out of 4 rows is blank. As here:
image

[
    {
        "id": "e9d02814f49e8375",
        "type": "tab",
        "label": "Flow 5",
        "disabled": false,
        "info": ""
    },
    {
        "id": "3744daf31a555ed2",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "16 -RGB-     -RGB-",
        "props": [
            {
                "p": "bank1",
                "v": "[\"#333333\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#444444\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "-RGB-     -RGB- 1",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"#333333\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#333333\",\"#444444\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#444444\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "-RGB-     -RGB- 2",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 240,
        "y": 140,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "6e7e1ea619492a2f",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "32 Colour Words",
        "props": [
            {
                "p": "bank1",
                "v": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "gpio 1",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "gpio 2",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 240,
        "y": 220,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "aef55f20d90b683c",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "16 WRGBWRGBW...",
        "props": [
            {
                "p": "bank1",
                "v": "[\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "WRGBW...1",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\",\"#FFFFFF\",\"#FF0000\",\"#00FF00\",\"#0000FF\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "WRGBW...2",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 260,
        "y": 180,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "f905a72cc994a903",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "32 \"blanks\" - ",
        "props": [
            {
                "p": "bank1",
                "v": "[\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "32 Blanks 1",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\",\"#444444\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "32 Blanks 2",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 230,
        "y": 100,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "3b481042da4d5d71",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "1 Clear",
        "props": [
            {
                "p": "bank1",
                "v": "[\"#333333\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "Clear 1",
                "vt": "str"
            },
            {
                "p": "title2",
                "v": "Clear 2",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"#333333\"]",
                "vt": "json"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 210,
        "y": 60,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "a997fd73ae39a097",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "d": true,
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 3,
        "width": "0",
        "height": "0",
        "format": "<style>\n.led-square {\n    float: right;\n    padding: 3px;\n    width: 2px;\n    height: 6px;\n/*    margin: 4px 2px 8px 0px;*/\n    border-radius: 0%;\n}\n</style>\n\n<div>{{msg.title}}\n    <span ng-repeat=\"led in msg.payload track by $index\">\n        <span class=\"led-square\" style=\"background-color: {{msg.payload[$index]}}; box-shadow: {{msg.payload[$index]}} 0 -1px 1px 0px, inset {{msg.payload[$index]}}  0 -1px 4px, {{msg.payload[$index]}} 0 3px 15px;\"></span>\n    </span>\n</div>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 540,
        "y": 60,
        "wires": [
            []
        ]
    },
    {
        "id": "772a9052d2614525",
        "type": "inject",
        "z": "e9d02814f49e8375",
        "name": "32 bank1 + 32 bank2",
        "props": [
            {
                "p": "bank1",
                "v": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
                "vt": "json"
            },
            {
                "p": "title2",
                "v": "gpio 2",
                "vt": "str"
            },
            {
                "p": "bank2",
                "v": "[\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\",\"yellow\",\"green\",\"darkgrey\",\"orange\",\"beige\",\"navy\",\"cyan\",\"magenta\",\"white\",\"lightgreen\",\"purple\",\"red\",\"black\",\"hotpink\",\"lightgrey\",\"blue\"]",
                "vt": "json"
            },
            {
                "p": "title1",
                "v": "gpio 1",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 280,
        "y": 280,
        "wires": [
            [
                "f03301c3b8671d1d",
                "a0cafa2e5bb52453"
            ]
        ]
    },
    {
        "id": "d71dd936ba304424",
        "type": "ui_button",
        "z": "e9d02814f49e8375",
        "name": "",
        "group": "45a28b30640ff9a5",
        "order": 4,
        "width": "8",
        "height": "1",
        "passthru": false,
        "label": "button",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 530,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "b0b420044b7d5165",
        "type": "ui_button",
        "z": "e9d02814f49e8375",
        "name": "",
        "group": "45a28b30640ff9a5",
        "order": 6,
        "width": "8",
        "height": "1",
        "passthru": false,
        "label": "button",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 530,
        "y": 280,
        "wires": [
            []
        ]
    },
    {
        "id": "ede609a5f526f011",
        "type": "ui_button",
        "z": "e9d02814f49e8375",
        "name": "",
        "group": "45a28b30640ff9a5",
        "order": 9,
        "width": "8",
        "height": "1",
        "passthru": false,
        "label": "button",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 530,
        "y": 320,
        "wires": [
            []
        ]
    },
    {
        "id": "f03301c3b8671d1d",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 5,
        "width": "8",
        "height": "1",
        "format": "<style>\n.led-squarex {\n    overflow: hidden;\n    float: right;\n    padding: 0px;\n    width: 8px;\n    height: 20px;\n    margin: 0px 2px 0px 0px;\n    border-radius: 0%;\n}\n</style>\n\n<div style=\"width: 100%; flex: 1; overflow: hidden; position: absolute; top: 3px; left: 6px; padding: 0px;\">{{msg.title1}}\n    <div style=\"min-width: 0; position: relative; float:right; padding-right: 7px;\">\n    <span ng-repeat=\"led in msg.bank1 track by $index\" style=\"position: relative; float: right;\">\n        <span class=\"led-squarex\" style=\"background-color: {{msg.bank1[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.bank1[$index]}} 0 3px 20px;\"></span>\n    </span>\n    </div>\n</div>\n<div style=\"width: 100%; flex: 1; overflow: hidden; position: absolute; top: 27px; left: 6px; padding: 0px;\">{{msg.title2}}    \n    <div style=\"min-width: 0; position: relative; float:right; padding-right: 7px;\">\n    <span ng-repeat=\"led in msg.bank2 track by $index\" style=\"position: relative; float: right;\">\n        <span class=\"led-squarex\" style=\"background-color: {{msg.bank2[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.bank2[$index]}} 0 3px 20px;\"></span>\n    </span>\n    </div>\n</div>\n",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 540,
        "y": 200,
        "wires": [
            []
        ]
    },
    {
        "id": "a0cafa2e5bb52453",
        "type": "ui_template",
        "z": "e9d02814f49e8375",
        "group": "45a28b30640ff9a5",
        "name": "LED Bar",
        "order": 5,
        "width": "8",
        "height": "1",
        "format": "<style>\n.led-squarex {\n    overflow: hidden;\n    float: right;\n    padding: 0px;\n    width: 8px;\n    height: 20px;\n    margin: 0px 2px 0px 0px;\n    border-radius: 0%;\n}\n</style>\n\n<div style=\"width: 100%; overflow: hidden; position: absolute; top: 3px; left: 6px; padding: 0px;\">{{msg.title1}}\n    <div style=\"min-width: 0; position: relative; float:right; padding-right: 7px;\">\n    <span ng-repeat=\"led in msg.bank1 track by $index\" style=\"position: relative; float: right;\">\n        <span class=\"led-squarex\" style=\"background-color: {{msg.bank1[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.bank1[$index]}} 0 3px 20px;\"></span>\n    </span>\n    </div>\n</div>\n<div style=\"width: 100%; overflow: hidden; position: absolute; top: 27px; left: 6px; padding: 0px;\">{{msg.title2}}    \n    <div style=\"min-width: 0; position: relative; float:right; padding-right: 7px;\">\n    <span ng-repeat=\"led in msg.bank2 track by $index\" style=\"position: relative; float: right;\">\n        <span class=\"led-square\" style=\"background-color: {{msg.bank2[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black  0 -1px 4px, {{msg.bank2[$index]}} 0 3px 20px;\"></span>\n    </span>\n    </div>\n</div>\n",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "x": 540,
        "y": 240,
        "wires": [
            []
        ]
    },
    {
        "id": "45a28b30640ff9a5",
        "type": "ui_group",
        "name": "LED Bar",
        "tab": "2b177a1903e90f6f",
        "order": 17,
        "disp": true,
        "width": "8",
        "collapse": false
    },
    {
        "id": "2b177a1903e90f6f",
        "type": "ui_tab",
        "name": "Home",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]

P.S. Do you know how I can insert my flow here and it show like this

When exporting, chose compact JSON

image

You are missing the x in the last span class="led-square" should be span class="led-squarex"

I make the same mistake when duplicating things :stuck_out_tongue:

Try adjusting this setting...

image

90% works good, as you can see in the top bar. Granted, I have additional padding built into my card space (custom dashboard settings) so you might be able to go higher if you wish.

image

Managed to push it to 98.5%. Also got rid of a shadow on the far right.

The only wrinkle is a shadow from clear. Not so bothered about it.


Not so good on light theme though.

Nearly there thank you very much.

All the LED colours, box shadows, insets, etc. are adjustable in the settings.

<span class="led-squarex" style="background-color: {{msg.bank1[$index]}}; box-shadow: black 0 -1px 1px 0px, inset black 0 -1px 4px, {{msg.bank1[$index]}} 0 3px 20px;"></span>

Change black to {{msg.bank1[$index]}}. Or some other stable colour if you want it to be always visible.

Hi @Gunner, Thank you, I know that as well and since there will be a controller to handle server restart persistence then the controller can send the correct colour.

The problem is how can you tell which theme is active ?
I found these:

:root {
    --nr-dashboard-pageBackgroundColor: #111111;
    --nr-dashboard-pageTitlebarBackgroundColor: #097479;
    --nr-dashboard-groupTextColor: #0eb8c0;
    --nr-dashboard-groupBackgroundColor: #333333;
    --nr-dashboard-groupBorderColor: #555555;
    --nr-dashboard-widgetTextColor: #eeeeee;
    --nr-dashboard-widgetBackgroundColor: #097479;
    --nr-dashboard-widgetBorderColor: #333333;
    --nr-dashboard-widgetColor: #097479;
    --nr-dashboard-widgetBgndColor: #333333;
}

Light theme:

:root {
    --nr-dashboard-pageBackgroundColor: #fafafa;
    --nr-dashboard-pageTitlebarBackgroundColor: #0094CE;
    --nr-dashboard-groupTextColor: #1bbfff;
    --nr-dashboard-groupBackgroundColor: #ffffff;
    --nr-dashboard-groupBorderColor: #ffffff;
    --nr-dashboard-widgetTextColor: #111111;
    --nr-dashboard-widgetBackgroundColor: #0094ce;
    --nr-dashboard-widgetBorderColor: #ffffff;
    --nr-dashboard-widgetColor: #0094ce;
    --nr-dashboard-widgetBgndColor: #ffffff;
}

Dynamic "monitoring" of the dashboard theme, if possible without hacking the core, and thus dynamically adjusting all those custom colors to match... would be a bit beyond my current abilities :stuck_out_tongue: