control_widgets.json 43.4 KB
{
  "widgetsBundle": {
    "alias": "control_widgets",
    "title": "Control widgets",
    "image": null
  },
  "widgetTypes": [
    {
      "alias": "rpc_debug_terminal",
      "name": "RPC debug terminal",
      "descriptor": {
        "type": "rpc",
        "sizeX": 9.5,
        "sizeY": 5.5,
        "resources": [],
        "templateHtml": "<div style=\"height: 100%; overflow-y: auto;\" id=\"device-terminal\"></div>",
        "templateCss": ".cmd .cursor.blink {\n    -webkit-animation-name: terminal-underline;\n       -moz-animation-name: terminal-underline;\n        -ms-animation-name: terminal-underline;\n            animation-name: terminal-underline;\n}\n.terminal .inverted, .cmd .inverted {\n    border-bottom-color: #aaa;\n}\n",
        "controllerScript": "var requestTimeout = 500;\n\nself.onInit = function() {\n    var subscription = self.ctx.defaultSubscription;\n    var rpcEnabled = subscription.rpcEnabled;\n    var deviceName = 'Simulated';\n    var prompt;\n    if (subscription.targetDeviceName && subscription.targetDeviceName.length) {\n        deviceName = subscription.targetDeviceName;\n    }\n    if (self.ctx.settings.requestTimeout) {\n        requestTimeout = self.ctx.settings.requestTimeout;\n    }\n    var greetings = 'Welcome to ThingsBoard RPC debug terminal.\\n\\n';\n    if (!rpcEnabled) {\n        greetings += 'Target device is not set!\\n\\n';\n        prompt = '';\n    } else {\n        greetings += 'Current target device for RPC commands: [[b;#fff;]' + deviceName + ']\\n\\n';\n        greetings += 'Please type [[b;#fff;]\\'help\\'] to see usage.\\n';\n        prompt = '[[b;#8bc34a;]' + deviceName +']> ';\n    }\n    \n    var terminal = $('#device-terminal', self.ctx.$container).terminal(\n        function(command) {\n            if (command !== '') {\n                try {\n                    var localCommand = angular.copy(command).trim();\n                    if (localCommand == 'help') {\n                        printUsage(this);\n                    } else {\n                        var cmdObj = $.terminal.parse_command(localCommand);\n                        if (cmdObj.args.length > 1) {\n                            this.error(\"Wrong number of arguments!\");\n                            this.echo(' ');\n                        } else {\n                            var params;\n                            if (cmdObj.args.length && cmdObj.args[0]) {\n                                try {\n                                    params = JSON.parse(cmdObj.args[0]);\n                                } catch (e) {\n                                    params = cmdObj.args[0];\n                                }\n                            }\n                            performRpc(this, cmdObj.name, params);\n                        }\n                    }\n                } catch(e) {\n                    this.error(new String(e));\n                }\n            } else {\n               this.echo('');\n            }\n        }, {\n            greetings: greetings,\n            prompt: prompt\n    });\n    \n    if (!rpcEnabled) {\n        terminal.error('No RPC target detected!').pause();\n    }\n}\n\n\nfunction printUsage(terminal) {\n    var commandsListText = '\\n[[b;#fff;]Usage:]\\n';\n    commandsListText += '   <method> [params body]\\n\\n';\n    commandsListText += '[[b;#fff;]Example 1:]\\n'; \n    commandsListText += '   myRemoteMethod1 myText\\n\\n'; \n    commandsListText += '[[b;#fff;]Example 2:]\\n'; \n    commandsListText += '   myOtherRemoteMethod \"{\\\\\"key1\\\\\": 2, \\\\\"key2\\\\\": \\\\\"myVal\\\\\"}\"\\n'; \n    terminal.echo(new String(commandsListText));\n}\n\nfunction performRpc(terminal, method, params) {\n    terminal.pause();\n    self.ctx.controlApi.sendTwoWayCommand(method, params, requestTimeout).then(\n        function success(responseBody) {\n            terminal.echo(JSON.stringify(responseBody));\n            terminal.echo(' ');\n            terminal.resume();\n        },\n        function fail() {\n            var errorText = self.ctx.defaultSubscription.rpcErrorText;\n            terminal.error(errorText);\n            terminal.echo(' ');\n            terminal.resume();\n        }\n    );\n}\n\n  \nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout (ms)\",\n                \"type\": \"number\",\n                \"default\": 500\n            }\n        },\n        \"required\": [\"requestTimeout\"]\n    },\n    \"form\": [\n        \"requestTimeout\"\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#010101\",\"color\":\"rgba(255, 254, 254, 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\":\"RPC debug terminal\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
      }
    },
    {
      "alias": "rpc_remote_shell",
      "name": "RPC remote shell",
      "descriptor": {
        "type": "rpc",
        "sizeX": 9.5,
        "sizeY": 5.5,
        "resources": [],
        "templateHtml": "<div style=\"height: 100%; overflow-y: auto;\" id=\"device-terminal\"></div>",
        "templateCss": ".cmd .cursor.blink {\n    -webkit-animation-name: terminal-underline;\n       -moz-animation-name: terminal-underline;\n        -ms-animation-name: terminal-underline;\n            animation-name: terminal-underline;\n}\n.terminal .inverted, .cmd .inverted {\n    border-bottom-color: #aaa;\n}\n",
        "controllerScript": "var requestTimeout = 500;\nconst commandStatusPollingInterval = 200;\n\nconst welcome = 'Welcome to ThingsBoard RPC remote shell.\\n';\n\nvar terminal, rpcEnabled, simulated, deviceName, cwd;\nvar commandExecuting = false;\n\nself.onInit = function() {\n    var subscription = self.ctx.defaultSubscription;\n    rpcEnabled = subscription.rpcEnabled;\n    if (subscription.targetDeviceName && subscription.targetDeviceName.length) {\n        deviceName = subscription.targetDeviceName;\n    } else {\n        deviceName = 'Simulated';\n        simulated = true;\n    }\n    if (self.ctx.settings.requestTimeout) {\n        requestTimeout = self.ctx.settings.requestTimeout;\n    }\n    \n    terminal = $('#device-terminal', self.ctx.$container).terminal(\n        function (command) {\n            if (command && command.trim().length) {\n                try {\n                    if (simulated) {\n                        this.echo(command);\n                    } else {\n                        sendCommand(this, command);\n                    }\n                } catch(e) {\n                    this.error(new String(e));\n                }\n            } else {\n               this.echo('');\n            }\n        }, {\n            greetings: false,\n            prompt: rpcEnabled ? currentPrompt : '',\n            name: 'shell',\n            pauseEvents: false,\n            keydown: (e, term) => {\n                if ((e.which == 67 || e.which == 68) && e.ctrlKey) { // CTRL+C || CTRL+D\n                    if (commandExecuting) {\n                        terminateCommand(term);\n                        return false;\n                    }\n                }\n            },\n            onInit: initTerm\n        }\n    );\n}\n\nfunction initTerm(terminal) {\n    terminal.echo(welcome);\n    if (!rpcEnabled) {\n        terminal.error('Target device is not set!\\n');\n    } else {\n        terminal.echo(`Current target device for RPC terminal: [[b;#fff;]${deviceName}]\\n`);\n        if (!simulated) {\n            terminal.pause();\n            getTermInfo(terminal,\n            (remoteTermInfo) => {\n                if (remoteTermInfo) {\n                    terminal.echo(`Remote platform info:`);\n                    terminal.echo(`OS: [[b;#fff;]${remoteTermInfo.platform}]`);\n                    if (remoteTermInfo.release) {\n                        terminal.echo(`OS release: [[b;#fff;]${remoteTermInfo.release}]`);\n                    }\n                    terminal.echo('\\r');\n                } else {\n                    terminal.echo('[[;#f00;]Unable to get remote platform info.\\nDevice is not responding.]\\n');\n                }\n                terminal.resume();\n            });\n        }\n    }\n}\n\nfunction currentPrompt(callback) {\n    if (cwd) {\n        callback('[[b;#2196f3;]' + deviceName +']: [[b;#8bc34a;]' + cwd +']> ');\n    } else {\n        callback('[[b;#8bc34a;]' + deviceName +']> ');\n    }\n}\n\nfunction getTermInfo(terminal, callback) {\n    self.ctx.controlApi.sendTwoWayCommand('getTermInfo', null, requestTimeout).then(\n        (termInfo) => {\n            cwd = termInfo.cwd;\n            if (callback) {\n                callback(termInfo);\n            } \n        },\n        () => {\n            if (callback) {\n                callback(null);\n            }\n        }\n    );\n}\n\nfunction sendCommand(terminal, command) {\n    terminal.pause();\n    var sendCommandRequest = {\n        command: command,\n        cwd: cwd\n    };\n    self.ctx.controlApi.sendTwoWayCommand('sendCommand', sendCommandRequest, requestTimeout).then(\n        (responseBody) => {\n            if (responseBody && responseBody.ok) {\n                commandExecuting = true;\n                setTimeout( pollCommandStatus.bind(null,terminal), commandStatusPollingInterval );\n            } else {\n                var error = responseBody ? responseBody.error : 'Unhandled error.';\n                terminal.error(error);\n                terminal.resume();\n            }\n        },\n        () => {\n            onRpcError(terminal);\n        }\n    );\n}\n\nfunction terminateCommand(terminal) {\n    self.ctx.controlApi.sendTwoWayCommand('terminateCommand', null, requestTimeout).then(\n        (responseBody) => {\n            if (!responseBody.ok) {\n                commandExecuting = false;\n                terminal.error(responseBody.error);\n                terminal.resume();\n            } \n        },\n        () => {\n            onRpcError(terminal);\n        }\n    );    \n}\n\nfunction onRpcError(terminal) {\n    var errorText = self.ctx.defaultSubscription.rpcErrorText;\n    terminal.error(errorText);\n    terminal.resume();\n}\n\nfunction pollCommandStatus(terminal) {\n    self.ctx.controlApi.sendTwoWayCommand('getCommandStatus', null, requestTimeout).then(\n        (commandStatusResponse) => {\n            commandStatusResponse.data.forEach((dataElement) => {\n                if (dataElement.stdout) {\n                    terminal.echo(dataElement.stdout);\n                }\n                if (dataElement.stderr) {\n                    terminal.error(dataElement.stderr);\n                }\n            });            \n            if (commandStatusResponse.done) {\n                commandExecuting = false;\n                cwd = commandStatusResponse.cwd;\n                terminal.resume();\n            } else {\n                var interval = commandStatusPollingInterval;\n                if (!commandStatusResponse.data.length) {\n                    interval *=5;\n                }\n                setTimeout( pollCommandStatus.bind(null,terminal), interval );\n            }\n        },\n        () => {\n            commandExecuting = false;\n            onRpcError(terminal);\n        }\n    );\n}\n\nself.onResize = function () {\n    if (terminal) {\n        terminal.resize(self.ctx.width, self.ctx.height);\n    }\n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout (ms)\",\n                \"type\": \"number\",\n                \"default\": 500\n            }\n        },\n        \"required\": [\"requestTimeout\"]\n    },\n    \"form\": [\n        \"requestTimeout\"\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#010101\",\"color\":\"rgba(255, 254, 254, 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\":\"RPC remote shell\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
      }
    },
    {
      "alias": "knob_control",
      "name": "Knob Control",
      "descriptor": {
        "type": "rpc",
        "sizeX": 5,
        "sizeY": 4.5,
        "resources": [],
        "templateHtml": "<tb-knob ctx='ctx'></tb-knob>",
        "templateCss": "",
        "controllerScript": "self.onInit = function() {\n    var scope = self.ctx.$scope;\n    scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n    if (self.ctx.resize) {\n        self.ctx.resize();\n    }\n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"minValue\": {\n                \"title\": \"Minimum value\",\n                \"type\": \"number\",\n                \"default\": 0\n            },\n            \"maxValue\": {\n                \"title\": \"Maximum value\",\n                \"type\": \"number\",\n                \"default\": 100\n            },\n            \"initialValue\": {\n                \"title\": \"Initial value\",\n                \"type\": \"number\",\n                \"default\": 50\n            },\n            \"title\": {\n                \"title\": \"Knob title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"getValueMethod\": {\n                \"title\": \"Get value method\",\n                \"type\": \"string\",\n                \"default\": \"getValue\"\n            },\n            \"setValueMethod\": {\n                \"title\": \"Set value method\",\n                \"type\": \"string\",\n                \"default\": \"setValue\"\n            },\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout\",\n                \"type\": \"number\",\n                \"default\": 500\n            }\n        },\n        \"required\": [\"minValue\", \"maxValue\", \"getValueMethod\", \"setValueMethod\", \"requestTimeout\"]\n    },\n    \"form\": [\n        \"minValue\",\n        \"maxValue\",\n        \"initialValue\",\n        \"title\",\n        \"getValueMethod\",\n        \"setValueMethod\",\n        \"requestTimeout\"\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"maxValue\":100,\"initialValue\":50,\"minValue\":0,\"title\":\"Knob control\",\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\"},\"title\":\"Knob Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
      }
    },
    {
      "alias": "switch_control",
      "name": "Switch Control",
      "descriptor": {
        "type": "rpc",
        "sizeX": 4,
        "sizeY": 2.5,
        "resources": [],
        "templateHtml": "<tb-switch ctx='ctx'></tb-switch>",
        "templateCss": "",
        "controllerScript": "self.onInit = function() {\n    var scope = self.ctx.$scope;\n    scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n    if (self.ctx.resize) {\n        self.ctx.resize();\n    }\n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"initialValue\": {\n                \"title\": \"Initial value\",\n                \"type\": \"boolean\",\n                \"default\": false\n            },\n            \"title\": {\n                \"title\": \"Switch title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"showOnOffLabels\": {\n                \"title\": \"Show on/off labels\",\n                \"type\": \"boolean\",\n                \"default\": true\n            },\n            \"retrieveValueMethod\": {\n                \"title\": \"Retrieve on/off value using method\",\n                \"type\": \"string\",\n                \"default\": \"rpc\"\n            },\n            \"valueKey\": {\n                \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n                \"type\": \"string\",\n                \"default\": \"value\"\n            },\n            \"getValueMethod\": {\n                \"title\": \"RPC get value method\",\n                \"type\": \"string\",\n                \"default\": \"getValue\"\n            },\n            \"setValueMethod\": {\n                \"title\": \"RPC set value method\",\n                \"type\": \"string\",\n                \"default\": \"setValue\"\n            },\n            \"parseValueFunction\": {\n                \"title\": \"Parse value function, f(data), returns boolean\",\n                \"type\": \"string\",\n                \"default\": \"return data ? true : false;\"\n            },\n            \"convertValueFunction\": {\n                \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n                \"type\": \"string\",\n                \"default\": \"return value;\"\n            },\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout\",\n                \"type\": \"number\",\n                \"default\": 500\n            }\n        },\n        \"required\": [\"requestTimeout\"]\n    },\n    \"form\": [\n        \"initialValue\",\n        \"title\",\n        \"showOnOffLabels\",\n        {\n            \"key\": \"retrieveValueMethod\",\n            \"type\": \"rc-select\",\n            \"multiple\": false,\n            \"items\": [\n                {\n                    \"value\": \"none\",\n                    \"label\": \"Don't retrieve\"\n                },\n                {\n                    \"value\": \"rpc\",\n                    \"label\": \"Call RPC get value method\"\n                },\n                {\n                    \"value\": \"attribute\",\n                    \"label\": \"Subscribe for attribute\"\n                },\n                {\n                    \"value\": \"timeseries\",\n                    \"label\": \"Subscribe for timeseries\"\n                }\n            ]\n        },\n        \"valueKey\",\n        \"getValueMethod\",\n        \"setValueMethod\",\n        {\n            \"key\": \"parseValueFunction\",\n            \"type\": \"javascript\"\n        },\n        {\n            \"key\": \"convertValueFunction\",\n            \"type\": \"javascript\"\n        },\n        \"requestTimeout\"\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
      }
    },
    {
      "alias": "round_switch",
      "name": "Round switch",
      "descriptor": {
        "type": "rpc",
        "sizeX": 2.5,
        "sizeY": 2,
        "resources": [],
        "templateHtml": "<tb-round-switch ctx='ctx'></tb-round-switch>",
        "templateCss": "",
        "controllerScript": "self.onInit = function() {\n    var scope = self.ctx.$scope;\n    scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n    if (self.ctx.resize) {\n        self.ctx.resize();\n    }\n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"initialValue\": {\n                \"title\": \"Initial value\",\n                \"type\": \"boolean\",\n                \"default\": false\n            },\n            \"title\": {\n                \"title\": \"Switch title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"retrieveValueMethod\": {\n                \"title\": \"Retrieve on/off value using method\",\n                \"type\": \"string\",\n                \"default\": \"rpc\"\n            },\n            \"valueKey\": {\n                \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n                \"type\": \"string\",\n                \"default\": \"value\"\n            },\n            \"getValueMethod\": {\n                \"title\": \"RPC get value method\",\n                \"type\": \"string\",\n                \"default\": \"getValue\"\n            },\n            \"setValueMethod\": {\n                \"title\": \"RPC set value method\",\n                \"type\": \"string\",\n                \"default\": \"setValue\"\n            },\n            \"parseValueFunction\": {\n                \"title\": \"Parse value function, f(data), returns boolean\",\n                \"type\": \"string\",\n                \"default\": \"return data ? true : false;\"\n            },\n            \"convertValueFunction\": {\n                \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n                \"type\": \"string\",\n                \"default\": \"return value;\"\n            },\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout\",\n                \"type\": \"number\",\n                \"default\": 500\n            }\n        },\n        \"required\": [\"requestTimeout\"]\n    },\n    \"form\": [\n        \"initialValue\",\n        \"title\",\n        {\n            \"key\": \"retrieveValueMethod\",\n            \"type\": \"rc-select\",\n            \"multiple\": false,\n            \"items\": [\n                {\n                    \"value\": \"none\",\n                    \"label\": \"Don't retrieve\"\n                },\n                {\n                    \"value\": \"rpc\",\n                    \"label\": \"Call RPC get value method\"\n                },\n                {\n                    \"value\": \"attribute\",\n                    \"label\": \"Subscribe for attribute\"\n                },\n                {\n                    \"value\": \"timeseries\",\n                    \"label\": \"Subscribe for timeseries\"\n                }\n            ]\n        },\n        \"valueKey\",\n        \"getValueMethod\",\n        \"setValueMethod\",\n        {\n            \"key\": \"parseValueFunction\",\n            \"type\": \"javascript\"\n        },\n        {\n            \"key\": \"convertValueFunction\",\n            \"type\": \"javascript\"\n        },\n        \"requestTimeout\"\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
      }
    },
    {
      "alias": "led_indicator",
      "name": "Led indicator",
      "descriptor": {
        "type": "rpc",
        "sizeX": 2.5,
        "sizeY": 2.5,
        "resources": [],
        "templateHtml": "<tb-led-indicator ctx='ctx'></tb-led-indicator>",
        "templateCss": "",
        "controllerScript": "self.onInit = function() {\n    var scope = self.ctx.$scope;\n    scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n    if (self.ctx.resize) {\n        self.ctx.resize();\n    }\n}\n\nself.onDestroy = function() {\n}\n",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"initialValue\": {\n                \"title\": \"Initial value\",\n                \"type\": \"boolean\",\n                \"default\": false\n            },\n            \"title\": {\n                \"title\": \"LED title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"ledColor\": {\n                \"title\": \"LED Color\",\n                \"type\": \"string\",\n                \"default\": \"green\"\n            },\n            \"performCheckStatus\": {\n                \"title\": \"Perform RPC device status check\",\n                \"type\": \"boolean\",\n                \"default\": true\n            },\n            \"checkStatusMethod\": {\n                \"title\": \"RPC check device status method\",\n                \"type\": \"string\",\n                \"default\": \"checkStatus\"\n            },\n            \"retrieveValueMethod\": {\n                \"title\": \"Retrieve led status value using method\",\n                \"type\": \"string\",\n                \"default\": \"attribute\"\n            },\n            \"valueAttribute\": {\n                \"title\": \"Device attribute/timeseries containing led status value\",\n                \"type\": \"string\",\n                \"default\": \"value\"\n            },\n            \"parseValueFunction\": {\n                \"title\": \"Parse led status value function, f(data), returns boolean\",\n                \"type\": \"string\",\n                \"default\": \"return data ? true : false;\"\n            },\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout (ms)\",\n                \"type\": \"number\",\n                \"default\": 500\n            }\n        },\n        \"required\": [\"valueAttribute\", \"requestTimeout\"]\n    },\n    \"form\": [\n        \"initialValue\",\n        \"title\",\n        {\n          \"key\": \"ledColor\",\n          \"type\": \"color\"\n        },\n        \"performCheckStatus\",\n        \"checkStatusMethod\",\n        {\n            \"key\": \"retrieveValueMethod\",\n            \"type\": \"rc-select\",\n            \"multiple\": false,\n            \"items\": [\n                {\n                    \"value\": \"attribute\",\n                    \"label\": \"Subscribe for attribute\"\n                },\n                {\n                    \"value\": \"timeseries\",\n                    \"label\": \"Subscribe for timeseries\"\n                }\n            ]\n        },\n        \"valueAttribute\",\n        {\n            \"key\": \"parseValueFunction\",\n            \"type\": \"javascript\"\n        },\n        \"requestTimeout\"\n    ]\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
      }
    },
    {
      "alias": "rpcbutton",
      "name": "RPC Button",
      "descriptor": {
        "type": "rpc",
        "sizeX": 4,
        "sizeY": 2,
        "resources": [],
        "templateHtml": "<div class=\"tb-rpc-button\" layout=\"column\">\n    <div flex=\"20\" class=\"title-container\" layout=\"row\"\n        layout-align=\"center center\" ng-show=\"showTitle\">\n        <span class=\"button-title\">{{title}}</span>\n    </div>\n    <div flex=\"{{showTitle ? 80 : 100}}\" ng-style=\"{paddingTop: showTitle ? '5px': '10px'}\"\n        class=\"button-container\" layout=\"column\" layout-align=\"center center\">\n        <div>\n            <md-button ng-click=\"sendCommand()\" ng-class=\"{'md-raised': styleButton.isRaised, 'md-primary': styleButton.isPrimary}\" ng-style=\"customStyle\">\n                {{buttonLabel}}\n            </md-button>\n        </div>\n    </div>\n    <div class=\"error-container\" ng-style=\"{'background': vm.error.length ? 'rgba(255,255,255,0.25)' : 'none'}\"\n         layout=\"row\" layout-align=\"center center\">\n        <span class=\"button-error\">{{ error }}</span>\n    </div>\n</div>",
        "templateCss": ".tb-rpc-button {\n    width: 100%;\n    height: 100%;\n}\n\n.tb-rpc-button .title-container {\n    font-weight: 500;\n    white-space: nowrap;\n    margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n    min-width: 80%\n}\n\n.tb-rpc-button .button-container .md-button{\n    width: 100%;\n    margin: 0;\n}\n\n.tb-rpc-button .error-container {\n    position: absolute;\n    top: 2%;\n    right: 0;\n    left: 0;\n    z-index: 4;\n    height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n    color: #ff3315;\n    white-space: nowrap;\n}",
        "controllerScript": "self.onInit = function() {\n    let rpcEnabled = self.ctx.defaultSubscription.rpcEnabled;\n\n    self.ctx.$scope.buttonLabel = self.ctx.settings.buttonText;\n    self.ctx.$scope.showTitle = self.ctx.settings.title &&\n        self.ctx.settings.title.length ? true : false;\n    self.ctx.$scope.title = self.ctx.settings.title;\n    self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n\n    if (self.ctx.settings.styleButton.isPrimary ===\n        false) {\n        self.ctx.$scope.customStyle = {\n            'background-color': self.ctx.$scope.styleButton.bgColor,\n            'color': self.ctx.$scope.styleButton.textColor\n        };\n    }\n\n    if (!rpcEnabled) {\n        self.ctx.$scope.error =\n            'Target device is not set!';\n    }\n\n    self.ctx.$scope.sendCommand = function() {\n        var rpcMethod = self.ctx.settings.methodName;\n        var rpcParams = self.ctx.settings.methodParams;\n        var timeout = self.ctx.settings.requestTimeout;\n        var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ?\n            true : false;\n\n        var commandPromise;\n        if (oneWayElseTwoWay) {\n            commandPromise = self.ctx.controlApi.sendOneWayCommand(\n                rpcMethod, rpcParams, timeout);\n        } else {\n            commandPromise = self.ctx.controlApi.sendTwoWayCommand(\n                rpcMethod, rpcParams, timeout);\n        }\n        commandPromise.then(\n            function success() {\n                self.ctx.$scope.error = \"\";\n            },\n            function fail(rejection) {\n                if (self.ctx.settings.showError) {\n                    self.ctx.$scope.error =\n                        rejection.status + \": \" +\n                        rejection.statusText;\n                }\n            }\n        );\n    };\n\n};",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"title\": {\n                \"title\": \"Widget title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"buttonText\": {\n                \"title\": \"Button label\",\n                \"type\": \"string\",\n                \"default\": \"Send RPC\"\n            },\n            \"oneWayElseTwoWay\": {\n                \"title\": \"Is One Way Command\",\n                \"type\": \"boolean\",\n                \"default\": true\n            },\n            \"showError\": {\n                \"title\": \"Show RPC command execution error\",\n                \"type\": \"boolean\",\n                \"default\": false\n            },\n            \"methodName\": {\n                \"title\": \"RPC method\",\n                \"type\": \"string\",\n                \"default\": \"rpcCommand\"\n            },\n            \"methodParams\": {\n                \"title\": \"RPC method params\",\n                \"type\": \"string\",\n                \"default\": \"{}\"\n            },\n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout\",\n                \"type\": \"number\",\n                \"default\": 5000\n            },\n            \"styleButton\": {\n                \"type\": \"object\",\n                \"title\": \"Button Style\",\n                \"properties\": {\n                    \"isRaised\": {\n                        \"type\": \"boolean\",\n                        \"title\": \"Raised\",\n                        \"default\": true\n                    },\n                    \"isPrimary\": {\n                        \"type\": \"boolean\",\n                        \"title\": \"Primary color\",\n                        \"default\": false\n                    },\n                    \"bgColor\": {\n                        \"type\": \"string\",\n                        \"title\": \"Button background color\",\n                        \"default\": null\n                    },\n                    \"textColor\": {\n                        \"type\": \"string\",\n                        \"title\": \"Button text color\",\n                        \"default\": null\n                    }\n                }\n            },\n            \"required\": []\n        }\n    },\n    \"form\": [\n        \"title\",\n        \"buttonText\",\n        \"oneWayElseTwoWay\",\n        \"showError\",\n        \"methodName\",\n        {\n            \"key\": \"methodParams\",\n            \"type\": \"json\"\n        },\n        \"requestTimeout\",\n        {\n            \"key\": \"styleButton\",\n            \"items\": [\n                \"styleButton.isRaised\",\n                \"styleButton.isPrimary\",\n                {\n                    \"key\": \"styleButton.bgColor\",\n                    \"type\": \"color\"\n                },\n                {\n                    \"key\": \"styleButton.textColor\",\n                    \"type\": \"color\"\n                }\n            ]\n        }\n    ]\n\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":5000,\"oneWayElseTwoWay\":true,\"buttonText\":\"Send RPC\",\"styleButton\":{\"isRaised\":true,\"isPrimary\":false},\"methodName\":\"rpcCommand\",\"methodParams\":\"{}\"},\"title\":\"RPC Button\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
      }
    },
    {
      "alias": "update_attributes",
      "name": "Update device attribute",
      "descriptor": {
        "type": "rpc",
        "sizeX": 4,
        "sizeY": 2,
        "resources": [],
        "templateHtml": "<div class=\"tb-rpc-button\" layout=\"column\">\n    <div flex=\"20\" class=\"title-container\" layout=\"row\"\n        layout-align=\"center center\" ng-show=\"showTitle\">\n        <span class=\"button-title\">{{title}}</span>\n    </div>\n    <div flex=\"{{showTitle ? 80 : 100}}\" ng-style=\"{paddingTop: showTitle ? '5px': '10px'}\"\n        class=\"button-container\" layout=\"column\" layout-align=\"center center\">\n        <div>\n            <md-button ng-click=\"sendUpdate()\" ng-class=\"{'md-raised': styleButton.isRaised, 'md-primary': styleButton.isPrimary}\" ng-style=\"customStyle\">\n                {{buttonLabel}}\n            </md-button>\n        </div>\n    </div>\n    <div class=\"error-container\" ng-style=\"{'background': vm.error.length ? 'rgba(255,255,255,0.25)' : 'none'}\"\n         layout=\"row\" layout-align=\"center center\">\n        <span class=\"button-error\">{{ error }}</span>\n    </div>\n</div>",
        "templateCss": ".tb-rpc-button {\n    width: 100%;\n    height: 100%;\n}\n\n.tb-rpc-button .title-container {\n    font-weight: 500;\n    white-space: nowrap;\n    margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n    min-width: 80%\n}\n\n.tb-rpc-button .button-container .md-button{\n    width: 100%;\n    margin: 0;\n}\n\n.tb-rpc-button .error-container {\n    position: absolute;\n    top: 2%;\n    right: 0;\n    left: 0;\n    z-index: 4;\n    height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n    color: #ff3315;\n    white-space: nowrap;\n}",
        "controllerScript": "self.onInit = function() {\n    self.ctx.$scope.buttonLabel = self.ctx.settings.buttonText;\n    self.ctx.$scope.showTitle = self.ctx.settings.title &&\n        self.ctx.settings.title.length ? true : false;\n    self.ctx.$scope.title = self.ctx.settings.title;\n    self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n    let entityAttributeType = self.ctx.settings.entityAttributeType;\n    let entityParameters = JSON.parse(self.ctx.settings.entityParameters);\n\n    if (self.ctx.settings.styleButton.isPrimary ===\n        false) {\n        self.ctx.$scope.customStyle = {\n            'background-color': self.ctx.$scope.styleButton\n                .bgColor,\n            'color': self.ctx.$scope.styleButton.textColor\n        };\n    }\n\n    console.log(self.ctx);\n\n    let attributeService = self.ctx.$scope.$injector.get('attributeService');\n\n    self.ctx.$scope.sendUpdate = function() {\n        let attributes = [];\n        for (let key in entityParameters) {\n            attributes.push({\n                \"key\": key,\n                \"value\": entityParameters[key]\n            });\n        }\n        \n        \n        attributeService.saveEntityAttributes(\"DEVICE\", self.ctx.defaultSubscription.targetDeviceId,\n            entityAttributeType, attributes).then(\n            function success() {\n                self.ctx.$scope.error = \"\";\n            },\n            function fail(rejection) {\n                if (self.ctx.settings.showError) {\n                    self.ctx.$scope.error =\n                        rejection.status + \": \" +\n                        rejection.statusText;\n                }\n                console.log(rejection);\n            }\n\n        );\n    };\n\n};",
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"title\": {\n                \"title\": \"Widget title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"buttonText\": {\n                \"title\": \"Button label\",\n                \"type\": \"string\",\n                \"default\": \"Update device attribute\"\n            },\n            \"entityAttributeType\": {\n                \"title\": \"Device attribute scope\",\n                \"type\": \"string\",\n                \"default\": \"SERVER_SCOPE\"\n            },\n            \"entityParameters\": {\n                \"title\": \"Device attribute parameters\",\n                \"type\": \"string\",\n                \"default\": \"{}\"\n            },\n            \"styleButton\": {\n                \"type\": \"object\",\n                \"title\": \"Button Style\",\n                \"properties\": {\n                    \"isRaised\": {\n                        \"type\": \"boolean\",\n                        \"title\": \"Raised\",\n                        \"default\": true\n                    },\n                    \"isPrimary\": {\n                        \"type\": \"boolean\",\n                        \"title\": \"Primary color\",\n                        \"default\": false\n                    },\n                    \"bgColor\": {\n                        \"type\": \"string\",\n                        \"title\": \"Button background color\",\n                        \"default\": null\n                    },\n                    \"textColor\": {\n                        \"type\": \"string\",\n                        \"title\": \"Button text color\",\n                        \"default\": null\n                    }\n                }\n            },\n            \"required\": []\n        }\n    },\n    \"form\": [\n        \"title\",\n        \"buttonText\",\n        {\n            \"key\": \"entityAttributeType\",\n            \"type\": \"rc-select\",\n            \"multiple\": false,\n            \"items\": [{\n                \"value\": \"SERVER_SCOPE\",\n                \"label\": \"Server attribute\"\n            }, {\n                \"value\": \"SHARED_SCOPE\",\n                \"label\": \"Shared attribute\"\n            }]\n        }, {\n            \"key\": \"entityParameters\",\n            \"type\": \"json\"\n        },\n        {\n            \"key\": \"styleButton\",\n            \"items\": [\n                \"styleButton.isRaised\",\n                \"styleButton.isPrimary\",\n                {\n                    \"key\": \"styleButton.bgColor\",\n                    \"type\": \"color\"\n                },\n                {\n                    \"key\": \"styleButton.textColor\",\n                    \"type\": \"color\"\n                }\n            ]\n        }\n    ]\n\n}",
        "dataKeySettingsSchema": "{}\n",
        "defaultConfig": "{\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"styleButton\":{\"isRaised\":true,\"isPrimary\":false},\"entityParameters\":\"{}\",\"entityAttributeType\":\"SERVER_SCOPE\",\"buttonText\":\"Update device attribute\"},\"title\":\"Update device attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"targetDeviceAliases\":[]}"
      }
    }
  ]
}