gpio_widgets.json
92.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
{
"widgetsBundle": {
"alias": "gpio_widgets",
"title": "GPIO widgets",
"image": "data:image/png;base64,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",
"description": "Visualization and control of GPIO state for target devices."
},
"widgetTypes": [
{
"alias": "basic_gpio_control",
"name": "Basic GPIO Control",
"image": "data:image/png;base64,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",
"description": "Allows to change state of the GPIO for target device using RPC commands. Requires handling of the RPC commands in the device firmware. Uses 'getGpioStatus' and 'setGpioStatus' RPC calls",
"descriptor": {
"type": "rpc",
"sizeX": 4,
"sizeY": 2,
"resources": [],
"templateHtml": "<fieldset class=\"gpio-panel\" style=\"height: 100%;\">\n <section class=\"gpio-row\" fxLayout=\"row\" *ngFor=\"let row of rows\" \n [ngStyle]=\"{'height': prefferedRowHeight+'px'}\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"switch-panel\" fxLayoutAlign=\"start center\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n <mat-slide-toggle\n [disabled]=\"!rpcEnabled || executingRpcRequest\"\n [checked]=\"cell.enabled\" \n (change)=\"gpioToggleChange($event, cell)\" \n (click)=\"gpioClick($event, cell)\">\n </mat-slide-toggle>\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"switch-panel\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\"></span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n </section>\n </section>\n </section> \n <span class=\"error\" style=\"position: absolute; bottom: 5px;\" [fxShow]=\"rpcErrorText\">{{rpcErrorText}}</span>\n <mat-progress-bar [fxShow]=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" mode=\"indeterminate\"></mat-progress-bar>\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.gpio-panel section[fxflex] {\n min-width: 0px;\n}\n\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\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": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-control-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\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 .subscribe(\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 self.ctx.detectChanges();\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 .subscribe(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n self.ctx.detectChanges();\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 if (scope.rpcEnabled && !scope.executingRpcRequest) {\n changeGpioStatus(gpio);\n }\n };\n \n scope.gpioToggleChange = function($event, gpio) {\n gpio.enabled = !$event.checked;\n $event.source.toggle();\n self.ctx.detectChanges();\n }\n \n if (scope.rpcEnabled) {\n requestGpioStatus(); \n }\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 \n var css = '.mat-slide-toggle .mat-slide-toggle-bar {\\n' +\n ' height: ' + 14*ratio+'px;\\n'+\n ' width: ' + 36*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb-container {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-ripple {\\n' +\n ' height: ' + 40*ratio+'px;\\n'+\n ' width: ' + 40*ratio+'px;\\n'+\n ' top: calc(50% - '+20*ratio+'px);\\n'+\n ' left: calc(50% - '+20*ratio+'px);\\n'+\n '}\\n';\n css += '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n\n cssParser.createStyleElement(namespace, css);\n \n self.ctx.detectChanges();\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 \"helpId\": \"widget/lib/rpc/parse_gpio_status_fn\"\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",
"image": "data:image/png;base64,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",
"description": "Allows to display state of the GPIO for target device using latest attribute values. You should set the label of the selected data key to GPIO pin number (e.g. '1') and use boolean values for widget to display the data.",
"descriptor": {
"type": "latest",
"sizeX": 5,
"sizeY": 2,
"resources": [],
"templateHtml": "<div class=\"gpio-panel\" style=\"height: 100%;\">\n <section fxLayout=\"row\" *ngFor=\"let row of rows\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"led-panel\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{backgroundColor: ledPanelBackgroundColor}\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span class=\"led-container\">\n <tb-led-light [size]=\"prefferedRowHeight\"\n [colorOn]=\"cell.colorOn\"\n [colorOff]=\"cell.colorOff\"\n [offOpacity]=\"'0.9'\"\n [enabled]=\"cell.enabled\">\n </tb-led-light>\n </span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"led-panel\"\n [ngStyle]=\"{backgroundColor: ledPanelBackgroundColor}\"></span>\n <span fxFlex [fxShow]=\"$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 section[fxflex] {\n min-width: 0px;\n}\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": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-panel-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\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.detectChanges();\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 css = '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n \n cssParser.createStyleElement(namespace, css); \n \n self.ctx.detectChanges();\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_panel",
"name": "Raspberry Pi GPIO Panel",
"image": "data:image/png;base64,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",
"description": "Allows to change state of the GPIO for Raspberry Pi device using RPC commands. Requires handling of the RPC commands in the device firmware. Uses 'getGpioStatus' and 'setGpioStatus' RPC calls",
"descriptor": {
"type": "latest",
"sizeX": 7,
"sizeY": 10.5,
"resources": [],
"templateHtml": "<div class=\"gpio-panel\" style=\"height: 100%;\">\n <section fxLayout=\"row\" *ngFor=\"let row of rows\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"led-panel\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{backgroundColor: ledPanelBackgroundColor}\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span class=\"led-container\">\n <tb-led-light [size]=\"prefferedRowHeight\"\n [colorOn]=\"cell.colorOn\"\n [colorOff]=\"cell.colorOff\"\n [offOpacity]=\"'0.9'\"\n [enabled]=\"cell.enabled\">\n </tb-led-light>\n </span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"led-panel\"\n [ngStyle]=\"{backgroundColor: ledPanelBackgroundColor}\"></span>\n <span fxFlex [fxShow]=\"$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 section[fxflex] {\n min-width: 0px;\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": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-panel-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\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.detectChanges();\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 css = '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n \n cssParser.createStyleElement(namespace, css); \n \n self.ctx.detectChanges();\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}}}"
}
},
{
"alias": "raspberry_pi_gpio_control",
"name": "Raspberry Pi GPIO Control",
"image": "data:image/png;base64,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",
"description": "Allows to display state of the GPIO for target Raspberry Pi device using latest attribute values. You should set the label of the selected data key to GPIO pin number (e.g. '1') and use boolean values for widget to display the data.",
"descriptor": {
"type": "rpc",
"sizeX": 6,
"sizeY": 10.5,
"resources": [],
"templateHtml": "<fieldset class=\"gpio-panel\" style=\"height: 100%;\">\n <section class=\"gpio-row\" fxLayout=\"row\" *ngFor=\"let row of rows\" \n [ngStyle]=\"{'height': prefferedRowHeight+'px'}\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"switch-panel\" fxLayoutAlign=\"start center\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n <mat-slide-toggle\n [disabled]=\"!rpcEnabled || executingRpcRequest\"\n [checked]=\"cell.enabled\" \n (change)=\"gpioToggleChange($event, cell)\" \n (click)=\"gpioClick($event, cell)\">\n </mat-slide-toggle>\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"switch-panel\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\"></span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n </section>\n </section>\n </section> \n <span class=\"error\" style=\"position: absolute; bottom: 5px;\" [fxShow]=\"rpcErrorText\">{{rpcErrorText}}</span>\n <mat-progress-bar [fxShow]=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" mode=\"indeterminate\"></mat-progress-bar>\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.gpio-panel section[fxflex] {\n min-width: 0px;\n}\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\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": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-control-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\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 .subscribe(\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 self.ctx.detectChanges();\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 .subscribe(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n self.ctx.detectChanges();\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 if (scope.rpcEnabled && !scope.executingRpcRequest) {\n changeGpioStatus(gpio);\n }\n };\n \n scope.gpioToggleChange = function($event, gpio) {\n gpio.enabled = !$event.checked;\n $event.source.toggle();\n self.ctx.detectChanges();\n }\n \n if (scope.rpcEnabled) {\n requestGpioStatus(); \n }\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 \n var css = '.mat-slide-toggle .mat-slide-toggle-bar {\\n' +\n ' height: ' + 14*ratio+'px;\\n'+\n ' width: ' + 36*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb-container {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-ripple {\\n' +\n ' height: ' + 40*ratio+'px;\\n'+\n ' width: ' + 40*ratio+'px;\\n'+\n ' top: calc(50% - '+20*ratio+'px);\\n'+\n ' left: calc(50% - '+20*ratio+'px);\\n'+\n '}\\n';\n css += '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n\n cssParser.createStyleElement(namespace, css);\n \n self.ctx.detectChanges();\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 \"helpId\": \"widget/lib/rpc/parse_gpio_status_fn\"\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\"}"
}
}
]
}