gpio_widgets.json 52 KB
{
  "widgetsBundle": {
    "alias": "gpio_widgets",
    "title": "GPIO widgets",
    "image": null
  },
  "widgetTypes": [
    {
      "alias": "basic_gpio_control",
      "name": "Basic GPIO Control",
      "descriptor": {
        "type": "rpc",
        "sizeX": 4,
        "sizeY": 2,
        "resources": [],
        "templateHtml": "<fieldset class=\"gpio-panel\" ng-disabled=\"!rpcEnabled || executingRpcRequest\" style=\"height: 100%;\">\n    <section class=\"gpio-row\" layout=\"row\" ng-repeat=\"row in rows track by $index\" \n            ng-style=\"{'height': prefferedRowHeight+'px'}\">\n        <section flex layout=\"row\" ng-repeat=\"cell in row track by $index\">\n            <section layout=\"row\" flex ng-if=\"cell\" layout-align=\"{{$index===0 ? 'end center' : 'start center'}}\">\n                <span class=\"gpio-left-label\" ng-show=\"$index===0\">{{ cell.label }}</span>\n                <section layout=\"row\" class=\"switch-panel\" layout-align=\"start center\" ng-class=\"$index===0 ? 'col-0' : 'col-1'\"\n                      ng-style=\"{'height': prefferedRowHeight+'px', 'backgroundColor': '{{ switchPanelBackgroundColor }}'}\">\n                    <span class=\"pin\" ng-show=\"$index===0\">{{cell.pin}}</span>\n                    <span flex ng-show=\"$index===1\"></span>\n                    <md-switch\n                        aria-label=\"{{ cell.label }}\"\n                        ng-disabled=\"!rpcEnabled || executingRpcRequest\"\n                        ng-model=\"cell.enabled\" \n                        ng-change=\"cell.enabled = !cell.enabled\" \n                        ng-click=\"gpioClick($event, cell)\">\n                    </md-switch>\n                    <span flex ng-show=\"$index===0\"></span>\n                    <span class=\"pin\" ng-show=\"$index===1\">{{cell.pin}}</span>\n                </section>\n                <span class=\"gpio-right-label\" ng-show=\"$index===1\">{{ cell.label }}</span>\n            </section>\n            <section layout=\"row\" flex ng-if=\"!cell\">\n                <span flex ng-show=\"$index===0\"></span>\n                <span class=\"switch-panel\"\n                      ng-style=\"{'height': prefferedRowHeight+'px', 'backgroundColor': '{{ switchPanelBackgroundColor }}'}\"></span>\n                <span flex ng-show=\"$index===1\"></span>\n            </section>\n        </section>\n    </section>                            \n    <span class=\"error\" style=\"position: absolute; bottom: 5px;\" ng-show=\"rpcErrorText\">{{rpcErrorText}}</span>\n    <md-progress-linear ng-show=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" md-mode=\"indeterminate\"></md-progress-linear>    \n</fieldset>",
        "templateCss": ".error {\n    font-size: 14px !important;\n    color: maroon;/*rgb(250,250,250);*/\n    background-color: transparent;\n    padding: 6px;\n}\n\n.error span {\n    margin: auto;\n}\n\n.gpio-panel {\n    padding-top: 10px;\n    white-space: nowrap;\n}\n\n.switch-panel {\n    margin: 0;\n    height: 32px;\n    width: 66px;\n    min-width: 66px;\n}\n\n.switch-panel md-switch {\n    margin: 0;\n    width: 36px;\n    min-width: 36px;\n}\n\n.switch-panel md-switch > div.md-container {\n    margin: 0;\n}\n\n.switch-panel.col-0 md-switch {\n    padding-left: 8px;\n    padding-right: 4px;\n}\n\n.switch-panel.col-1 md-switch {\n    padding-left: 4px;\n    padding-right: 8px;\n}\n\n.gpio-row {\n    height: 32px;\n}\n\n.pin {\n    margin-top: auto;\n    margin-bottom: auto;\n    color: white;\n    font-size: 12px;\n    width: 16px;\n    min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n    margin-left: auto;\n    padding-left: 2px;\n    text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n    margin-right: auto;\n    \n    text-align: left;\n}\n\n.gpio-left-label {\n    margin-right: 8px;\n}\n\n.gpio-right-label {\n    margin-left: 8px;\n}",
        "controllerScript": "self.onInit = function() {\n    \n    var i, gpio;\n    var scope = self.ctx.$scope;\n    var settings = self.ctx.settings;\n    scope.gpioList = [];\n    for (var g = 0; g < settings.gpioList.length; g++) {\n        gpio = settings.gpioList[g];\n        scope.gpioList.push(\n            {\n                row: gpio.row,\n                col: gpio.col,\n                pin: gpio.pin,\n                label: gpio.label,\n                enabled: false\n            }\n        );\n    }\n\n    scope.requestTimeout = settings.requestTimeout || 1000;\n\n    scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n    scope.gpioStatusRequest = {\n        method: \"getGpioStatus\",\n        paramsBody: \"{}\"\n    };\n    \n    if (settings.gpioStatusRequest) {\n        scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n        scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n    }\n    \n    scope.gpioStatusChangeRequest = {\n        method: \"setGpioStatus\",\n        paramsBody: \"{\\n   \\\"pin\\\": \\\"{$pin}\\\",\\n   \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n    };\n    \n    if (settings.gpioStatusChangeRequest) {\n        scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n        scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n    }\n    \n    scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n    \n    if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n        scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n    }\n    \n    scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n    \n    function requestGpioStatus() {\n        self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n                            scope.gpioStatusRequest.paramsBody, \n                            scope.requestTimeout)\n            .then(\n                function success(responseBody) {\n                    for (var g = 0; g < scope.gpioList.length; g++) {\n                        var gpio = scope.gpioList[g];\n                        var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n                        gpio.enabled = enabled;                        \n                    }\n                }\n            );\n    }\n    \n    function changeGpioStatus(gpio) {\n        var pin = gpio.pin + '';\n        var enabled = !gpio.enabled;\n        enabled = enabled === true ? 'true' : 'false';\n        var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n        var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n        self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n                                    requestBody, scope.requestTimeout)\n                    .then(\n                        function success(responseBody) {\n                            var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n                            gpio.enabled = enabled;\n                        }\n                    );\n    }\n    \n    scope.gpioCells = {};\n    var rowCount = 0;\n    for (i = 0; i < scope.gpioList.length; i++) {\n        gpio = scope.gpioList[i];\n        scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n        rowCount = Math.max(rowCount, gpio.row+1);\n    }\n    \n    scope.prefferedRowHeight = 32;\n    scope.rows = [];\n    for (i = 0; i < rowCount; i++) {\n        var row = [];\n        for (var c =0; c<2;c++) {\n            if (scope.gpioCells[i+'_'+c]) {\n                row[c] = scope.gpioCells[i+'_'+c];\n            } else {\n                row[c] = null;\n            }\n        }\n        scope.rows.push(row);\n    }\n\n    scope.gpioClick = function($event, gpio) {\n        changeGpioStatus(gpio);\n    };\n\n    requestGpioStatus();    \n    \n    self.onResize();\n}\n\nself.onResize = function() {\n    var scope = self.ctx.$scope;\n    var rowCount = scope.rows.length;\n    var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n    prefferedRowHeight = Math.min(32, prefferedRowHeight);\n    prefferedRowHeight = Math.max(12, prefferedRowHeight);\n    scope.prefferedRowHeight = prefferedRowHeight;\n    var ratio = prefferedRowHeight/32;\n    var switches = $('md-switch', self.ctx.$container);\n    switches.css('height', 30*ratio+'px');\n    switches.css('width', 36*ratio+'px');\n    switches.css('min-width', 36*ratio+'px');\n    $('.md-container', switches).css('height', 24*ratio+'px');\n    $('.md-container', switches).css('width', 36*ratio+'px');\n    var bars = $('.md-bar', self.ctx.$container);\n    bars.css('height', 14*ratio+'px');\n    bars.css('width', 34*ratio+'px');\n    var thumbs = $('.md-thumb', self.ctx.$container);\n    thumbs.css('height', 20*ratio+'px');\n    thumbs.css('width', 20*ratio+'px');\n    \n    var leftLabels = $('.gpio-left-label', self.ctx.$container);\n    leftLabels.css('font-size', 16*ratio+'px');\n    var rightLabels = $('.gpio-right-label', self.ctx.$container);\n    rightLabels.css('font-size', 16*ratio+'px');\n    var pins = $('.pin', self.ctx.$container);\n    var pinsFontSize = Math.max(9, 12*ratio);\n    pins.css('font-size', pinsFontSize+'px');    \n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"gpioList\": {\n                \"title\": \"Gpio switches\",\n                \"type\": \"array\",\n                \"minItems\" : 1,\n                \"items\": {\n                    \"title\": \"Gpio switch\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"pin\": {\n                            \"title\": \"Pin\",\n                            \"type\": \"number\"\n                        },\n                        \"label\": {\n                            \"title\": \"Label\",\n                            \"type\": \"string\"\n                        },\n                        \"row\": {\n                            \"title\": \"Row\",\n                            \"type\": \"number\"\n                        },\n                        \"col\": {\n                            \"title\": \"Column\",\n                            \"type\": \"number\"\n                        }\n                    },\n                    \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n                }\n            },\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout\",\n                \"type\": \"number\",\n                \"default\": 500\n            },\n            \"switchPanelBackgroundColor\": {\n                \"title\": \"Switches panel background color\",\n                \"type\": \"string\",\n                \"default\": \"#008a00\"\n            },\n            \"gpioStatusRequest\": {\n                \"title\": \"GPIO status request\",\n                \"type\": \"object\",\n                 \"properties\": {\n                    \"method\": {\n                        \"title\": \"Method name\",\n                        \"type\": \"string\",\n                        \"default\": \"getGpioStatus\"\n                    },\n                    \"paramsBody\": {\n                      \"title\": \"Method body\",\n                      \"type\": \"string\",\n                      \"default\": \"{}\"\n                    }\n                },\n                \"required\": [\"method\", \"paramsBody\"]\n            },\n            \"gpioStatusChangeRequest\": {\n                \"title\": \"GPIO status change request\",\n                \"type\": \"object\",\n                 \"properties\": {\n                    \"method\": {\n                        \"title\": \"Method name\",\n                        \"type\": \"string\",\n                        \"default\": \"setGpioStatus\"\n                    },\n                    \"paramsBody\": {\n                      \"title\": \"Method body\",\n                      \"type\": \"string\",\n                      \"default\": \"{\\n   \\\"pin\\\": \\\"{$pin}\\\",\\n   \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n                    }\n                },\n                \"required\": [\"method\", \"paramsBody\"]\n            },\n            \"parseGpioStatusFunction\": {\n                \"title\": \"Parse gpio status function\",\n                \"type\": \"string\",\n                \"default\": \"return body[pin] === true;\"\n            } \n        },\n        \"required\": [\"gpioList\", \n                     \"requestTimeout\",\n                     \"switchPanelBackgroundColor\",\n                     \"gpioStatusRequest\",\n                     \"gpioStatusChangeRequest\",\n                     \"parseGpioStatusFunction\"]\n    },\n    \"form\": [\n        \"gpioList\",\n        \"requestTimeout\",\n        {\n            \"key\": \"switchPanelBackgroundColor\",\n            \"type\": \"color\"\n        },\n        {\n            \"key\": \"gpioStatusRequest\",\n            \"items\": [\n                \"gpioStatusRequest.method\",\n                {\n                    \"key\": \"gpioStatusRequest.paramsBody\",\n                    \"type\": \"json\"\n                }\n            ]\n        },\n        {\n            \"key\": \"gpioStatusChangeRequest\",\n            \"items\": [\n                \"gpioStatusChangeRequest.method\",\n                {\n                    \"key\": \"gpioStatusChangeRequest.paramsBody\",\n                    \"type\": \"json\"\n                }\n            ]\n        },\n        {\n            \"key\": \"parseGpioStatusFunction\",\n            \"type\": \"javascript\"\n        }\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n   \\\"pin\\\": \\\"{$pin}\\\",\\n   \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#b71c1c\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"_uniqueKey\":2}]},\"title\":\"Basic GPIO Control\"}"
      }
    },
    {
      "alias": "gpio_panel",
      "name": "Basic GPIO Panel",
      "descriptor": {
        "type": "latest",
        "sizeX": 5,
        "sizeY": 2,
        "resources": [],
        "templateHtml": "<div class=\"gpio-panel\" style=\"height: 100%;\">\n    <section layout=\"row\" ng-repeat=\"row in rows\">\n        <section flex layout=\"row\" ng-repeat=\"cell in row\">\n            <section layout=\"row\" flex ng-if=\"cell\" layout-align=\"{{$index===0 ? 'end center' : 'start center'}}\">\n                <span class=\"gpio-left-label\" ng-show=\"$index===0\">{{ cell.label }}</span>\n                <section layout=\"row\" class=\"led-panel\" ng-class=\"$index===0 ? 'col-0' : 'col-1'\"\n                      ng-style=\"{backgroundColor: ledPanelBackgroundColor }\">\n                    <span class=\"pin\" ng-show=\"$index===0\">{{cell.pin}}</span>\n                    <span class=\"led-container\">\n                        <tb-led-light size=\"prefferedRowHeight\"\n                                      color-on=\"cell.colorOn\"\n                                      color-off=\"cell.colorOff\"\n                                      off-opacity=\"'0.9'\"\n                                      tb-enabled=\"cell.enabled\">\n                        </tb-led-light>\n                    </span>\n                    <span class=\"pin\" ng-show=\"$index===1\">{{cell.pin}}</span>\n                </section>\n                <span class=\"gpio-right-label\" ng-show=\"$index===1\">{{ cell.label }}</span>\n            </section>\n            <section layout=\"row\" flex ng-if=\"!cell\">\n                <span flex ng-show=\"$index===0\"></span>\n                <span class=\"led-panel\"\n                      ng-style=\"{backgroundColor: ledPanelBackgroundColor }\"></span>\n                <span flex ng-show=\"$index===1\"></span>\n            </section>\n        </section>\n    </section>                            \n</div>",
        "templateCss": ".error {\n    font-size: 14px !important;\n    color: maroon;/*rgb(250,250,250);*/\n    background-color: transparent;\n    padding: 6px;\n}\n\n.error span {\n    margin: auto;\n}\n\n.gpio-panel {\n    padding-top: 10px;\n    white-space: nowrap;\n}\n\n.gpio-panel tb-led-light > div {\n    margin: auto;\n}\n\n.led-panel {\n    margin: 0;\n    width: 66px;\n    min-width: 66px;\n}\n\n.led-container {\n    width: 48px;\n    min-width: 48px;\n}\n\n.pin {\n    margin-top: auto;\n    margin-bottom: auto;\n    color: white;\n    font-size: 12px;\n    width: 16px;\n    min-width: 16px;\n}\n\n.led-panel.col-0 .pin {\n    margin-left: auto;\n    padding-left: 2px;\n    text-align: right;\n}\n\n.led-panel.col-1 .pin {\n    margin-right: auto;\n    \n    text-align: left;\n}\n\n.gpio-left-label {\n    margin-right: 8px;\n}\n\n.gpio-right-label {\n    margin-left: 8px;\n}",
        "controllerScript": "self.onInit = function() {\n    var i, gpio;\n    \n    var scope = self.ctx.$scope;\n    var settings = self.ctx.settings;\n    \n    scope.gpioList = [];\n    scope.gpioByPin = {};\n    for (var g = 0; g < settings.gpioList.length; g++) {\n        gpio = settings.gpioList[g];\n        scope.gpioList.push(\n            {\n                row: gpio.row,\n                col: gpio.col,\n                pin: gpio.pin,\n                label: gpio.label,\n                enabled: false,\n                colorOn: tinycolor(gpio.color).lighten(20).toHexString(),\n                colorOff: tinycolor(gpio.color).darken().toHexString()\n            }\n        );\n        scope.gpioByPin[gpio.pin] = scope.gpioList[scope.gpioList.length-1];\n    }\n\n    scope.ledPanelBackgroundColor = settings.ledPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n    scope.gpioCells = {};\n    var rowCount = 0;\n    for (i = 0; i < scope.gpioList.length; i++) {\n        gpio = scope.gpioList[i];\n        scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n        rowCount = Math.max(rowCount, gpio.row+1);\n    }\n    \n    scope.prefferedRowHeight = 32;\n    scope.rows = [];\n    for (i = 0; i < rowCount; i++) {\n        var row = [];\n        for (var c =0; c<2;c++) {\n            if (scope.gpioCells[i+'_'+c]) {\n                row[c] = scope.gpioCells[i+'_'+c];\n            } else {\n                row[c] = null;\n            }\n        }\n        scope.rows.push(row);\n    }    \n    \n    self.onResize();\n}\n\nself.onDataUpdated = function() {\n    var changed = false;\n    for (var d = 0; d < self.ctx.data.length; d++) {\n        var cellData = self.ctx.data[d];\n        var dataKey = cellData.dataKey;\n        var gpio = self.ctx.$scope.gpioByPin[dataKey.label];\n        if (gpio) {\n            var enabled = false;\n            if (cellData.data.length > 0) {\n                var tvPair = cellData.data[cellData.data.length - 1];\n                enabled = (tvPair[1] === true || tvPair[1] === 'true');\n            }\n            if (gpio.enabled != enabled) {\n                changed = true;\n                gpio.enabled = enabled;\n            }\n        }\n    }\n    if (changed) {\n        self.ctx.$scope.$digest();\n    }    \n}\n\nself.onResize = function() {\n    var rowCount = self.ctx.$scope.rows.length;\n    var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n    prefferedRowHeight = Math.min(32, prefferedRowHeight);\n    prefferedRowHeight = Math.max(12, prefferedRowHeight);\n    self.ctx.$scope.prefferedRowHeight = prefferedRowHeight;\n    \n    var ratio = prefferedRowHeight/32;\n    \n    var leftLabels = $('.gpio-left-label', self.ctx.$container);\n    leftLabels.css('font-size', 16*ratio+'px');\n    var rightLabels = $('.gpio-right-label', self.ctx.$container);\n    rightLabels.css('font-size', 16*ratio+'px');\n    var pins = $('.pin', self.ctx.$container);\n    var pinsFontSize = Math.max(9, 12*ratio);\n    pins.css('font-size', pinsFontSize+'px');    \n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"gpioList\": {\n                \"title\": \"Gpio leds\",\n                \"type\": \"array\",\n                \"minItems\" : 1,\n                \"items\": {\n                    \"title\": \"Gpio led\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"pin\": {\n                            \"title\": \"Pin\",\n                            \"type\": \"number\"\n                        },\n                        \"label\": {\n                            \"title\": \"Label\",\n                            \"type\": \"string\"\n                        },\n                        \"row\": {\n                            \"title\": \"Row\",\n                            \"type\": \"number\"\n                        },\n                        \"col\": {\n                            \"title\": \"Column\",\n                            \"type\": \"number\"\n                        },\n                        \"color\": {\n                            \"title\": \"Color\",\n                            \"type\": \"string\",\n                            \"default\": \"red\"\n                        }\n                    },\n                    \"required\": [\"pin\", \"label\", \"row\", \"col\", \"color\"]\n                }\n            },\n            \"ledPanelBackgroundColor\": {\n                \"title\": \"LED panel background color\",\n                \"type\": \"string\",\n                \"default\": \"#008a00\"\n            } \n        },\n        \"required\": [\"gpioList\", \n                     \"ledPanelBackgroundColor\"]\n    },\n    \"form\": [\n        {\n            \"key\": \"gpioList\",\n            \"items\": [\n                \"gpioList[].pin\",\n                \"gpioList[].label\",\n                \"gpioList[].row\",\n                \"gpioList[].col\",\n                {\n                    \"key\": \"gpioList[].color\",\n                    \"type\": \"color\"\n                }\n            ]\n        },\n        {\n            \"key\": \"ledPanelBackgroundColor\",\n            \"type\": \"color\"\n        }\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"color\":\"#008000\",\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"color\":\"#ffff00\",\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"color\":\"#cf006f\",\"_uniqueKey\":2}],\"ledPanelBackgroundColor\":\"#b71c1c\"},\"title\":\"Basic GPIO Panel\",\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"1\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.22518255793320163,\"funcBody\":\"var period = time % 1500;\\nreturn period < 500;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"2\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7008206860666621,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 500 && period < 1000;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"3\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.42600325102193426,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 1000;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}}}"
      }
    },
    {
      "alias": "raspberry_pi_gpio_control",
      "name": "Raspberry Pi GPIO Control",
      "descriptor": {
        "type": "rpc",
        "sizeX": 6,
        "sizeY": 10.5,
        "resources": [],
        "templateHtml": "<fieldset class=\"gpio-panel\" ng-disabled=\"!rpcEnabled || executingRpcRequest\" style=\"height: 100%;\">\n    <section class=\"gpio-row\" layout=\"row\" ng-repeat=\"row in rows track by $index\" \n            ng-style=\"{'height': prefferedRowHeight+'px'}\">\n        <section flex layout=\"row\" ng-repeat=\"cell in row track by $index\">\n            <section layout=\"row\" flex ng-if=\"cell\" layout-align=\"{{$index===0 ? 'end center' : 'start center'}}\">\n                <span class=\"gpio-left-label\" ng-show=\"$index===0\">{{ cell.label }}</span>\n                <section layout=\"row\" class=\"switch-panel\" layout-align=\"start center\" ng-class=\"$index===0 ? 'col-0' : 'col-1'\"\n                      ng-style=\"{'height': prefferedRowHeight+'px', 'backgroundColor': '{{ switchPanelBackgroundColor }}'}\">\n                    <span class=\"pin\" ng-show=\"$index===0\">{{cell.pin}}</span>\n                    <span flex ng-show=\"$index===1\"></span>\n                    <md-switch\n                        aria-label=\"{{ cell.label }}\"\n                        ng-disabled=\"!rpcEnabled || executingRpcRequest\"\n                        ng-model=\"cell.enabled\" \n                        ng-change=\"cell.enabled = !cell.enabled\" \n                        ng-click=\"gpioClick($event, cell)\">\n                    </md-switch>\n                    <span flex ng-show=\"$index===0\"></span>\n                    <span class=\"pin\" ng-show=\"$index===1\">{{cell.pin}}</span>\n                </section>\n                <span class=\"gpio-right-label\" ng-show=\"$index===1\">{{ cell.label }}</span>\n            </section>\n            <section layout=\"row\" flex ng-if=\"!cell\">\n                <span flex ng-show=\"$index===0\"></span>\n                <span class=\"switch-panel\"\n                      ng-style=\"{'height': prefferedRowHeight+'px', 'backgroundColor': '{{ switchPanelBackgroundColor }}'}\"></span>\n                <span flex ng-show=\"$index===1\"></span>\n            </section>\n        </section>\n    </section>                            \n    <span class=\"error\" style=\"position: absolute; bottom: 5px;\" ng-show=\"rpcErrorText\">{{rpcErrorText}}</span>\n    <md-progress-linear ng-show=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" md-mode=\"indeterminate\"></md-progress-linear>    \n</fieldset>",
        "templateCss": ".error {\n    font-size: 14px !important;\n    color: maroon;/*rgb(250,250,250);*/\n    background-color: transparent;\n    padding: 6px;\n}\n\n.error span {\n    margin: auto;\n}\n\n.gpio-panel {\n    padding-top: 10px;\n    white-space: nowrap;\n}\n\n.switch-panel {\n    margin: 0;\n    height: 32px;\n    width: 66px;\n    min-width: 66px;\n}\n\n.switch-panel md-switch {\n    margin: 0;\n    width: 36px;\n    min-width: 36px;\n}\n\n.switch-panel md-switch > div.md-container {\n    margin: 0;\n}\n\n.switch-panel.col-0 md-switch {\n    margin-left: 8px;\n    margin-right: 4px;\n}\n\n.switch-panel.col-1 md-switch {\n    margin-left: 4px;\n    margin-right: 8px;\n}\n\n.gpio-row {\n    height: 32px;\n}\n\n.pin {\n    margin-top: auto;\n    margin-bottom: auto;\n    color: white;\n    font-size: 12px;\n    width: 16px;\n    min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n    margin-left: auto;\n    padding-left: 2px;\n    text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n    margin-right: auto;\n    \n    text-align: left;\n}\n\n.gpio-left-label {\n    margin-right: 8px;\n}\n\n.gpio-right-label {\n    margin-left: 8px;\n}",
        "controllerScript": "self.onInit = function() {\n    \n    var i, gpio;\n    var scope = self.ctx.$scope;\n    var settings = self.ctx.settings;\n    scope.gpioList = [];\n    for (var g = 0; g < settings.gpioList.length; g++) {\n        gpio = settings.gpioList[g];\n        scope.gpioList.push(\n            {\n                row: gpio.row,\n                col: gpio.col,\n                pin: gpio.pin,\n                label: gpio.label,\n                enabled: false\n            }\n        );\n    }\n\n    scope.requestTimeout = settings.requestTimeout || 1000;\n\n    scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n    scope.gpioStatusRequest = {\n        method: \"getGpioStatus\",\n        paramsBody: \"{}\"\n    };\n    \n    if (settings.gpioStatusRequest) {\n        scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n        scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n    }\n    \n    scope.gpioStatusChangeRequest = {\n        method: \"setGpioStatus\",\n        paramsBody: \"{\\n   \\\"pin\\\": \\\"{$pin}\\\",\\n   \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n    };\n    \n    if (settings.gpioStatusChangeRequest) {\n        scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n        scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n    }\n    \n    scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n    \n    if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n        scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n    }\n    \n    scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n    \n    function requestGpioStatus() {\n        self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n                            scope.gpioStatusRequest.paramsBody, \n                            scope.requestTimeout)\n            .then(\n                function success(responseBody) {\n                    for (var g = 0; g < scope.gpioList.length; g++) {\n                        var gpio = scope.gpioList[g];\n                        var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n                        gpio.enabled = enabled;                        \n                    }\n                }\n            );\n    }\n    \n    function changeGpioStatus(gpio) {\n        var pin = gpio.pin + '';\n        var enabled = !gpio.enabled;\n        enabled = enabled === true ? 'true' : 'false';\n        var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n        var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n        self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n                                    requestBody, scope.requestTimeout)\n                    .then(\n                        function success(responseBody) {\n                            var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n                            gpio.enabled = enabled;\n                        }\n                    );\n    }\n    \n    scope.gpioCells = {};\n    var rowCount = 0;\n    for (i = 0; i < scope.gpioList.length; i++) {\n        gpio = scope.gpioList[i];\n        scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n        rowCount = Math.max(rowCount, gpio.row+1);\n    }\n    \n    scope.prefferedRowHeight = 32;\n    scope.rows = [];\n    for (i = 0; i < rowCount; i++) {\n        var row = [];\n        for (var c =0; c<2;c++) {\n            if (scope.gpioCells[i+'_'+c]) {\n                row[c] = scope.gpioCells[i+'_'+c];\n            } else {\n                row[c] = null;\n            }\n        }\n        scope.rows.push(row);\n    }\n\n    scope.gpioClick = function($event, gpio) {\n        changeGpioStatus(gpio);\n    };\n\n    requestGpioStatus();    \n    \n    self.onResize();\n}\n\nself.onResize = function() {\n    var scope = self.ctx.$scope;\n    var rowCount = scope.rows.length;\n    var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n    prefferedRowHeight = Math.min(32, prefferedRowHeight);\n    prefferedRowHeight = Math.max(12, prefferedRowHeight);\n    scope.prefferedRowHeight = prefferedRowHeight;\n    var ratio = prefferedRowHeight/32;\n    var switches = $('md-switch', self.ctx.$container);\n    switches.css('height', 30*ratio+'px');\n    switches.css('width', 36*ratio+'px');\n    switches.css('min-width', 36*ratio+'px');\n    $('.md-container', switches).css('height', 24*ratio+'px');\n    $('.md-container', switches).css('width', 36*ratio+'px');\n    var bars = $('.md-bar', self.ctx.$container);\n    bars.css('height', 14*ratio+'px');\n    bars.css('width', 34*ratio+'px');\n    var thumbs = $('.md-thumb', self.ctx.$container);\n    thumbs.css('height', 20*ratio+'px');\n    thumbs.css('width', 20*ratio+'px');\n    \n    var leftLabels = $('.gpio-left-label', self.ctx.$container);\n    leftLabels.css('font-size', 16*ratio+'px');\n    var rightLabels = $('.gpio-right-label', self.ctx.$container);\n    rightLabels.css('font-size', 16*ratio+'px');\n    var pins = $('.pin', self.ctx.$container);\n    var pinsFontSize = Math.max(9, 12*ratio);\n    pins.css('font-size', pinsFontSize+'px');    \n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"gpioList\": {\n                \"title\": \"Gpio switches\",\n                \"type\": \"array\",\n                \"minItems\" : 1,\n                \"items\": {\n                    \"title\": \"Gpio switch\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"pin\": {\n                            \"title\": \"Pin\",\n                            \"type\": \"number\"\n                        },\n                        \"label\": {\n                            \"title\": \"Label\",\n                            \"type\": \"string\"\n                        },\n                        \"row\": {\n                            \"title\": \"Row\",\n                            \"type\": \"number\"\n                        },\n                        \"col\": {\n                            \"title\": \"Column\",\n                            \"type\": \"number\"\n                        }\n                    },\n                    \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n                }\n            },\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout\",\n                \"type\": \"number\",\n                \"default\": 500\n            },\n            \"switchPanelBackgroundColor\": {\n                \"title\": \"Switches panel background color\",\n                \"type\": \"string\",\n                \"default\": \"#008a00\"\n            },\n            \"gpioStatusRequest\": {\n                \"title\": \"GPIO status request\",\n                \"type\": \"object\",\n                 \"properties\": {\n                    \"method\": {\n                        \"title\": \"Method name\",\n                        \"type\": \"string\",\n                        \"default\": \"getGpioStatus\"\n                    },\n                    \"paramsBody\": {\n                      \"title\": \"Method body\",\n                      \"type\": \"string\",\n                      \"default\": \"{}\"\n                    }\n                },\n                \"required\": [\"method\", \"paramsBody\"]\n            },\n            \"gpioStatusChangeRequest\": {\n                \"title\": \"GPIO status change request\",\n                \"type\": \"object\",\n                 \"properties\": {\n                    \"method\": {\n                        \"title\": \"Method name\",\n                        \"type\": \"string\",\n                        \"default\": \"setGpioStatus\"\n                    },\n                    \"paramsBody\": {\n                      \"title\": \"Method body\",\n                      \"type\": \"string\",\n                      \"default\": \"{\\n   \\\"pin\\\": \\\"{$pin}\\\",\\n   \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n                    }\n                },\n                \"required\": [\"method\", \"paramsBody\"]\n            },\n            \"parseGpioStatusFunction\": {\n                \"title\": \"Parse gpio status function\",\n                \"type\": \"string\",\n                \"default\": \"return body[pin] === true;\"\n            } \n        },\n        \"required\": [\"gpioList\", \n                     \"requestTimeout\",\n                     \"switchPanelBackgroundColor\",\n                     \"gpioStatusRequest\",\n                     \"gpioStatusChangeRequest\",\n                     \"parseGpioStatusFunction\"]\n    },\n    \"form\": [\n        \"gpioList\",\n        \"requestTimeout\",\n        {\n            \"key\": \"switchPanelBackgroundColor\",\n            \"type\": \"color\"\n        },\n        {\n            \"key\": \"gpioStatusRequest\",\n            \"items\": [\n                \"gpioStatusRequest.method\",\n                {\n                    \"key\": \"gpioStatusRequest.paramsBody\",\n                    \"type\": \"json\"\n                }\n            ]\n        },\n        {\n            \"key\": \"gpioStatusChangeRequest\",\n            \"items\": [\n                \"gpioStatusChangeRequest.method\",\n                {\n                    \"key\": \"gpioStatusChangeRequest.paramsBody\",\n                    \"type\": \"json\"\n                }\n            ]\n        },\n        {\n            \"key\": \"parseGpioStatusFunction\",\n            \"type\": \"javascript\"\n        }\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n   \\\"pin\\\": \\\"{$pin}\\\",\\n   \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#008a00\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":7,\"label\":\"GPIO 4 (GPCLK0)\",\"row\":3,\"col\":0,\"_uniqueKey\":0},{\"pin\":11,\"label\":\"GPIO 17\",\"row\":5,\"col\":0,\"_uniqueKey\":1},{\"pin\":12,\"label\":\"GPIO 18\",\"row\":5,\"col\":1,\"_uniqueKey\":2},{\"_uniqueKey\":3,\"pin\":13,\"label\":\"GPIO 27\",\"row\":6,\"col\":0},{\"_uniqueKey\":4,\"pin\":15,\"label\":\"GPIO 22\",\"row\":7,\"col\":0},{\"_uniqueKey\":5,\"pin\":16,\"label\":\"GPIO 23\",\"row\":7,\"col\":1},{\"_uniqueKey\":6,\"pin\":18,\"label\":\"GPIO 24\",\"row\":8,\"col\":1},{\"_uniqueKey\":7,\"pin\":22,\"label\":\"GPIO 25\",\"row\":10,\"col\":1},{\"_uniqueKey\":8,\"pin\":29,\"label\":\"GPIO 5\",\"row\":14,\"col\":0},{\"_uniqueKey\":9,\"pin\":31,\"label\":\"GPIO 6\",\"row\":15,\"col\":0},{\"_uniqueKey\":10,\"pin\":32,\"label\":\"GPIO 12\",\"row\":15,\"col\":1},{\"_uniqueKey\":11,\"pin\":33,\"label\":\"GPIO 13\",\"row\":16,\"col\":0},{\"_uniqueKey\":12,\"pin\":35,\"label\":\"GPIO 19\",\"row\":17,\"col\":0},{\"_uniqueKey\":13,\"pin\":36,\"label\":\"GPIO 16\",\"row\":17,\"col\":1},{\"_uniqueKey\":14,\"pin\":37,\"label\":\"GPIO 26\",\"row\":18,\"col\":0},{\"_uniqueKey\":15,\"pin\":38,\"label\":\"GPIO 20\",\"row\":18,\"col\":1},{\"_uniqueKey\":16,\"pin\":40,\"label\":\"GPIO 21\",\"row\":19,\"col\":1}]},\"title\":\"Raspberry Pi GPIO Control\"}"
      }
    },
    {
      "alias": "raspberry_pi_gpio_panel",
      "name": "Raspberry Pi GPIO Panel",
      "descriptor": {
        "type": "latest",
        "sizeX": 7,
        "sizeY": 10.5,
        "resources": [],
        "templateHtml": "<div class=\"gpio-panel\" style=\"height: 100%;\">\n    <section layout=\"row\" ng-repeat=\"row in rows\">\n        <section flex layout=\"row\" ng-repeat=\"cell in row\">\n            <section layout=\"row\" flex ng-if=\"cell\" layout-align=\"{{$index===0 ? 'end center' : 'start center'}}\">\n                <span class=\"gpio-left-label\" ng-show=\"$index===0\">{{ cell.label }}</span>\n                <section layout=\"row\" class=\"led-panel\" ng-class=\"$index===0 ? 'col-0' : 'col-1'\"\n                      ng-style=\"{backgroundColor: ledPanelBackgroundColor}\">\n                    <span class=\"pin\" ng-show=\"$index===0\">{{cell.pin}}</span>\n                    <span class=\"led-container\">\n                        <tb-led-light size=\"prefferedRowHeight\"\n                                      color-on=\"cell.colorOn\"\n                                      color-off=\"cell.colorOff\"\n                                      off-opacity=\"'0.9'\"\n                                      tb-enabled=\"cell.enabled\">\n                        </tb-led-light>\n                    </span>\n                    <span class=\"pin\" ng-show=\"$index===1\">{{cell.pin}}</span>\n                </section>\n                <span class=\"gpio-right-label\" ng-show=\"$index===1\">{{ cell.label }}</span>\n            </section>\n            <section layout=\"row\" flex ng-if=\"!cell\">\n                <span flex ng-show=\"$index===0\"></span>\n                <span class=\"led-panel\"\n                      ng-style=\"{backgroundColor: ledPanelBackgroundColor}\"></span>\n                <span flex ng-show=\"$index===1\"></span>\n            </section>\n        </section>\n    </section>                            \n</div>",
        "templateCss": ".error {\n    font-size: 14px !important;\n    color: maroon;/*rgb(250,250,250);*/\n    background-color: transparent;\n    padding: 6px;\n}\n\n.error span {\n    margin: auto;\n}\n\n.gpio-panel {\n    padding-top: 10px;\n    white-space: nowrap;\n}\n\n.gpio-panel tb-led-light > div {\n    margin: auto;\n}\n\n.led-panel {\n    margin: 0;\n    width: 66px;\n    min-width: 66px;\n}\n\n.led-container {\n    width: 48px;\n    min-width: 48px;\n}\n\n.pin {\n    margin-top: auto;\n    margin-bottom: auto;\n    color: white;\n    font-size: 12px;\n    width: 16px;\n    min-width: 16px;\n}\n\n.led-panel.col-0 .pin {\n    margin-left: auto;\n    padding-left: 2px;\n    text-align: right;\n}\n\n.led-panel.col-1 .pin {\n    margin-right: auto;\n    \n    text-align: left;\n}\n\n.gpio-left-label {\n    margin-right: 8px;\n}\n\n.gpio-right-label {\n    margin-left: 8px;\n}",
        "controllerScript": "self.onInit = function() {\n    var i, gpio;\n    \n    var scope = self.ctx.$scope;\n    var settings = self.ctx.settings;\n    \n    scope.gpioList = [];\n    scope.gpioByPin = {};\n    for (var g = 0; g < settings.gpioList.length; g++) {\n        gpio = settings.gpioList[g];\n        scope.gpioList.push(\n            {\n                row: gpio.row,\n                col: gpio.col,\n                pin: gpio.pin,\n                label: gpio.label,\n                enabled: false,\n                colorOn: tinycolor(gpio.color).lighten(20).toHexString(),\n                colorOff: tinycolor(gpio.color).darken().toHexString()\n            }\n        );\n        scope.gpioByPin[gpio.pin] = scope.gpioList[scope.gpioList.length-1];\n    }\n\n    scope.ledPanelBackgroundColor = settings.ledPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n    scope.gpioCells = {};\n    var rowCount = 0;\n    for (i = 0; i < scope.gpioList.length; i++) {\n        gpio = scope.gpioList[i];\n        scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n        rowCount = Math.max(rowCount, gpio.row+1);\n    }\n    \n    scope.prefferedRowHeight = 32;\n    scope.rows = [];\n    for (i = 0; i < rowCount; i++) {\n        var row = [];\n        for (var c =0; c<2;c++) {\n            if (scope.gpioCells[i+'_'+c]) {\n                row[c] = scope.gpioCells[i+'_'+c];\n            } else {\n                row[c] = null;\n            }\n        }\n        scope.rows.push(row);\n    }    \n    \n    self.onResize();\n}\n\nself.onDataUpdated = function() {\n    var changed = false;\n    for (var d = 0; d < self.ctx.data.length; d++) {\n        var cellData = self.ctx.data[d];\n        var dataKey = cellData.dataKey;\n        var gpio = self.ctx.$scope.gpioByPin[dataKey.label];\n        if (gpio) {\n            var enabled = false;\n            if (cellData.data.length > 0) {\n                var tvPair = cellData.data[cellData.data.length - 1];\n                enabled = (tvPair[1] === true || tvPair[1] === 'true');\n            }\n            if (gpio.enabled != enabled) {\n                changed = true;\n                gpio.enabled = enabled;\n            }\n        }\n    }\n    if (changed) {\n        self.ctx.$scope.$digest();\n    }    \n}\n\nself.onResize = function() {\n    var rowCount = self.ctx.$scope.rows.length;\n    var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n    prefferedRowHeight = Math.min(32, prefferedRowHeight);\n    prefferedRowHeight = Math.max(12, prefferedRowHeight);\n    self.ctx.$scope.prefferedRowHeight = prefferedRowHeight;\n    \n    var ratio = prefferedRowHeight/32;\n    \n    var leftLabels = $('.gpio-left-label', self.ctx.$container);\n    leftLabels.css('font-size', 16*ratio+'px');\n    var rightLabels = $('.gpio-right-label', self.ctx.$container);\n    rightLabels.css('font-size', 16*ratio+'px');\n    var pins = $('.pin', self.ctx.$container);\n    var pinsFontSize = Math.max(9, 12*ratio);\n    pins.css('font-size', pinsFontSize+'px');    \n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"gpioList\": {\n                \"title\": \"Gpio leds\",\n                \"type\": \"array\",\n                \"minItems\" : 1,\n                \"items\": {\n                    \"title\": \"Gpio led\",\n                    \"type\": \"object\",\n                    \"properties\": {\n                        \"pin\": {\n                            \"title\": \"Pin\",\n                            \"type\": \"number\"\n                        },\n                        \"label\": {\n                            \"title\": \"Label\",\n                            \"type\": \"string\"\n                        },\n                        \"row\": {\n                            \"title\": \"Row\",\n                            \"type\": \"number\"\n                        },\n                        \"col\": {\n                            \"title\": \"Column\",\n                            \"type\": \"number\"\n                        },\n                        \"color\": {\n                            \"title\": \"Color\",\n                            \"type\": \"string\",\n                            \"default\": \"red\"\n                        }\n                    },\n                    \"required\": [\"pin\", \"label\", \"row\", \"col\", \"color\"]\n                }\n            },\n            \"ledPanelBackgroundColor\": {\n                \"title\": \"LED panel background color\",\n                \"type\": \"string\",\n                \"default\": \"#008a00\"\n            } \n        },\n        \"required\": [\"gpioList\", \n                     \"ledPanelBackgroundColor\"]\n    },\n    \"form\": [\n        {\n            \"key\": \"gpioList\",\n            \"items\": [\n                \"gpioList[].pin\",\n                \"gpioList[].label\",\n                \"gpioList[].row\",\n                \"gpioList[].col\",\n                {\n                    \"key\": \"gpioList[].color\",\n                    \"type\": \"color\"\n                }\n            ]\n        },\n        {\n            \"key\": \"ledPanelBackgroundColor\",\n            \"type\": \"color\"\n        }\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"gpioList\":[{\"pin\":1,\"label\":\"3.3V\",\"row\":0,\"col\":0,\"color\":\"#fc9700\",\"_uniqueKey\":0},{\"pin\":2,\"label\":\"5V\",\"row\":0,\"col\":1,\"color\":\"#fb0000\",\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 2 (I2C1_SDA)\",\"row\":1,\"col\":0,\"color\":\"#02fefb\",\"_uniqueKey\":2},{\"color\":\"#fb0000\",\"pin\":4,\"label\":\"5V\",\"row\":1,\"col\":1},{\"color\":\"#02fefb\",\"pin\":5,\"label\":\"GPIO 3 (I2C1_SCL)\",\"row\":2,\"col\":0},{\"color\":\"#000000\",\"pin\":6,\"label\":\"GND\",\"row\":2,\"col\":1},{\"color\":\"#00fd00\",\"pin\":7,\"label\":\"GPIO 4 (GPCLK0)\",\"row\":3,\"col\":0},{\"color\":\"#fdfb00\",\"pin\":8,\"label\":\"GPIO 14 (UART_TXD)\",\"row\":3,\"col\":1},{\"color\":\"#000000\",\"pin\":9,\"label\":\"GND\",\"row\":4,\"col\":0},{\"color\":\"#fdfb00\",\"pin\":10,\"label\":\"GPIO 15 (UART_RXD)\",\"row\":4,\"col\":1},{\"color\":\"#00fd00\",\"pin\":11,\"label\":\"GPIO 17\",\"row\":5,\"col\":0},{\"color\":\"#00fd00\",\"pin\":12,\"label\":\"GPIO 18\",\"row\":5,\"col\":1},{\"color\":\"#00fd00\",\"pin\":13,\"label\":\"GPIO 27\",\"row\":6,\"col\":0},{\"color\":\"#000000\",\"pin\":14,\"label\":\"GND\",\"row\":6,\"col\":1},{\"color\":\"#00fd00\",\"pin\":15,\"label\":\"GPIO 22\",\"row\":7,\"col\":0},{\"color\":\"#00fd00\",\"pin\":16,\"label\":\"GPIO 23\",\"row\":7,\"col\":1},{\"color\":\"#fc9700\",\"pin\":17,\"label\":\"3.3V\",\"row\":8,\"col\":0},{\"color\":\"#00fd00\",\"pin\":18,\"label\":\"GPIO 24\",\"row\":8,\"col\":1},{\"color\":\"#fd01fd\",\"pin\":19,\"label\":\"GPIO 10 (SPI_MOSI)\",\"row\":9,\"col\":0},{\"color\":\"#000000\",\"pin\":20,\"label\":\"GND\",\"row\":9,\"col\":1},{\"color\":\"#fd01fd\",\"pin\":21,\"label\":\"GPIO 9 (SPI_MISO)\",\"row\":10,\"col\":0},{\"color\":\"#00fd00\",\"pin\":22,\"label\":\"GPIO 25\",\"row\":10,\"col\":1},{\"color\":\"#fd01fd\",\"pin\":23,\"label\":\"GPIO 11 (SPI_SCLK)\",\"row\":11,\"col\":0},{\"color\":\"#fd01fd\",\"pin\":24,\"label\":\"GPIO 8 (SPI_CE0)\",\"row\":11,\"col\":1},{\"color\":\"#000000\",\"pin\":25,\"label\":\"GND\",\"row\":12,\"col\":0},{\"color\":\"#fd01fd\",\"pin\":26,\"label\":\"GPIO 7 (SPI_CE1)\",\"row\":12,\"col\":1},{\"color\":\"#ffffff\",\"pin\":27,\"label\":\"ID_SD\",\"row\":13,\"col\":0},{\"color\":\"#ffffff\",\"pin\":28,\"label\":\"ID_SC\",\"row\":13,\"col\":1},{\"color\":\"#00fd00\",\"pin\":29,\"label\":\"GPIO 5\",\"row\":14,\"col\":0},{\"color\":\"#000000\",\"pin\":30,\"label\":\"GND\",\"row\":14,\"col\":1},{\"color\":\"#00fd00\",\"pin\":31,\"label\":\"GPIO 6\",\"row\":15,\"col\":0},{\"color\":\"#00fd00\",\"pin\":32,\"label\":\"GPIO 12\",\"row\":15,\"col\":1},{\"color\":\"#00fd00\",\"pin\":33,\"label\":\"GPIO 13\",\"row\":16,\"col\":0},{\"color\":\"#000000\",\"pin\":34,\"label\":\"GND\",\"row\":16,\"col\":1},{\"color\":\"#00fd00\",\"pin\":35,\"label\":\"GPIO 19\",\"row\":17,\"col\":0},{\"color\":\"#00fd00\",\"pin\":36,\"label\":\"GPIO 16\",\"row\":17,\"col\":1},{\"color\":\"#00fd00\",\"pin\":37,\"label\":\"GPIO 26\",\"row\":18,\"col\":0},{\"color\":\"#00fd00\",\"pin\":38,\"label\":\"GPIO 20\",\"row\":18,\"col\":1},{\"color\":\"#000000\",\"pin\":39,\"label\":\"GND\",\"row\":19,\"col\":0},{\"color\":\"#00fd00\",\"pin\":40,\"label\":\"GPIO 21\",\"row\":19,\"col\":1}],\"ledPanelBackgroundColor\":\"#008a00\"},\"title\":\"Raspberry Pi GPIO Panel\",\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"7\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.22518255793320163,\"funcBody\":\"var period = time % 1500;\\nreturn period < 500;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"11\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7008206860666621,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 500 && period < 1000;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"12\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.42600325102193426,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 1000;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"13\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.48362241571415243,\"funcBody\":\"var period = time % 1500;\\nreturn period < 500;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"29\",\"color\":\"#607d8b\",\"settings\":{},\"_hash\":0.7217670147518815,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 500 && period < 1000;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}}}"
      }
    }
  ]
}