Commit ef21d2ae415e588bca993ed008a11e34683acc20

Authored by Volodymyr Babak
2 parents e65b8e99 7e66fd26

Merge remote-tracking branch 'upstream/master' into feature/stateful-services

Too many changes to show.

To preserve performance only 18 of 834 files are displayed.

... ... @@ -133,6 +133,18 @@
133 133 <artifactId>spring-boot-starter-websocket</artifactId>
134 134 </dependency>
135 135 <dependency>
  136 + <groupId>org.springframework.cloud</groupId>
  137 + <artifactId>spring-cloud-starter-oauth2</artifactId>
  138 + </dependency>
  139 + <dependency>
  140 + <groupId>org.springframework.security</groupId>
  141 + <artifactId>spring-security-oauth2-client</artifactId>
  142 + </dependency>
  143 + <dependency>
  144 + <groupId>org.springframework.security</groupId>
  145 + <artifactId>spring-security-oauth2-jose</artifactId>
  146 + </dependency>
  147 + <dependency>
136 148 <groupId>io.jsonwebtoken</groupId>
137 149 <artifactId>jjwt</artifactId>
138 150 </dependency>
... ... @@ -181,8 +193,8 @@
181 193 <artifactId>logback-classic</artifactId>
182 194 </dependency>
183 195 <dependency>
184   - <groupId>javax.mail</groupId>
185   - <artifactId>mail</artifactId>
  196 + <groupId>com.sun.mail</groupId>
  197 + <artifactId>javax.mail</artifactId>
186 198 </dependency>
187 199 <dependency>
188 200 <groupId>org.apache.curator</groupId>
... ... @@ -221,6 +233,11 @@
221 233 <scope>test</scope>
222 234 </dependency>
223 235 <dependency>
  236 + <groupId>org.thingsboard</groupId>
  237 + <artifactId>rest-client</artifactId>
  238 + <scope>test</scope>
  239 + </dependency>
  240 + <dependency>
224 241 <groupId>org.springframework.boot</groupId>
225 242 <artifactId>spring-boot-starter-test</artifactId>
226 243 <scope>test</scope>
... ... @@ -547,7 +564,7 @@
547 564 </executions>
548 565 </plugin>
549 566 <plugin>
550   - <groupId>org.fortasoft</groupId>
  567 + <groupId>org.thingsboard</groupId>
551 568 <artifactId>gradle-maven-plugin</artifactId>
552 569 <configuration>
553 570 <tasks>
... ...
... ... @@ -36,6 +36,7 @@
36 36
37 37 <logger name="org.thingsboard.server" level="INFO" />
38 38 <logger name="akka" level="INFO" />
  39 + <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" />
39 40
40 41 <root level="INFO">
41 42 <appender-ref ref="fileLogAppender"/>
... ...
  1 +{
  2 + "title": "Gateways",
  3 + "configuration": {
  4 + "widgets": {
  5 + "94715984-ae74-76e4-20b7-2f956b01ed80": {
  6 + "isSystemType": true,
  7 + "bundleAlias": "entity_admin_widgets",
  8 + "typeAlias": "device_admin_table",
  9 + "type": "latest",
  10 + "title": "New widget",
  11 + "sizeX": 24,
  12 + "sizeY": 12,
  13 + "config": {
  14 + "timewindow": {
  15 + "realtime": {
  16 + "interval": 1000,
  17 + "timewindowMs": 86400000
  18 + },
  19 + "aggregation": {
  20 + "type": "NONE",
  21 + "limit": 200
  22 + }
  23 + },
  24 + "showTitle": true,
  25 + "backgroundColor": "rgb(255, 255, 255)",
  26 + "color": "rgba(0, 0, 0, 0.87)",
  27 + "padding": "4px",
  28 + "settings": {
  29 + "enableSearch": true,
  30 + "displayPagination": true,
  31 + "defaultPageSize": 10,
  32 + "defaultSortOrder": "entityName",
  33 + "displayEntityName": true,
  34 + "displayEntityType": false,
  35 + "entitiesTitle": "List of gateways",
  36 + "enableSelectColumnDisplay": true,
  37 + "displayEntityLabel": false,
  38 + "entityNameColumnTitle": "Gateway Name"
  39 + },
  40 + "title": "Devices gateway table",
  41 + "dropShadow": true,
  42 + "enableFullscreen": true,
  43 + "titleStyle": {
  44 + "fontSize": "16px",
  45 + "fontWeight": 400,
  46 + "padding": "5px 10px 5px 10px"
  47 + },
  48 + "useDashboardTimewindow": false,
  49 + "showLegend": false,
  50 + "datasources": [
  51 + {
  52 + "type": "entity",
  53 + "dataKeys": [
  54 + {
  55 + "name": "active",
  56 + "type": "attribute",
  57 + "label": "Active",
  58 + "color": "#2196f3",
  59 + "settings": {
  60 + "columnWidth": "0px",
  61 + "useCellStyleFunction": true,
  62 + "useCellContentFunction": true,
  63 + "cellContentFunction": "value = '&#11044;';\nreturn value;",
  64 + "cellStyleFunction": "var color;\nif (value == 'false') {\n color = '#EB5757';\n} else {\n color = '#27AE60';\n}\nreturn {\n color: color,\n fontSize: '18px'\n};"
  65 + },
  66 + "_hash": 0.3646047595211721
  67 + },
  68 + {
  69 + "name": "eventsSent",
  70 + "type": "timeseries",
  71 + "label": "Sent",
  72 + "color": "#4caf50",
  73 + "settings": {
  74 + "columnWidth": "0px",
  75 + "useCellStyleFunction": false,
  76 + "useCellContentFunction": false
  77 + },
  78 + "_hash": 0.7235710720767985
  79 + },
  80 + {
  81 + "name": "eventsProduced",
  82 + "type": "timeseries",
  83 + "label": "Events",
  84 + "color": "#f44336",
  85 + "settings": {
  86 + "columnWidth": "0px",
  87 + "useCellStyleFunction": false,
  88 + "useCellContentFunction": false
  89 + },
  90 + "_hash": 0.5085933386303254
  91 + },
  92 + {
  93 + "name": "LOGS",
  94 + "type": "timeseries",
  95 + "label": "Latest log",
  96 + "color": "#ffc107",
  97 + "settings": {
  98 + "columnWidth": "0px",
  99 + "useCellStyleFunction": false,
  100 + "useCellContentFunction": false
  101 + },
  102 + "_hash": 0.3504240371585048,
  103 + "postFuncBody": "if(value) {\n return value.substring(0, 31) + \"...\";\n} else {\n return '';\n}"
  104 + },
  105 + {
  106 + "name": "RemoteLoggingLevel",
  107 + "type": "attribute",
  108 + "label": "Log level",
  109 + "color": "#607d8b",
  110 + "settings": {
  111 + "columnWidth": "0px",
  112 + "useCellStyleFunction": false,
  113 + "useCellContentFunction": false
  114 + },
  115 + "_hash": 0.9785994222542516
  116 + }
  117 + ],
  118 + "entityAliasId": "3e0f533a-0db1-3292-184f-06e73535061a"
  119 + }
  120 + ],
  121 + "showTitleIcon": true,
  122 + "titleIcon": "list",
  123 + "iconColor": "rgba(0, 0, 0, 0.87)",
  124 + "iconSize": "24px",
  125 + "titleTooltip": "List device",
  126 + "widgetStyle": {},
  127 + "displayTimewindow": true,
  128 + "actions": {
  129 + "headerButton": [
  130 + {
  131 + "id": "70837a9d-c3de-a9a7-03c5-dccd14998758",
  132 + "name": "Add device",
  133 + "icon": "add",
  134 + "type": "customPretty",
  135 + "customHtml": "<md-dialog aria-label=\"Add entity\" style=\"width: 480px\">\n <form name=\"addDeviceForm\" ng-submit=\"vm.save()\">\n <md-toolbar>\n <div class=\"md-toolbar-tools\">\n <h2>Add device</h2>\n <span flex></span>\n <md-button class=\"md-icon-button\" ng-click=\"vm.cancel()\">\n <ng-md-icon icon=\"close\" aria-label=\"Close\"></ng-md-icon>\n </md-button>\n </div>\n </md-toolbar>\n <md-progress-linear class=\"md-warn\" md-mode=\"indeterminate\" ng-disabled=\"!$root.loading && !vm.loading\" ng-show=\"$root.loading || vm.loading\"></md-progress-linear>\n <span style=\"min-height: 5px;\" flex=\"\" ng-show=\"!$root.loading && !vm.loading\"></span>\n <md-dialog-content>\n <div class=\"md-dialog-content\">\n <fieldset ng-disabled=\"$root.loading || vm.loading\">\n <md-input-container flex class=\"md-block\">\n <label>Device name</label>\n <input ng-model=\"vm.deviceName\" name=deviceName required>\n <div ng-messages=\"addDeviceForm.deviceName.$error\">\n <div ng-message=\"required\">Device name is required.</div>\n </div>\n </md-input-container>\n <div flex layout=\"row\">\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Latitude</label>\n <input type=\"number\" step=\"any\" name=\"latitude\" ng-model=\"vm.attributes.latitude\">\n </md-input-container>\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Longitude</label>\n <input type=\"number\" step=\"any\" name=\"longitude\" ng-model=\"vm.attributes.longitude\">\n </md-input-container>\n </div>\n <md-input-container class=\"md-block\">\n <label>Label</label>\n <input name=\"deviceLabel\" ng-model=\"vm.deviceLabel\">\n </md-input-container>\n </fieldset>\n </div>\n </md-dialog-content>\n <md-dialog-actions>\n <md-button type=\"submit\" ng-disabled=\"vm.loading || addDeviceForm.$invalid || !addDeviceForm.$dirty\" class=\"md-raised md-primary\">Create</md-button>\n <md-button ng-click=\"vm.cancel()\" class=\"md-primary\">Cancel</md-button>\n </md-dialog-actions>\n </form>\n</md-dialog>\n",
  136 + "customCss": "",
  137 + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n $q = $injector.get('$q'),\n $rootScope = $injector.get('$rootScope'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n attributeService = $injector.get('attributeService');\n\nopenAddDeviceDialog();\n\nfunction openAddDeviceDialog() {\n $mdDialog.show({\n controller: ['$scope', '$mdDialog',\n AddDeviceDialogController\n ],\n controllerAs: 'vm',\n template: htmlTemplate,\n parent: angular.element($document[0].body),\n targetEvent: $event,\n multiple: true,\n clickOutsideToClose: false\n });\n}\n\nfunction AddDeviceDialogController($scope, $mdDialog) {\n let vm = this;\n vm.types = types;\n vm.attributes = {};\n vm.deviceType = \"gateway\";\n\n vm.cancel = () => {\n $mdDialog.hide();\n };\n\n vm.save = () => {\n vm.loading = true;\n $scope.addDeviceForm.$setPristine();\n let device = {\n additionalInfo: {gateway: true},\n name: vm.deviceName,\n type: vm.deviceType,\n label: vm.deviceLabel\n };\n deviceService.saveDevice(device).then(\n (device) => {\n saveAttributes(device.id).then(\n () => {\n vm.loading = false;\n updateAliasData();\n $mdDialog.hide();\n }\n );\n },\n () => {\n vm.loading = false;\n }\n );\n };\n\n function saveAttributes(entityId) {\n let attributesArray = [];\n for (let key in vm.attributes) {\n attributesArray.push({\n key: key,\n value: vm.attributes[key]\n });\n }\n if (attributesArray.length > 0) {\n return attributeService.saveEntityAttributes(\n entityId.entityType, entityId.id,\n \"SERVER_SCOPE\", attributesArray);\n } else {\n return $q.when([]);\n }\n }\n\n function updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController\n .resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController\n .setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController\n .getAliasInfo(aliasId));\n });\n $q.all(tasks).then(() => {\n $rootScope.$broadcast(\n 'widgetForceReInit');\n });\n }\n}"
  138 + }
  139 + ],
  140 + "actionCellButton": [
  141 + {
  142 + "id": "78845501-234e-a452-6819-82b5b776e99f",
  143 + "name": "Configuration",
  144 + "icon": "settings",
  145 + "type": "openDashboardState",
  146 + "targetDashboardStateId": "__entityname__config",
  147 + "openRightLayout": false,
  148 + "setEntityId": true
  149 + },
  150 + {
  151 + "id": "f6ffdba8-e40f-2b8d-851b-f5ecaf18606b",
  152 + "name": "Graphs",
  153 + "icon": "show_chart",
  154 + "type": "openDashboardState",
  155 + "targetDashboardStateId": "__entityname_grafic",
  156 + "setEntityId": true
  157 + },
  158 + {
  159 + "id": "242671f3-76c6-6982-7acc-6f12addf0ccc",
  160 + "name": "Edit device",
  161 + "icon": "edit",
  162 + "type": "customPretty",
  163 + "customHtml": "<md-dialog aria-label=\"Edit entity\" style=\"width: 480px\">\n <form name=\"editDeviceForm\" ng-submit=\"vm.save()\">\n <md-toolbar>\n <div class=\"md-toolbar-tools\">\n <h2>Edit device</h2>\n <span flex></span>\n <md-button class=\"md-icon-button\" ng-click=\"vm.cancel()\">\n <ng-md-icon icon=\"close\" aria-label=\"Close\"></ng-md-icon>\n </md-button>\n </div>\n </md-toolbar>\n <md-progress-linear class=\"md-warn\" md-mode=\"indeterminate\" ng-disabled=\"!$root.loading && !vm.loading\" ng-show=\"$root.loading || vm.loading\"></md-progress-linear>\n <span style=\"min-height: 5px;\" flex=\"\" ng-show=\"!$root.loading && !vm.loading\"></span>\n <md-dialog-content>\n <div class=\"md-dialog-content\">\n <fieldset ng-disabled=\"$root.loading || vm.loading\">\n <md-input-container flex class=\"md-block\">\n <label>Device name</label>\n <input ng-model=\"vm.device.name\" name=deviceName required>\n <div ng-messages=\"editDeviceForm.deviceName.$error\">\n <div ng-message=\"required\">Device name is required.</div>\n </div>\n </md-input-container>\n <!--<div flex layout=\"row\">-->\n <!--<tb-entity-subtype-autocomplete flex=\"50\"-->\n <!-- ng-disabled=\"true\"-->\n <!-- tb-required=\"true\"-->\n <!-- the-form=\"editDeviceForm\"-->\n <!-- ng-model=\"vm.device.type\"-->\n <!-- entity-type=\"vm.types.entityType.device\">-->\n <!--</tb-entity-subtype-autocomplete>-->\n <!-- <md-input-container flex=\"50\" class=\"md-block\">-->\n <!-- <label>Label</label>-->\n <!-- <input name=\"deviceLabel\" ng-model=\"vm.device.label\">-->\n <!-- </md-input-container>-->\n <!--</div>-->\n <div flex layout=\"row\">\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Latitude</label>\n <input type=\"number\" step=\"any\" name=\"latitude\" ng-model=\"vm.attributes.latitude\">\n </md-input-container>\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Longitude</label>\n <input type=\"number\" step=\"any\" name=\"longitude\" ng-model=\"vm.attributes.longitude\">\n </md-input-container>\n </div>\n <md-input-container class=\"md-block\">\n <label>Label</label>\n <input name=\"deviceLabel\" ng-model=\"vm.device.label\">\n </md-input-container>\n </fieldset>\n </div>\n </md-dialog-content>\n <md-dialog-actions>\n <md-button type=\"submit\" ng-disabled=\"vm.loading || editDeviceForm.$invalid || !editDeviceForm.$dirty\" class=\"md-raised md-primary\">Create</md-button>\n <md-button ng-click=\"vm.cancel()\" class=\"md-primary\">Cancel</md-button>\n </md-dialog-actions>\n </form>\n</md-dialog>",
  164 + "customCss": "/*=======================================================================*/\n/*========== There are two examples: for edit and add entity ==========*/\n/*=======================================================================*/\n/*======================== Edit entity example ========================*/\n/*=======================================================================*/\n/*\n.edit-entity-form md-input-container {\n padding-right: 10px;\n}\n\n.edit-entity-form .boolean-value-input {\n padding-left: 5px;\n}\n\n.edit-entity-form .boolean-value-input .checkbox-label {\n margin-bottom: 8px;\n color: rgba(0,0,0,0.54);\n font-size: 12px;\n}\n\n.relations-list .header {\n padding-right: 5px;\n padding-bottom: 5px;\n padding-left: 5px;\n}\n\n.relations-list .header .cell {\n padding-right: 5px;\n padding-left: 5px;\n font-size: 12px;\n font-weight: 700;\n color: rgba(0, 0, 0, .54);\n white-space: nowrap;\n}\n\n.relations-list .body {\n padding-right: 5px;\n padding-bottom: 15px;\n padding-left: 5px;\n}\n\n.relations-list .body .row {\n padding-top: 5px;\n}\n\n.relations-list .body .cell {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.relations-list .body md-autocomplete-wrap md-input-container {\n height: 30px;\n}\n\n.relations-list .body .md-button {\n margin: 0;\n}\n\n.relations-list.old-relations tb-entity-select tb-entity-autocomplete button {\n display: none;\n} \n*/\n/*========================================================================*/\n/*========================= Add entity example =========================*/\n/*========================================================================*/\n/*\n.add-entity-form md-input-container {\n padding-right: 10px;\n}\n\n.add-entity-form .boolean-value-input {\n padding-left: 5px;\n}\n\n.add-entity-form .boolean-value-input .checkbox-label {\n margin-bottom: 8px;\n color: rgba(0,0,0,0.54);\n font-size: 12px;\n}\n\n.relations-list .header {\n padding-right: 5px;\n padding-bottom: 5px;\n padding-left: 5px;\n}\n\n.relations-list .header .cell {\n padding-right: 5px;\n padding-left: 5px;\n font-size: 12px;\n font-weight: 700;\n color: rgba(0, 0, 0, .54);\n white-space: nowrap;\n}\n\n.relations-list .body {\n padding-right: 5px;\n padding-bottom: 15px;\n padding-left: 5px;\n}\n\n.relations-list .body .row {\n padding-top: 5px;\n}\n\n.relations-list .body .cell {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.relations-list .body md-autocomplete-wrap md-input-container {\n height: 30px;\n}\n\n.relations-list .body .md-button {\n margin: 0;\n}\n*/\n",
  165 + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n $q = $injector.get('$q'),\n $rootScope = $injector.get('$rootScope'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n attributeService = $injector.get('attributeService');\n \nopenEditDeviceDialog();\n\nfunction openEditDeviceDialog() {\n $mdDialog.show({\n controller: ['$scope','$mdDialog', EditDeviceDialogController],\n controllerAs: 'vm',\n template: htmlTemplate,\n parent: angular.element($document[0].body),\n targetEvent: $event,\n multiple: true,\n clickOutsideToClose: false\n });\n}\n\nfunction EditDeviceDialogController($scope,$mdDialog) {\n let vm = this;\n vm.types = types;\n vm.loading = false;\n vm.attributes = {};\n \n getEntityInfo();\n \n function getEntityInfo() {\n vm.loading = true;\n deviceService.getDevice(entityId.id).then(\n (device) => {\n attributeService.getEntityAttributesValues(entityId.entityType, entityId.id, 'SERVER_SCOPE').then(\n (data) => {\n if (data.length) {\n getEntityAttributes(data);\n }\n vm.device = device;\n vm.loading = false;\n } \n );\n }\n )\n }\n \n vm.cancel = function() {\n $mdDialog.hide();\n };\n \n vm.save = () => {\n vm.loading = true;\n $scope.editDeviceForm.$setPristine();\n deviceService.saveDevice(vm.device).then(\n () => {\n saveAttributes().then(\n () => {\n updateAliasData();\n vm.loading = false;\n $mdDialog.hide();\n }\n );\n },\n () => {\n vm.loading = false;\n }\n );\n }\n \n function getEntityAttributes(attributes) {\n for (let i = 0; i < attributes.length; i++) {\n vm.attributes[attributes[i].key] = attributes[i].value; \n }\n }\n \n function saveAttributes() {\n let attributesArray = [];\n for (let key in vm.attributes) {\n attributesArray.push({key: key, value: vm.attributes[key]});\n }\n if (attributesArray.length > 0) {\n return attributeService.saveEntityAttributes(entityId.entityType, entityId.id, \"SERVER_SCOPE\", attributesArray);\n } else {\n return $q.when([]);\n }\n }\n \n function updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController.resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController.setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController.getAliasInfo(aliasId));\n });\n console.log(widgetContext);\n $q.all(tasks).then(() => {\n $rootScope.$broadcast('widgetForceReInit');\n });\n }\n}\n"
  166 + },
  167 + {
  168 + "id": "862ec2b7-fbcf-376e-f85f-b77c07f36efa",
  169 + "name": "Delete device",
  170 + "icon": "delete",
  171 + "type": "custom",
  172 + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n $rootScope = $injector.get('$rootScope'),\n $q = $injector.get('$q');\n\nopenDeleteDeviceDialog();\n\nfunction openDeleteDeviceDialog() {\n let title = \"Are you sure you want to delete the device \" + entityName + \"?\";\n let content = \"Be careful, after the confirmation, the device and all related data will become unrecoverable!\";\n let confirm = $mdDialog.confirm()\n .targetEvent($event)\n .title(title)\n .htmlContent(content)\n .ariaLabel(title)\n .cancel('Cancel')\n .ok('Delete');\n $mdDialog.show(confirm).then(() => {\n deleteDevice();\n })\n}\n\nfunction deleteDevice() {\n deviceService.deleteDevice(entityId.id).then(\n () => {\n updateAliasData();\n }\n );\n}\n\nfunction updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController.resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController.setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController.getAliasInfo(aliasId));\n });\n $q.all(tasks).then(() => {\n $rootScope.$broadcast('entityAliasesChanged', aliasIds);\n });\n}"
  173 + }
  174 + ],
  175 + "rowClick": [
  176 + {
  177 + "id": "ad5fc7e1-5e60-e056-6940-a75a383466a1",
  178 + "name": "to_entityname__config",
  179 + "icon": "more_horiz",
  180 + "type": "openDashboardState",
  181 + "targetDashboardStateId": "__entityname__config",
  182 + "setEntityId": true,
  183 + "stateEntityParamName": ""
  184 + }
  185 + ]
  186 + }
  187 + },
  188 + "id": "94715984-ae74-76e4-20b7-2f956b01ed80"
  189 + },
  190 + "eadabbc7-519e-76fc-ba10-b3fe8c18da10": {
  191 + "isSystemType": true,
  192 + "bundleAlias": "cards",
  193 + "typeAlias": "timeseries_table",
  194 + "type": "timeseries",
  195 + "title": "New widget",
  196 + "sizeX": 14,
  197 + "sizeY": 13,
  198 + "config": {
  199 + "datasources": [
  200 + {
  201 + "type": "entity",
  202 + "dataKeys": [
  203 + {
  204 + "name": "LOGS",
  205 + "type": "timeseries",
  206 + "label": "LOGS",
  207 + "color": "#2196f3",
  208 + "settings": {
  209 + "useCellStyleFunction": false,
  210 + "useCellContentFunction": false
  211 + },
  212 + "_hash": 0.3496649158709739,
  213 + "postFuncBody": "return value.replace(/ - (.*) - \\[/gi, ' - <b style=\"color:#0f0;\">$1</b> - [');"
  214 + }
  215 + ],
  216 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  217 + }
  218 + ],
  219 + "timewindow": {
  220 + "realtime": {
  221 + "interval": 1000,
  222 + "timewindowMs": 2592000000
  223 + },
  224 + "aggregation": {
  225 + "type": "NONE",
  226 + "limit": 200
  227 + }
  228 + },
  229 + "showTitle": true,
  230 + "backgroundColor": "rgb(255, 255, 255)",
  231 + "color": "rgba(0, 0, 0, 0.87)",
  232 + "padding": "8px",
  233 + "settings": {
  234 + "showTimestamp": true,
  235 + "displayPagination": true,
  236 + "defaultPageSize": 10
  237 + },
  238 + "title": "Debug events (logs)",
  239 + "dropShadow": true,
  240 + "enableFullscreen": true,
  241 + "titleStyle": {
  242 + "fontSize": "16px",
  243 + "fontWeight": 400
  244 + },
  245 + "useDashboardTimewindow": false,
  246 + "showLegend": false,
  247 + "widgetStyle": {},
  248 + "actions": {},
  249 + "showTitleIcon": false,
  250 + "titleIcon": null,
  251 + "iconColor": "rgba(0, 0, 0, 0.87)",
  252 + "iconSize": "24px",
  253 + "titleTooltip": "",
  254 + "displayTimewindow": true
  255 + },
  256 + "id": "eadabbc7-519e-76fc-ba10-b3fe8c18da10"
  257 + },
  258 + "f928afc4-30d1-8d0c-e3cf-777f9f9d1155": {
  259 + "isSystemType": true,
  260 + "bundleAlias": "charts",
  261 + "typeAlias": "basic_timeseries",
  262 + "type": "timeseries",
  263 + "title": "New widget",
  264 + "sizeX": 17,
  265 + "sizeY": 4,
  266 + "config": {
  267 + "datasources": [
  268 + {
  269 + "type": "entity",
  270 + "dataKeys": [
  271 + {
  272 + "name": "opcuaEventsProduced",
  273 + "type": "timeseries",
  274 + "label": "opcuaEventsProduced",
  275 + "color": "#2196f3",
  276 + "settings": {
  277 + "excludeFromStacking": false,
  278 + "hideDataByDefault": false,
  279 + "disableDataHiding": false,
  280 + "removeFromLegend": false,
  281 + "showLines": true,
  282 + "fillLines": false,
  283 + "showPoints": false,
  284 + "showPointShape": "circle",
  285 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  286 + "showPointsLineWidth": 5,
  287 + "showPointsRadius": 3,
  288 + "tooltipValueFormatter": "",
  289 + "showSeparateAxis": false,
  290 + "axisTitle": "",
  291 + "axisPosition": "left",
  292 + "axisTicksFormatter": "",
  293 + "comparisonSettings": {
  294 + "showValuesForComparison": true,
  295 + "comparisonValuesLabel": "",
  296 + "color": ""
  297 + }
  298 + },
  299 + "_hash": 0.1477920581839779
  300 + },
  301 + {
  302 + "name": "opcuaEventsSent",
  303 + "type": "timeseries",
  304 + "label": "opcuaEventsSent",
  305 + "color": "#4caf50",
  306 + "settings": {
  307 + "excludeFromStacking": false,
  308 + "hideDataByDefault": false,
  309 + "disableDataHiding": false,
  310 + "removeFromLegend": false,
  311 + "showLines": true,
  312 + "fillLines": false,
  313 + "showPoints": false,
  314 + "showPointShape": "circle",
  315 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  316 + "showPointsLineWidth": 5,
  317 + "showPointsRadius": 3,
  318 + "tooltipValueFormatter": "",
  319 + "showSeparateAxis": false,
  320 + "axisTitle": "",
  321 + "axisPosition": "left",
  322 + "axisTicksFormatter": "",
  323 + "comparisonSettings": {
  324 + "showValuesForComparison": true,
  325 + "comparisonValuesLabel": "",
  326 + "color": ""
  327 + }
  328 + },
  329 + "_hash": 0.6500957113784758
  330 + }
  331 + ],
  332 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  333 + }
  334 + ],
  335 + "timewindow": {
  336 + "realtime": {
  337 + "interval": 1000,
  338 + "timewindowMs": 120000
  339 + },
  340 + "aggregation": {
  341 + "type": "NONE",
  342 + "limit": 25000
  343 + },
  344 + "hideInterval": false,
  345 + "hideAggregation": false
  346 + },
  347 + "showTitle": true,
  348 + "backgroundColor": "#fff",
  349 + "color": "rgba(0, 0, 0, 0.87)",
  350 + "padding": "8px",
  351 + "settings": {
  352 + "shadowSize": 4,
  353 + "fontColor": "#545454",
  354 + "fontSize": 10,
  355 + "xaxis": {
  356 + "showLabels": true,
  357 + "color": "#545454"
  358 + },
  359 + "yaxis": {
  360 + "showLabels": true,
  361 + "color": "#545454"
  362 + },
  363 + "grid": {
  364 + "color": "#545454",
  365 + "tickColor": "#DDDDDD",
  366 + "verticalLines": true,
  367 + "horizontalLines": true,
  368 + "outlineWidth": 1
  369 + },
  370 + "stack": false,
  371 + "tooltipIndividual": false,
  372 + "timeForComparison": "months",
  373 + "xaxisSecond": {
  374 + "axisPosition": "top",
  375 + "showLabels": true
  376 + }
  377 + },
  378 + "title": "Real time information",
  379 + "dropShadow": true,
  380 + "enableFullscreen": true,
  381 + "titleStyle": {
  382 + "fontSize": "16px",
  383 + "fontWeight": 400
  384 + },
  385 + "mobileHeight": null,
  386 + "showTitleIcon": false,
  387 + "titleIcon": null,
  388 + "iconColor": "rgba(0, 0, 0, 0.87)",
  389 + "iconSize": "24px",
  390 + "titleTooltip": "",
  391 + "widgetStyle": {},
  392 + "useDashboardTimewindow": false,
  393 + "displayTimewindow": true,
  394 + "showLegend": true,
  395 + "legendConfig": {
  396 + "direction": "column",
  397 + "position": "right",
  398 + "showMin": true,
  399 + "showMax": true,
  400 + "showAvg": true,
  401 + "showTotal": true
  402 + },
  403 + "actions": {}
  404 + },
  405 + "id": "f928afc4-30d1-8d0c-e3cf-777f9f9d1155"
  406 + },
  407 + "2a95b473-042d-59d0-2da2-40d0cccb6c8a": {
  408 + "isSystemType": true,
  409 + "bundleAlias": "cards",
  410 + "typeAlias": "timeseries_table",
  411 + "type": "timeseries",
  412 + "title": "New widget",
  413 + "sizeX": 7,
  414 + "sizeY": 7,
  415 + "config": {
  416 + "datasources": [
  417 + {
  418 + "type": "entity",
  419 + "dataKeys": [
  420 + {
  421 + "name": "eventsSent",
  422 + "type": "timeseries",
  423 + "label": "Events",
  424 + "color": "#2196f3",
  425 + "settings": {
  426 + "useCellStyleFunction": false,
  427 + "useCellContentFunction": false
  428 + },
  429 + "_hash": 0.8156044798125357
  430 + },
  431 + {
  432 + "name": "eventsProduced",
  433 + "type": "timeseries",
  434 + "label": "Produced",
  435 + "color": "#4caf50",
  436 + "settings": {
  437 + "useCellStyleFunction": false,
  438 + "useCellContentFunction": false
  439 + },
  440 + "_hash": 0.6538259344015449
  441 + }
  442 + ],
  443 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  444 + }
  445 + ],
  446 + "timewindow": {
  447 + "realtime": {
  448 + "interval": 1000,
  449 + "timewindowMs": 604800000
  450 + },
  451 + "aggregation": {
  452 + "type": "NONE",
  453 + "limit": 200
  454 + }
  455 + },
  456 + "showTitle": true,
  457 + "backgroundColor": "rgb(255, 255, 255)",
  458 + "color": "rgba(0, 0, 0, 0.87)",
  459 + "padding": "8px",
  460 + "settings": {
  461 + "showTimestamp": true,
  462 + "displayPagination": true,
  463 + "defaultPageSize": 6,
  464 + "hideEmptyLines": true
  465 + },
  466 + "title": "Total Messages",
  467 + "dropShadow": true,
  468 + "enableFullscreen": true,
  469 + "titleStyle": {
  470 + "fontSize": "16px",
  471 + "fontWeight": 400
  472 + },
  473 + "useDashboardTimewindow": false,
  474 + "showLegend": false,
  475 + "widgetStyle": {},
  476 + "actions": {},
  477 + "showTitleIcon": false,
  478 + "titleIcon": null,
  479 + "iconColor": "rgba(0, 0, 0, 0.87)",
  480 + "iconSize": "24px",
  481 + "titleTooltip": "",
  482 + "displayTimewindow": true,
  483 + "legendConfig": {
  484 + "direction": "column",
  485 + "position": "bottom",
  486 + "showMin": false,
  487 + "showMax": false,
  488 + "showAvg": true,
  489 + "showTotal": false
  490 + }
  491 + },
  492 + "id": "2a95b473-042d-59d0-2da2-40d0cccb6c8a"
  493 + },
  494 + "aaa69366-aacc-9028-65aa-645c0f8533ec": {
  495 + "isSystemType": true,
  496 + "bundleAlias": "charts",
  497 + "typeAlias": "basic_timeseries",
  498 + "type": "timeseries",
  499 + "title": "New widget",
  500 + "sizeX": 17,
  501 + "sizeY": 4,
  502 + "config": {
  503 + "datasources": [
  504 + {
  505 + "type": "entity",
  506 + "dataKeys": [
  507 + {
  508 + "name": "eventsSent",
  509 + "type": "timeseries",
  510 + "label": "eventsSent",
  511 + "color": "#2196f3",
  512 + "settings": {
  513 + "excludeFromStacking": false,
  514 + "hideDataByDefault": false,
  515 + "disableDataHiding": false,
  516 + "removeFromLegend": false,
  517 + "showLines": true,
  518 + "fillLines": false,
  519 + "showPoints": false,
  520 + "showPointShape": "circle",
  521 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  522 + "showPointsLineWidth": 5,
  523 + "showPointsRadius": 3,
  524 + "tooltipValueFormatter": "",
  525 + "showSeparateAxis": false,
  526 + "axisTitle": "",
  527 + "axisPosition": "left",
  528 + "axisTicksFormatter": "",
  529 + "comparisonSettings": {
  530 + "showValuesForComparison": true,
  531 + "comparisonValuesLabel": "",
  532 + "color": ""
  533 + }
  534 + },
  535 + "_hash": 0.41414001784591314
  536 + },
  537 + {
  538 + "name": "eventsProduced",
  539 + "type": "timeseries",
  540 + "label": "eventsProduced",
  541 + "color": "#4caf50",
  542 + "settings": {
  543 + "excludeFromStacking": false,
  544 + "hideDataByDefault": false,
  545 + "disableDataHiding": false,
  546 + "removeFromLegend": false,
  547 + "showLines": true,
  548 + "fillLines": false,
  549 + "showPoints": false,
  550 + "showPointShape": "circle",
  551 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  552 + "showPointsLineWidth": 5,
  553 + "showPointsRadius": 3,
  554 + "tooltipValueFormatter": "",
  555 + "showSeparateAxis": false,
  556 + "axisTitle": "",
  557 + "axisPosition": "left",
  558 + "axisTicksFormatter": "",
  559 + "comparisonSettings": {
  560 + "showValuesForComparison": true,
  561 + "comparisonValuesLabel": "",
  562 + "color": ""
  563 + }
  564 + },
  565 + "_hash": 0.7819101846284422
  566 + }
  567 + ],
  568 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  569 + }
  570 + ],
  571 + "timewindow": {
  572 + "realtime": {
  573 + "timewindowMs": 60000
  574 + }
  575 + },
  576 + "showTitle": true,
  577 + "backgroundColor": "#fff",
  578 + "color": "rgba(0, 0, 0, 0.87)",
  579 + "padding": "8px",
  580 + "settings": {
  581 + "shadowSize": 4,
  582 + "fontColor": "#545454",
  583 + "fontSize": 10,
  584 + "xaxis": {
  585 + "showLabels": true,
  586 + "color": "#545454"
  587 + },
  588 + "yaxis": {
  589 + "showLabels": true,
  590 + "color": "#545454"
  591 + },
  592 + "grid": {
  593 + "color": "#545454",
  594 + "tickColor": "#DDDDDD",
  595 + "verticalLines": true,
  596 + "horizontalLines": true,
  597 + "outlineWidth": 1
  598 + },
  599 + "stack": false,
  600 + "tooltipIndividual": false,
  601 + "timeForComparison": "months",
  602 + "xaxisSecond": {
  603 + "axisPosition": "top",
  604 + "showLabels": true
  605 + }
  606 + },
  607 + "title": "History information",
  608 + "dropShadow": true,
  609 + "enableFullscreen": true,
  610 + "titleStyle": {
  611 + "fontSize": "16px",
  612 + "fontWeight": 400
  613 + },
  614 + "mobileHeight": null,
  615 + "showTitleIcon": false,
  616 + "titleIcon": null,
  617 + "iconColor": "rgba(0, 0, 0, 0.87)",
  618 + "iconSize": "24px",
  619 + "titleTooltip": "",
  620 + "widgetStyle": {},
  621 + "useDashboardTimewindow": true,
  622 + "displayTimewindow": true,
  623 + "showLegend": true,
  624 + "legendConfig": {
  625 + "direction": "column",
  626 + "position": "right",
  627 + "showMin": true,
  628 + "showMax": true,
  629 + "showAvg": true,
  630 + "showTotal": true
  631 + },
  632 + "actions": {}
  633 + },
  634 + "id": "aaa69366-aacc-9028-65aa-645c0f8533ec"
  635 + },
  636 + "ce5c7d01-a3ef-5cf0-4578-8505135c23a0": {
  637 + "isSystemType": true,
  638 + "bundleAlias": "charts",
  639 + "typeAlias": "basic_timeseries",
  640 + "type": "timeseries",
  641 + "title": "New widget",
  642 + "sizeX": 17,
  643 + "sizeY": 4,
  644 + "config": {
  645 + "datasources": [
  646 + {
  647 + "type": "entity",
  648 + "dataKeys": [
  649 + {
  650 + "name": "bleEventsProduced",
  651 + "type": "timeseries",
  652 + "label": "bleEventsProduced",
  653 + "color": "#2196f3",
  654 + "settings": {
  655 + "excludeFromStacking": false,
  656 + "hideDataByDefault": false,
  657 + "disableDataHiding": false,
  658 + "removeFromLegend": false,
  659 + "showLines": true,
  660 + "fillLines": false,
  661 + "showPoints": false,
  662 + "showPointShape": "circle",
  663 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  664 + "showPointsLineWidth": 5,
  665 + "showPointsRadius": 3,
  666 + "tooltipValueFormatter": "",
  667 + "showSeparateAxis": false,
  668 + "axisTitle": "",
  669 + "axisPosition": "left",
  670 + "axisTicksFormatter": "",
  671 + "comparisonSettings": {
  672 + "showValuesForComparison": true,
  673 + "comparisonValuesLabel": "",
  674 + "color": ""
  675 + }
  676 + },
  677 + "_hash": 0.5625165504526104
  678 + },
  679 + {
  680 + "name": "bleEventsSent",
  681 + "type": "timeseries",
  682 + "label": "bleEventsSent",
  683 + "color": "#4caf50",
  684 + "settings": {
  685 + "excludeFromStacking": false,
  686 + "hideDataByDefault": false,
  687 + "disableDataHiding": false,
  688 + "removeFromLegend": false,
  689 + "showLines": true,
  690 + "fillLines": false,
  691 + "showPoints": false,
  692 + "showPointShape": "circle",
  693 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  694 + "showPointsLineWidth": 5,
  695 + "showPointsRadius": 3,
  696 + "tooltipValueFormatter": "",
  697 + "showSeparateAxis": false,
  698 + "axisTitle": "",
  699 + "axisPosition": "left",
  700 + "axisTicksFormatter": "",
  701 + "comparisonSettings": {
  702 + "showValuesForComparison": true,
  703 + "comparisonValuesLabel": "",
  704 + "color": ""
  705 + }
  706 + },
  707 + "_hash": 0.6817950080745288
  708 + }
  709 + ],
  710 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  711 + }
  712 + ],
  713 + "timewindow": {
  714 + "realtime": {
  715 + "interval": 5000,
  716 + "timewindowMs": 120000
  717 + },
  718 + "aggregation": {
  719 + "type": "AVG",
  720 + "limit": 25000
  721 + }
  722 + },
  723 + "showTitle": true,
  724 + "backgroundColor": "#fff",
  725 + "color": "rgba(0, 0, 0, 0.87)",
  726 + "padding": "8px",
  727 + "settings": {
  728 + "shadowSize": 4,
  729 + "fontColor": "#545454",
  730 + "fontSize": 10,
  731 + "xaxis": {
  732 + "showLabels": true,
  733 + "color": "#545454"
  734 + },
  735 + "yaxis": {
  736 + "showLabels": true,
  737 + "color": "#545454"
  738 + },
  739 + "grid": {
  740 + "color": "#545454",
  741 + "tickColor": "#DDDDDD",
  742 + "verticalLines": true,
  743 + "horizontalLines": true,
  744 + "outlineWidth": 1
  745 + },
  746 + "stack": false,
  747 + "tooltipIndividual": false,
  748 + "timeForComparison": "months",
  749 + "xaxisSecond": {
  750 + "axisPosition": "top",
  751 + "showLabels": true
  752 + }
  753 + },
  754 + "title": "Real time information",
  755 + "dropShadow": true,
  756 + "enableFullscreen": true,
  757 + "titleStyle": {
  758 + "fontSize": "16px",
  759 + "fontWeight": 400
  760 + },
  761 + "mobileHeight": null,
  762 + "showTitleIcon": false,
  763 + "titleIcon": null,
  764 + "iconColor": "rgba(0, 0, 0, 0.87)",
  765 + "iconSize": "24px",
  766 + "titleTooltip": "",
  767 + "widgetStyle": {},
  768 + "useDashboardTimewindow": false,
  769 + "displayTimewindow": true,
  770 + "showLegend": true,
  771 + "legendConfig": {
  772 + "direction": "column",
  773 + "position": "right",
  774 + "showMin": true,
  775 + "showMax": true,
  776 + "showAvg": true,
  777 + "showTotal": true
  778 + },
  779 + "actions": {}
  780 + },
  781 + "id": "ce5c7d01-a3ef-5cf0-4578-8505135c23a0"
  782 + },
  783 + "466f046d-6005-a168-b107-60fcb2469cd5": {
  784 + "isSystemType": true,
  785 + "bundleAlias": "gateway_widgets",
  786 + "typeAlias": "attributes_card",
  787 + "type": "latest",
  788 + "title": "New widget",
  789 + "sizeX": 7,
  790 + "sizeY": 5,
  791 + "config": {
  792 + "datasources": [
  793 + {
  794 + "type": "entity",
  795 + "dataKeys": [],
  796 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  797 + }
  798 + ],
  799 + "timewindow": {
  800 + "realtime": {
  801 + "timewindowMs": 60000
  802 + }
  803 + },
  804 + "showTitle": true,
  805 + "backgroundColor": "#fff",
  806 + "color": "rgba(0, 0, 0, 0.87)",
  807 + "padding": "8px",
  808 + "settings": {
  809 + "eventsTitle": "Gateway Events Form",
  810 + "eventsReg": [
  811 + "EventsProduced",
  812 + "EventsSent"
  813 + ]
  814 + },
  815 + "title": "Gateway events",
  816 + "showTitleIcon": false,
  817 + "titleIcon": null,
  818 + "iconColor": "rgba(0, 0, 0, 0.87)",
  819 + "iconSize": "24px",
  820 + "titleTooltip": "",
  821 + "dropShadow": true,
  822 + "enableFullscreen": true,
  823 + "widgetStyle": {},
  824 + "titleStyle": {
  825 + "fontSize": "16px",
  826 + "fontWeight": 400
  827 + },
  828 + "useDashboardTimewindow": true,
  829 + "displayTimewindow": true,
  830 + "showLegend": false,
  831 + "actions": {}
  832 + },
  833 + "id": "466f046d-6005-a168-b107-60fcb2469cd5"
  834 + },
  835 + "8fc32225-164f-3258-73f7-e6b6d959cf0b": {
  836 + "isSystemType": true,
  837 + "bundleAlias": "gateway_widgets",
  838 + "typeAlias": "config_form_latest",
  839 + "type": "latest",
  840 + "title": "New widget",
  841 + "sizeX": 10,
  842 + "sizeY": 9,
  843 + "config": {
  844 + "datasources": [
  845 + {
  846 + "type": "entity",
  847 + "dataKeys": [],
  848 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  849 + }
  850 + ],
  851 + "timewindow": {
  852 + "realtime": {
  853 + "timewindowMs": 60000
  854 + }
  855 + },
  856 + "showTitle": true,
  857 + "backgroundColor": "#fff",
  858 + "color": "rgba(0, 0, 0, 0.87)",
  859 + "padding": "8px",
  860 + "settings": {
  861 + "gatewayTitle": "Gateway configuration (Single device)",
  862 + "readOnly": false
  863 + },
  864 + "title": "New Gateway configuration (Single device)",
  865 + "showTitleIcon": false,
  866 + "titleIcon": null,
  867 + "iconColor": "rgba(0, 0, 0, 0.87)",
  868 + "iconSize": "24px",
  869 + "titleTooltip": "",
  870 + "dropShadow": true,
  871 + "enableFullscreen": true,
  872 + "widgetStyle": {},
  873 + "titleStyle": {
  874 + "fontSize": "16px",
  875 + "fontWeight": 400
  876 + },
  877 + "useDashboardTimewindow": true,
  878 + "displayTimewindow": true,
  879 + "showLegend": false,
  880 + "actions": {}
  881 + },
  882 + "id": "8fc32225-164f-3258-73f7-e6b6d959cf0b"
  883 + },
  884 + "063fc179-c9fd-f952-e714-f24e9c43c05c": {
  885 + "isSystemType": true,
  886 + "bundleAlias": "control_widgets",
  887 + "typeAlias": "rpcbutton",
  888 + "type": "rpc",
  889 + "title": "New widget",
  890 + "sizeX": 4,
  891 + "sizeY": 2,
  892 + "config": {
  893 + "targetDeviceAliases": [],
  894 + "showTitle": false,
  895 + "backgroundColor": "#e6e7e8",
  896 + "color": "rgba(0, 0, 0, 0.87)",
  897 + "padding": "0px",
  898 + "settings": {
  899 + "requestTimeout": 5000,
  900 + "oneWayElseTwoWay": true,
  901 + "styleButton": {
  902 + "isRaised": true,
  903 + "isPrimary": false
  904 + },
  905 + "methodParams": "{}",
  906 + "methodName": "gateway_reboot",
  907 + "buttonText": "GATEWAY REBOOT"
  908 + },
  909 + "title": "New RPC Button",
  910 + "dropShadow": true,
  911 + "enableFullscreen": false,
  912 + "widgetStyle": {},
  913 + "titleStyle": {
  914 + "fontSize": "16px",
  915 + "fontWeight": 400
  916 + },
  917 + "useDashboardTimewindow": true,
  918 + "showLegend": false,
  919 + "actions": {},
  920 + "datasources": [],
  921 + "showTitleIcon": false,
  922 + "titleIcon": null,
  923 + "iconColor": "rgba(0, 0, 0, 0.87)",
  924 + "iconSize": "24px",
  925 + "titleTooltip": "",
  926 + "displayTimewindow": true,
  927 + "targetDeviceAliasIds": [
  928 + "b2487e75-2fa4-f211-142c-434dfd50c70c"
  929 + ]
  930 + },
  931 + "id": "063fc179-c9fd-f952-e714-f24e9c43c05c"
  932 + },
  933 + "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7": {
  934 + "isSystemType": true,
  935 + "bundleAlias": "control_widgets",
  936 + "typeAlias": "rpcbutton",
  937 + "type": "rpc",
  938 + "title": "New widget",
  939 + "sizeX": 4,
  940 + "sizeY": 2,
  941 + "config": {
  942 + "targetDeviceAliases": [],
  943 + "showTitle": false,
  944 + "backgroundColor": "#e6e7e8",
  945 + "color": "rgba(0, 0, 0, 0.87)",
  946 + "padding": "0px",
  947 + "settings": {
  948 + "requestTimeout": 5000,
  949 + "oneWayElseTwoWay": true,
  950 + "styleButton": {
  951 + "isRaised": true,
  952 + "isPrimary": false
  953 + },
  954 + "methodName": "gateway_restart",
  955 + "methodParams": "{}",
  956 + "buttonText": "gateway restart"
  957 + },
  958 + "title": "New RPC Button",
  959 + "dropShadow": true,
  960 + "enableFullscreen": false,
  961 + "widgetStyle": {},
  962 + "titleStyle": {
  963 + "fontSize": "16px",
  964 + "fontWeight": 400
  965 + },
  966 + "useDashboardTimewindow": true,
  967 + "showLegend": false,
  968 + "actions": {},
  969 + "datasources": [],
  970 + "showTitleIcon": false,
  971 + "titleIcon": null,
  972 + "iconColor": "rgba(0, 0, 0, 0.87)",
  973 + "iconSize": "24px",
  974 + "titleTooltip": "",
  975 + "displayTimewindow": true,
  976 + "targetDeviceAliasIds": [
  977 + "b2487e75-2fa4-f211-142c-434dfd50c70c"
  978 + ]
  979 + },
  980 + "id": "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7"
  981 + },
  982 + "6770b6ba-eff8-df05-75f8-c1f9326d4842": {
  983 + "isSystemType": true,
  984 + "bundleAlias": "input_widgets",
  985 + "typeAlias": "markers_placement_openstreetmap",
  986 + "type": "latest",
  987 + "title": "New widget",
  988 + "sizeX": 6,
  989 + "sizeY": 4,
  990 + "config": {
  991 + "datasources": [
  992 + {
  993 + "type": "entity",
  994 + "dataKeys": [
  995 + {
  996 + "name": "latitude",
  997 + "type": "attribute",
  998 + "label": "latitude",
  999 + "color": "#2196f3",
  1000 + "settings": {},
  1001 + "_hash": 0.9743324774725604
  1002 + },
  1003 + {
  1004 + "name": "longitude",
  1005 + "type": "attribute",
  1006 + "label": "longitude",
  1007 + "color": "#4caf50",
  1008 + "settings": {},
  1009 + "_hash": 0.5530093635101525
  1010 + }
  1011 + ],
  1012 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  1013 + }
  1014 + ],
  1015 + "timewindow": {
  1016 + "realtime": {
  1017 + "timewindowMs": 60000
  1018 + }
  1019 + },
  1020 + "showTitle": false,
  1021 + "backgroundColor": "#fff",
  1022 + "color": "rgba(0, 0, 0, 0.87)",
  1023 + "padding": "8px",
  1024 + "settings": {
  1025 + "fitMapBounds": true,
  1026 + "latKeyName": "latitude",
  1027 + "lngKeyName": "longitude",
  1028 + "showLabel": true,
  1029 + "label": "${entityName}",
  1030 + "tooltipPattern": "<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><br/><link-act name='delete'>Delete</link-act>",
  1031 + "markerImageSize": 34,
  1032 + "useColorFunction": false,
  1033 + "markerImages": [],
  1034 + "useMarkerImageFunction": false,
  1035 + "color": "#fe7569",
  1036 + "mapProvider": "OpenStreetMap.Mapnik",
  1037 + "showTooltip": true,
  1038 + "autocloseTooltip": true,
  1039 + "defaultCenterPosition": [
  1040 + 0,
  1041 + 0
  1042 + ],
  1043 + "customProviderTileUrl": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
  1044 + "showTooltipAction": "click",
  1045 + "polygonKeyName": "coordinates",
  1046 + "polygonOpacity": 0.5,
  1047 + "polygonStrokeOpacity": 1,
  1048 + "polygonStrokeWeight": 1,
  1049 + "zoomOnClick": true,
  1050 + "showCoverageOnHover": true,
  1051 + "animate": true,
  1052 + "maxClusterRadius": 80,
  1053 + "removeOutsideVisibleBounds": true,
  1054 + "defaultZoomLevel": 5
  1055 + },
  1056 + "title": "Gateway Location",
  1057 + "dropShadow": true,
  1058 + "enableFullscreen": false,
  1059 + "titleStyle": {
  1060 + "fontSize": "16px",
  1061 + "fontWeight": 400
  1062 + },
  1063 + "useDashboardTimewindow": true,
  1064 + "showLegend": false,
  1065 + "widgetStyle": {},
  1066 + "actions": {
  1067 + "tooltipAction": [
  1068 + {
  1069 + "id": "54c293c4-9ca6-e34f-dc6a-0271944c1c66",
  1070 + "name": "delete",
  1071 + "icon": "more_horiz",
  1072 + "type": "custom",
  1073 + "customFunction": "var $rootScope = widgetContext.$scope.$injector.get('$rootScope');\nvar entityDatasource = widgetContext.map.subscription.datasources.filter(\n function(entity) {\n return entity.entityId === entityId.id\n });\n\nwidgetContext.map.saveMarkerLocation(entityDatasource[0],\n widgetContext.map.locations[0], {\n \"lat\": null,\n \"lng\": null\n }).then(function succes() {\n $rootScope.$broadcast('widgetForceReInit');\n });"
  1074 + }
  1075 + ]
  1076 + },
  1077 + "showTitleIcon": false,
  1078 + "titleIcon": null,
  1079 + "iconColor": "rgba(0, 0, 0, 0.87)",
  1080 + "iconSize": "24px",
  1081 + "titleTooltip": "",
  1082 + "displayTimewindow": true
  1083 + },
  1084 + "id": "6770b6ba-eff8-df05-75f8-c1f9326d4842"
  1085 + }
  1086 + },
  1087 + "states": {
  1088 + "main_gateway": {
  1089 + "name": "Gateways",
  1090 + "root": true,
  1091 + "layouts": {
  1092 + "main": {
  1093 + "widgets": {
  1094 + "94715984-ae74-76e4-20b7-2f956b01ed80": {
  1095 + "sizeX": 24,
  1096 + "sizeY": 12,
  1097 + "row": 0,
  1098 + "col": 0
  1099 + }
  1100 + },
  1101 + "gridSettings": {
  1102 + "backgroundColor": "#eeeeee",
  1103 + "color": "rgba(0,0,0,0.870588)",
  1104 + "columns": 24,
  1105 + "margins": [
  1106 + 10,
  1107 + 10
  1108 + ],
  1109 + "backgroundSizeMode": "100%",
  1110 + "autoFillHeight": true,
  1111 + "mobileAutoFillHeight": false,
  1112 + "mobileRowHeight": 70
  1113 + }
  1114 + }
  1115 + }
  1116 + },
  1117 + "__entityname__config": {
  1118 + "name": "${entityName} Configuration",
  1119 + "root": false,
  1120 + "layouts": {
  1121 + "main": {
  1122 + "widgets": {
  1123 + "eadabbc7-519e-76fc-ba10-b3fe8c18da10": {
  1124 + "sizeX": 14,
  1125 + "sizeY": 13,
  1126 + "row": 0,
  1127 + "col": 10
  1128 + },
  1129 + "8fc32225-164f-3258-73f7-e6b6d959cf0b": {
  1130 + "sizeX": 10,
  1131 + "sizeY": 9,
  1132 + "row": 0,
  1133 + "col": 0
  1134 + },
  1135 + "063fc179-c9fd-f952-e714-f24e9c43c05c": {
  1136 + "sizeX": 4,
  1137 + "sizeY": 2,
  1138 + "row": 9,
  1139 + "col": 0
  1140 + },
  1141 + "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7": {
  1142 + "sizeX": 4,
  1143 + "sizeY": 2,
  1144 + "row": 11,
  1145 + "col": 0
  1146 + },
  1147 + "6770b6ba-eff8-df05-75f8-c1f9326d4842": {
  1148 + "sizeX": 6,
  1149 + "sizeY": 4,
  1150 + "row": 9,
  1151 + "col": 4
  1152 + }
  1153 + },
  1154 + "gridSettings": {
  1155 + "backgroundColor": "#eeeeee",
  1156 + "color": "rgba(0,0,0,0.870588)",
  1157 + "columns": 24,
  1158 + "margins": [
  1159 + 10,
  1160 + 10
  1161 + ],
  1162 + "backgroundSizeMode": "100%",
  1163 + "autoFillHeight": true,
  1164 + "mobileAutoFillHeight": false,
  1165 + "mobileRowHeight": 70
  1166 + }
  1167 + }
  1168 + }
  1169 + },
  1170 + "__entityname_grafic": {
  1171 + "name": "${entityName} Details",
  1172 + "root": false,
  1173 + "layouts": {
  1174 + "main": {
  1175 + "widgets": {
  1176 + "f928afc4-30d1-8d0c-e3cf-777f9f9d1155": {
  1177 + "sizeX": 17,
  1178 + "sizeY": 4,
  1179 + "mobileHeight": null,
  1180 + "row": 4,
  1181 + "col": 7
  1182 + },
  1183 + "2a95b473-042d-59d0-2da2-40d0cccb6c8a": {
  1184 + "sizeX": 7,
  1185 + "sizeY": 7,
  1186 + "row": 5,
  1187 + "col": 0
  1188 + },
  1189 + "aaa69366-aacc-9028-65aa-645c0f8533ec": {
  1190 + "sizeX": 17,
  1191 + "sizeY": 4,
  1192 + "mobileHeight": null,
  1193 + "row": 0,
  1194 + "col": 7
  1195 + },
  1196 + "ce5c7d01-a3ef-5cf0-4578-8505135c23a0": {
  1197 + "sizeX": 17,
  1198 + "sizeY": 4,
  1199 + "mobileHeight": null,
  1200 + "row": 8,
  1201 + "col": 7
  1202 + },
  1203 + "466f046d-6005-a168-b107-60fcb2469cd5": {
  1204 + "sizeX": 7,
  1205 + "sizeY": 5,
  1206 + "row": 0,
  1207 + "col": 0
  1208 + }
  1209 + },
  1210 + "gridSettings": {
  1211 + "backgroundColor": "#eeeeee",
  1212 + "color": "rgba(0,0,0,0.870588)",
  1213 + "columns": 24,
  1214 + "margins": [
  1215 + 10,
  1216 + 10
  1217 + ],
  1218 + "backgroundSizeMode": "auto 100%",
  1219 + "autoFillHeight": true,
  1220 + "mobileAutoFillHeight": true,
  1221 + "mobileRowHeight": 70
  1222 + }
  1223 + }
  1224 + }
  1225 + }
  1226 + },
  1227 + "entityAliases": {
  1228 + "3e0f533a-0db1-3292-184f-06e73535061a": {
  1229 + "id": "3e0f533a-0db1-3292-184f-06e73535061a",
  1230 + "alias": "Gateways",
  1231 + "filter": {
  1232 + "type": "deviceType",
  1233 + "resolveMultiple": true,
  1234 + "deviceType": "gateway",
  1235 + "deviceNameFilter": ""
  1236 + }
  1237 + },
  1238 + "b2487e75-2fa4-f211-142c-434dfd50c70c": {
  1239 + "id": "b2487e75-2fa4-f211-142c-434dfd50c70c",
  1240 + "alias": "Current Gateway",
  1241 + "filter": {
  1242 + "type": "stateEntity",
  1243 + "resolveMultiple": false,
  1244 + "stateEntityParamName": "",
  1245 + "defaultStateEntity": null
  1246 + }
  1247 + }
  1248 + },
  1249 + "timewindow": {
  1250 + "realtime": {
  1251 + "interval": 1000,
  1252 + "timewindowMs": 86400000
  1253 + },
  1254 + "aggregation": {
  1255 + "type": "NONE",
  1256 + "limit": 25000
  1257 + },
  1258 + "hideInterval": false,
  1259 + "hideAggregation": false,
  1260 + "hideAggInterval": false
  1261 + },
  1262 + "settings": {
  1263 + "stateControllerId": "entity",
  1264 + "showTitle": true,
  1265 + "showDashboardsSelect": true,
  1266 + "showEntitiesSelect": true,
  1267 + "showDashboardTimewindow": true,
  1268 + "showDashboardExport": true,
  1269 + "toolbarAlwaysOpen": true,
  1270 + "titleColor": "rgba(0,0,0,0.870588)"
  1271 + }
  1272 + },
  1273 + "name": "Gateways"
  1274 +}
... ...
  1 +{
  2 + "title": "Rule Engine Statistics",
  3 + "configuration": {
  4 + "widgets": {
  5 + "81987f19-3eac-e4ce-b790-d96e9b54d9a0": {
  6 + "isSystemType": true,
  7 + "bundleAlias": "charts",
  8 + "typeAlias": "basic_timeseries",
  9 + "type": "timeseries",
  10 + "title": "New widget",
  11 + "sizeX": 12,
  12 + "sizeY": 7,
  13 + "config": {
  14 + "datasources": [
  15 + {
  16 + "type": "entity",
  17 + "dataKeys": [
  18 + {
  19 + "name": "successfulMsgs",
  20 + "type": "timeseries",
  21 + "label": "${entityName} Successful",
  22 + "color": "#4caf50",
  23 + "settings": {
  24 + "excludeFromStacking": false,
  25 + "hideDataByDefault": false,
  26 + "disableDataHiding": false,
  27 + "removeFromLegend": false,
  28 + "showLines": true,
  29 + "fillLines": false,
  30 + "showPoints": false,
  31 + "showPointShape": "circle",
  32 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  33 + "showPointsLineWidth": 5,
  34 + "showPointsRadius": 3,
  35 + "showSeparateAxis": false,
  36 + "axisPosition": "left",
  37 + "thresholds": [
  38 + {
  39 + "thresholdValueSource": "predefinedValue"
  40 + }
  41 + ],
  42 + "comparisonSettings": {
  43 + "showValuesForComparison": true
  44 + }
  45 + },
  46 + "_hash": 0.15490750967648736
  47 + },
  48 + {
  49 + "name": "failedMsgs",
  50 + "type": "timeseries",
  51 + "label": "${entityName} Permanent Failures",
  52 + "color": "#ef5350",
  53 + "settings": {
  54 + "excludeFromStacking": false,
  55 + "hideDataByDefault": false,
  56 + "disableDataHiding": false,
  57 + "removeFromLegend": false,
  58 + "showLines": true,
  59 + "fillLines": false,
  60 + "showPoints": false,
  61 + "showPointShape": "circle",
  62 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  63 + "showPointsLineWidth": 5,
  64 + "showPointsRadius": 3,
  65 + "showSeparateAxis": false,
  66 + "axisPosition": "left",
  67 + "thresholds": [
  68 + {
  69 + "thresholdValueSource": "predefinedValue"
  70 + }
  71 + ],
  72 + "comparisonSettings": {
  73 + "showValuesForComparison": true
  74 + }
  75 + },
  76 + "_hash": 0.4186621166514697
  77 + },
  78 + {
  79 + "name": "tmpFailed",
  80 + "type": "timeseries",
  81 + "label": "${entityName} Processing Failures",
  82 + "color": "#ffc107",
  83 + "settings": {
  84 + "excludeFromStacking": false,
  85 + "hideDataByDefault": false,
  86 + "disableDataHiding": false,
  87 + "removeFromLegend": false,
  88 + "showLines": true,
  89 + "fillLines": false,
  90 + "showPoints": false,
  91 + "showPointShape": "circle",
  92 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  93 + "showPointsLineWidth": 5,
  94 + "showPointsRadius": 3,
  95 + "showSeparateAxis": false,
  96 + "axisPosition": "left",
  97 + "thresholds": [
  98 + {
  99 + "thresholdValueSource": "predefinedValue"
  100 + }
  101 + ],
  102 + "comparisonSettings": {
  103 + "showValuesForComparison": true
  104 + }
  105 + },
  106 + "_hash": 0.49891007198715376
  107 + }
  108 + ],
  109 + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018"
  110 + }
  111 + ],
  112 + "timewindow": {
  113 + "realtime": {
  114 + "interval": 1000,
  115 + "timewindowMs": 300000
  116 + },
  117 + "aggregation": {
  118 + "type": "NONE",
  119 + "limit": 8640
  120 + },
  121 + "hideInterval": false,
  122 + "hideAggregation": false,
  123 + "hideAggInterval": false
  124 + },
  125 + "showTitle": true,
  126 + "backgroundColor": "#fff",
  127 + "color": "rgba(0, 0, 0, 0.87)",
  128 + "padding": "8px",
  129 + "settings": {
  130 + "shadowSize": 4,
  131 + "fontColor": "#545454",
  132 + "fontSize": 10,
  133 + "xaxis": {
  134 + "showLabels": true,
  135 + "color": "#545454"
  136 + },
  137 + "yaxis": {
  138 + "showLabels": true,
  139 + "color": "#545454"
  140 + },
  141 + "grid": {
  142 + "color": "#545454",
  143 + "tickColor": "#DDDDDD",
  144 + "verticalLines": true,
  145 + "horizontalLines": true,
  146 + "outlineWidth": 1
  147 + },
  148 + "stack": false,
  149 + "tooltipIndividual": false,
  150 + "timeForComparison": "months",
  151 + "xaxisSecond": {
  152 + "axisPosition": "top",
  153 + "showLabels": true
  154 + }
  155 + },
  156 + "title": "Queue Stats",
  157 + "dropShadow": true,
  158 + "enableFullscreen": true,
  159 + "titleStyle": {
  160 + "fontSize": "16px",
  161 + "fontWeight": 400
  162 + },
  163 + "mobileHeight": null,
  164 + "showTitleIcon": false,
  165 + "titleIcon": null,
  166 + "iconColor": "rgba(0, 0, 0, 0.87)",
  167 + "iconSize": "24px",
  168 + "titleTooltip": "",
  169 + "widgetStyle": {},
  170 + "useDashboardTimewindow": false,
  171 + "displayTimewindow": true,
  172 + "showLegend": true,
  173 + "actions": {},
  174 + "legendConfig": {
  175 + "direction": "column",
  176 + "position": "bottom",
  177 + "showMin": true,
  178 + "showMax": true,
  179 + "showAvg": false,
  180 + "showTotal": true
  181 + }
  182 + },
  183 + "id": "81987f19-3eac-e4ce-b790-d96e9b54d9a0"
  184 + },
  185 + "5eb79712-5c24-3060-7e4f-6af36b8f842d": {
  186 + "isSystemType": true,
  187 + "bundleAlias": "cards",
  188 + "typeAlias": "timeseries_table",
  189 + "type": "timeseries",
  190 + "title": "New widget",
  191 + "sizeX": 24,
  192 + "sizeY": 5,
  193 + "config": {
  194 + "datasources": [
  195 + {
  196 + "type": "entity",
  197 + "dataKeys": [
  198 + {
  199 + "name": "ruleEngineException",
  200 + "type": "timeseries",
  201 + "label": "Rule Chain",
  202 + "color": "#2196f3",
  203 + "settings": {
  204 + "useCellStyleFunction": false,
  205 + "useCellContentFunction": true,
  206 + "cellContentFunction": "return JSON.parse(value).ruleChainName;"
  207 + },
  208 + "_hash": 0.9954481282345906
  209 + },
  210 + {
  211 + "name": "ruleEngineException",
  212 + "type": "timeseries",
  213 + "label": "Rule Node",
  214 + "color": "#4caf50",
  215 + "settings": {
  216 + "useCellStyleFunction": false,
  217 + "useCellContentFunction": true,
  218 + "cellContentFunction": "return JSON.parse(value).ruleNodeName;"
  219 + },
  220 + "_hash": 0.18580357036589978
  221 + },
  222 + {
  223 + "name": "ruleEngineException",
  224 + "type": "timeseries",
  225 + "label": "Latest Error",
  226 + "color": "#f44336",
  227 + "settings": {
  228 + "useCellStyleFunction": false,
  229 + "useCellContentFunction": true,
  230 + "cellContentFunction": "return JSON.parse(value).message;"
  231 + },
  232 + "_hash": 0.7255162989552142
  233 + }
  234 + ],
  235 + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018"
  236 + }
  237 + ],
  238 + "timewindow": {
  239 + "realtime": {
  240 + "interval": 1000,
  241 + "timewindowMs": 86400000
  242 + },
  243 + "aggregation": {
  244 + "type": "NONE",
  245 + "limit": 200
  246 + }
  247 + },
  248 + "showTitle": true,
  249 + "backgroundColor": "rgb(255, 255, 255)",
  250 + "color": "rgba(0, 0, 0, 0.87)",
  251 + "padding": "8px",
  252 + "settings": {
  253 + "showTimestamp": true,
  254 + "displayPagination": true,
  255 + "defaultPageSize": 10
  256 + },
  257 + "title": "Exceptions",
  258 + "dropShadow": true,
  259 + "enableFullscreen": true,
  260 + "titleStyle": {
  261 + "fontSize": "16px",
  262 + "fontWeight": 400
  263 + },
  264 + "useDashboardTimewindow": false,
  265 + "showLegend": false,
  266 + "widgetStyle": {},
  267 + "actions": {},
  268 + "showTitleIcon": false,
  269 + "titleIcon": null,
  270 + "iconColor": "rgba(0, 0, 0, 0.87)",
  271 + "iconSize": "24px",
  272 + "titleTooltip": "",
  273 + "displayTimewindow": true
  274 + },
  275 + "id": "5eb79712-5c24-3060-7e4f-6af36b8f842d"
  276 + },
  277 + "ad3f1417-87a8-750e-fc67-49a2de1466d4": {
  278 + "isSystemType": true,
  279 + "bundleAlias": "charts",
  280 + "typeAlias": "basic_timeseries",
  281 + "type": "timeseries",
  282 + "title": "New widget",
  283 + "sizeX": 12,
  284 + "sizeY": 7,
  285 + "config": {
  286 + "datasources": [
  287 + {
  288 + "type": "entity",
  289 + "dataKeys": [
  290 + {
  291 + "name": "timeoutMsgs",
  292 + "type": "timeseries",
  293 + "label": "${entityName} Permanent Timeouts",
  294 + "color": "#4caf50",
  295 + "settings": {
  296 + "excludeFromStacking": false,
  297 + "hideDataByDefault": false,
  298 + "disableDataHiding": false,
  299 + "removeFromLegend": false,
  300 + "showLines": true,
  301 + "fillLines": false,
  302 + "showPoints": false,
  303 + "showPointShape": "circle",
  304 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  305 + "showPointsLineWidth": 5,
  306 + "showPointsRadius": 3,
  307 + "showSeparateAxis": false,
  308 + "axisPosition": "left",
  309 + "thresholds": [
  310 + {
  311 + "thresholdValueSource": "predefinedValue"
  312 + }
  313 + ],
  314 + "comparisonSettings": {
  315 + "showValuesForComparison": true
  316 + }
  317 + },
  318 + "_hash": 0.565222981550328
  319 + },
  320 + {
  321 + "name": "tmpTimeout",
  322 + "type": "timeseries",
  323 + "label": "${entityName} Processing Timeouts",
  324 + "color": "#9c27b0",
  325 + "settings": {
  326 + "excludeFromStacking": false,
  327 + "hideDataByDefault": false,
  328 + "disableDataHiding": false,
  329 + "removeFromLegend": false,
  330 + "showLines": true,
  331 + "fillLines": false,
  332 + "showPoints": false,
  333 + "showPointShape": "circle",
  334 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  335 + "showPointsLineWidth": 5,
  336 + "showPointsRadius": 3,
  337 + "showSeparateAxis": false,
  338 + "axisPosition": "left",
  339 + "thresholds": [
  340 + {
  341 + "thresholdValueSource": "predefinedValue"
  342 + }
  343 + ],
  344 + "comparisonSettings": {
  345 + "showValuesForComparison": true
  346 + }
  347 + },
  348 + "_hash": 0.2679547062508352
  349 + }
  350 + ],
  351 + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018"
  352 + }
  353 + ],
  354 + "timewindow": {
  355 + "realtime": {
  356 + "interval": 1000,
  357 + "timewindowMs": 300000
  358 + },
  359 + "aggregation": {
  360 + "type": "NONE",
  361 + "limit": 8640
  362 + },
  363 + "hideInterval": false,
  364 + "hideAggregation": false,
  365 + "hideAggInterval": false
  366 + },
  367 + "showTitle": true,
  368 + "backgroundColor": "#fff",
  369 + "color": "rgba(0, 0, 0, 0.87)",
  370 + "padding": "8px",
  371 + "settings": {
  372 + "shadowSize": 4,
  373 + "fontColor": "#545454",
  374 + "fontSize": 10,
  375 + "xaxis": {
  376 + "showLabels": true,
  377 + "color": "#545454"
  378 + },
  379 + "yaxis": {
  380 + "showLabels": true,
  381 + "color": "#545454"
  382 + },
  383 + "grid": {
  384 + "color": "#545454",
  385 + "tickColor": "#DDDDDD",
  386 + "verticalLines": true,
  387 + "horizontalLines": true,
  388 + "outlineWidth": 1
  389 + },
  390 + "stack": false,
  391 + "tooltipIndividual": false,
  392 + "timeForComparison": "months",
  393 + "xaxisSecond": {
  394 + "axisPosition": "top",
  395 + "showLabels": true
  396 + }
  397 + },
  398 + "title": "Processing Failures and Timeouts",
  399 + "dropShadow": true,
  400 + "enableFullscreen": true,
  401 + "titleStyle": {
  402 + "fontSize": "16px",
  403 + "fontWeight": 400
  404 + },
  405 + "mobileHeight": null,
  406 + "showTitleIcon": false,
  407 + "titleIcon": null,
  408 + "iconColor": "rgba(0, 0, 0, 0.87)",
  409 + "iconSize": "24px",
  410 + "titleTooltip": "",
  411 + "widgetStyle": {},
  412 + "useDashboardTimewindow": false,
  413 + "displayTimewindow": true,
  414 + "showLegend": true,
  415 + "actions": {},
  416 + "legendConfig": {
  417 + "direction": "column",
  418 + "position": "bottom",
  419 + "showMin": true,
  420 + "showMax": true,
  421 + "showAvg": false,
  422 + "showTotal": true
  423 + }
  424 + },
  425 + "id": "ad3f1417-87a8-750e-fc67-49a2de1466d4"
  426 + }
  427 + },
  428 + "states": {
  429 + "default": {
  430 + "name": "Rule Engine Statistics",
  431 + "root": true,
  432 + "layouts": {
  433 + "main": {
  434 + "widgets": {
  435 + "81987f19-3eac-e4ce-b790-d96e9b54d9a0": {
  436 + "sizeX": 12,
  437 + "sizeY": 7,
  438 + "mobileHeight": null,
  439 + "row": 0,
  440 + "col": 0
  441 + },
  442 + "5eb79712-5c24-3060-7e4f-6af36b8f842d": {
  443 + "sizeX": 24,
  444 + "sizeY": 5,
  445 + "row": 7,
  446 + "col": 0
  447 + },
  448 + "ad3f1417-87a8-750e-fc67-49a2de1466d4": {
  449 + "sizeX": 12,
  450 + "sizeY": 7,
  451 + "mobileHeight": null,
  452 + "row": 0,
  453 + "col": 12
  454 + }
  455 + },
  456 + "gridSettings": {
  457 + "backgroundColor": "#eeeeee",
  458 + "color": "rgba(0,0,0,0.870588)",
  459 + "columns": 24,
  460 + "margins": [
  461 + 10,
  462 + 10
  463 + ],
  464 + "backgroundSizeMode": "100%",
  465 + "autoFillHeight": true,
  466 + "mobileAutoFillHeight": false,
  467 + "mobileRowHeight": 70
  468 + }
  469 + }
  470 + }
  471 + }
  472 + },
  473 + "entityAliases": {
  474 + "140f23dd-e3a0-ed98-6189-03c49d2d8018": {
  475 + "id": "140f23dd-e3a0-ed98-6189-03c49d2d8018",
  476 + "alias": "TbServiceQueues",
  477 + "filter": {
  478 + "type": "assetType",
  479 + "resolveMultiple": true,
  480 + "assetType": "TbServiceQueue",
  481 + "assetNameFilter": ""
  482 + }
  483 + }
  484 + },
  485 + "timewindow": {
  486 + "displayValue": "",
  487 + "selectedTab": 0,
  488 + "hideInterval": false,
  489 + "hideAggregation": false,
  490 + "hideAggInterval": false,
  491 + "realtime": {
  492 + "interval": 1000,
  493 + "timewindowMs": 60000
  494 + },
  495 + "history": {
  496 + "historyType": 0,
  497 + "interval": 1000,
  498 + "timewindowMs": 60000,
  499 + "fixedTimewindow": {
  500 + "startTimeMs": 1586176634823,
  501 + "endTimeMs": 1586263034823
  502 + }
  503 + },
  504 + "aggregation": {
  505 + "type": "AVG",
  506 + "limit": 25000
  507 + }
  508 + },
  509 + "settings": {
  510 + "stateControllerId": "entity",
  511 + "showTitle": false,
  512 + "showDashboardsSelect": true,
  513 + "showEntitiesSelect": true,
  514 + "showDashboardTimewindow": true,
  515 + "showDashboardExport": true,
  516 + "toolbarAlwaysOpen": true
  517 + }
  518 + },
  519 + "name": "Rule Engine Statistics"
  520 +}
\ No newline at end of file
... ...
  1 +{
  2 + "title": "Thermostats",
  3 + "configuration": {
  4 + "widgets": {
  5 + "f33c746c-0dfc-c212-395b-b448c8a17209": {
  6 + "isSystemType": true,
  7 + "bundleAlias": "cards",
  8 + "typeAlias": "entities_table",
  9 + "type": "latest",
  10 + "title": "New widget",
  11 + "sizeX": 11,
  12 + "sizeY": 11,
  13 + "config": {
  14 + "timewindow": {
  15 + "realtime": {
  16 + "interval": 1000,
  17 + "timewindowMs": 86400000
  18 + },
  19 + "aggregation": {
  20 + "type": "NONE",
  21 + "limit": 200
  22 + }
  23 + },
  24 + "showTitle": true,
  25 + "backgroundColor": "rgb(255, 255, 255)",
  26 + "color": "rgba(0, 0, 0, 0.87)",
  27 + "padding": "4px",
  28 + "settings": {
  29 + "enableSearch": true,
  30 + "displayPagination": true,
  31 + "defaultPageSize": 10,
  32 + "defaultSortOrder": "entityName",
  33 + "displayEntityName": true,
  34 + "displayEntityType": false,
  35 + "enableSelectColumnDisplay": false,
  36 + "entitiesTitle": "Thermostats",
  37 + "displayEntityLabel": false,
  38 + "entityNameColumnTitle": "Thermostat name"
  39 + },
  40 + "title": "Thermostats",
  41 + "dropShadow": true,
  42 + "enableFullscreen": false,
  43 + "titleStyle": {
  44 + "fontSize": "16px",
  45 + "fontWeight": 400,
  46 + "padding": "5px 10px 5px 10px"
  47 + },
  48 + "useDashboardTimewindow": false,
  49 + "showLegend": false,
  50 + "datasources": [
  51 + {
  52 + "type": "entity",
  53 + "dataKeys": [
  54 + {
  55 + "name": "active",
  56 + "type": "attribute",
  57 + "label": "Active",
  58 + "color": "#2196f3",
  59 + "settings": {
  60 + "columnWidth": "0px",
  61 + "useCellStyleFunction": true,
  62 + "useCellContentFunction": true,
  63 + "cellContentFunction": "value = '&#11044;';\nreturn value;",
  64 + "cellStyleFunction": "var color;\nif (value === \"true\") {\n color = 'rgb(39, 134, 34)';\n} else {\n color = 'rgb(255, 0, 0)';\n}\nreturn {\n color: color,\n fontSize: '18px'\n};"
  65 + },
  66 + "_hash": 0.9264526512320641
  67 + },
  68 + {
  69 + "name": "temperature",
  70 + "type": "timeseries",
  71 + "label": "Temperature",
  72 + "color": "#4caf50",
  73 + "settings": {
  74 + "columnWidth": "0px",
  75 + "useCellStyleFunction": false,
  76 + "useCellContentFunction": false
  77 + },
  78 + "_hash": 0.9801965063904188,
  79 + "units": "°C",
  80 + "decimals": 1
  81 + },
  82 + {
  83 + "name": "humidity",
  84 + "type": "timeseries",
  85 + "label": "Humidity",
  86 + "color": "#f44336",
  87 + "settings": {
  88 + "columnWidth": "0px",
  89 + "useCellStyleFunction": false,
  90 + "useCellContentFunction": false
  91 + },
  92 + "_hash": 0.5726727868178358,
  93 + "units": "%",
  94 + "decimals": 0
  95 + }
  96 + ],
  97 + "entityAliasId": "68a058e1-fdda-8482-715b-3ae4a488568e"
  98 + }
  99 + ],
  100 + "showTitleIcon": false,
  101 + "titleIcon": null,
  102 + "iconColor": "rgba(0, 0, 0, 0.87)",
  103 + "iconSize": "24px",
  104 + "titleTooltip": "",
  105 + "widgetStyle": {},
  106 + "displayTimewindow": true,
  107 + "actions": {
  108 + "headerButton": [
  109 + {
  110 + "id": "85b803db-90f2-5c63-1388-a378e0eb10d6",
  111 + "name": "Edit location",
  112 + "icon": "map",
  113 + "type": "openDashboardState",
  114 + "targetDashboardStateId": "map",
  115 + "setEntityId": false
  116 + },
  117 + {
  118 + "id": "8ab5a518-67d2-b6a2-956d-81fd512294b2",
  119 + "name": "Add",
  120 + "icon": "add",
  121 + "type": "customPretty",
  122 + "customHtml": "<md-dialog aria-label=\"Add entity\">\n <form name=\"addEntityForm\" class=\"add-entity-form\" ng-submit=\"vm.save()\">\n <md-toolbar>\n <div class=\"md-toolbar-tools\">\n <h2>Add thermostat</h2>\n <span flex></span>\n <md-button class=\"md-icon-button\" ng-click=\"vm.cancel()\">\n <ng-md-icon icon=\"close\" aria-label=\"Close\"></ng-md-icon>\n </md-button>\n </div>\n </md-toolbar>\n <md-dialog-content>\n <div class=\"md-dialog-content\">\n <md-input-container flex class=\"md-block\">\n <label>Thermostat name</label>\n <input ng-model=\"vm.entityName\" name=entityName required>\n <div ng-messages=\"addEntityForm.entityName.$error\">\n <div ng-message=\"required\">Thermostat name is required.</div>\n </div>\n </md-input-container>\n <md-switch ng-model=\"vm.attributes.alarmTemperature\">\n High temperature alarm\n </md-switch>\n <md-input-container flex class=\"md-block\">\n <label>High temperature threshold, °C</label>\n <input name=\"thresholdTemperature\" type=\"number\" step=\"any\" \n ng-model=\"vm.attributes.thresholdTemperature\"\n ng-disabled=\"!vm.attributes.alarmTemperature\"\n ng-required=\"vm.attributes.alarmTemperature\">\n <div ng-messages=\"addEntityForm.thresholdTemperature.$error\">\n <div ng-message=\"required\">High temperature threshold is required.</div>\n </div>\n </md-input-container>\n <md-switch ng-model=\"vm.attributes.alarmHumidity\">\n Low humidity alarm\n </md-switch>\n <md-input-container flex class=\"md-block\">\n <label>Low humidity threshold, %</label>\n <input name=\"thresholdHumidity\" type=\"number\" step=\"any\" \n ng-model=\"vm.attributes.thresholdHumidity\"\n ng-disabled=\"!vm.attributes.alarmHumidity\"\n ng-required=\"vm.attributes.alarmHumidity\">\n <div ng-messages=\"addEntityForm.thresholdHumidity.$error\">\n <div ng-message=\"required\">Low humidity threshold is required.</div>\n </div>\n </md-input-container>\n </div>\n </md-dialog-content>\n <md-dialog-actions>\n <md-button type=\"submit\" ng-disabled=\"addEntityForm.$invalid || !addEntityForm.$dirty\" class=\"md-raised md-primary\">Create</md-button>\n <md-button ng-click=\"vm.cancel()\" class=\"md-primary\">Cancel</md-button>\n </md-dialog-actions>\n </form>\n</md-dialog>",
  123 + "customCss": ".add-entity-form md-input-container {\n padding-right: 10px;\n}\n\n.add-entity-form .boolean-value-input {\n padding-left: 5px;\n}\n\n.add-entity-form .boolean-value-input .checkbox-label {\n margin-bottom: 8px;\n color: rgba(0,0,0,0.54);\n font-size: 12px;\n}\n\n",
  124 + "customFunction": "var $injector = widgetContext.$scope.$injector;\nvar $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n $q = $injector.get('$q'),\n $rootScope = $injector.get('$rootScope'),\n deviceService = $injector.get('deviceService'),\n attributeService = $injector.get('attributeService');\n\nopenAddEntityDialog();\n\nfunction openAddEntityDialog() {\n $mdDialog.show({\n controller: ['$scope','$mdDialog', AddEntityDialogController],\n controllerAs: 'vm',\n template: htmlTemplate,\n locals: {\n entityId: entityId\n },\n parent: angular.element($document[0].body),\n targetEvent: $event,\n multiple: true,\n clickOutsideToClose: false\n });\n}\n\nfunction AddEntityDialogController($scope, $mdDialog) {\n var vm = this;\n vm.attributes = {};\n\n vm.save = function() {\n $scope.addEntityForm.$setPristine();\n saveEntityPromise().then(\n function (entity) {\n saveAttributes(entity.id).then(() => {\n updateAliasData();\n $mdDialog.hide();\n });\n }\n );\n };\n vm.cancel = function() {\n $mdDialog.hide();\n };\n \n \n function saveEntityPromise() {\n var entity = {\n name: vm.entityName,\n type: \"thermostat\"\n };\n return deviceService.saveDevice(entity);\n }\n \n function saveAttributes(entityId) {\n var attributesArray = [];\n for (var key in vm.attributes) {\n attributesArray.push({key: key, value: vm.attributes[key]});\n }\n if (attributesArray.length > 0) {\n return attributeService.saveEntityAttributes(entityId.entityType, entityId.id, \"SERVER_SCOPE\", attributesArray);\n } else {\n return $q.when(null);\n } \n }\n \n function updateAliasData() {\n var aliasIds = [];\n for (var id in widgetContext.aliasController.resolvedAliases) {\n aliasIds.push(id);\n }\n var tasks = [];\n aliasIds.forEach(function(aliasId) {\n widgetContext.aliasController.setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController.getAliasInfo(aliasId));\n });\n $q.all(tasks).then(function() {\n $rootScope.$broadcast('widgetForceReInit');\n });\n }\n}"
  125 + }
  126 + ],
  127 + "actionCellButton": [
  128 + {
  129 + "id": "ca241cd8-788d-5508-a9ce-74b03ef42a7f",
  130 + "name": "Chart",
  131 + "icon": "show_chart",
  132 + "type": "openDashboardState",
  133 + "targetDashboardStateId": "chart",
  134 + "setEntityId": true
  135 + },
  136 + {
  137 + "id": "7506576f-87ba-d3a0-88fb-e304d451776d",
  138 + "name": "Edit",
  139 + "icon": "edit",
  140 + "type": "customPretty",
  141 + "customHtml": "<md-dialog aria-label=\"Edit entity\">\n <form name=\"editEntityForm\" class=\"edit-entity-form\" ng-submit=\"vm.save()\">\n <md-toolbar>\n <div class=\"md-toolbar-tools\">\n <h2>Edit thermostat {{vm.entityName}}</h2>\n <span flex></span>\n <md-button class=\"md-icon-button\" ng-click=\"vm.cancel()\">\n <ng-md-icon icon=\"close\" aria-label=\"Close\"></ng-md-icon>\n </md-button>\n </div>\n </md-toolbar>\n <md-dialog-content>\n <div class=\"md-dialog-content\">\n <md-input-container flex class=\"md-block\">\n <label>Thermostat name</label>\n <input ng-model=\"vm.entityName\" readonly>\n </md-input-container>\n <md-switch ng-model=\"vm.attributes.alarmTemperature\">\n High temperature alarm\n </md-switch>\n <md-input-container flex class=\"md-block\">\n <label>High temperature threshold, °C</label>\n <input name=\"thresholdTemperature\" type=\"number\" step=\"any\" \n ng-model=\"vm.attributes.thresholdTemperature\"\n ng-disabled=\"!vm.attributes.alarmTemperature\"\n ng-required=\"vm.attributes.alarmTemperature\">\n <div ng-messages=\"editEntityForm.thresholdTemperature.$error\">\n <div ng-message=\"required\">High temperature threshold is required.</div>\n </div>\n </md-input-container>\n <md-switch ng-model=\"vm.attributes.alarmHumidity\">\n Low humidity alarm\n </md-switch>\n <md-input-container flex class=\"md-block\">\n <label>Low humidity threshold, %</label>\n <input name=\"thresholdHumidity\" type=\"number\" step=\"any\" \n ng-model=\"vm.attributes.thresholdHumidity\"\n ng-disabled=\"!vm.attributes.alarmHumidity\"\n ng-required=\"vm.attributes.alarmHumidity\">\n <div ng-messages=\"editEntityForm.thresholdHumidity.$error\">\n <div ng-message=\"required\">Low humidity threshold is required.</div>\n </div>\n </md-input-container>\n </div>\n </md-dialog-content>\n <md-dialog-actions>\n <md-button type=\"submit\" ng-disabled=\"editEntityForm.$invalid || !editEntityForm.$dirty\" class=\"md-raised md-primary\">Save</md-button>\n <md-button ng-click=\"vm.cancel()\" class=\"md-primary\">Cancel</md-button>\n </md-dialog-actions>\n </form>\n</md-dialog>",
  142 + "customCss": ".edit-entity-form md-input-container {\n padding-right: 10px;\n}\n\n.edit-entity-form .boolean-value-input {\n padding-left: 5px;\n}\n\n.edit-entity-form .boolean-value-input .checkbox-label {\n margin-bottom: 8px;\n color: rgba(0,0,0,0.54);\n font-size: 12px;\n}\n",
  143 + "customFunction": "var $injector = widgetContext.$scope.$injector;\nvar $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n attributeService = $injector.get('attributeService');\n\nopenEditEntityDialog();\n\nfunction openEditEntityDialog() {\n $mdDialog.show({\n controller: ['$scope','$mdDialog', EditEntityDialogController],\n controllerAs: 'vm',\n template: htmlTemplate,\n locals: {\n entityId: entityId\n },\n parent: angular.element($document[0].body),\n targetEvent: $event,\n multiple: true,\n clickOutsideToClose: false\n });\n}\n\nfunction EditEntityDialogController($scope,$mdDialog) {\n var vm = this;\n vm.entityId = entityId;\n vm.entityName = entityName;\n vm.entityType = entityId.entityType;\n vm.attributes = {};\n vm.serverAttributes = {};\n getEntityInfo();\n \n vm.save = function() {\n saveAttributes();\n $mdDialog.hide();\n };\n vm.cancel = function() {\n $mdDialog.hide();\n };\n \n function getEntityAttributes(attributes) {\n for (var i = 0; i < attributes.length; i++) {\n vm.attributes[attributes[i].key] = attributes[i].value; \n }\n vm.serverAttributes = angular.copy(vm.attributes);\n }\n \n function getEntityInfo() {\n attributeService.getEntityAttributesValues(entityId.entityType, entityId.id, 'SERVER_SCOPE').then(\n function(data){\n if (data.length) {\n getEntityAttributes(data);\n }\n });\n }\n \n function saveAttributes() {\n var attributesArray = [];\n for (var key in vm.attributes) {\n if (vm.attributes[key] !== vm.serverAttributes[key]) {\n attributesArray.push({key: key, value: vm.attributes[key]});\n }\n }\n if (attributesArray.length > 0) {\n attributeService.saveEntityAttributes(entityId.entityType, entityId.id, \"SERVER_SCOPE\", attributesArray);\n } \n }\n}"
  144 + },
  145 + {
  146 + "id": "3488848b-e47d-6af6-659f-5d78369ece5e",
  147 + "name": "Delete",
  148 + "icon": "delete",
  149 + "type": "custom",
  150 + "customFunction": "var $injector = widgetContext.$scope.$injector;\nvar $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n deviceService = $injector.get('deviceService')\n $rootScope = $injector.get('$rootScope'),\n $q = $injector.get('$q');\n\nopenDeleteEntityDialog();\n\nfunction openDeleteEntityDialog() {\n var title = 'Delete thermostat \"' + entityName + '\"';\n var content = 'Are you sure you want to delete the thermostat \"' +\n entityName + '\"?';\n var confirm = $mdDialog.confirm()\n .targetEvent($event)\n .title(title)\n .htmlContent(content)\n .ariaLabel(title)\n .cancel('Cancel')\n .ok('Delete');\n $mdDialog.show(confirm).then(function() {\n deleteEntity();\n })\n}\n\nfunction deleteEntity() {\n deviceService.deleteDevice(entityId.id).then(\n function success() {\n updateAliasData();\n },\n function fail() {\n showErrorDialog();\n }\n );\n}\n\nfunction updateAliasData() {\n var aliasIds = [];\n for (var id in widgetContext.aliasController.resolvedAliases) {\n aliasIds.push(id);\n }\n var tasks = [];\n aliasIds.forEach(function(aliasId) {\n widgetContext.aliasController.setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController.getAliasInfo(aliasId));\n });\n $q.all(tasks).then(function() {\n $rootScope.$broadcast('entityAliasesChanged', aliasIds);\n });\n}\n\nfunction showErrorDialog() {\n var title = 'Error';\n var content = 'An error occurred while deleting the thermostat. Please try again.';\n var alert = $mdDialog.alert()\n .title(title)\n .htmlContent(content)\n .ariaLabel(title)\n .parent(angular.element($document[0].body))\n .targetEvent($event)\n .multiple(true)\n .clickOutsideToClose(true)\n .ok('CLOSE');\n $mdDialog.show(alert);\n}"
  151 + }
  152 + ],
  153 + "rowClick": []
  154 + }
  155 + },
  156 + "id": "f33c746c-0dfc-c212-395b-b448c8a17209"
  157 + },
  158 + "7943196b-eedb-d422-f9c3-b32d379ad172": {
  159 + "isSystemType": true,
  160 + "bundleAlias": "alarm_widgets",
  161 + "typeAlias": "alarms_table",
  162 + "type": "alarm",
  163 + "title": "New widget",
  164 + "sizeX": 13,
  165 + "sizeY": 5,
  166 + "config": {
  167 + "timewindow": {
  168 + "realtime": {
  169 + "interval": 1000,
  170 + "timewindowMs": 86400000
  171 + },
  172 + "aggregation": {
  173 + "type": "NONE",
  174 + "limit": 200
  175 + }
  176 + },
  177 + "showTitle": true,
  178 + "backgroundColor": "rgb(255, 255, 255)",
  179 + "color": "rgba(0, 0, 0, 0.87)",
  180 + "padding": "4px",
  181 + "settings": {
  182 + "enableSelection": true,
  183 + "enableSearch": true,
  184 + "displayDetails": true,
  185 + "allowAcknowledgment": true,
  186 + "allowClear": true,
  187 + "displayPagination": true,
  188 + "defaultPageSize": 10,
  189 + "defaultSortOrder": "-createdTime",
  190 + "enableSelectColumnDisplay": false,
  191 + "enableStatusFilter": true,
  192 + "alarmsTitle": "Alarms"
  193 + },
  194 + "title": "New Alarms table",
  195 + "dropShadow": true,
  196 + "enableFullscreen": false,
  197 + "titleStyle": {
  198 + "fontSize": "16px",
  199 + "fontWeight": 400,
  200 + "padding": "5px 10px 5px 10px"
  201 + },
  202 + "useDashboardTimewindow": false,
  203 + "showLegend": false,
  204 + "alarmSource": {
  205 + "type": "entity",
  206 + "dataKeys": [
  207 + {
  208 + "name": "createdTime",
  209 + "type": "alarm",
  210 + "label": "Created time",
  211 + "color": "#2196f3",
  212 + "settings": {},
  213 + "_hash": 0.7308410188824108
  214 + },
  215 + {
  216 + "name": "originator",
  217 + "type": "alarm",
  218 + "label": "Originator",
  219 + "color": "#4caf50",
  220 + "settings": {},
  221 + "_hash": 0.056085530105439485
  222 + },
  223 + {
  224 + "name": "type",
  225 + "type": "alarm",
  226 + "label": "Type",
  227 + "color": "#f44336",
  228 + "settings": {},
  229 + "_hash": 0.10212012352561795
  230 + },
  231 + {
  232 + "name": "severity",
  233 + "type": "alarm",
  234 + "label": "Severity",
  235 + "color": "#ffc107",
  236 + "settings": {},
  237 + "_hash": 0.1777349980531262
  238 + },
  239 + {
  240 + "name": "status",
  241 + "type": "alarm",
  242 + "label": "Status",
  243 + "color": "#607d8b",
  244 + "settings": {},
  245 + "_hash": 0.7977920750136249
  246 + }
  247 + ],
  248 + "entityAliasId": "ce27a9d0-93bf-b7a4-054d-d0369a8cf813",
  249 + "name": "alarms"
  250 + },
  251 + "alarmSearchStatus": "ANY",
  252 + "alarmsPollingInterval": 5,
  253 + "showTitleIcon": false,
  254 + "titleIcon": null,
  255 + "iconColor": "rgba(0, 0, 0, 0.87)",
  256 + "iconSize": "24px",
  257 + "titleTooltip": "",
  258 + "widgetStyle": {},
  259 + "displayTimewindow": true,
  260 + "actions": {},
  261 + "datasources": [],
  262 + "alarmsMaxCountLoad": 0,
  263 + "alarmsFetchSize": 100
  264 + },
  265 + "id": "7943196b-eedb-d422-f9c3-b32d379ad172"
  266 + },
  267 + "14a19183-f0b2-d6be-0f62-9863f0a51111": {
  268 + "isSystemType": true,
  269 + "bundleAlias": "charts",
  270 + "typeAlias": "basic_timeseries",
  271 + "type": "timeseries",
  272 + "title": "New widget",
  273 + "sizeX": 18,
  274 + "sizeY": 6,
  275 + "config": {
  276 + "datasources": [
  277 + {
  278 + "type": "entity",
  279 + "dataKeys": [
  280 + {
  281 + "name": "temperature",
  282 + "type": "timeseries",
  283 + "label": "Temperature",
  284 + "color": "#ef5350",
  285 + "settings": {
  286 + "excludeFromStacking": false,
  287 + "hideDataByDefault": false,
  288 + "disableDataHiding": false,
  289 + "removeFromLegend": false,
  290 + "showLines": true,
  291 + "fillLines": true,
  292 + "showPoints": false,
  293 + "showPointShape": "circle",
  294 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  295 + "showPointsLineWidth": 5,
  296 + "showPointsRadius": 3,
  297 + "showSeparateAxis": false,
  298 + "axisPosition": "left",
  299 + "thresholds": [
  300 + {
  301 + "thresholdValueSource": "predefinedValue"
  302 + }
  303 + ],
  304 + "comparisonSettings": {
  305 + "showValuesForComparison": true
  306 + }
  307 + },
  308 + "_hash": 0.7852346160709658,
  309 + "units": "°C",
  310 + "decimals": 1
  311 + }
  312 + ],
  313 + "entityAliasId": "12ae98c7-1ea2-52cf-64d5-763e9d993547"
  314 + }
  315 + ],
  316 + "timewindow": {
  317 + "realtime": {
  318 + "interval": 30000,
  319 + "timewindowMs": 3600000
  320 + },
  321 + "aggregation": {
  322 + "type": "AVG",
  323 + "limit": 25000
  324 + }
  325 + },
  326 + "showTitle": true,
  327 + "backgroundColor": "#fff",
  328 + "color": "rgba(0, 0, 0, 0.87)",
  329 + "padding": "8px",
  330 + "settings": {
  331 + "shadowSize": 4,
  332 + "fontColor": "#545454",
  333 + "fontSize": 10,
  334 + "xaxis": {
  335 + "showLabels": true,
  336 + "color": "#545454"
  337 + },
  338 + "yaxis": {
  339 + "showLabels": true,
  340 + "color": "#545454"
  341 + },
  342 + "grid": {
  343 + "color": "#545454",
  344 + "tickColor": "#DDDDDD",
  345 + "verticalLines": true,
  346 + "horizontalLines": true,
  347 + "outlineWidth": 1
  348 + },
  349 + "stack": false,
  350 + "tooltipIndividual": false,
  351 + "timeForComparison": "months",
  352 + "xaxisSecond": {
  353 + "axisPosition": "top",
  354 + "showLabels": true
  355 + },
  356 + "smoothLines": true
  357 + },
  358 + "title": "Temperature",
  359 + "dropShadow": true,
  360 + "enableFullscreen": true,
  361 + "titleStyle": {
  362 + "fontSize": "16px",
  363 + "fontWeight": 400
  364 + },
  365 + "mobileHeight": null,
  366 + "showTitleIcon": false,
  367 + "titleIcon": null,
  368 + "iconColor": "rgba(0, 0, 0, 0.87)",
  369 + "iconSize": "24px",
  370 + "titleTooltip": "",
  371 + "widgetStyle": {},
  372 + "useDashboardTimewindow": false,
  373 + "displayTimewindow": true,
  374 + "showLegend": true,
  375 + "legendConfig": {
  376 + "direction": "column",
  377 + "position": "bottom",
  378 + "showMin": true,
  379 + "showMax": true,
  380 + "showAvg": true,
  381 + "showTotal": false
  382 + },
  383 + "actions": {}
  384 + },
  385 + "id": "14a19183-f0b2-d6be-0f62-9863f0a51111"
  386 + },
  387 + "07f49fd5-a73b-d74c-c220-362c20af81f4": {
  388 + "isSystemType": true,
  389 + "bundleAlias": "charts",
  390 + "typeAlias": "basic_timeseries",
  391 + "type": "timeseries",
  392 + "title": "New widget",
  393 + "sizeX": 18,
  394 + "sizeY": 6,
  395 + "config": {
  396 + "datasources": [
  397 + {
  398 + "type": "entity",
  399 + "dataKeys": [
  400 + {
  401 + "name": "humidity",
  402 + "type": "timeseries",
  403 + "label": "Humidity",
  404 + "color": "#2196f3",
  405 + "settings": {
  406 + "excludeFromStacking": false,
  407 + "hideDataByDefault": false,
  408 + "disableDataHiding": false,
  409 + "removeFromLegend": false,
  410 + "showLines": true,
  411 + "fillLines": true,
  412 + "showPoints": false,
  413 + "showPointShape": "circle",
  414 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  415 + "showPointsLineWidth": 5,
  416 + "showPointsRadius": 3,
  417 + "showSeparateAxis": false,
  418 + "axisPosition": "left",
  419 + "thresholds": [
  420 + {
  421 + "thresholdValueSource": "predefinedValue"
  422 + }
  423 + ],
  424 + "comparisonSettings": {
  425 + "showValuesForComparison": true
  426 + }
  427 + },
  428 + "_hash": 0.28640715926957183,
  429 + "units": "%",
  430 + "decimals": 0
  431 + }
  432 + ],
  433 + "entityAliasId": "12ae98c7-1ea2-52cf-64d5-763e9d993547"
  434 + }
  435 + ],
  436 + "timewindow": {
  437 + "realtime": {
  438 + "interval": 30000,
  439 + "timewindowMs": 3600000
  440 + },
  441 + "aggregation": {
  442 + "type": "AVG",
  443 + "limit": 25000
  444 + }
  445 + },
  446 + "showTitle": true,
  447 + "backgroundColor": "#fff",
  448 + "color": "rgba(0, 0, 0, 0.87)",
  449 + "padding": "8px",
  450 + "settings": {
  451 + "shadowSize": 4,
  452 + "fontColor": "#545454",
  453 + "fontSize": 10,
  454 + "xaxis": {
  455 + "showLabels": true,
  456 + "color": "#545454"
  457 + },
  458 + "yaxis": {
  459 + "showLabels": true,
  460 + "color": "#545454"
  461 + },
  462 + "grid": {
  463 + "color": "#545454",
  464 + "tickColor": "#DDDDDD",
  465 + "verticalLines": true,
  466 + "horizontalLines": true,
  467 + "outlineWidth": 1
  468 + },
  469 + "stack": false,
  470 + "tooltipIndividual": false,
  471 + "timeForComparison": "months",
  472 + "xaxisSecond": {
  473 + "axisPosition": "top",
  474 + "showLabels": true
  475 + },
  476 + "smoothLines": true
  477 + },
  478 + "title": "Humidity",
  479 + "dropShadow": true,
  480 + "enableFullscreen": true,
  481 + "titleStyle": {
  482 + "fontSize": "16px",
  483 + "fontWeight": 400
  484 + },
  485 + "mobileHeight": null,
  486 + "showTitleIcon": false,
  487 + "titleIcon": null,
  488 + "iconColor": "rgba(0, 0, 0, 0.87)",
  489 + "iconSize": "24px",
  490 + "titleTooltip": "",
  491 + "widgetStyle": {},
  492 + "useDashboardTimewindow": false,
  493 + "displayTimewindow": true,
  494 + "showLegend": true,
  495 + "legendConfig": {
  496 + "direction": "column",
  497 + "position": "bottom",
  498 + "showMin": true,
  499 + "showMax": true,
  500 + "showAvg": true,
  501 + "showTotal": false
  502 + },
  503 + "actions": {}
  504 + },
  505 + "id": "07f49fd5-a73b-d74c-c220-362c20af81f4"
  506 + },
  507 + "c4631f94-2db3-523b-4d09-2a1a0a75d93f": {
  508 + "isSystemType": true,
  509 + "bundleAlias": "input_widgets",
  510 + "typeAlias": "update_multiple_attributes",
  511 + "type": "latest",
  512 + "title": "New widget",
  513 + "sizeX": 6,
  514 + "sizeY": 6,
  515 + "config": {
  516 + "datasources": [
  517 + {
  518 + "type": "entity",
  519 + "dataKeys": [
  520 + {
  521 + "name": "alarmTemperature",
  522 + "type": "attribute",
  523 + "label": "High temperature alarm",
  524 + "color": "#4caf50",
  525 + "settings": {
  526 + "dataKeyType": "server",
  527 + "dataKeyValueType": "booleanCheckbox",
  528 + "required": false,
  529 + "isEditable": "editable",
  530 + "dataKeyHidden": false,
  531 + "step": 1
  532 + },
  533 + "_hash": 0.8725278440159361
  534 + },
  535 + {
  536 + "name": "thresholdTemperature",
  537 + "type": "attribute",
  538 + "label": "High temperature threshold, °C",
  539 + "color": "#f44336",
  540 + "settings": {
  541 + "dataKeyType": "server",
  542 + "dataKeyValueType": "double",
  543 + "required": false,
  544 + "isEditable": "editable",
  545 + "dataKeyHidden": false,
  546 + "step": 1,
  547 + "disabledOnDataKey": "alarmTemperature"
  548 + },
  549 + "_hash": 0.7316078472857874
  550 + },
  551 + {
  552 + "name": "alarmHumidity",
  553 + "type": "attribute",
  554 + "label": "Low humidity alarm",
  555 + "color": "#ffc107",
  556 + "settings": {
  557 + "dataKeyType": "server",
  558 + "dataKeyValueType": "booleanCheckbox",
  559 + "required": false,
  560 + "isEditable": "editable",
  561 + "dataKeyHidden": false,
  562 + "step": 1
  563 + },
  564 + "_hash": 0.5339673667431057
  565 + },
  566 + {
  567 + "name": "thresholdHumidity",
  568 + "type": "attribute",
  569 + "label": "Low humidity threshold, %",
  570 + "color": "#607d8b",
  571 + "settings": {
  572 + "dataKeyType": "server",
  573 + "dataKeyValueType": "double",
  574 + "required": false,
  575 + "isEditable": "editable",
  576 + "dataKeyHidden": false,
  577 + "step": 1,
  578 + "disabledOnDataKey": "alarmHumidity"
  579 + },
  580 + "_hash": 0.2687091190358901
  581 + }
  582 + ],
  583 + "entityAliasId": "12ae98c7-1ea2-52cf-64d5-763e9d993547"
  584 + }
  585 + ],
  586 + "timewindow": {
  587 + "realtime": {
  588 + "timewindowMs": 60000
  589 + }
  590 + },
  591 + "showTitle": true,
  592 + "backgroundColor": "#fff",
  593 + "color": "rgba(0, 0, 0, 0.87)",
  594 + "padding": "8px",
  595 + "settings": {
  596 + "showActionButtons": false,
  597 + "showResultMessage": true,
  598 + "fieldsAlignment": "column",
  599 + "fieldsInRow": 2,
  600 + "groupTitle": "${entityName}",
  601 + "widgetTitle": "Termostat settings"
  602 + },
  603 + "title": "New Update Multiple Attributes",
  604 + "dropShadow": true,
  605 + "enableFullscreen": false,
  606 + "enableDataExport": false,
  607 + "widgetStyle": {},
  608 + "titleStyle": {
  609 + "fontSize": "16px",
  610 + "fontWeight": 400
  611 + },
  612 + "useDashboardTimewindow": true,
  613 + "showLegend": false,
  614 + "actions": {},
  615 + "showTitleIcon": false,
  616 + "titleIcon": null,
  617 + "iconColor": "rgba(0, 0, 0, 0.87)",
  618 + "iconSize": "24px",
  619 + "titleTooltip": "",
  620 + "displayTimewindow": true
  621 + },
  622 + "id": "c4631f94-2db3-523b-4d09-2a1a0a75d93f"
  623 + },
  624 + "3da9a9a1-0b9a-2e1f-0dcb-0ff34a695abb": {
  625 + "isSystemType": true,
  626 + "bundleAlias": "maps_v2",
  627 + "typeAlias": "openstreetmap",
  628 + "type": "latest",
  629 + "title": "New widget",
  630 + "sizeX": 13,
  631 + "sizeY": 6,
  632 + "config": {
  633 + "datasources": [
  634 + {
  635 + "type": "entity",
  636 + "dataKeys": [
  637 + {
  638 + "name": "temperature",
  639 + "type": "timeseries",
  640 + "label": "temperature",
  641 + "color": "#2196f3",
  642 + "settings": {},
  643 + "_hash": 0.1371919646686739,
  644 + "decimals": 1,
  645 + "postFuncBody": "return value || \"\";"
  646 + },
  647 + {
  648 + "name": "humidity",
  649 + "type": "timeseries",
  650 + "label": "humidity",
  651 + "color": "#4caf50",
  652 + "settings": {},
  653 + "_hash": 0.043177186765847475,
  654 + "decimals": 0,
  655 + "postFuncBody": "return value || \"\";"
  656 + },
  657 + {
  658 + "name": "longitude",
  659 + "type": "attribute",
  660 + "label": "longitude",
  661 + "color": "#f44336",
  662 + "settings": {},
  663 + "_hash": 0.5548964320315584
  664 + },
  665 + {
  666 + "name": "latitude",
  667 + "type": "attribute",
  668 + "label": "latitude",
  669 + "color": "#ffc107",
  670 + "settings": {},
  671 + "_hash": 0.1803778014971602
  672 + },
  673 + {
  674 + "name": "active",
  675 + "type": "attribute",
  676 + "label": "active",
  677 + "color": "#607d8b",
  678 + "settings": {},
  679 + "_hash": 0.30926987994082844
  680 + }
  681 + ],
  682 + "entityAliasId": "68a058e1-fdda-8482-715b-3ae4a488568e"
  683 + }
  684 + ],
  685 + "timewindow": {
  686 + "realtime": {
  687 + "timewindowMs": 60000
  688 + }
  689 + },
  690 + "showTitle": false,
  691 + "backgroundColor": "#fff",
  692 + "color": "rgba(0, 0, 0, 0.87)",
  693 + "padding": "8px",
  694 + "settings": {
  695 + "fitMapBounds": true,
  696 + "latKeyName": "latitude",
  697 + "lngKeyName": "longitude",
  698 + "showLabel": true,
  699 + "label": "${entityName}",
  700 + "tooltipPattern": "<b>${entityName}</b><br/><br/><b>Temperature:</b> ${temperature:1} °C<br/><b>Humidity:</b> ${humidity:0} %<br/><br/><link-act name=\"navigate_to_details\">Thermostat details</link-act><br/>",
  701 + "markerImageSize": 48,
  702 + "useColorFunction": false,
  703 + "markerImages": [
  704 + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJzdmc0NDA4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAxNTAgMTUwIiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGU+LnN0MntmaWxsOiNmNDQzMzZ9PC9zdHlsZT48ZyBpZD0ibGF5ZXIxIj48ZyBpZD0icGF0aDY4ODEtMy01LTUtMS04LTQtNC03LTgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNDYuNDM4IC0yNzYuMDI4KSIgb3BhY2l0eT0iLjg5MiI+PHJhZGlhbEdyYWRpZW50IGlkPSJTVkdJRF8xXyIgY3g9IjMwODUuMjE1IiBjeT0iMzE3OC40NTgiIHI9IjQ5LjkwMSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCguNjc5MyAuMDA3NiAtLjUwOSAuNTYxMiAtMjMyLjYyOSAtMTQxMS43MjUpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLW9wYWNpdHk9Ii4xODgiLz48L3JhZGlhbEdyYWRpZW50PjxwYXRoIGQ9Ik0yODUuNiAzODguNWMxMC4zLTEyLjQgNC40LTIyLjQtMTQuNC0yMi40LTE4LjkgMC00Mi40IDEwLTUzLjkgMjIuNC0xNi44IDE4IC40IDIzLjUtLjIgMzUtLjEgMS44IDMuOSAxLjggNyAwIDE5LjgtMTEuNSA0Ni41LTE3IDYxLjUtMzUiIGZpbGw9InVybCgjU1ZHSURfMV8pIi8+PC9nPjxwYXRoIGlkPSJwYXRoNjg4MS0zLTUtNS0xLTgtNC00IiBjbGFzcz0ic3QyIiBkPSJNMTI0LjcgNjkuMWMtLjktMjcuNS0yMi4zLTQ5LjgtNDkuOC00OS44cy00OSAyMi4zLTQ5LjggNDkuOGMtMS4zIDQwLjEgMzAuNyA1Mi4yIDQ0LjcgNzggMi4yIDQgOCA0IDEwLjEgMCAxNC4xLTI1LjggNDYuMS0zNy45IDQ0LjgtNzgiLz48L2c+PGcgaWQ9Imc0OTI4Ij48Y2lyY2xlIGlkPSJwYXRoNDk3OCIgY2xhc3M9InN0MiIgY3g9Ijc0LjkiIGN5PSI2OS4xIiByPSI0OS45Ii8+PGcgaWQ9Imc0OTE1Ij48cGF0aCBpZD0icGF0aDY4ODMtMi0zLTUtMi00LTktNC05IiBkPSJNNzQuOCAxMDYuNGMtMjAuNiAwLTM3LjQtMTYuNy0zNy40LTM3LjQgMC0yMC42IDE2LjctMzcuNCAzNy40LTM3LjQgMjAuNiAwIDM3LjQgMTYuNyAzNy40IDM3LjRzLTE2LjcgMzcuNC0zNy40IDM3LjQiIGZpbGw9IiNmZmYiLz48L2c+PC9nPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik05NS45IDQ2LjZWNDloLTEwdi0yLjVsMTAgLjF6bS0yIDUuM2gtOHYyLjVoOHYtMi41em0tOCA3LjloNnYtMi41aC02djIuNXptNCAyLjloLTR2Mi41aDR2LTIuNXptLTQgNy44aDJWNjhoLTJ2Mi41em0xLjUgMTRjMCA2LjktNS41IDEyLjUtMTIuMyAxMi41cy0xMi4zLTUuNi0xMi4zLTEyLjVjMC00LjUgMi4zLTguNSA2LjEtMTAuN1Y0NS41YzAtMy41IDIuOC02LjMgNi4yLTYuM3M2LjIgMi44IDYuMiA2LjN2MjguM2MzLjggMi4yIDYuMSA2LjMgNi4xIDEwLjd6bS0yLjQgMGMwLTMuOC0yLjEtNy4yLTUuNC04LjlsLS43LS4zVjQ1LjVjMC0yLjEtMS43LTMuOC0zLjgtMy44LTIuMSAwLTMuOCAxLjctMy44IDMuOHYyOS44bC0uNy4zYy0zLjMgMS43LTUuNCA1LjEtNS40IDguOSAwIDUuNSA0LjQgMTAgOS45IDEwUzg1IDkwIDg1IDg0LjV6bS0yLjEgMGMwIDQuNC0zLjUgOC03LjggOHMtNy44LTMuNi03LjgtOGMwLTMuNiAyLjQtNi44IDUuOC03LjdsLjUtLjFWNjEuNWgzLjF2MTUuMmwuNS4xYzMuMyAxIDUuNyA0LjEgNS43IDcuN3ptLTcuNC01LjNjLS4yLS44LTEtMS40LTEuOS0xLjItMyAuNy01IDMuMy01IDYuNCAwIC45LjcgMS42IDEuNiAxLjZzMS42LS43IDEuNi0xLjZjMC0xLjYgMS4xLTMgMi42LTMuMy43LS4yIDEuMy0xIDEuMS0xLjl6Ii8+PC9zdmc+",
  705 + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJzdmc0NDA4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAxNTAgMTUwIiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGU+LnN0MntmaWxsOiMyNzg2MjJ9PC9zdHlsZT48ZyBpZD0ibGF5ZXIxIj48ZyBpZD0icGF0aDY4ODEtMy01LTUtMS04LTQtNC03LTgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNDYuNDM4IC0yNzYuMDI4KSIgb3BhY2l0eT0iLjg5MiI+PHJhZGlhbEdyYWRpZW50IGlkPSJTVkdJRF8xXyIgY3g9IjMwODUuMjE1IiBjeT0iMzE3OC40NTgiIHI9IjQ5LjkwMSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCguNjc5MyAuMDA3NiAtLjUwOSAuNTYxMiAtMjMyLjYyOSAtMTQxMS43MjUpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLW9wYWNpdHk9Ii4xODgiLz48L3JhZGlhbEdyYWRpZW50PjxwYXRoIGQ9Ik0yODUuNiAzODguNWMxMC4zLTEyLjQgNC40LTIyLjQtMTQuNC0yMi40LTE4LjkgMC00Mi40IDEwLTUzLjkgMjIuNC0xNi44IDE4IC40IDIzLjUtLjIgMzUtLjEgMS44IDMuOSAxLjggNyAwIDE5LjgtMTEuNSA0Ni41LTE3IDYxLjUtMzUiIGZpbGw9InVybCgjU1ZHSURfMV8pIi8+PC9nPjxwYXRoIGlkPSJwYXRoNjg4MS0zLTUtNS0xLTgtNC00IiBjbGFzcz0ic3QyIiBkPSJNMTI0LjcgNjkuMWMtLjktMjcuNS0yMi4zLTQ5LjgtNDkuOC00OS44cy00OSAyMi4zLTQ5LjggNDkuOGMtMS4zIDQwLjEgMzAuNyA1Mi4yIDQ0LjcgNzggMi4yIDQgOCA0IDEwLjEgMCAxNC4xLTI1LjggNDYuMS0zNy45IDQ0LjgtNzgiLz48L2c+PGcgaWQ9Imc0OTI4Ij48Y2lyY2xlIGlkPSJwYXRoNDk3OCIgY2xhc3M9InN0MiIgY3g9Ijc0LjkiIGN5PSI2OS4xIiByPSI0OS45Ii8+PGcgaWQ9Imc0OTE1Ij48cGF0aCBpZD0icGF0aDY4ODMtMi0zLTUtMi00LTktNC05IiBkPSJNNzQuOCAxMDYuNGMtMjAuNiAwLTM3LjQtMTYuNy0zNy40LTM3LjQgMC0yMC42IDE2LjctMzcuNCAzNy40LTM3LjQgMjAuNiAwIDM3LjQgMTYuNyAzNy40IDM3LjRzLTE2LjcgMzcuNC0zNy40IDM3LjQiIGZpbGw9IiNmZmYiLz48L2c+PC9nPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik05NS45IDQ2LjZWNDloLTEwdi0yLjVsMTAgLjF6bS0yIDUuM2gtOHYyLjVoOHYtMi41em0tOCA3LjloNnYtMi41aC02djIuNXptNCAyLjloLTR2Mi41aDR2LTIuNXptLTQgNy44aDJWNjhoLTJ2Mi41em0xLjUgMTRjMCA2LjktNS41IDEyLjUtMTIuMyAxMi41cy0xMi4zLTUuNi0xMi4zLTEyLjVjMC00LjUgMi4zLTguNSA2LjEtMTAuN1Y0NS41YzAtMy41IDIuOC02LjMgNi4yLTYuM3M2LjIgMi44IDYuMiA2LjN2MjguM2MzLjggMi4yIDYuMSA2LjMgNi4xIDEwLjd6bS0yLjQgMGMwLTMuOC0yLjEtNy4yLTUuNC04LjlsLS43LS4zVjQ1LjVjMC0yLjEtMS43LTMuOC0zLjgtMy44LTIuMSAwLTMuOCAxLjctMy44IDMuOHYyOS44bC0uNy4zYy0zLjMgMS43LTUuNCA1LjEtNS40IDguOSAwIDUuNSA0LjQgMTAgOS45IDEwUzg1IDkwIDg1IDg0LjV6bS0yLjEgMGMwIDQuNC0zLjUgOC03LjggOHMtNy44LTMuNi03LjgtOGMwLTMuNiAyLjQtNi44IDUuOC03LjdsLjUtLjFWNjEuNWgzLjF2MTUuMmwuNS4xYzMuMyAxIDUuNyA0LjEgNS43IDcuN3ptLTcuNC01LjNjLS4yLS44LTEtMS40LTEuOS0xLjItMyAuNy01IDMuMy01IDYuNCAwIC45LjcgMS42IDEuNiAxLjZzMS42LS43IDEuNi0xLjZjMC0xLjYgMS4xLTMgMi42LTMuMy43LS4yIDEuMy0xIDEuMS0xLjl6Ii8+PC9zdmc+Cg=="
  706 + ],
  707 + "useMarkerImageFunction": true,
  708 + "colorFunction": "\n",
  709 + "color": "#fe7569",
  710 + "mapProvider": "OpenStreetMap.HOT",
  711 + "showTooltip": true,
  712 + "autocloseTooltip": true,
  713 + "customProviderTileUrl": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
  714 + "defaultCenterPosition": [
  715 + 0,
  716 + 0
  717 + ],
  718 + "showTooltipAction": "click",
  719 + "polygonKeyName": "coordinates",
  720 + "polygonOpacity": 0.5,
  721 + "polygonStrokeOpacity": 1,
  722 + "polygonStrokeWeight": 1,
  723 + "zoomOnClick": true,
  724 + "showCoverageOnHover": true,
  725 + "animate": true,
  726 + "maxClusterRadius": 80,
  727 + "removeOutsideVisibleBounds": true,
  728 + "useLabelFunction": true,
  729 + "labelFunction": "var color;\nif(dsData[dsIndex].active !== \"true\"){\n color = 'rgb(255, 0, 0)';\n} else {\n color = 'rgb(39, 134, 34)';\n}\nreturn '<span style=\"border: solid ' + color + '; border-radius: 10px; color: ' + color + '; background-color: #fff; padding: 3px 5px; font-size: 14px\">' + \n '${entityLabel}' + \n '</span>'",
  730 + "defaultZoomLevel": 14,
  731 + "markerImageFunction": "var res;\nif(dsData[dsIndex].active !== \"true\"){\n\tvar res = {\n\t url: images[0],\n\t size: 48\n\t}\n} else {\n var res = {\n\t url: images[1],\n\t size: 48\n\t}\n}\nreturn res;"
  732 + },
  733 + "title": "Thermostat maps",
  734 + "dropShadow": true,
  735 + "enableFullscreen": false,
  736 + "titleStyle": {
  737 + "fontSize": "16px",
  738 + "fontWeight": 400
  739 + },
  740 + "useDashboardTimewindow": true,
  741 + "showLegend": false,
  742 + "widgetStyle": {},
  743 + "actions": {
  744 + "headerButton": [],
  745 + "tooltipAction": [
  746 + {
  747 + "id": "bef25673-b37a-8821-bc0f-5d6dd3680f24",
  748 + "name": "navigate_to_details",
  749 + "icon": "more_horiz",
  750 + "type": "openDashboardState",
  751 + "targetDashboardStateId": "chart",
  752 + "setEntityId": true
  753 + }
  754 + ]
  755 + },
  756 + "showTitleIcon": false,
  757 + "titleIcon": null,
  758 + "iconColor": "rgba(0, 0, 0, 0.87)",
  759 + "iconSize": "24px",
  760 + "titleTooltip": "",
  761 + "displayTimewindow": true
  762 + },
  763 + "id": "3da9a9a1-0b9a-2e1f-0dcb-0ff34a695abb"
  764 + },
  765 + "00fb2742-ba1f-7e43-673f-d6c08b72ed06": {
  766 + "isSystemType": true,
  767 + "bundleAlias": "input_widgets",
  768 + "typeAlias": "markers_placement_openstreetmap",
  769 + "type": "latest",
  770 + "title": "New widget",
  771 + "sizeX": 24,
  772 + "sizeY": 12,
  773 + "config": {
  774 + "datasources": [
  775 + {
  776 + "type": "entity",
  777 + "dataKeys": [
  778 + {
  779 + "name": "longitude",
  780 + "type": "attribute",
  781 + "label": "longitude",
  782 + "color": "#2196f3",
  783 + "settings": {},
  784 + "_hash": 0.3640193654284214
  785 + },
  786 + {
  787 + "name": "latitude",
  788 + "type": "attribute",
  789 + "label": "latitude",
  790 + "color": "#4caf50",
  791 + "settings": {},
  792 + "_hash": 0.49020393887695923
  793 + },
  794 + {
  795 + "name": "temperature",
  796 + "type": "timeseries",
  797 + "label": "temperature",
  798 + "color": "#f44336",
  799 + "settings": {},
  800 + "_hash": 0.5885892766009955,
  801 + "postFuncBody": "return value || \"\";"
  802 + },
  803 + {
  804 + "name": "humidity",
  805 + "type": "timeseries",
  806 + "label": "humidity",
  807 + "color": "#ffc107",
  808 + "settings": {},
  809 + "_hash": 0.21077893588180707,
  810 + "postFuncBody": "return value || \"\";"
  811 + },
  812 + {
  813 + "name": "active",
  814 + "type": "attribute",
  815 + "label": "active",
  816 + "color": "#607d8b",
  817 + "settings": {},
  818 + "_hash": 0.34722983638504346
  819 + }
  820 + ],
  821 + "entityAliasId": "68a058e1-fdda-8482-715b-3ae4a488568e"
  822 + }
  823 + ],
  824 + "timewindow": {
  825 + "realtime": {
  826 + "timewindowMs": 60000
  827 + }
  828 + },
  829 + "showTitle": false,
  830 + "backgroundColor": "#fff",
  831 + "color": "rgba(0, 0, 0, 0.87)",
  832 + "padding": "8px",
  833 + "settings": {
  834 + "fitMapBounds": true,
  835 + "latKeyName": "latitude",
  836 + "lngKeyName": "longitude",
  837 + "showLabel": true,
  838 + "label": "${entityName}",
  839 + "tooltipPattern": "<b>${entityName}</b><br/><br/><b>Temperature:</b> ${temperature:1} °C<br/><b>Humidity:</b> ${humidity:0} %<br/><br/><link-act name='delete'>Delete</link-act>",
  840 + "markerImageSize": 34,
  841 + "useColorFunction": false,
  842 + "markerImages": [
  843 + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJzdmc0NDA4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAxNTAgMTUwIiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGU+LnN0MntmaWxsOiNmNDQzMzZ9PC9zdHlsZT48ZyBpZD0ibGF5ZXIxIj48ZyBpZD0icGF0aDY4ODEtMy01LTUtMS04LTQtNC03LTgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNDYuNDM4IC0yNzYuMDI4KSIgb3BhY2l0eT0iLjg5MiI+PHJhZGlhbEdyYWRpZW50IGlkPSJTVkdJRF8xXyIgY3g9IjMwODUuMjE1IiBjeT0iMzE3OC40NTgiIHI9IjQ5LjkwMSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCguNjc5MyAuMDA3NiAtLjUwOSAuNTYxMiAtMjMyLjYyOSAtMTQxMS43MjUpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLW9wYWNpdHk9Ii4xODgiLz48L3JhZGlhbEdyYWRpZW50PjxwYXRoIGQ9Ik0yODUuNiAzODguNWMxMC4zLTEyLjQgNC40LTIyLjQtMTQuNC0yMi40LTE4LjkgMC00Mi40IDEwLTUzLjkgMjIuNC0xNi44IDE4IC40IDIzLjUtLjIgMzUtLjEgMS44IDMuOSAxLjggNyAwIDE5LjgtMTEuNSA0Ni41LTE3IDYxLjUtMzUiIGZpbGw9InVybCgjU1ZHSURfMV8pIi8+PC9nPjxwYXRoIGlkPSJwYXRoNjg4MS0zLTUtNS0xLTgtNC00IiBjbGFzcz0ic3QyIiBkPSJNMTI0LjcgNjkuMWMtLjktMjcuNS0yMi4zLTQ5LjgtNDkuOC00OS44cy00OSAyMi4zLTQ5LjggNDkuOGMtMS4zIDQwLjEgMzAuNyA1Mi4yIDQ0LjcgNzggMi4yIDQgOCA0IDEwLjEgMCAxNC4xLTI1LjggNDYuMS0zNy45IDQ0LjgtNzgiLz48L2c+PGcgaWQ9Imc0OTI4Ij48Y2lyY2xlIGlkPSJwYXRoNDk3OCIgY2xhc3M9InN0MiIgY3g9Ijc0LjkiIGN5PSI2OS4xIiByPSI0OS45Ii8+PGcgaWQ9Imc0OTE1Ij48cGF0aCBpZD0icGF0aDY4ODMtMi0zLTUtMi00LTktNC05IiBkPSJNNzQuOCAxMDYuNGMtMjAuNiAwLTM3LjQtMTYuNy0zNy40LTM3LjQgMC0yMC42IDE2LjctMzcuNCAzNy40LTM3LjQgMjAuNiAwIDM3LjQgMTYuNyAzNy40IDM3LjRzLTE2LjcgMzcuNC0zNy40IDM3LjQiIGZpbGw9IiNmZmYiLz48L2c+PC9nPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik05NS45IDQ2LjZWNDloLTEwdi0yLjVsMTAgLjF6bS0yIDUuM2gtOHYyLjVoOHYtMi41em0tOCA3LjloNnYtMi41aC02djIuNXptNCAyLjloLTR2Mi41aDR2LTIuNXptLTQgNy44aDJWNjhoLTJ2Mi41em0xLjUgMTRjMCA2LjktNS41IDEyLjUtMTIuMyAxMi41cy0xMi4zLTUuNi0xMi4zLTEyLjVjMC00LjUgMi4zLTguNSA2LjEtMTAuN1Y0NS41YzAtMy41IDIuOC02LjMgNi4yLTYuM3M2LjIgMi44IDYuMiA2LjN2MjguM2MzLjggMi4yIDYuMSA2LjMgNi4xIDEwLjd6bS0yLjQgMGMwLTMuOC0yLjEtNy4yLTUuNC04LjlsLS43LS4zVjQ1LjVjMC0yLjEtMS43LTMuOC0zLjgtMy44LTIuMSAwLTMuOCAxLjctMy44IDMuOHYyOS44bC0uNy4zYy0zLjMgMS43LTUuNCA1LjEtNS40IDguOSAwIDUuNSA0LjQgMTAgOS45IDEwUzg1IDkwIDg1IDg0LjV6bS0yLjEgMGMwIDQuNC0zLjUgOC03LjggOHMtNy44LTMuNi03LjgtOGMwLTMuNiAyLjQtNi44IDUuOC03LjdsLjUtLjFWNjEuNWgzLjF2MTUuMmwuNS4xYzMuMyAxIDUuNyA0LjEgNS43IDcuN3ptLTcuNC01LjNjLS4yLS44LTEtMS40LTEuOS0xLjItMyAuNy01IDMuMy01IDYuNCAwIC45LjcgMS42IDEuNiAxLjZzMS42LS43IDEuNi0xLjZjMC0xLjYgMS4xLTMgMi42LTMuMy43LS4yIDEuMy0xIDEuMS0xLjl6Ii8+PC9zdmc+",
  844 + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJzdmc0NDA4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAxNTAgMTUwIiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGU+LnN0MntmaWxsOiMyNzg2MjJ9PC9zdHlsZT48ZyBpZD0ibGF5ZXIxIj48ZyBpZD0icGF0aDY4ODEtMy01LTUtMS04LTQtNC03LTgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNDYuNDM4IC0yNzYuMDI4KSIgb3BhY2l0eT0iLjg5MiI+PHJhZGlhbEdyYWRpZW50IGlkPSJTVkdJRF8xXyIgY3g9IjMwODUuMjE1IiBjeT0iMzE3OC40NTgiIHI9IjQ5LjkwMSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCguNjc5MyAuMDA3NiAtLjUwOSAuNTYxMiAtMjMyLjYyOSAtMTQxMS43MjUpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLW9wYWNpdHk9Ii4xODgiLz48L3JhZGlhbEdyYWRpZW50PjxwYXRoIGQ9Ik0yODUuNiAzODguNWMxMC4zLTEyLjQgNC40LTIyLjQtMTQuNC0yMi40LTE4LjkgMC00Mi40IDEwLTUzLjkgMjIuNC0xNi44IDE4IC40IDIzLjUtLjIgMzUtLjEgMS44IDMuOSAxLjggNyAwIDE5LjgtMTEuNSA0Ni41LTE3IDYxLjUtMzUiIGZpbGw9InVybCgjU1ZHSURfMV8pIi8+PC9nPjxwYXRoIGlkPSJwYXRoNjg4MS0zLTUtNS0xLTgtNC00IiBjbGFzcz0ic3QyIiBkPSJNMTI0LjcgNjkuMWMtLjktMjcuNS0yMi4zLTQ5LjgtNDkuOC00OS44cy00OSAyMi4zLTQ5LjggNDkuOGMtMS4zIDQwLjEgMzAuNyA1Mi4yIDQ0LjcgNzggMi4yIDQgOCA0IDEwLjEgMCAxNC4xLTI1LjggNDYuMS0zNy45IDQ0LjgtNzgiLz48L2c+PGcgaWQ9Imc0OTI4Ij48Y2lyY2xlIGlkPSJwYXRoNDk3OCIgY2xhc3M9InN0MiIgY3g9Ijc0LjkiIGN5PSI2OS4xIiByPSI0OS45Ii8+PGcgaWQ9Imc0OTE1Ij48cGF0aCBpZD0icGF0aDY4ODMtMi0zLTUtMi00LTktNC05IiBkPSJNNzQuOCAxMDYuNGMtMjAuNiAwLTM3LjQtMTYuNy0zNy40LTM3LjQgMC0yMC42IDE2LjctMzcuNCAzNy40LTM3LjQgMjAuNiAwIDM3LjQgMTYuNyAzNy40IDM3LjRzLTE2LjcgMzcuNC0zNy40IDM3LjQiIGZpbGw9IiNmZmYiLz48L2c+PC9nPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik05NS45IDQ2LjZWNDloLTEwdi0yLjVsMTAgLjF6bS0yIDUuM2gtOHYyLjVoOHYtMi41em0tOCA3LjloNnYtMi41aC02djIuNXptNCAyLjloLTR2Mi41aDR2LTIuNXptLTQgNy44aDJWNjhoLTJ2Mi41em0xLjUgMTRjMCA2LjktNS41IDEyLjUtMTIuMyAxMi41cy0xMi4zLTUuNi0xMi4zLTEyLjVjMC00LjUgMi4zLTguNSA2LjEtMTAuN1Y0NS41YzAtMy41IDIuOC02LjMgNi4yLTYuM3M2LjIgMi44IDYuMiA2LjN2MjguM2MzLjggMi4yIDYuMSA2LjMgNi4xIDEwLjd6bS0yLjQgMGMwLTMuOC0yLjEtNy4yLTUuNC04LjlsLS43LS4zVjQ1LjVjMC0yLjEtMS43LTMuOC0zLjgtMy44LTIuMSAwLTMuOCAxLjctMy44IDMuOHYyOS44bC0uNy4zYy0zLjMgMS43LTUuNCA1LjEtNS40IDguOSAwIDUuNSA0LjQgMTAgOS45IDEwUzg1IDkwIDg1IDg0LjV6bS0yLjEgMGMwIDQuNC0zLjUgOC03LjggOHMtNy44LTMuNi03LjgtOGMwLTMuNiAyLjQtNi44IDUuOC03LjdsLjUtLjFWNjEuNWgzLjF2MTUuMmwuNS4xYzMuMyAxIDUuNyA0LjEgNS43IDcuN3ptLTcuNC01LjNjLS4yLS44LTEtMS40LTEuOS0xLjItMyAuNy01IDMuMy01IDYuNCAwIC45LjcgMS42IDEuNiAxLjZzMS42LS43IDEuNi0xLjZjMC0xLjYgMS4xLTMgMi42LTMuMy43LS4yIDEuMy0xIDEuMS0xLjl6Ii8+PC9zdmc+Cg=="
  845 + ],
  846 + "useMarkerImageFunction": true,
  847 + "color": "#fe7569",
  848 + "mapProvider": "OpenStreetMap.HOT",
  849 + "showTooltip": true,
  850 + "autocloseTooltip": true,
  851 + "defaultCenterPosition": [
  852 + 0,
  853 + 0
  854 + ],
  855 + "customProviderTileUrl": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
  856 + "showTooltipAction": "click",
  857 + "polygonKeyName": "coordinates",
  858 + "polygonOpacity": 0.5,
  859 + "polygonStrokeOpacity": 1,
  860 + "polygonStrokeWeight": 1,
  861 + "zoomOnClick": true,
  862 + "showCoverageOnHover": true,
  863 + "animate": true,
  864 + "maxClusterRadius": 80,
  865 + "removeOutsideVisibleBounds": true,
  866 + "defaultZoomLevel": 12,
  867 + "labelFunction": "var color;\nif(dsData[dsIndex].active !== \"true\"){\n color = 'rgb(255, 0, 0)';\n} else {\n color = 'rgb(39, 134, 34)';\n}\nreturn '<span style=\"border: solid ' + color + '; border-radius: 10px; color: ' + color + '; background-color: #fff; padding: 3px 5px; font-size: 14px\">' + \n '${entityLabel}' + \n '</span>'",
  868 + "markerImageFunction": "var res;\nif(dsData[dsIndex].active !== \"true\"){\n\tvar res = {\n\t url: images[0],\n\t size: 48\n\t}\n} else {\n var res = {\n\t url: images[1],\n\t size: 48\n\t}\n}\nreturn res;",
  869 + "useLabelFunction": true
  870 + },
  871 + "title": "New Markers Placement - OpenStreetMap",
  872 + "dropShadow": true,
  873 + "enableFullscreen": false,
  874 + "titleStyle": {
  875 + "fontSize": "16px",
  876 + "fontWeight": 400
  877 + },
  878 + "useDashboardTimewindow": true,
  879 + "showLegend": false,
  880 + "widgetStyle": {},
  881 + "actions": {
  882 + "tooltipAction": [
  883 + {
  884 + "id": "54c293c4-9ca6-e34f-dc6a-0271944c1c66",
  885 + "name": "delete",
  886 + "icon": "more_horiz",
  887 + "type": "custom",
  888 + "customFunction": "var $rootScope = widgetContext.$scope.$injector.get('$rootScope');\nvar entityDatasource = widgetContext.map.subscription.datasources.filter(\n function(entity) {\n return entity.entityId === entityId.id\n });\n\nwidgetContext.map.saveMarkerLocation(entityDatasource[0],\n widgetContext.map.locations[0], {\n \"lat\": null,\n \"lng\": null\n }).then(function succes() {\n $rootScope.$broadcast('widgetForceReInit');\n });"
  889 + }
  890 + ]
  891 + },
  892 + "showTitleIcon": false,
  893 + "titleIcon": null,
  894 + "iconColor": "rgba(0, 0, 0, 0.87)",
  895 + "iconSize": "24px",
  896 + "titleTooltip": "",
  897 + "displayTimewindow": true
  898 + },
  899 + "id": "00fb2742-ba1f-7e43-673f-d6c08b72ed06"
  900 + },
  901 + "0a430429-9078-9ae6-2b67-e4a15a2bf8bf": {
  902 + "isSystemType": true,
  903 + "bundleAlias": "input_widgets",
  904 + "typeAlias": "markers_placement_openstreetmap",
  905 + "type": "latest",
  906 + "title": "New widget",
  907 + "sizeX": 6,
  908 + "sizeY": 6,
  909 + "config": {
  910 + "datasources": [
  911 + {
  912 + "type": "entity",
  913 + "dataKeys": [
  914 + {
  915 + "name": "longitude",
  916 + "type": "attribute",
  917 + "label": "longitude",
  918 + "color": "#2196f3",
  919 + "settings": {},
  920 + "_hash": 0.3640193654284214
  921 + },
  922 + {
  923 + "name": "latitude",
  924 + "type": "attribute",
  925 + "label": "latitude",
  926 + "color": "#4caf50",
  927 + "settings": {},
  928 + "_hash": 0.49020393887695923
  929 + },
  930 + {
  931 + "name": "temperature",
  932 + "type": "timeseries",
  933 + "label": "temperature",
  934 + "color": "#f44336",
  935 + "settings": {},
  936 + "_hash": 0.5885892766009955,
  937 + "postFuncBody": "return value || \"\";"
  938 + },
  939 + {
  940 + "name": "humidity",
  941 + "type": "timeseries",
  942 + "label": "humidity",
  943 + "color": "#ffc107",
  944 + "settings": {},
  945 + "_hash": 0.21077893588180707,
  946 + "postFuncBody": "return value || \"\";"
  947 + },
  948 + {
  949 + "name": "active",
  950 + "type": "attribute",
  951 + "label": "active",
  952 + "color": "#607d8b",
  953 + "settings": {},
  954 + "_hash": 0.34722983638504346
  955 + }
  956 + ],
  957 + "entityAliasId": "12ae98c7-1ea2-52cf-64d5-763e9d993547"
  958 + }
  959 + ],
  960 + "timewindow": {
  961 + "realtime": {
  962 + "timewindowMs": 60000
  963 + }
  964 + },
  965 + "showTitle": false,
  966 + "backgroundColor": "#fff",
  967 + "color": "rgba(0, 0, 0, 0.87)",
  968 + "padding": "8px",
  969 + "settings": {
  970 + "fitMapBounds": true,
  971 + "latKeyName": "latitude",
  972 + "lngKeyName": "longitude",
  973 + "showLabel": true,
  974 + "label": "${entityName}",
  975 + "tooltipPattern": "<b>${entityName}</b><br/><br/><b>Temperature:</b> ${temperature:1} °C<br/><b>Humidity:</b> ${humidity:0} %<br/><br/><link-act name='delete'>Delete</link-act>",
  976 + "markerImageSize": 34,
  977 + "useColorFunction": false,
  978 + "markerImages": [
  979 + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJzdmc0NDA4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAxNTAgMTUwIiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGU+LnN0MntmaWxsOiNmNDQzMzZ9PC9zdHlsZT48ZyBpZD0ibGF5ZXIxIj48ZyBpZD0icGF0aDY4ODEtMy01LTUtMS04LTQtNC03LTgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNDYuNDM4IC0yNzYuMDI4KSIgb3BhY2l0eT0iLjg5MiI+PHJhZGlhbEdyYWRpZW50IGlkPSJTVkdJRF8xXyIgY3g9IjMwODUuMjE1IiBjeT0iMzE3OC40NTgiIHI9IjQ5LjkwMSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCguNjc5MyAuMDA3NiAtLjUwOSAuNTYxMiAtMjMyLjYyOSAtMTQxMS43MjUpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLW9wYWNpdHk9Ii4xODgiLz48L3JhZGlhbEdyYWRpZW50PjxwYXRoIGQ9Ik0yODUuNiAzODguNWMxMC4zLTEyLjQgNC40LTIyLjQtMTQuNC0yMi40LTE4LjkgMC00Mi40IDEwLTUzLjkgMjIuNC0xNi44IDE4IC40IDIzLjUtLjIgMzUtLjEgMS44IDMuOSAxLjggNyAwIDE5LjgtMTEuNSA0Ni41LTE3IDYxLjUtMzUiIGZpbGw9InVybCgjU1ZHSURfMV8pIi8+PC9nPjxwYXRoIGlkPSJwYXRoNjg4MS0zLTUtNS0xLTgtNC00IiBjbGFzcz0ic3QyIiBkPSJNMTI0LjcgNjkuMWMtLjktMjcuNS0yMi4zLTQ5LjgtNDkuOC00OS44cy00OSAyMi4zLTQ5LjggNDkuOGMtMS4zIDQwLjEgMzAuNyA1Mi4yIDQ0LjcgNzggMi4yIDQgOCA0IDEwLjEgMCAxNC4xLTI1LjggNDYuMS0zNy45IDQ0LjgtNzgiLz48L2c+PGcgaWQ9Imc0OTI4Ij48Y2lyY2xlIGlkPSJwYXRoNDk3OCIgY2xhc3M9InN0MiIgY3g9Ijc0LjkiIGN5PSI2OS4xIiByPSI0OS45Ii8+PGcgaWQ9Imc0OTE1Ij48cGF0aCBpZD0icGF0aDY4ODMtMi0zLTUtMi00LTktNC05IiBkPSJNNzQuOCAxMDYuNGMtMjAuNiAwLTM3LjQtMTYuNy0zNy40LTM3LjQgMC0yMC42IDE2LjctMzcuNCAzNy40LTM3LjQgMjAuNiAwIDM3LjQgMTYuNyAzNy40IDM3LjRzLTE2LjcgMzcuNC0zNy40IDM3LjQiIGZpbGw9IiNmZmYiLz48L2c+PC9nPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik05NS45IDQ2LjZWNDloLTEwdi0yLjVsMTAgLjF6bS0yIDUuM2gtOHYyLjVoOHYtMi41em0tOCA3LjloNnYtMi41aC02djIuNXptNCAyLjloLTR2Mi41aDR2LTIuNXptLTQgNy44aDJWNjhoLTJ2Mi41em0xLjUgMTRjMCA2LjktNS41IDEyLjUtMTIuMyAxMi41cy0xMi4zLTUuNi0xMi4zLTEyLjVjMC00LjUgMi4zLTguNSA2LjEtMTAuN1Y0NS41YzAtMy41IDIuOC02LjMgNi4yLTYuM3M2LjIgMi44IDYuMiA2LjN2MjguM2MzLjggMi4yIDYuMSA2LjMgNi4xIDEwLjd6bS0yLjQgMGMwLTMuOC0yLjEtNy4yLTUuNC04LjlsLS43LS4zVjQ1LjVjMC0yLjEtMS43LTMuOC0zLjgtMy44LTIuMSAwLTMuOCAxLjctMy44IDMuOHYyOS44bC0uNy4zYy0zLjMgMS43LTUuNCA1LjEtNS40IDguOSAwIDUuNSA0LjQgMTAgOS45IDEwUzg1IDkwIDg1IDg0LjV6bS0yLjEgMGMwIDQuNC0zLjUgOC03LjggOHMtNy44LTMuNi03LjgtOGMwLTMuNiAyLjQtNi44IDUuOC03LjdsLjUtLjFWNjEuNWgzLjF2MTUuMmwuNS4xYzMuMyAxIDUuNyA0LjEgNS43IDcuN3ptLTcuNC01LjNjLS4yLS44LTEtMS40LTEuOS0xLjItMyAuNy01IDMuMy01IDYuNCAwIC45LjcgMS42IDEuNiAxLjZzMS42LS43IDEuNi0xLjZjMC0xLjYgMS4xLTMgMi42LTMuMy43LS4yIDEuMy0xIDEuMS0xLjl6Ii8+PC9zdmc+",
  980 + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJzdmc0NDA4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAxNTAgMTUwIiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGU+LnN0MntmaWxsOiMyNzg2MjJ9PC9zdHlsZT48ZyBpZD0ibGF5ZXIxIj48ZyBpZD0icGF0aDY4ODEtMy01LTUtMS04LTQtNC03LTgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xNDYuNDM4IC0yNzYuMDI4KSIgb3BhY2l0eT0iLjg5MiI+PHJhZGlhbEdyYWRpZW50IGlkPSJTVkdJRF8xXyIgY3g9IjMwODUuMjE1IiBjeT0iMzE3OC40NTgiIHI9IjQ5LjkwMSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCguNjc5MyAuMDA3NiAtLjUwOSAuNTYxMiAtMjMyLjYyOSAtMTQxMS43MjUpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLW9wYWNpdHk9Ii4xODgiLz48L3JhZGlhbEdyYWRpZW50PjxwYXRoIGQ9Ik0yODUuNiAzODguNWMxMC4zLTEyLjQgNC40LTIyLjQtMTQuNC0yMi40LTE4LjkgMC00Mi40IDEwLTUzLjkgMjIuNC0xNi44IDE4IC40IDIzLjUtLjIgMzUtLjEgMS44IDMuOSAxLjggNyAwIDE5LjgtMTEuNSA0Ni41LTE3IDYxLjUtMzUiIGZpbGw9InVybCgjU1ZHSURfMV8pIi8+PC9nPjxwYXRoIGlkPSJwYXRoNjg4MS0zLTUtNS0xLTgtNC00IiBjbGFzcz0ic3QyIiBkPSJNMTI0LjcgNjkuMWMtLjktMjcuNS0yMi4zLTQ5LjgtNDkuOC00OS44cy00OSAyMi4zLTQ5LjggNDkuOGMtMS4zIDQwLjEgMzAuNyA1Mi4yIDQ0LjcgNzggMi4yIDQgOCA0IDEwLjEgMCAxNC4xLTI1LjggNDYuMS0zNy45IDQ0LjgtNzgiLz48L2c+PGcgaWQ9Imc0OTI4Ij48Y2lyY2xlIGlkPSJwYXRoNDk3OCIgY2xhc3M9InN0MiIgY3g9Ijc0LjkiIGN5PSI2OS4xIiByPSI0OS45Ii8+PGcgaWQ9Imc0OTE1Ij48cGF0aCBpZD0icGF0aDY4ODMtMi0zLTUtMi00LTktNC05IiBkPSJNNzQuOCAxMDYuNGMtMjAuNiAwLTM3LjQtMTYuNy0zNy40LTM3LjQgMC0yMC42IDE2LjctMzcuNCAzNy40LTM3LjQgMjAuNiAwIDM3LjQgMTYuNyAzNy40IDM3LjRzLTE2LjcgMzcuNC0zNy40IDM3LjQiIGZpbGw9IiNmZmYiLz48L2c+PC9nPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik05NS45IDQ2LjZWNDloLTEwdi0yLjVsMTAgLjF6bS0yIDUuM2gtOHYyLjVoOHYtMi41em0tOCA3LjloNnYtMi41aC02djIuNXptNCAyLjloLTR2Mi41aDR2LTIuNXptLTQgNy44aDJWNjhoLTJ2Mi41em0xLjUgMTRjMCA2LjktNS41IDEyLjUtMTIuMyAxMi41cy0xMi4zLTUuNi0xMi4zLTEyLjVjMC00LjUgMi4zLTguNSA2LjEtMTAuN1Y0NS41YzAtMy41IDIuOC02LjMgNi4yLTYuM3M2LjIgMi44IDYuMiA2LjN2MjguM2MzLjggMi4yIDYuMSA2LjMgNi4xIDEwLjd6bS0yLjQgMGMwLTMuOC0yLjEtNy4yLTUuNC04LjlsLS43LS4zVjQ1LjVjMC0yLjEtMS43LTMuOC0zLjgtMy44LTIuMSAwLTMuOCAxLjctMy44IDMuOHYyOS44bC0uNy4zYy0zLjMgMS43LTUuNCA1LjEtNS40IDguOSAwIDUuNSA0LjQgMTAgOS45IDEwUzg1IDkwIDg1IDg0LjV6bS0yLjEgMGMwIDQuNC0zLjUgOC03LjggOHMtNy44LTMuNi03LjgtOGMwLTMuNiAyLjQtNi44IDUuOC03LjdsLjUtLjFWNjEuNWgzLjF2MTUuMmwuNS4xYzMuMyAxIDUuNyA0LjEgNS43IDcuN3ptLTcuNC01LjNjLS4yLS44LTEtMS40LTEuOS0xLjItMyAuNy01IDMuMy01IDYuNCAwIC45LjcgMS42IDEuNiAxLjZzMS42LS43IDEuNi0xLjZjMC0xLjYgMS4xLTMgMi42LTMuMy43LS4yIDEuMy0xIDEuMS0xLjl6Ii8+PC9zdmc+Cg=="
  981 + ],
  982 + "useMarkerImageFunction": true,
  983 + "color": "#fe7569",
  984 + "mapProvider": "OpenStreetMap.HOT",
  985 + "showTooltip": true,
  986 + "autocloseTooltip": true,
  987 + "defaultCenterPosition": [
  988 + 37.7749,
  989 + -122.4194
  990 + ],
  991 + "customProviderTileUrl": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
  992 + "showTooltipAction": "click",
  993 + "polygonKeyName": "coordinates",
  994 + "polygonOpacity": 0.5,
  995 + "polygonStrokeOpacity": 1,
  996 + "polygonStrokeWeight": 1,
  997 + "zoomOnClick": true,
  998 + "showCoverageOnHover": true,
  999 + "animate": true,
  1000 + "maxClusterRadius": 80,
  1001 + "removeOutsideVisibleBounds": true,
  1002 + "defaultZoomLevel": 5,
  1003 + "labelFunction": "var color;\nif(dsData[dsIndex].active !== \"true\"){\n color = 'rgb(255, 0, 0)';\n} else {\n color = 'rgb(39, 134, 34)';\n}\nreturn '<span style=\"border: solid ' + color + '; border-radius: 10px; color: ' + color + '; background-color: #fff; padding: 3px 5px; font-size: 14px\">' + \n '${entityLabel}' + \n '</span>'",
  1004 + "markerImageFunction": "var res;\nif(dsData[dsIndex].active !== \"true\"){\n\tvar res = {\n\t url: images[0],\n\t size: 48\n\t}\n} else {\n var res = {\n\t url: images[1],\n\t size: 48\n\t}\n}\nreturn res;",
  1005 + "useLabelFunction": true,
  1006 + "useDefaultCenterPosition": true
  1007 + },
  1008 + "title": "New Markers Placement - OpenStreetMap",
  1009 + "dropShadow": true,
  1010 + "enableFullscreen": false,
  1011 + "titleStyle": {
  1012 + "fontSize": "16px",
  1013 + "fontWeight": 400
  1014 + },
  1015 + "useDashboardTimewindow": true,
  1016 + "showLegend": false,
  1017 + "widgetStyle": {},
  1018 + "actions": {
  1019 + "tooltipAction": [
  1020 + {
  1021 + "id": "54c293c4-9ca6-e34f-dc6a-0271944c1c66",
  1022 + "name": "delete",
  1023 + "icon": "more_horiz",
  1024 + "type": "custom",
  1025 + "customFunction": "var $rootScope = widgetContext.$scope.$injector.get('$rootScope');\nvar entityDatasource = widgetContext.map.subscription.datasources.filter(\n function(entity) {\n return entity.entityId === entityId.id\n });\n\nwidgetContext.map.saveMarkerLocation(entityDatasource[0],\n widgetContext.map.locations[0], {\n \"lat\": null,\n \"lng\": null\n }).then(function succes() {\n $rootScope.$broadcast('widgetForceReInit');\n });"
  1026 + }
  1027 + ]
  1028 + },
  1029 + "showTitleIcon": false,
  1030 + "titleIcon": null,
  1031 + "iconColor": "rgba(0, 0, 0, 0.87)",
  1032 + "iconSize": "24px",
  1033 + "titleTooltip": "",
  1034 + "displayTimewindow": true
  1035 + },
  1036 + "id": "0a430429-9078-9ae6-2b67-e4a15a2bf8bf"
  1037 + }
  1038 + },
  1039 + "states": {
  1040 + "default": {
  1041 + "name": "Thermostats",
  1042 + "root": true,
  1043 + "layouts": {
  1044 + "main": {
  1045 + "widgets": {
  1046 + "f33c746c-0dfc-c212-395b-b448c8a17209": {
  1047 + "sizeX": 11,
  1048 + "sizeY": 11,
  1049 + "row": 0,
  1050 + "col": 0
  1051 + },
  1052 + "7943196b-eedb-d422-f9c3-b32d379ad172": {
  1053 + "sizeX": 13,
  1054 + "sizeY": 5,
  1055 + "row": 0,
  1056 + "col": 11
  1057 + },
  1058 + "3da9a9a1-0b9a-2e1f-0dcb-0ff34a695abb": {
  1059 + "sizeX": 13,
  1060 + "sizeY": 6,
  1061 + "row": 5,
  1062 + "col": 11
  1063 + }
  1064 + },
  1065 + "gridSettings": {
  1066 + "backgroundColor": "#eeeeee",
  1067 + "color": "rgba(0,0,0,0.870588)",
  1068 + "columns": 24,
  1069 + "margins": [
  1070 + 10,
  1071 + 10
  1072 + ],
  1073 + "backgroundSizeMode": "100%",
  1074 + "autoFillHeight": true,
  1075 + "mobileAutoFillHeight": false,
  1076 + "mobileRowHeight": 70
  1077 + }
  1078 + }
  1079 + }
  1080 + },
  1081 + "map": {
  1082 + "name": "Edit location",
  1083 + "root": false,
  1084 + "layouts": {
  1085 + "main": {
  1086 + "widgets": {
  1087 + "00fb2742-ba1f-7e43-673f-d6c08b72ed06": {
  1088 + "sizeX": 24,
  1089 + "sizeY": 12,
  1090 + "row": 0,
  1091 + "col": 0
  1092 + }
  1093 + },
  1094 + "gridSettings": {
  1095 + "backgroundColor": "#eeeeee",
  1096 + "color": "rgba(0,0,0,0.870588)",
  1097 + "columns": 24,
  1098 + "margins": [
  1099 + 10,
  1100 + 10
  1101 + ],
  1102 + "backgroundSizeMode": "100%",
  1103 + "autoFillHeight": true,
  1104 + "mobileAutoFillHeight": false,
  1105 + "mobileRowHeight": 70
  1106 + }
  1107 + }
  1108 + }
  1109 + },
  1110 + "chart": {
  1111 + "name": "${entityName}",
  1112 + "root": false,
  1113 + "layouts": {
  1114 + "main": {
  1115 + "widgets": {
  1116 + "14a19183-f0b2-d6be-0f62-9863f0a51111": {
  1117 + "sizeX": 18,
  1118 + "sizeY": 6,
  1119 + "mobileHeight": null,
  1120 + "row": 0,
  1121 + "col": 6
  1122 + },
  1123 + "07f49fd5-a73b-d74c-c220-362c20af81f4": {
  1124 + "sizeX": 18,
  1125 + "sizeY": 6,
  1126 + "mobileHeight": null,
  1127 + "row": 6,
  1128 + "col": 6
  1129 + },
  1130 + "c4631f94-2db3-523b-4d09-2a1a0a75d93f": {
  1131 + "sizeX": 6,
  1132 + "sizeY": 6,
  1133 + "row": 0,
  1134 + "col": 0
  1135 + },
  1136 + "0a430429-9078-9ae6-2b67-e4a15a2bf8bf": {
  1137 + "sizeX": 6,
  1138 + "sizeY": 6,
  1139 + "row": 6,
  1140 + "col": 0
  1141 + }
  1142 + },
  1143 + "gridSettings": {
  1144 + "backgroundColor": "#eeeeee",
  1145 + "color": "rgba(0,0,0,0.870588)",
  1146 + "columns": 24,
  1147 + "margins": [
  1148 + 10,
  1149 + 10
  1150 + ],
  1151 + "backgroundSizeMode": "100%",
  1152 + "autoFillHeight": true,
  1153 + "mobileAutoFillHeight": false,
  1154 + "mobileRowHeight": 70
  1155 + }
  1156 + }
  1157 + }
  1158 + }
  1159 + },
  1160 + "entityAliases": {
  1161 + "68a058e1-fdda-8482-715b-3ae4a488568e": {
  1162 + "id": "68a058e1-fdda-8482-715b-3ae4a488568e",
  1163 + "alias": "Thermostats",
  1164 + "filter": {
  1165 + "type": "deviceType",
  1166 + "resolveMultiple": true,
  1167 + "deviceType": "thermostat",
  1168 + "deviceNameFilter": ""
  1169 + }
  1170 + },
  1171 + "12ae98c7-1ea2-52cf-64d5-763e9d993547": {
  1172 + "id": "12ae98c7-1ea2-52cf-64d5-763e9d993547",
  1173 + "alias": "Thermostat",
  1174 + "filter": {
  1175 + "type": "stateEntity",
  1176 + "resolveMultiple": false,
  1177 + "stateEntityParamName": null,
  1178 + "defaultStateEntity": null
  1179 + }
  1180 + },
  1181 + "ce27a9d0-93bf-b7a4-054d-d0369a8cf813": {
  1182 + "id": "ce27a9d0-93bf-b7a4-054d-d0369a8cf813",
  1183 + "alias": "Thermostat-alarm",
  1184 + "filter": {
  1185 + "type": "entityName",
  1186 + "resolveMultiple": false,
  1187 + "entityType": "ASSET",
  1188 + "entityNameFilter": "Thermostat Alarms"
  1189 + }
  1190 + }
  1191 + },
  1192 + "timewindow": {
  1193 + "displayValue": "",
  1194 + "selectedTab": 0,
  1195 + "hideInterval": false,
  1196 + "hideAggregation": false,
  1197 + "hideAggInterval": false,
  1198 + "realtime": {
  1199 + "interval": 1000,
  1200 + "timewindowMs": 60000
  1201 + },
  1202 + "history": {
  1203 + "historyType": 0,
  1204 + "interval": 1000,
  1205 + "timewindowMs": 60000,
  1206 + "fixedTimewindow": {
  1207 + "startTimeMs": 1587473857304,
  1208 + "endTimeMs": 1587560257304
  1209 + }
  1210 + },
  1211 + "aggregation": {
  1212 + "type": "AVG",
  1213 + "limit": 25000
  1214 + }
  1215 + },
  1216 + "settings": {
  1217 + "stateControllerId": "entity",
  1218 + "showTitle": false,
  1219 + "showDashboardsSelect": true,
  1220 + "showEntitiesSelect": true,
  1221 + "showDashboardTimewindow": true,
  1222 + "showDashboardExport": true,
  1223 + "toolbarAlwaysOpen": true
  1224 + }
  1225 + },
  1226 + "name": "Thermostats"
  1227 +}
\ No newline at end of file
... ...
  1 +{
  2 + "ruleChain": {
  3 + "additionalInfo": null,
  4 + "name": "Root Rule Chain",
  5 + "firstRuleNodeId": null,
  6 + "root": true,
  7 + "debugMode": false,
  8 + "configuration": null
  9 + },
  10 + "metadata": {
  11 + "firstNodeIndex": 3,
  12 + "nodes": [
  13 + {
  14 + "additionalInfo": {
  15 + "layoutX": 1069,
  16 + "layoutY": 267
  17 + },
  18 + "type": "org.thingsboard.rule.engine.filter.TbJsFilterNode",
  19 + "name": "Is Thermostat?",
  20 + "debugMode": false,
  21 + "configuration": {
  22 + "jsScript": "return msg.id.entityType === \"DEVICE\" && msg.type === \"thermostat\";"
  23 + }
  24 + },
  25 + {
  26 + "additionalInfo": {
  27 + "layoutX": 824,
  28 + "layoutY": 156
  29 + },
  30 + "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode",
  31 + "name": "Save Timeseries",
  32 + "debugMode": false,
  33 + "configuration": {
  34 + "defaultTTL": 0
  35 + }
  36 + },
  37 + {
  38 + "additionalInfo": {
  39 + "layoutX": 825,
  40 + "layoutY": 52
  41 + },
  42 + "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode",
  43 + "name": "Save Client Attributes",
  44 + "debugMode": false,
  45 + "configuration": {
  46 + "scope": "CLIENT_SCOPE"
  47 + }
  48 + },
  49 + {
  50 + "additionalInfo": {
  51 + "layoutX": 347,
  52 + "layoutY": 149
  53 + },
  54 + "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode",
  55 + "name": "Message Type Switch",
  56 + "debugMode": false,
  57 + "configuration": {
  58 + "version": 0
  59 + }
  60 + },
  61 + {
  62 + "additionalInfo": {
  63 + "layoutX": 839,
  64 + "layoutY": 345
  65 + },
  66 + "type": "org.thingsboard.rule.engine.action.TbLogNode",
  67 + "name": "Log RPC from Device",
  68 + "debugMode": false,
  69 + "configuration": {
  70 + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
  71 + }
  72 + },
  73 + {
  74 + "additionalInfo": {
  75 + "layoutX": 832,
  76 + "layoutY": 407
  77 + },
  78 + "type": "org.thingsboard.rule.engine.action.TbLogNode",
  79 + "name": "Log Other",
  80 + "debugMode": false,
  81 + "configuration": {
  82 + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
  83 + }
  84 + },
  85 + {
  86 + "additionalInfo": {
  87 + "layoutX": 825,
  88 + "layoutY": 468
  89 + },
  90 + "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode",
  91 + "name": "RPC Call Request",
  92 + "debugMode": false,
  93 + "configuration": {
  94 + "timeoutInSeconds": 60
  95 + }
  96 + },
  97 + {
  98 + "additionalInfo": {
  99 + "layoutX": 1069,
  100 + "layoutY": 90
  101 + },
  102 + "type": "org.thingsboard.rule.engine.filter.TbJsFilterNode",
  103 + "name": "Is Thermostat?",
  104 + "debugMode": false,
  105 + "configuration": {
  106 + "jsScript": "return metadata[\"deviceType\"] === \"thermostat\";"
  107 + }
  108 + },
  109 + {
  110 + "additionalInfo": {
  111 + "layoutX": 1090,
  112 + "layoutY": 360
  113 + },
  114 + "type": "org.thingsboard.rule.engine.action.TbCreateRelationNode",
  115 + "name": "Relate to Asset",
  116 + "debugMode": false,
  117 + "configuration": {
  118 + "direction": "FROM",
  119 + "relationType": "ToAlarmPropagationAsset",
  120 + "entityType": "ASSET",
  121 + "entityNamePattern": "Thermostat Alarms",
  122 + "entityTypePattern": "AlarmPropagationAsset",
  123 + "entityCacheExpiration": 300,
  124 + "createEntityIfNotExists": true,
  125 + "changeOriginatorToRelatedEntity": false,
  126 + "removeCurrentRelations": false
  127 + }
  128 + }
  129 + ],
  130 + "connections": [
  131 + {
  132 + "fromIndex": 0,
  133 + "toIndex": 8,
  134 + "type": "True"
  135 + },
  136 + {
  137 + "fromIndex": 1,
  138 + "toIndex": 7,
  139 + "type": "Success"
  140 + },
  141 + {
  142 + "fromIndex": 3,
  143 + "toIndex": 5,
  144 + "type": "Other"
  145 + },
  146 + {
  147 + "fromIndex": 3,
  148 + "toIndex": 2,
  149 + "type": "Post attributes"
  150 + },
  151 + {
  152 + "fromIndex": 3,
  153 + "toIndex": 1,
  154 + "type": "Post telemetry"
  155 + },
  156 + {
  157 + "fromIndex": 3,
  158 + "toIndex": 4,
  159 + "type": "RPC Request from Device"
  160 + },
  161 + {
  162 + "fromIndex": 3,
  163 + "toIndex": 6,
  164 + "type": "RPC Request to Device"
  165 + },
  166 + {
  167 + "fromIndex": 3,
  168 + "toIndex": 0,
  169 + "type": "Entity Created"
  170 + }
  171 + ],
  172 + "ruleChainConnections": [
  173 + {
  174 + "fromIndex": 7,
  175 + "targetRuleChainId": {
  176 + "entityType": "RULE_CHAIN",
  177 + "id": "25e26570-89ed-11ea-a650-cd6e14e633bd"
  178 + },
  179 + "additionalInfo": {
  180 + "layoutX": 1109,
  181 + "layoutY": 182,
  182 + "ruleChainNodeId": "rule-chain-node-10"
  183 + },
  184 + "type": "True"
  185 + }
  186 + ]
  187 + }
  188 +}
\ No newline at end of file
... ...
  1 +{
  2 + "ruleChain": {
  3 + "additionalInfo": null,
  4 + "name": "Thermostat Alarms",
  5 + "firstRuleNodeId": null,
  6 + "root": false,
  7 + "debugMode": false,
  8 + "configuration": null
  9 + },
  10 + "metadata": {
  11 + "firstNodeIndex": 5,
  12 + "nodes": [
  13 + {
  14 + "additionalInfo": {
  15 + "layoutX": 929,
  16 + "layoutY": 67
  17 + },
  18 + "type": "org.thingsboard.rule.engine.action.TbCreateAlarmNode",
  19 + "name": "Create Temp Alarm",
  20 + "debugMode": false,
  21 + "configuration": {
  22 + "alarmType": "High Temperature",
  23 + "alarmDetailsBuildJs": "var details = {};\nif (metadata.prevAlarmDetails) {\n details = JSON.parse(metadata.prevAlarmDetails);\n}\ndetails.triggerValue = msg.temperature;\nreturn details;",
  24 + "severity": "MAJOR",
  25 + "propagate": true,
  26 + "useMessageAlarmData": false,
  27 + "relationTypes": [
  28 + "ToAlarmPropagationAsset"
  29 + ]
  30 + }
  31 + },
  32 + {
  33 + "additionalInfo": {
  34 + "layoutX": 930,
  35 + "layoutY": 201
  36 + },
  37 + "type": "org.thingsboard.rule.engine.action.TbClearAlarmNode",
  38 + "name": "Clear Temp Alarm",
  39 + "debugMode": false,
  40 + "configuration": {
  41 + "alarmType": "High Temperature",
  42 + "alarmDetailsBuildJs": "var details = {};\nif (metadata.prevAlarmDetails) {\n details = JSON.parse(metadata.prevAlarmDetails);\n}\nreturn details;"
  43 + }
  44 + },
  45 + {
  46 + "additionalInfo": {
  47 + "layoutX": 930,
  48 + "layoutY": 131
  49 + },
  50 + "type": "org.thingsboard.rule.engine.action.TbCreateAlarmNode",
  51 + "name": "Create Humidity Alarm",
  52 + "debugMode": false,
  53 + "configuration": {
  54 + "alarmType": "Low Humidity",
  55 + "alarmDetailsBuildJs": "var details = {};\nif (metadata.prevAlarmDetails) {\n details = JSON.parse(metadata.prevAlarmDetails);\n}\ndetails.triggerValue = msg.humidity;\nreturn details;",
  56 + "severity": "MINOR",
  57 + "propagate": true,
  58 + "useMessageAlarmData": false,
  59 + "relationTypes": [
  60 + "ToAlarmPropagationAsset"
  61 + ]
  62 + }
  63 + },
  64 + {
  65 + "additionalInfo": {
  66 + "layoutX": 929,
  67 + "layoutY": 275
  68 + },
  69 + "type": "org.thingsboard.rule.engine.action.TbClearAlarmNode",
  70 + "name": "Clear Humidity Alarm",
  71 + "debugMode": false,
  72 + "configuration": {
  73 + "alarmType": "Low Humidity",
  74 + "alarmDetailsBuildJs": "var details = {};\nif (metadata.prevAlarmDetails) {\n details = JSON.parse(metadata.prevAlarmDetails);\n}\nreturn details;"
  75 + }
  76 + },
  77 + {
  78 + "additionalInfo": {
  79 + "layoutX": 586,
  80 + "layoutY": 148
  81 + },
  82 + "type": "org.thingsboard.rule.engine.filter.TbJsSwitchNode",
  83 + "name": "Check Alarms",
  84 + "debugMode": false,
  85 + "configuration": {
  86 + "jsScript": "var relations = [];\nif(metadata[\"ss_alarmTemperature\"] === \"true\"){\n if(msg.temperature > metadata[\"ss_thresholdTemperature\"]){\n relations.push(\"NewTempAlarm\");\n } else {\n relations.push(\"ClearTempAlarm\");\n }\n}\nif(metadata[\"ss_alarmHumidity\"] === \"true\"){\n if(msg.humidity < metadata[\"ss_thresholdHumidity\"]){\n relations.push(\"NewHumidityAlarm\");\n } else {\n relations.push(\"ClearHumidityAlarm\");\n }\n}\n\nreturn relations;"
  87 + }
  88 + },
  89 + {
  90 + "additionalInfo": {
  91 + "layoutX": 321,
  92 + "layoutY": 149
  93 + },
  94 + "type": "org.thingsboard.rule.engine.metadata.TbGetAttributesNode",
  95 + "name": "Fetch Configuration",
  96 + "debugMode": false,
  97 + "configuration": {
  98 + "clientAttributeNames": [],
  99 + "sharedAttributeNames": [],
  100 + "serverAttributeNames": [
  101 + "alarmTemperature",
  102 + "thresholdTemperature",
  103 + "alarmHumidity",
  104 + "thresholdHumidity"
  105 + ],
  106 + "latestTsKeyNames": [],
  107 + "tellFailureIfAbsent": false,
  108 + "getLatestValueWithTs": false
  109 + }
  110 + }
  111 + ],
  112 + "connections": [
  113 + {
  114 + "fromIndex": 4,
  115 + "toIndex": 0,
  116 + "type": "NewTempAlarm"
  117 + },
  118 + {
  119 + "fromIndex": 4,
  120 + "toIndex": 1,
  121 + "type": "ClearTempAlarm"
  122 + },
  123 + {
  124 + "fromIndex": 4,
  125 + "toIndex": 2,
  126 + "type": "NewHumidityAlarm"
  127 + },
  128 + {
  129 + "fromIndex": 4,
  130 + "toIndex": 3,
  131 + "type": "ClearHumidityAlarm"
  132 + },
  133 + {
  134 + "fromIndex": 5,
  135 + "toIndex": 4,
  136 + "type": "Success"
  137 + }
  138 + ],
  139 + "ruleChainConnections": null
  140 + }
  141 +}
\ No newline at end of file
... ...
... ... @@ -6,7 +6,7 @@
6 6 },
7 7 "widgetTypes": [
8 8 {
9   - "alias": "device_admin_table2",
  9 + "alias": "device_admin_table",
10 10 "name": "Device admin table",
11 11 "descriptor": {
12 12 "type": "latest",
... ... @@ -22,7 +22,7 @@
22 22 }
23 23 },
24 24 {
25   - "alias": "device_admin_table",
  25 + "alias": "asset_admin_table",
26 26 "name": "Asset admin table",
27 27 "descriptor": {
28 28 "type": "latest",
... ...
... ... @@ -6,6 +6,38 @@
6 6 },
7 7 "widgetTypes": [
8 8 {
  9 + "alias": "attributes_card",
  10 + "name": "Gateway events",
  11 + "descriptor": {
  12 + "type": "latest",
  13 + "sizeX": 7.5,
  14 + "sizeY": 8,
  15 + "resources": [],
  16 + "templateHtml": "",
  17 + "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
  18 + "controllerScript": "let types;\nlet eventsReg = \"eventsReg\";\n\nself.onInit = function() {\n \n self.ctx.datasourceTitleCells = [];\n self.ctx.valueCells = [];\n self.ctx.labelCells = [];\n types = self.ctx.$scope.$injector.get('types');\n \n if (self.ctx.datasources.length && self.ctx.datasources[0].type === types.datasourceType.entity) {\n getDatasourceKeys(self.ctx.datasources[0]);\n } else {\n processDatasources(self.ctx.datasources);\n }\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.valueCells.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData && cellData.data && cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n var textValue;\n //toDo -> + IsNumber\n \n if (isNumber(value)) {\n var decimals = self.ctx.decimals;\n var units = self.ctx.units;\n if (cellData.dataKey.decimals || cellData.dataKey.decimals === 0) {\n decimals = cellData.dataKey.decimals;\n }\n if (cellData.dataKey.units) {\n units = cellData.dataKey.units;\n }\n txtValue = self.ctx.utils.formatValue(value, decimals, units, false);\n }\n else {\n txtValue = value;\n }\n self.ctx.valueCells[i].html(txtValue);\n }\n }\n \n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n}\n\nself.onResize = function() {\n var datasourceTitleFontSize = self.ctx.height/8;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n datasourceTitleFontSize = self.ctx.width/12;\n }\n datasourceTitleFontSize = Math.min(datasourceTitleFontSize, 20);\n for (var i = 0; i < self.ctx.datasourceTitleCells.length; i++) {\n self.ctx.datasourceTitleCells[i].css('font-size', datasourceTitleFontSize+'px');\n }\n var valueFontSize = self.ctx.height/9;\n var labelFontSize = self.ctx.height/9;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n valueFontSize = self.ctx.width/15;\n labelFontSize = self.ctx.width/15;\n }\n valueFontSize = Math.min(valueFontSize, 18);\n labelFontSize = Math.min(labelFontSize, 18);\n\n for (i = 0; i < self.ctx.valueCells; i++) {\n self.ctx.valueCells[i].css('font-size', valueFontSize+'px');\n self.ctx.valueCells[i].css('height', valueFontSize*2.5+'px');\n self.ctx.valueCells[i].css('padding', '0px ' + valueFontSize + 'px');\n self.ctx.labelCells[i].css('font-size', labelFontSize+'px');\n self.ctx.labelCells[i].css('height', labelFontSize*2.5+'px');\n self.ctx.labelCells[i].css('padding', '0px ' + labelFontSize + 'px');\n } \n}\n\nfunction processDatasources(datasources) {\n var i = 0;\n var tbDatasource = datasources[i];\n var datasourceId = 'tbDatasource' + i;\n self.ctx.$container.append(\n \"<div id='\" + datasourceId +\n \"' class='tbDatasource-container'></div>\"\n );\n\n var datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n\n datasourceContainer.append(\n \"<div class='tbDatasource-title'>\" +\n tbDatasource.name + \"</div>\"\n );\n \n var datasourceTitleCell = $('.tbDatasource-title', datasourceContainer);\n self.ctx.datasourceTitleCells.push(datasourceTitleCell);\n \n var tableId = 'table' + i;\n datasourceContainer.append(\n \"<table id='\" + tableId +\n \"' class='tbDatasource-table'><col width='30%'><col width='70%'></table>\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n\n for (var a = 0; a < tbDatasource.dataKeys.length; a++) {\n var dataKey = tbDatasource.dataKeys[a];\n var labelCellId = 'labelCell' + a;\n var cellId = 'cell' + a;\n table.append(\"<tr><td id='\" + labelCellId + \"'>\" + dataKey.label +\n \"</td><td id='\" + cellId +\n \"'></td></tr>\");\n var labelCell = $('#' + labelCellId, table);\n self.ctx.labelCells.push(labelCell);\n var valueCell = $('#' + cellId, table);\n self.ctx.valueCells.push(valueCell);\n }\n self.onResize();\n}\n\nfunction getDatasourceKeys (datasource) {\n let attributeService = self.ctx.$scope.$injector.get('attributeService');\n if (datasource.entityId && datasource.entityType) {\n attributeService.getEntityKeys(datasource.entityType, datasource.entityId, \"\" , types.dataKeyType.timeseries).then(\n function(data){\n if (data.length) {\n subscribeForKeys (datasource, data);\n }\n });\n }\n}\n\nfunction subscribeForKeys (datasource, data) {\n let eventsRegVals = self.ctx.settings[eventsReg];\n if (eventsRegVals && eventsRegVals.length > 0) {\n var dataKeys = [];\n data.sort();\n data.forEach(dataValue => {eventsRegVals.forEach(event => {\n if (dataValue.toLowerCase().includes(event.toLowerCase())) {\n var dataKey = {\n type: types.dataKeyType.timeseries,\n name: dataValue,\n label: dataValue,\n settings: {},\n _hash: Math.random()\n };\n dataKeys.push(dataKey);\n }\n })});\n\n if (dataKeys.length) {\n updateSubscription (datasource, dataKeys);\n }\n }\n}\n\nfunction updateSubscription (datasource, dataKeys) {\n var datasources = [\n {\n type: types.datasourceType.entity,\n name: datasource.aliasName,\n aliasName: datasource.aliasName,\n entityAliasId: datasource.entityAliasId,\n dataKeys: dataKeys\n }\n ];\n \n var subscriptionOptions = {\n datasources: datasources,\n useDashboardTimewindow: false,\n type: types.widgetType.latest.value,\n callbacks: {\n onDataUpdated: (subscription) => {\n self.ctx.data = subscription.data;\n self.onDataUpdated();\n }\n }\n };\n \n processDatasources(datasources);\n self.ctx.subscriptionApi.createSubscription(subscriptionOptions, true).then(\n (subscription) => {\n self.ctx.defaultSubscription = subscription;\n }\n );\n}\n\nself.onDestroy = function() {\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\t\n dataKeysOptional: true\n };\n}\n\n",
  19 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"GatewayEventsForm\",\n \"properties\": {\n \"eventsTitle\": {\n \"title\": \"Gateway events form title\",\n \"type\": \"string\",\n \"default\": \"Gateway Events Form\"\n },\n \"eventsReg\": {\n \"title\": \"Events filten.\",\n \"type\": \"array\",\n \"items\": {\n \"title\": \"Event key contains\",\n \"type\": \"string\"\n }\n }\n }\n },\n \"form\": [\n \"eventsTitle\",\n \"eventsReg\"\n ]\n}",
  20 + "dataKeySettingsSchema": "{}\n",
  21 + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Function Math.round\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.826503672916844,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"eventsTitle\":\"Gateway Events Form\",\"eventsReg\":[]},\"title\":\"Gateway events\",\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
  22 + }
  23 + },
  24 + {
  25 + "alias": "config_form_latest",
  26 + "name": "Gateway configuration (Single device)",
  27 + "descriptor": {
  28 + "type": "latest",
  29 + "sizeX": 7.5,
  30 + "sizeY": 9,
  31 + "resources": [],
  32 + "templateHtml": "<tb-gateway-form\n form-id=\"formId\"\n ctx=\"ctx\"\n is-state-form=\"isStateForm\">\n</tb-gateway-form>",
  33 + "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
  34 + "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.formId = \"form-\"+id;\n scope.ctx = self.ctx;\n scope.isStateForm = true;\n}\n\nself.onResize = function() {\n self.ctx.$scope.$broadcast('gateway-form-resize', self.ctx.$scope.formId);\n}\n\n\nself.onDestroy = function() {\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\t\t\t\n dataKeysOptional: true\t\t\n };\n}\n\n",
  35 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"GatewayConfigForm\",\n \"properties\": {\n \"gatewayTitle\": {\n \"title\": \"Gateway form\",\n \"type\": \"string\",\n \"default\": \"Gateway configuration (Single device)\"\n },\n \"readOnly\": {\n \"title\": \"Read Only\",\n \"type\": \"boolean\",\n \"default\": false\n }\n }\n },\n \"form\": [\n \"gatewayTitle\",\n \"readOnly\"\n ]\n}\n",
  36 + "dataKeySettingsSchema": "{}\n",
  37 + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Gateway configuration (Single device)\"}"
  38 + }
  39 + },
  40 + {
9 41 "alias": "extension_configuration_widget",
10 42 "name": "Extensions table",
11 43 "descriptor": {
... ... @@ -20,6 +52,22 @@
20 52 "dataKeySettingsSchema": "{}\n",
21 53 "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{},\"title\":\"Extensions table\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"18px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
22 54 }
  55 + },
  56 + {
  57 + "alias": "gateway_configuration",
  58 + "name": "Gateway Configuration",
  59 + "descriptor": {
  60 + "type": "static",
  61 + "sizeX": 8,
  62 + "sizeY": 6.5,
  63 + "resources": [],
  64 + "templateHtml": "<tb-gateway-form\n form-id=\"formId\"\n ctx=\"ctx\">\n</tb-gateway-form>\n",
  65 + "templateCss": "",
  66 + "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.formId = \"form-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n self.ctx.$scope.$broadcast('gateway-form-resize', self.ctx.$scope.formId);\n}\n",
  67 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"Gateway Configuration\"\n },\n \"archiveFileName\": {\n \"title\": \"Default archive file name\",\n \"type\": \"string\",\n \"default\": \"gatewayConfiguration\"\n },\n \"gatewayType\": {\n \"title\": \"Device type for new gateway\",\n \"type\": \"string\",\n \"default\": \"Gateway\"\n },\n \"successfulSave\": {\n \"title\": \"Text message about successfully saved gateway configuration\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"gatewayNameExists\": {\n \"title\": \"Text message when device with entered name is already exists\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n [\n \"widgetTitle\",\n \"archiveFileName\",\n \"gatewayType\"\n ],\n [\n \"successfulSave\",\n \"gatewayNameExists\"\n ]\n ],\n \"groupInfoes\": [{\n \"formIndex\": 0,\n \"GroupTitle\": \"General settings\"\n }, {\n \"formIndex\": 1,\n \"GroupTitle\": \"Messages settings\"\n }]\n}",
  68 + "dataKeySettingsSchema": "{}\n",
  69 + "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetTitle\":\"Gateway Configuration\",\"archiveFileName\":\"configurationGateway\"},\"title\":\"Gateway Configuration\",\"dropShadow\":true,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
  70 + }
23 71 }
24 72 ]
25   -}
\ No newline at end of file
  73 +}
... ...
... ... @@ -330,13 +330,13 @@
330 330 "name": "Web Camera Input",
331 331 "descriptor": {
332 332 "type": "latest",
333   - "sizeX": 9.5,
334   - "sizeY": 6.5,
  333 + "sizeX": 7.5,
  334 + "sizeY": 3,
335 335 "resources": [],
336 336 "templateHtml": "<tb-web-camera-widget ctx=\"ctx\">\n</tb-web-camera-widget>",
337   - "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
  337 + "templateCss": "",
338 338 "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n}\n",
339   - "settingsSchema": "{}",
  339 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Web Camera\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"imageFormat\": {\n \"title\": \"Image Format\",\n \"type\": \"string\",\n \"default\": \"image/png\"\n },\n \"imageQuality\":{\n \"title\":\"Image quality that use lossy compression such as jpeg and webp\",\n \"type\":\"number\",\n \"default\": 0.92,\n \"min\": 0,\n \"max\": 1\n },\n \"maxWidth\": {\n \"title\": \"The maximal image width\",\n \"type\": \"number\",\n \"default\": 640\n }, \n \"maxHeight\": {\n \"title\": \"The maximal image heigth\",\n \"type\": \"number\",\n \"default\": 480\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n {\n \"key\": \"imageFormat\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"image/jpeg\",\n \"label\": \"JPEG\"\n },\n {\n \"value\": \"image/png\",\n \"label\": \"PNG\"\n },\n {\n \"value\": \"image/webp\",\n \"label\": \"WEBP\"\n }\n ]\n },\n \"imageQuality\",\n \"maxWidth\",\n \"maxHeight\"\n ]\n}",
340 340 "dataKeySettingsSchema": "{}\n",
341 341 "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Web Camera Input\",\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
342 342 }
... ...
... ... @@ -128,10 +128,10 @@
128 128 "templateHtml": "<trip-animation self=\"self\" ctx=\"self.ctx\" ></trip-animation>",
129 129 "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
130 130 "controllerScript": " self.onInit = function() {\n var $scope = self.ctx.$scope;\n $scope.self = self;\n }\n \n \n self.actionSources = function () {\n return {\n 'tooltipAction': {\n name: 'widget-action.tooltip-tag-action',\n multiple: false\n }\n }\n };\n",
131   - "settingsSchema": "{\n \"schema\": {\n \"title\": \"Openstreet Map Configuration\",\n \"type\": \"object\",\n \"properties\": {\n \"mapProvider\": {\n \"title\": \"Map provider\",\n \"type\": \"string\",\n \"default\": \"OpenStreetMap.Mapnik\"\n },\n \"normalizationStep\": {\n \"title\": \"Normalization data step (ms)\",\n \"type\": \"number\",\n \"default\": 1000\n },\n \"latKeyName\": {\n \"title\": \"Latitude key name\",\n \"type\": \"string\",\n \"default\": \"latitude\"\n },\n \"lngKeyName\": {\n \"title\": \"Longitude key name\",\n \"type\": \"string\",\n \"default\": \"longitude\"\n },\n \"polKeyName\": {\n \"title\": \"Polygon key name\",\n \"type\": \"string\",\n \"default\": \"coordinates\"\n },\n \"showLabel\": {\n \"title\": \"Show label\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"label\": {\n \"title\": \"Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useLabelFunction\": {\n \"title\": \"Use label function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"labelFunction\": {\n \"title\": \"Label function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"showTooltip\": {\n \"title\": \"Show tooltip\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"tooltipColor\": {\n \"title\": \"Tooltip background color\",\n \"type\": \"string\",\n \"default\": \"#fff\"\n },\n \"tooltipFontColor\": {\n \"title\": \"Tooltip font color\",\n \"type\": \"string\",\n \"default\": \"#000\"\n },\n \"tooltipOpacity\": {\n \"title\": \"Tooltip opacity (0-1)\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"tooltipPattern\": {\n \"title\": \"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')\",\n \"type\": \"string\",\n \"default\": \"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}\"\n },\n \"useTooltipFunction\": {\n \"title\": \"Use tooltip function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"tooltipFunction\": {\n \"title\": \"Tooltip function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"color\": {\n \"title\": \"Path color\",\n \"type\": \"string\"\n },\n \"strokeWeight\": {\n \"title\": \"Stroke weight\",\n \"type\": \"number\",\n \"default\": 2\n },\n \"strokeOpacity\": {\n \"title\": \"Stroke opacity\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"useColorFunction\": {\n \"title\": \"Use path color function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"colorFunction\": {\n \"title\": \"Path color function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"usePolylineDecorator\": {\n \"title\": \"Use path decorator\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"decoratorSymbol\": {\n \"title\": \"Decorator symbol\",\n \"type\": \"string\",\n \"default\": \"arrowHead\"\n },\n \"decoratorSymbolSize\": {\n \"title\": \"Decorator symbol size (px)\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"useDecoratorCustomColor\": {\n \"title\": \"Use path decorator custom color\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"decoratorCustomColor\": {\n \"title\": \"Decorator custom color\",\n \"type\": \"string\",\n \"default\": \"#000\"\n },\n \"decoratorOffset\": {\n \"title\": \"Decorator offset\",\n \"type\": \"string\",\n \"default\": \"20px\"\n },\n \"endDecoratorOffset\": {\n \"title\": \"End decorator offset\",\n \"type\": \"string\",\n \"default\": \"20px\"\n },\n \"decoratorRepeat\": {\n \"title\": \"Decorator repeat\",\n \"type\": \"string\",\n \"default\": \"20px\"\n },\n \"showPolygon\": {\n \"title\": \"Show polygon\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"polygonTooltipPattern\": {\n \"title\": \"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')\",\n \"type\": \"string\",\n \"default\": \"<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}\"\n },\n \"usePolygonTooltipFunction\": {\n \"title\": \"Use polygon tooltip function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"polygonTooltipFunction\": {\n \"title\": \"Polygon tooltip function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"polygonColor\": {\n \"title\": \"Polygon color\",\n \"type\": \"string\"\n },\n \"polygonOpacity\": {\n \"title\": \"Polygon opacity\",\n \"type\": \"number\",\n \"default\": 0.5\n },\n \"polygonStrokeColor\": {\n \"title\": \"Polygon border color\",\n \"type\": \"string\"\n },\n \"polygonStrokeOpacity\": {\n \"title\": \"Polygon border opacity\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"polygonStrokeWeight\": {\n \"title\": \"Polygon border weight\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"usePolygonColorFunction\": {\n \"title\": \"Use polygon color function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"polygonColorFunction\": {\n \"title\": \"Polygon Color function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"showPoints\": {\n \"title\": \"Show points\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"pointColor\": {\n \"title\": \"Point color\",\n \"type\": \"string\"\n },\n \"pointSize\": {\n \"title\": \"Point size (px)\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"usePointAsAnchor\": {\n \"title\": \"Use point as anchor\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"pointAsAnchorFunction\": {\n \"title\": \"Point as anchor function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"pointTooltipOnRightPanel\": {\n \"title\": \"Independant point tooltip\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"autocloseTooltip\": {\n \"title\": \"Auto-close point popup\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultMarkerColor\": {\n \"title\": \"color for default marker\",\n \"type\": \"string\"\n },\n \"markerImage\": {\n \"title\": \"Custom marker image\",\n \"type\": \"string\"\n },\n \"markerImageSize\": {\n \"title\": \"Custom marker image size (px)\",\n \"type\": \"number\",\n \"default\": 34\n },\n \"rotationAngle\": {\n \"title\": \"Set additional rotation angle for marker (deg)\",\n \"type\": \"number\",\n \"default\": 180\n },\n \"useMarkerImageFunction\":{\n \"title\":\"Use marker image function\",\n \"type\":\"boolean\",\n \"default\":false\n },\n \"markerImageFunction\":{\n \"title\":\"Marker image function: f(data, images, dsData, dsIndex)\",\n \"type\":\"string\"\n },\n \"markerImages\":{\n \"title\":\"Marker images\",\n \"type\":\"array\",\n \"items\":{\n \"title\":\"Marker image\",\n \"type\":\"string\"\n }\n }\n },\n \"required\": []\n },\n \"form\": [{\n \"key\": \"mapProvider\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [{\n \"value\": \"OpenStreetMap.Mapnik\",\n \"label\": \"OpenStreetMap.Mapnik (Default)\"\n }, {\n \"value\": \"OpenStreetMap.BlackAndWhite\",\n \"label\": \"OpenStreetMap.BlackAndWhite\"\n }, {\n \"value\": \"OpenStreetMap.HOT\",\n \"label\": \"OpenStreetMap.HOT\"\n }, {\n \"value\": \"Esri.WorldStreetMap\",\n \"label\": \"Esri.WorldStreetMap\"\n }, {\n \"value\": \"Esri.WorldTopoMap\",\n \"label\": \"Esri.WorldTopoMap\"\n }, {\n \"value\": \"CartoDB.Positron\",\n \"label\": \"CartoDB.Positron\"\n }, {\n \"value\": \"CartoDB.DarkMatter\",\n \"label\": \"CartoDB.DarkMatter\"\n }]\n }, \"normalizationStep\", \"latKeyName\", \"lngKeyName\", \"polKeyName\", \"showLabel\", \"label\", \"useLabelFunction\", {\n \"key\": \"labelFunction\",\n \"type\": \"javascript\"\n }, \"showTooltip\", {\n \"key\": \"tooltipColor\",\n \"type\": \"color\"\n }, {\n \"key\": \"tooltipFontColor\",\n \"type\": \"color\"\n },\"tooltipOpacity\", {\n \"key\": \"tooltipPattern\",\n \"type\": \"textarea\"\n }, \"useTooltipFunction\", {\n \"key\": \"tooltipFunction\",\n \"type\": \"javascript\"\n }, {\n \"key\": \"color\",\n \"type\": \"color\"\n }, \"useColorFunction\", {\n \"key\": \"colorFunction\",\n \"type\": \"javascript\"\n }, \"usePolylineDecorator\", {\n \"key\": \"decoratorSymbol\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [{\n \"value\": \"arrowHead\",\n \"label\": \"Arrow\"\n }, {\n \"value\": \"dash\",\n \"label\": \"Dash\"\n }]\n }, \"decoratorSymbolSize\", \"useDecoratorCustomColor\", {\n \"key\": \"decoratorCustomColor\",\n \"type\": \"color\"\n }, {\n \"key\": \"decoratorOffset\",\n \"type\": \"textarea\"\n },{\n \"key\": \"endDecoratorOffset\",\n \"type\": \"textarea\"\n }, {\n \"key\": \"decoratorRepeat\",\n \"type\": \"textarea\"\n }, \"strokeWeight\", \"strokeOpacity\", \"showPolygon\", {\n \"key\": \"polygonTooltipPattern\",\n \"type\": \"textarea\"\n },\"usePolygonTooltipFunction\", {\n \"key\": \"polygonTooltipFunction\",\n \"type\": \"javascript\"\n },{\n \"key\": \"polygonColor\",\n \"type\": \"color\"\n },\t\"polygonOpacity\", {\n \"key\": \"polygonStrokeColor\",\n \"type\": \"color\"\n },\t\"polygonStrokeOpacity\",\"polygonStrokeWeight\",\"usePolygonColorFunction\",\t{\n \"key\": \"polygonColorFunction\",\n \"type\": \"javascript\"\n },\"showPoints\",{\n \"key\": \"pointColor\",\n \"type\": \"color\"\n }, \"pointSize\",\"usePointAsAnchor\", {\n \"key\": \"pointAsAnchorFunction\",\n \"type\": \"javascript\"\n },\"pointTooltipOnRightPanel\", \"autocloseTooltip\", {\n \"key\": \"defaultMarkerColor\",\n \"type\": \"color\"\n }, {\n \"key\": \"markerImage\",\n \"type\": \"image\"\n }, \"markerImageSize\", \"rotationAngle\",\"useMarkerImageFunction\",\n {\n \"key\":\"markerImageFunction\",\n \"type\":\"javascript\"\n }, {\n \"key\":\"markerImages\",\n \"items\":[\n {\n \"key\":\"markerImages[]\",\n \"type\":\"image\"\n }\n ]\n }]\n}",
  131 + "settingsSchema": "{\n \"schema\": {\n \"title\": \"Openstreet Map Configuration\",\n \"type\": \"object\",\n \"properties\": {\n \"mapProvider\": {\n \"title\": \"Map provider\",\n \"type\": \"string\",\n \"default\": \"OpenStreetMap.Mapnik\"\n },\n \"normalizationStep\": {\n \"title\": \"Normalization data step (ms)\",\n \"type\": \"number\",\n \"default\": 1000\n },\n \"latKeyName\": {\n \"title\": \"Latitude key name\",\n \"type\": \"string\",\n \"default\": \"latitude\"\n },\n \"lngKeyName\": {\n \"title\": \"Longitude key name\",\n \"type\": \"string\",\n \"default\": \"longitude\"\n },\n \"polKeyName\": {\n \"title\": \"Polygon key name\",\n \"type\": \"string\",\n \"default\": \"coordinates\"\n },\n \"showLabel\": {\n \"title\": \"Show label\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"label\": {\n \"title\": \"Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useLabelFunction\": {\n \"title\": \"Use label function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"labelFunction\": {\n \"title\": \"Label function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"showTooltip\": {\n \"title\": \"Show tooltip\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"tooltipColor\": {\n \"title\": \"Tooltip background color\",\n \"type\": \"string\",\n \"default\": \"#fff\"\n },\n \"tooltipFontColor\": {\n \"title\": \"Tooltip font color\",\n \"type\": \"string\",\n \"default\": \"#000\"\n },\n \"tooltipOpacity\": {\n \"title\": \"Tooltip opacity (0-1)\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"tooltipPattern\": {\n \"title\": \"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')\",\n \"type\": \"string\",\n \"default\": \"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}\"\n },\n \"useTooltipFunction\": {\n \"title\": \"Use tooltip function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"tooltipFunction\": {\n \"title\": \"Tooltip function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"color\": {\n \"title\": \"Path color\",\n \"type\": \"string\"\n },\n \"strokeWeight\": {\n \"title\": \"Stroke weight\",\n \"type\": \"number\",\n \"default\": 2\n },\n \"strokeOpacity\": {\n \"title\": \"Stroke opacity\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"useColorFunction\": {\n \"title\": \"Use path color function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"colorFunction\": {\n \"title\": \"Path color function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"usePolylineDecorator\": {\n \"title\": \"Use path decorator\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"decoratorSymbol\": {\n \"title\": \"Decorator symbol\",\n \"type\": \"string\",\n \"default\": \"arrowHead\"\n },\n \"decoratorSymbolSize\": {\n \"title\": \"Decorator symbol size (px)\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"useDecoratorCustomColor\": {\n \"title\": \"Use path decorator custom color\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"decoratorCustomColor\": {\n \"title\": \"Decorator custom color\",\n \"type\": \"string\",\n \"default\": \"#000\"\n },\n \"decoratorOffset\": {\n \"title\": \"Decorator offset\",\n \"type\": \"string\",\n \"default\": \"20px\"\n },\n \"endDecoratorOffset\": {\n \"title\": \"End decorator offset\",\n \"type\": \"string\",\n \"default\": \"20px\"\n },\n \"decoratorRepeat\": {\n \"title\": \"Decorator repeat\",\n \"type\": \"string\",\n \"default\": \"20px\"\n },\n \"showPolygon\": {\n \"title\": \"Show polygon\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"polygonTooltipPattern\": {\n \"title\": \"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')\",\n \"type\": \"string\",\n \"default\": \"<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}\"\n },\n \"usePolygonTooltipFunction\": {\n \"title\": \"Use polygon tooltip function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"polygonTooltipFunction\": {\n \"title\": \"Polygon tooltip function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"polygonColor\": {\n \"title\": \"Polygon color\",\n \"type\": \"string\"\n },\n \"polygonOpacity\": {\n \"title\": \"Polygon opacity\",\n \"type\": \"number\",\n \"default\": 0.5\n },\n \"polygonStrokeColor\": {\n \"title\": \"Polygon border color\",\n \"type\": \"string\"\n },\n \"polygonStrokeOpacity\": {\n \"title\": \"Polygon border opacity\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"polygonStrokeWeight\": {\n \"title\": \"Polygon border weight\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"usePolygonColorFunction\": {\n \"title\": \"Use polygon color function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"polygonColorFunction\": {\n \"title\": \"Polygon Color function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"showPoints\": {\n \"title\": \"Show points\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"pointColor\": {\n \"title\": \"Point color\",\n \"type\": \"string\"\n },\n \"pointSize\": {\n \"title\": \"Point size (px)\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"usePointAsAnchor\": {\n \"title\": \"Use point as anchor\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"pointAsAnchorFunction\": {\n \"title\": \"Point as anchor function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"pointTooltipOnRightPanel\": {\n \"title\": \"Independant point tooltip\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"autocloseTooltip\": {\n \"title\": \"Auto-close point popup\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"markerImage\": {\n \"title\": \"Custom marker image\",\n \"type\": \"string\"\n },\n \"markerImageSize\": {\n \"title\": \"Custom marker image size (px)\",\n \"type\": \"number\",\n \"default\": 34\n },\n \"rotationAngle\": {\n \"title\": \"Set additional rotation angle for marker (deg)\",\n \"type\": \"number\",\n \"default\": 180\n },\n \"useMarkerImageFunction\":{\n \"title\":\"Use marker image function\",\n \"type\":\"boolean\",\n \"default\":false\n },\n \"markerImageFunction\":{\n \"title\":\"Marker image function: f(data, images, dsData, dsIndex)\",\n \"type\":\"string\"\n },\n \"markerImages\":{\n \"title\":\"Marker images\",\n \"type\":\"array\",\n \"items\":{\n \"title\":\"Marker image\",\n \"type\":\"string\"\n }\n }\n },\n \"required\": []\n },\n \"form\": [{\n \"key\": \"mapProvider\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [{\n \"value\": \"OpenStreetMap.Mapnik\",\n \"label\": \"OpenStreetMap.Mapnik (Default)\"\n }, {\n \"value\": \"OpenStreetMap.BlackAndWhite\",\n \"label\": \"OpenStreetMap.BlackAndWhite\"\n }, {\n \"value\": \"OpenStreetMap.HOT\",\n \"label\": \"OpenStreetMap.HOT\"\n }, {\n \"value\": \"Esri.WorldStreetMap\",\n \"label\": \"Esri.WorldStreetMap\"\n }, {\n \"value\": \"Esri.WorldTopoMap\",\n \"label\": \"Esri.WorldTopoMap\"\n }, {\n \"value\": \"CartoDB.Positron\",\n \"label\": \"CartoDB.Positron\"\n }, {\n \"value\": \"CartoDB.DarkMatter\",\n \"label\": \"CartoDB.DarkMatter\"\n }]\n }, \"normalizationStep\", \"latKeyName\", \"lngKeyName\", \"polKeyName\", \"showLabel\", \"label\", \"useLabelFunction\", {\n \"key\": \"labelFunction\",\n \"type\": \"javascript\"\n }, \"showTooltip\", {\n \"key\": \"tooltipColor\",\n \"type\": \"color\"\n }, {\n \"key\": \"tooltipFontColor\",\n \"type\": \"color\"\n },\"tooltipOpacity\", {\n \"key\": \"tooltipPattern\",\n \"type\": \"textarea\"\n }, \"useTooltipFunction\", {\n \"key\": \"tooltipFunction\",\n \"type\": \"javascript\"\n }, {\n \"key\": \"color\",\n \"type\": \"color\"\n }, \"useColorFunction\", {\n \"key\": \"colorFunction\",\n \"type\": \"javascript\"\n }, \"usePolylineDecorator\", {\n \"key\": \"decoratorSymbol\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [{\n \"value\": \"arrowHead\",\n \"label\": \"Arrow\"\n }, {\n \"value\": \"dash\",\n \"label\": \"Dash\"\n }]\n }, \"decoratorSymbolSize\", \"useDecoratorCustomColor\", {\n \"key\": \"decoratorCustomColor\",\n \"type\": \"color\"\n }, {\n \"key\": \"decoratorOffset\",\n \"type\": \"textarea\"\n },{\n \"key\": \"endDecoratorOffset\",\n \"type\": \"textarea\"\n }, {\n \"key\": \"decoratorRepeat\",\n \"type\": \"textarea\"\n }, \"strokeWeight\", \"strokeOpacity\", \"showPolygon\", {\n \"key\": \"polygonTooltipPattern\",\n \"type\": \"textarea\"\n },\"usePolygonTooltipFunction\", {\n \"key\": \"polygonTooltipFunction\",\n \"type\": \"javascript\"\n },{\n \"key\": \"polygonColor\",\n \"type\": \"color\"\n },\t\"polygonOpacity\", {\n \"key\": \"polygonStrokeColor\",\n \"type\": \"color\"\n },\t\"polygonStrokeOpacity\",\"polygonStrokeWeight\",\"usePolygonColorFunction\",\t{\n \"key\": \"polygonColorFunction\",\n \"type\": \"javascript\"\n },\"showPoints\",{\n \"key\": \"pointColor\",\n \"type\": \"color\"\n }, \"pointSize\",\"usePointAsAnchor\", {\n \"key\": \"pointAsAnchorFunction\",\n \"type\": \"javascript\"\n },\"pointTooltipOnRightPanel\", \"autocloseTooltip\", {\n \"key\": \"markerImage\",\n \"type\": \"image\"\n }, \"markerImageSize\", \"rotationAngle\",\"useMarkerImageFunction\",\n {\n \"key\":\"markerImageFunction\",\n \"type\":\"javascript\"\n }, {\n \"key\":\"markerImages\",\n \"items\":[\n {\n \"key\":\"markerImages[]\",\n \"type\":\"image\"\n }\n ]\n }]\n}",
132 132 "dataKeySettingsSchema": "{}",
133 133 "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var gpsData = [\\n\\t37.771210000,-122.510960000,\\n\\t37.771340000,-122.510980000,\\n\\t37.771340000,-122.510980000,\\n\\t37.771360000,-122.510850000,\\n\\t37.771380000,-122.510550000,\\n\\t37.771400000,-122.509900000,\\n\\t37.771410000,-122.509660000,\\n\\t37.771430000,-122.509360000,\\n\\t37.771430000,-122.509270000,\\n\\t37.771450000,-122.508840000,\\n\\t37.771490000,-122.507880000,\\n\\t37.771490000,-122.507780000,\\n\\t37.771530000,-122.507140000,\\n\\t37.771550000,-122.506690000,\\n\\t37.771560000,-122.506310000,\\n\\t37.771600000,-122.505640000,\\n\\t37.771650000,-122.504540000,\\n\\t37.771670000,-122.503990000,\\n\\t37.771700000,-122.503490000,\\n\\t37.771740000,-122.502430000,\\n\\t37.771790000,-122.501360000,\\n\\t37.771840000,-122.500290000,\\n\\t37.771870000,-122.499730000,\\n\\t37.771890000,-122.499210000,\\n\\t37.771940000,-122.498140000,\\n\\t37.771990000,-122.497070000,\\n\\t37.772000000,-122.496690000,\\n\\t37.772020000,-122.496350000,\\n\\t37.772030000,-122.496110000,\\n\\t37.772040000,-122.496000000,\\n\\t37.772040000,-122.495890000,\\n\\t37.772060000,-122.495440000,\\n\\t37.772090000,-122.494930000,\\n\\t37.772120000,-122.494160000,\\n\\t37.772130000,-122.493860000,\\n\\t37.772180000,-122.492790000,\\n\\t37.772200000,-122.492300000,\\n\\t37.772220000,-122.491840000,\\n\\t37.772230000,-122.491710000,\\n\\t37.772280000,-122.490630000,\\n\\t37.772330000,-122.489560000,\\n\\t37.772330000,-122.489470000,\\n\\t37.772360000,-122.489030000,\\n\\t37.772380000,-122.488490000,\\n\\t37.772430000,-122.487420000,\\n\\t37.772450000,-122.486980000,\\n\\t37.772480000,-122.486360000,\\n\\t37.772520000,-122.485280000,\\n\\t37.772560000,-122.484400000,\\n\\t37.772570000,-122.484300000,\\n\\t37.772570000,-122.484150000,\\n\\t37.772620000,-122.483140000,\\n\\t37.772680000,-122.482050000,\\n\\t37.772700000,-122.481370000,\\n\\t37.772710000,-122.481000000,\\n\\t37.772730000,-122.480740000,\\n\\t37.772770000,-122.479930000,\\n\\t37.772820000,-122.478860000,\\n\\t37.772870000,-122.477790000,\\n\\t37.772900000,-122.477110000,\\n\\t37.772920000,-122.476710000,\\n\\t37.772960000,-122.475650000,\\n\\t37.772990000,-122.474950000,\\n\\t37.773010000,-122.474580000,\\n\\t37.773060000,-122.473450000,\\n\\t37.773120000,-122.472330000,\\n\\t37.773140000,-122.471850000,\\n\\t37.773140000,-122.471730000,\\n\\t37.773150000,-122.471640000,\\n\\t37.773170000,-122.471260000,\\n\\t37.773190000,-122.470570000,\\n\\t37.773210000,-122.470190000,\\n\\t37.773230000,-122.469770000,\\n\\t37.773250000,-122.469370000,\\n\\t37.773260000,-122.469120000,\\n\\t37.773290000,-122.468490000,\\n\\t37.773300000,-122.468150000,\\n\\t37.773310000,-122.468050000,\\n\\t37.773310000,-122.467940000,\\n\\t37.773320000,-122.467740000,\\n\\t37.773350000,-122.467270000,\\n\\t37.773360000,-122.466980000,\\n\\t37.773360000,-122.466870000,\\n\\t37.773370000,-122.466610000,\\n\\t37.773390000,-122.466300000,\\n\\t37.773400000,-122.466000000,\\n\\t37.773400000,-122.465910000,\\n\\t37.773410000,-122.465790000,\\n\\t37.773430000,-122.465520000,\\n\\t37.773460000,-122.465210000,\\n\\t37.773490000,-122.464980000,\\n\\t37.773500000,-122.464910000,\\n\\t37.773460000,-122.464830000,\\n\\t37.773560000,-122.464070000,\\n\\t37.773580000,-122.463900000,\\n\\t37.773590000,-122.463810000,\\n\\t37.773600000,-122.463780000,\\n\\t37.773610000,-122.463670000,\\n\\t37.773660000,-122.463320000,\\n\\t37.773740000,-122.462700000,\\n\\t37.773770000,-122.462440000,\\n\\t37.773860000,-122.461730000,\\n\\t37.773870000,-122.461640000,\\n\\t37.773920000,-122.461260000,\\n\\t37.773970000,-122.460890000,\\n\\t37.774010000,-122.460570000,\\n\\t37.774110000,-122.459760000,\\n\\t37.774140000,-122.459490000,\\n\\t37.774270000,-122.458520000,\\n\\t37.774270000,-122.458440000,\\n\\t37.774270000,-122.458380000,\\n\\t37.774320000,-122.458270000,\\n\\t37.774340000,-122.458050000,\\n\\t37.774510000,-122.456680000,\\n\\t37.774560000,-122.456310000,\\n\\t37.774700000,-122.455280000,\\n\\t37.774760000,-122.454780000,\\n\\t37.774770000,-122.454670000,\\n\\t37.774770000,-122.454670000,\\n\\t37.774670000,-122.454650000,\\n\\t37.774670000,-122.454650000,\\n\\t37.774580000,-122.454640000,\\n\\t37.774300000,-122.454580000,\\n\\t37.774190000,-122.454560000,\\n\\t37.773700000,-122.454460000,\\n\\t37.772910000,-122.454310000,\\n\\t37.772620000,-122.454260000,\\n\\t37.772430000,-122.454220000,\\n\\t37.771980000,-122.454110000,\\n\\t37.771910000,-122.454100000,\\n\\t37.771760000,-122.454060000,\\n\\t37.771690000,-122.454050000,\\n\\t37.771620000,-122.454030000,\\n\\t37.771530000,-122.454010000,\\n\\t37.771380000,-122.453970000,\\n\\t37.771250000,-122.453950000,\\n\\t37.771100000,-122.453930000,\\n\\t37.771020000,-122.453920000,\\n\\t37.770920000,-122.453900000,\\n\\t37.770810000,-122.453890000,\\n\\t37.770660000,-122.453860000,\\n\\t37.770110000,-122.453750000,\\n\\t37.769560000,-122.453640000,\\n\\t37.769360000,-122.453600000,\\n\\t37.769250000,-122.453580000,\\n\\t37.769180000,-122.453560000,\\n\\t37.769090000,-122.453540000,\\n\\t37.768780000,-122.453480000,\\n\\t37.768250000,-122.453380000,\\n\\t37.768160000,-122.453360000,\\n\\t37.767820000,-122.453290000,\\n\\t37.767310000,-122.453190000,\\n\\t37.767160000,-122.453160000,\\n\\t37.767010000,-122.453130000,\\n\\t37.766760000,-122.453070000,\\n\\t37.766550000,-122.453030000,\\n\\t37.766550000,-122.453030000,\\n\\t37.766390000,-122.452990000,\\n\\t37.766390000,-122.452990000,\\n\\t37.766290000,-122.453720000,\\n\\t37.766180000,-122.454610000,\\n\\t37.766130000,-122.454980000,\\n\\t37.765960000,-122.456290000,\\n\\t37.765960000,-122.456340000,\\n\\t37.765960000,-122.456360000,\\n\\t37.765960000,-122.456380000,\\n\\t37.765960000,-122.456410000,\\n\\t37.765960000,-122.456460000,\\n\\t37.765940000,-122.456630000,\\n\\t37.765930000,-122.456700000,\\n\\t37.765920000,-122.456810000,\\n\\t37.765910000,-122.456930000,\\n\\t37.765910000,-122.457020000,\\n\\t37.765920000,-122.457160000,\\n\\t37.765930000,-122.457270000,\\n\\t37.765940000,-122.457360000,\\n\\t37.765950000,-122.457410000,\\n\\t37.765960000,-122.457470000,\\n\\t37.765980000,-122.457560000,\\n\\t37.766010000,-122.457660000,\\n\\t37.766070000,-122.457830000,\\n\\t37.766070000,-122.457830000,\\n\\t37.766120000,-122.457980000,\\n\\t37.766180000,-122.458180000,\\n\\t37.766190000,-122.458200000,\\n\\t37.766240000,-122.458400000,\\n\\t37.766270000,-122.458530000,\\n\\t37.766290000,-122.458600000,\\n\\t37.766300000,-122.458690000,\\n\\t37.766300000,-122.458880000,\\n\\t37.766300000,-122.458970000,\\n\\t37.766280000,-122.459470000,\\n\\t37.766270000,-122.459520000,\\n\\t37.766270000,-122.459560000,\\n\\t37.766280000,-122.459600000,\\n\\t37.766280000,-122.459630000,\\n\\t37.766290000,-122.459670000,\\n\\t37.766300000,-122.459700000,\\n\\t37.766310000,-122.459730000,\\n\\t37.766320000,-122.459750000,\\n\\t37.766330000,-122.459770000,\\n\\t37.766350000,-122.459800000,\\n\\t37.766390000,-122.459860000,\\n\\t37.766340000,-122.459970000,\\n\\t37.766290000,-122.460150000,\\n\\t37.766290000,-122.460230000,\\n\\t37.766280000,-122.460280000,\\n\\t37.766260000,-122.460330000,\\n\\t37.766250000,-122.460420000,\\n\\t37.766240000,-122.460520000,\\n\\t37.766230000,-122.460670000,\\n\\t37.766230000,-122.460800000,\\n\\t37.766230000,-122.460900000,\\n\\t37.766210000,-122.461110000,\\n\\t37.766170000,-122.462030000,\\n\\t37.766160000,-122.462170000,\\n\\t37.766150000,-122.462520000,\\n\\t37.766120000,-122.463260000,\\n\\t37.766090000,-122.464130000,\\n\\t37.766070000,-122.464350000,\\n\\t37.766070000,-122.464440000,\\n\\t37.766060000,-122.464620000,\\n\\t37.766030000,-122.465400000,\\n\\t37.765980000,-122.466470000,\\n\\t37.765940000,-122.467530000,\\n\\t37.765930000,-122.467680000,\\n\\t37.765890000,-122.468600000,\\n\\t37.765860000,-122.468980000,\\n\\t37.765830000,-122.469660000,\\n\\t37.765780000,-122.470740000,\\n\\t37.765770000,-122.471030000,\\n\\t37.765770000,-122.471140000,\\n\\t37.765760000,-122.471380000,\\n\\t37.765740000,-122.471820000,\\n\\t37.765690000,-122.472950000,\\n\\t37.765680000,-122.473220000,\\n\\t37.765670000,-122.473320000,\\n\\t37.765640000,-122.474070000,\\n\\t37.765590000,-122.475140000,\\n\\t37.765590000,-122.475400000,\\n\\t37.765580000,-122.475520000,\\n\\t37.765550000,-122.476200000,\\n\\t37.765500000,-122.477180000,\\n\\t37.765500000,-122.477280000,\\n\\t37.765490000,-122.477400000,\\n\\t37.765490000,-122.477440000,\\n\\t37.765490000,-122.477440000,\\n\\t37.765490000,-122.477490000,\\n\\t37.765470000,-122.477770000,\\n\\t37.765450000,-122.478340000,\\n\\t37.765450000,-122.478420000,\\n\\t37.765430000,-122.478870000,\\n\\t37.765400000,-122.479430000,\\n\\t37.765380000,-122.479810000,\\n\\t37.765350000,-122.480480000,\\n\\t37.765300000,-122.481570000,\\n\\t37.765300000,-122.481660000,\\n\\t37.765290000,-122.481950000,\\n\\t37.765260000,-122.482640000,\\n\\t37.765220000,-122.483570000,\\n\\t37.765210000,-122.483710000,\\n\\t37.765210000,-122.483810000,\\n\\t37.765190000,-122.484130000,\\n\\t37.765160000,-122.484780000,\\n\\t37.765120000,-122.485860000,\\n\\t37.765110000,-122.485960000,\\n\\t37.765100000,-122.486170000,\\n\\t37.765070000,-122.486930000,\\n\\t37.765020000,-122.488000000,\\n\\t37.765020000,-122.488100000,\\n\\t37.765000000,-122.488360000,\\n\\t37.764980000,-122.488970000,\\n\\t37.764970000,-122.489070000,\\n\\t37.764930000,-122.490150000,\\n\\t37.764920000,-122.490240000,\\n\\t37.764910000,-122.490490000,\\n\\t37.764880000,-122.491210000,\\n\\t37.764830000,-122.492290000,\\n\\t37.764790000,-122.493260000,\\n\\t37.764780000,-122.493350000,\\n\\t37.764740000,-122.494420000,\\n\\t37.764720000,-122.494730000,\\n\\t37.764710000,-122.495500000,\\n\\t37.764700000,-122.495630000,\\n\\t37.764690000,-122.495940000,\\n\\t37.764680000,-122.496260000,\\n\\t37.764670000,-122.496480000,\\n\\t37.764600000,-122.497490000,\\n\\t37.764590000,-122.497650000,\\n\\t37.764550000,-122.498720000,\\n\\t37.764500000,-122.499780000,\\n\\t37.764450000,-122.500870000,\\n\\t37.764440000,-122.501060000,\\n\\t37.764400000,-122.501930000,\\n\\t37.764360000,-122.502990000,\\n\\t37.764310000,-122.504080000,\\n\\t37.764260000,-122.505140000,\\n\\t37.764260000,-122.505250000,\\n\\t37.764220000,-122.506220000,\\n\\t37.764170000,-122.507280000,\\n\\t37.764120000,-122.508360000,\\n\\t37.764100000,-122.508850000,\\n\\t37.764100000,-122.509150000,\\n\\t37.764100000,-122.509440000,\\n\\t37.764090000,-122.509760000,\\n\\t37.764080000,-122.510200000,\\n\\t37.764070000,-122.510320000,\\n\\t37.764060000,-122.510430000,\\n\\t37.764030000,-122.510430000,\\n\\t37.764030000,-122.510430000,\\n\\t37.763960000,-122.510430000,\\n\\t37.763960000,-122.510290000,\\n\\t37.764070000,-122.510320000,\\n\\t37.764170000,-122.510320000,\\n\\t37.764410000,-122.510340000,\\n\\t37.764610000,-122.510350000,\\n\\t37.764780000,-122.510330000,\\n\\t37.764960000,-122.510310000,\\n\\t37.765340000,-122.510280000,\\n\\t37.765570000,-122.510260000,\\n\\t37.765840000,-122.510250000,\\n\\t37.765900000,-122.510250000,\\n\\t37.766140000,-122.510260000,\\n\\t37.766410000,-122.510260000,\\n\\t37.766620000,-122.510270000,\\n\\t37.767040000,-122.510310000,\\n\\t37.767270000,-122.510330000,\\n\\t37.767620000,-122.510390000,\\n\\t37.767670000,-122.510390000,\\n\\t37.767740000,-122.510410000,\\n\\t37.767840000,-122.510430000,\\n\\t37.768280000,-122.510530000,\\n\\t37.768620000,-122.510600000,\\n\\t37.768690000,-122.510620000,\\n\\t37.769020000,-122.510690000,\\n\\t37.769260000,-122.510730000,\\n\\t37.769420000,-122.510750000,\\n\\t37.770010000,-122.510830000,\\n\\t37.770340000,-122.510860000,\\n\\t37.770460000,-122.510870000,\\n\\t37.770930000,-122.510930000,\\n\\t37.770980000,-122.510930000,\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 0 : value + 2)];\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var gpsData = [\\n\\t37.771210000,-122.510960000,\\n\\t37.771340000,-122.510980000,\\n\\t37.771340000,-122.510980000,\\n\\t37.771360000,-122.510850000,\\n\\t37.771380000,-122.510550000,\\n\\t37.771400000,-122.509900000,\\n\\t37.771410000,-122.509660000,\\n\\t37.771430000,-122.509360000,\\n\\t37.771430000,-122.509270000,\\n\\t37.771450000,-122.508840000,\\n\\t37.771490000,-122.507880000,\\n\\t37.771490000,-122.507780000,\\n\\t37.771530000,-122.507140000,\\n\\t37.771550000,-122.506690000,\\n\\t37.771560000,-122.506310000,\\n\\t37.771600000,-122.505640000,\\n\\t37.771650000,-122.504540000,\\n\\t37.771670000,-122.503990000,\\n\\t37.771700000,-122.503490000,\\n\\t37.771740000,-122.502430000,\\n\\t37.771790000,-122.501360000,\\n\\t37.771840000,-122.500290000,\\n\\t37.771870000,-122.499730000,\\n\\t37.771890000,-122.499210000,\\n\\t37.771940000,-122.498140000,\\n\\t37.771990000,-122.497070000,\\n\\t37.772000000,-122.496690000,\\n\\t37.772020000,-122.496350000,\\n\\t37.772030000,-122.496110000,\\n\\t37.772040000,-122.496000000,\\n\\t37.772040000,-122.495890000,\\n\\t37.772060000,-122.495440000,\\n\\t37.772090000,-122.494930000,\\n\\t37.772120000,-122.494160000,\\n\\t37.772130000,-122.493860000,\\n\\t37.772180000,-122.492790000,\\n\\t37.772200000,-122.492300000,\\n\\t37.772220000,-122.491840000,\\n\\t37.772230000,-122.491710000,\\n\\t37.772280000,-122.490630000,\\n\\t37.772330000,-122.489560000,\\n\\t37.772330000,-122.489470000,\\n\\t37.772360000,-122.489030000,\\n\\t37.772380000,-122.488490000,\\n\\t37.772430000,-122.487420000,\\n\\t37.772450000,-122.486980000,\\n\\t37.772480000,-122.486360000,\\n\\t37.772520000,-122.485280000,\\n\\t37.772560000,-122.484400000,\\n\\t37.772570000,-122.484300000,\\n\\t37.772570000,-122.484150000,\\n\\t37.772620000,-122.483140000,\\n\\t37.772680000,-122.482050000,\\n\\t37.772700000,-122.481370000,\\n\\t37.772710000,-122.481000000,\\n\\t37.772730000,-122.480740000,\\n\\t37.772770000,-122.479930000,\\n\\t37.772820000,-122.478860000,\\n\\t37.772870000,-122.477790000,\\n\\t37.772900000,-122.477110000,\\n\\t37.772920000,-122.476710000,\\n\\t37.772960000,-122.475650000,\\n\\t37.772990000,-122.474950000,\\n\\t37.773010000,-122.474580000,\\n\\t37.773060000,-122.473450000,\\n\\t37.773120000,-122.472330000,\\n\\t37.773140000,-122.471850000,\\n\\t37.773140000,-122.471730000,\\n\\t37.773150000,-122.471640000,\\n\\t37.773170000,-122.471260000,\\n\\t37.773190000,-122.470570000,\\n\\t37.773210000,-122.470190000,\\n\\t37.773230000,-122.469770000,\\n\\t37.773250000,-122.469370000,\\n\\t37.773260000,-122.469120000,\\n\\t37.773290000,-122.468490000,\\n\\t37.773300000,-122.468150000,\\n\\t37.773310000,-122.468050000,\\n\\t37.773310000,-122.467940000,\\n\\t37.773320000,-122.467740000,\\n\\t37.773350000,-122.467270000,\\n\\t37.773360000,-122.466980000,\\n\\t37.773360000,-122.466870000,\\n\\t37.773370000,-122.466610000,\\n\\t37.773390000,-122.466300000,\\n\\t37.773400000,-122.466000000,\\n\\t37.773400000,-122.465910000,\\n\\t37.773410000,-122.465790000,\\n\\t37.773430000,-122.465520000,\\n\\t37.773460000,-122.465210000,\\n\\t37.773490000,-122.464980000,\\n\\t37.773500000,-122.464910000,\\n\\t37.773460000,-122.464830000,\\n\\t37.773560000,-122.464070000,\\n\\t37.773580000,-122.463900000,\\n\\t37.773590000,-122.463810000,\\n\\t37.773600000,-122.463780000,\\n\\t37.773610000,-122.463670000,\\n\\t37.773660000,-122.463320000,\\n\\t37.773740000,-122.462700000,\\n\\t37.773770000,-122.462440000,\\n\\t37.773860000,-122.461730000,\\n\\t37.773870000,-122.461640000,\\n\\t37.773920000,-122.461260000,\\n\\t37.773970000,-122.460890000,\\n\\t37.774010000,-122.460570000,\\n\\t37.774110000,-122.459760000,\\n\\t37.774140000,-122.459490000,\\n\\t37.774270000,-122.458520000,\\n\\t37.774270000,-122.458440000,\\n\\t37.774270000,-122.458380000,\\n\\t37.774320000,-122.458270000,\\n\\t37.774340000,-122.458050000,\\n\\t37.774510000,-122.456680000,\\n\\t37.774560000,-122.456310000,\\n\\t37.774700000,-122.455280000,\\n\\t37.774760000,-122.454780000,\\n\\t37.774770000,-122.454670000,\\n\\t37.774770000,-122.454670000,\\n\\t37.774670000,-122.454650000,\\n\\t37.774670000,-122.454650000,\\n\\t37.774580000,-122.454640000,\\n\\t37.774300000,-122.454580000,\\n\\t37.774190000,-122.454560000,\\n\\t37.773700000,-122.454460000,\\n\\t37.772910000,-122.454310000,\\n\\t37.772620000,-122.454260000,\\n\\t37.772430000,-122.454220000,\\n\\t37.771980000,-122.454110000,\\n\\t37.771910000,-122.454100000,\\n\\t37.771760000,-122.454060000,\\n\\t37.771690000,-122.454050000,\\n\\t37.771620000,-122.454030000,\\n\\t37.771530000,-122.454010000,\\n\\t37.771380000,-122.453970000,\\n\\t37.771250000,-122.453950000,\\n\\t37.771100000,-122.453930000,\\n\\t37.771020000,-122.453920000,\\n\\t37.770920000,-122.453900000,\\n\\t37.770810000,-122.453890000,\\n\\t37.770660000,-122.453860000,\\n\\t37.770110000,-122.453750000,\\n\\t37.769560000,-122.453640000,\\n\\t37.769360000,-122.453600000,\\n\\t37.769250000,-122.453580000,\\n\\t37.769180000,-122.453560000,\\n\\t37.769090000,-122.453540000,\\n\\t37.768780000,-122.453480000,\\n\\t37.768250000,-122.453380000,\\n\\t37.768160000,-122.453360000,\\n\\t37.767820000,-122.453290000,\\n\\t37.767310000,-122.453190000,\\n\\t37.767160000,-122.453160000,\\n\\t37.767010000,-122.453130000,\\n\\t37.766760000,-122.453070000,\\n\\t37.766550000,-122.453030000,\\n\\t37.766550000,-122.453030000,\\n\\t37.766390000,-122.452990000,\\n\\t37.766390000,-122.452990000,\\n\\t37.766290000,-122.453720000,\\n\\t37.766180000,-122.454610000,\\n\\t37.766130000,-122.454980000,\\n\\t37.765960000,-122.456290000,\\n\\t37.765960000,-122.456340000,\\n\\t37.765960000,-122.456360000,\\n\\t37.765960000,-122.456380000,\\n\\t37.765960000,-122.456410000,\\n\\t37.765960000,-122.456460000,\\n\\t37.765940000,-122.456630000,\\n\\t37.765930000,-122.456700000,\\n\\t37.765920000,-122.456810000,\\n\\t37.765910000,-122.456930000,\\n\\t37.765910000,-122.457020000,\\n\\t37.765920000,-122.457160000,\\n\\t37.765930000,-122.457270000,\\n\\t37.765940000,-122.457360000,\\n\\t37.765950000,-122.457410000,\\n\\t37.765960000,-122.457470000,\\n\\t37.765980000,-122.457560000,\\n\\t37.766010000,-122.457660000,\\n\\t37.766070000,-122.457830000,\\n\\t37.766070000,-122.457830000,\\n\\t37.766120000,-122.457980000,\\n\\t37.766180000,-122.458180000,\\n\\t37.766190000,-122.458200000,\\n\\t37.766240000,-122.458400000,\\n\\t37.766270000,-122.458530000,\\n\\t37.766290000,-122.458600000,\\n\\t37.766300000,-122.458690000,\\n\\t37.766300000,-122.458880000,\\n\\t37.766300000,-122.458970000,\\n\\t37.766280000,-122.459470000,\\n\\t37.766270000,-122.459520000,\\n\\t37.766270000,-122.459560000,\\n\\t37.766280000,-122.459600000,\\n\\t37.766280000,-122.459630000,\\n\\t37.766290000,-122.459670000,\\n\\t37.766300000,-122.459700000,\\n\\t37.766310000,-122.459730000,\\n\\t37.766320000,-122.459750000,\\n\\t37.766330000,-122.459770000,\\n\\t37.766350000,-122.459800000,\\n\\t37.766390000,-122.459860000,\\n\\t37.766340000,-122.459970000,\\n\\t37.766290000,-122.460150000,\\n\\t37.766290000,-122.460230000,\\n\\t37.766280000,-122.460280000,\\n\\t37.766260000,-122.460330000,\\n\\t37.766250000,-122.460420000,\\n\\t37.766240000,-122.460520000,\\n\\t37.766230000,-122.460670000,\\n\\t37.766230000,-122.460800000,\\n\\t37.766230000,-122.460900000,\\n\\t37.766210000,-122.461110000,\\n\\t37.766170000,-122.462030000,\\n\\t37.766160000,-122.462170000,\\n\\t37.766150000,-122.462520000,\\n\\t37.766120000,-122.463260000,\\n\\t37.766090000,-122.464130000,\\n\\t37.766070000,-122.464350000,\\n\\t37.766070000,-122.464440000,\\n\\t37.766060000,-122.464620000,\\n\\t37.766030000,-122.465400000,\\n\\t37.765980000,-122.466470000,\\n\\t37.765940000,-122.467530000,\\n\\t37.765930000,-122.467680000,\\n\\t37.765890000,-122.468600000,\\n\\t37.765860000,-122.468980000,\\n\\t37.765830000,-122.469660000,\\n\\t37.765780000,-122.470740000,\\n\\t37.765770000,-122.471030000,\\n\\t37.765770000,-122.471140000,\\n\\t37.765760000,-122.471380000,\\n\\t37.765740000,-122.471820000,\\n\\t37.765690000,-122.472950000,\\n\\t37.765680000,-122.473220000,\\n\\t37.765670000,-122.473320000,\\n\\t37.765640000,-122.474070000,\\n\\t37.765590000,-122.475140000,\\n\\t37.765590000,-122.475400000,\\n\\t37.765580000,-122.475520000,\\n\\t37.765550000,-122.476200000,\\n\\t37.765500000,-122.477180000,\\n\\t37.765500000,-122.477280000,\\n\\t37.765490000,-122.477400000,\\n\\t37.765490000,-122.477440000,\\n\\t37.765490000,-122.477440000,\\n\\t37.765490000,-122.477490000,\\n\\t37.765470000,-122.477770000,\\n\\t37.765450000,-122.478340000,\\n\\t37.765450000,-122.478420000,\\n\\t37.765430000,-122.478870000,\\n\\t37.765400000,-122.479430000,\\n\\t37.765380000,-122.479810000,\\n\\t37.765350000,-122.480480000,\\n\\t37.765300000,-122.481570000,\\n\\t37.765300000,-122.481660000,\\n\\t37.765290000,-122.481950000,\\n\\t37.765260000,-122.482640000,\\n\\t37.765220000,-122.483570000,\\n\\t37.765210000,-122.483710000,\\n\\t37.765210000,-122.483810000,\\n\\t37.765190000,-122.484130000,\\n\\t37.765160000,-122.484780000,\\n\\t37.765120000,-122.485860000,\\n\\t37.765110000,-122.485960000,\\n\\t37.765100000,-122.486170000,\\n\\t37.765070000,-122.486930000,\\n\\t37.765020000,-122.488000000,\\n\\t37.765020000,-122.488100000,\\n\\t37.765000000,-122.488360000,\\n\\t37.764980000,-122.488970000,\\n\\t37.764970000,-122.489070000,\\n\\t37.764930000,-122.490150000,\\n\\t37.764920000,-122.490240000,\\n\\t37.764910000,-122.490490000,\\n\\t37.764880000,-122.491210000,\\n\\t37.764830000,-122.492290000,\\n\\t37.764790000,-122.493260000,\\n\\t37.764780000,-122.493350000,\\n\\t37.764740000,-122.494420000,\\n\\t37.764720000,-122.494730000,\\n\\t37.764710000,-122.495500000,\\n\\t37.764700000,-122.495630000,\\n\\t37.764690000,-122.495940000,\\n\\t37.764680000,-122.496260000,\\n\\t37.764670000,-122.496480000,\\n\\t37.764600000,-122.497490000,\\n\\t37.764590000,-122.497650000,\\n\\t37.764550000,-122.498720000,\\n\\t37.764500000,-122.499780000,\\n\\t37.764450000,-122.500870000,\\n\\t37.764440000,-122.501060000,\\n\\t37.764400000,-122.501930000,\\n\\t37.764360000,-122.502990000,\\n\\t37.764310000,-122.504080000,\\n\\t37.764260000,-122.505140000,\\n\\t37.764260000,-122.505250000,\\n\\t37.764220000,-122.506220000,\\n\\t37.764170000,-122.507280000,\\n\\t37.764120000,-122.508360000,\\n\\t37.764100000,-122.508850000,\\n\\t37.764100000,-122.509150000,\\n\\t37.764100000,-122.509440000,\\n\\t37.764090000,-122.509760000,\\n\\t37.764080000,-122.510200000,\\n\\t37.764070000,-122.510320000,\\n\\t37.764060000,-122.510430000,\\n\\t37.764030000,-122.510430000,\\n\\t37.764030000,-122.510430000,\\n\\t37.763960000,-122.510430000,\\n\\t37.763960000,-122.510290000,\\n\\t37.764070000,-122.510320000,\\n\\t37.764170000,-122.510320000,\\n\\t37.764410000,-122.510340000,\\n\\t37.764610000,-122.510350000,\\n\\t37.764780000,-122.510330000,\\n\\t37.764960000,-122.510310000,\\n\\t37.765340000,-122.510280000,\\n\\t37.765570000,-122.510260000,\\n\\t37.765840000,-122.510250000,\\n\\t37.765900000,-122.510250000,\\n\\t37.766140000,-122.510260000,\\n\\t37.766410000,-122.510260000,\\n\\t37.766620000,-122.510270000,\\n\\t37.767040000,-122.510310000,\\n\\t37.767270000,-122.510330000,\\n\\t37.767620000,-122.510390000,\\n\\t37.767670000,-122.510390000,\\n\\t37.767740000,-122.510410000,\\n\\t37.767840000,-122.510430000,\\n\\t37.768280000,-122.510530000,\\n\\t37.768620000,-122.510600000,\\n\\t37.768690000,-122.510620000,\\n\\t37.769020000,-122.510690000,\\n\\t37.769260000,-122.510730000,\\n\\t37.769420000,-122.510750000,\\n\\t37.770010000,-122.510830000,\\n\\t37.770340000,-122.510860000,\\n\\t37.770460000,-122.510870000,\\n\\t37.770930000,-122.510930000,\\n\\t37.770980000,-122.510930000,\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 1 : value + 2)];\"}]}],\"timewindow\":{\"history\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":500}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"mapProvider\":\"OpenStreetMap.Mapnik\",\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"showTooltip\":true,\"tooltipColor\":\"#fff\",\"tooltipFontColor\":\"#000\",\"tooltipOpacity\":1,\"tooltipPattern\":\"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><b>End Time:</b> ${maxTime}<br/><b>Start Time:</b> ${minTime}\",\"strokeWeight\":2,\"strokeOpacity\":1,\"pointSize\":10,\"markerImageSize\":34,\"rotationAngle\":180},\"title\":\"Trip Animation\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":false,\"showLegend\":false,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}"
134 134 }
135 135 }
136 136 ]
137   -}
\ No newline at end of file
  137 +}
... ...
  1 +--
  2 +-- Copyright © 2016-2020 The Thingsboard Authors
  3 +--
  4 +-- Licensed under the Apache License, Version 2.0 (the "License");
  5 +-- you may not use this file except in compliance with the License.
  6 +-- You may obtain a copy of the License at
  7 +--
  8 +-- http://www.apache.org/licenses/LICENSE-2.0
  9 +--
  10 +-- Unless required by applicable law or agreed to in writing, software
  11 +-- distributed under the License is distributed on an "AS IS" BASIS,
  12 +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +-- See the License for the specific language governing permissions and
  14 +-- limitations under the License.
  15 +--
  16 +
  17 +CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar, IN system_ttl bigint, INOUT deleted bigint)
  18 + LANGUAGE plpgsql AS
  19 +$$
  20 +DECLARE
  21 + max_tenant_ttl bigint;
  22 + max_customer_ttl bigint;
  23 + max_ttl bigint;
  24 + date timestamp;
  25 + partition_by_max_ttl_date varchar;
  26 + partition_month varchar;
  27 + partition_day varchar;
  28 + partition_year varchar;
  29 + partition varchar;
  30 + partition_to_delete varchar;
  31 +
  32 +
  33 +BEGIN
  34 + SELECT max(attribute_kv.long_v)
  35 + FROM tenant
  36 + INNER JOIN attribute_kv ON tenant.id = attribute_kv.entity_id
  37 + WHERE attribute_kv.attribute_key = 'TTL'
  38 + into max_tenant_ttl;
  39 + SELECT max(attribute_kv.long_v)
  40 + FROM customer
  41 + INNER JOIN attribute_kv ON customer.id = attribute_kv.entity_id
  42 + WHERE attribute_kv.attribute_key = 'TTL'
  43 + into max_customer_ttl;
  44 + max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl);
  45 + if max_ttl IS NOT NULL AND max_ttl > 0 THEN
  46 + date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - (max_ttl / 1000));
  47 + partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date);
  48 + RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date;
  49 + IF partition_by_max_ttl_date IS NOT NULL THEN
  50 + CASE
  51 + WHEN partition_type = 'DAYS' THEN
  52 + partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3);
  53 + partition_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4);
  54 + partition_day := SPLIT_PART(partition_by_max_ttl_date, '_', 5);
  55 + WHEN partition_type = 'MONTHS' THEN
  56 + partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3);
  57 + partition_month := SPLIT_PART(partition_by_max_ttl_date, '_', 4);
  58 + ELSE
  59 + partition_year := SPLIT_PART(partition_by_max_ttl_date, '_', 3);
  60 + END CASE;
  61 + FOR partition IN SELECT tablename
  62 + FROM pg_tables
  63 + WHERE schemaname = 'public'
  64 + AND tablename like 'ts_kv_' || '%'
  65 + AND tablename != 'ts_kv_latest'
  66 + AND tablename != 'ts_kv_dictionary'
  67 + LOOP
  68 + IF partition != partition_by_max_ttl_date THEN
  69 + IF partition_year IS NOT NULL THEN
  70 + IF SPLIT_PART(partition, '_', 3)::integer < partition_year::integer THEN
  71 + partition_to_delete := partition;
  72 + ELSE
  73 + IF partition_month IS NOT NULL THEN
  74 + IF SPLIT_PART(partition, '_', 4)::integer < partition_month::integer THEN
  75 + partition_to_delete := partition;
  76 + ELSE
  77 + IF partition_day IS NOT NULL THEN
  78 + IF SPLIT_PART(partition, '_', 5)::integer < partition_day::integer THEN
  79 + partition_to_delete := partition;
  80 + END IF;
  81 + END IF;
  82 + END IF;
  83 + END IF;
  84 + END IF;
  85 + END IF;
  86 + END IF;
  87 + IF partition_to_delete IS NOT NULL THEN
  88 + RAISE NOTICE 'Partition to delete by max ttl: %', partition_to_delete;
  89 + EXECUTE format('DROP TABLE %I', partition_to_delete);
  90 + deleted := deleted + 1;
  91 + END IF;
  92 + END LOOP;
  93 + END IF;
  94 + END IF;
  95 +END
  96 +$$;
  97 +
  98 +CREATE OR REPLACE FUNCTION get_partition_by_max_ttl_date(IN partition_type varchar, IN date timestamp, OUT partition varchar) AS
  99 +$$
  100 +BEGIN
  101 + CASE
  102 + WHEN partition_type = 'DAYS' THEN
  103 + partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM') || '_' || to_char(date, 'dd');
  104 + WHEN partition_type = 'MONTHS' THEN
  105 + partition := 'ts_kv_' || to_char(date, 'yyyy') || '_' || to_char(date, 'MM');
  106 + WHEN partition_type = 'YEARS' THEN
  107 + partition := 'ts_kv_' || to_char(date, 'yyyy');
  108 + WHEN partition_type = 'INDEFINITE' THEN
  109 + partition := NULL;
  110 + ELSE
  111 + partition := NULL;
  112 + END CASE;
  113 + IF partition IS NOT NULL THEN
  114 + IF NOT EXISTS(SELECT
  115 + FROM pg_tables
  116 + WHERE schemaname = 'public'
  117 + AND tablename = partition) THEN
  118 + partition := NULL;
  119 + RAISE NOTICE 'Failed to found partition by ttl';
  120 + END IF;
  121 + END IF;
  122 +END;
  123 +$$ LANGUAGE plpgsql;
... ...
  1 +--
  2 +-- Copyright © 2016-2020 The Thingsboard Authors
  3 +--
  4 +-- Licensed under the Apache License, Version 2.0 (the "License");
  5 +-- you may not use this file except in compliance with the License.
  6 +-- You may obtain a copy of the License at
  7 +--
  8 +-- http://www.apache.org/licenses/LICENSE-2.0
  9 +--
  10 +-- Unless required by applicable law or agreed to in writing, software
  11 +-- distributed under the License is distributed on an "AS IS" BASIS,
  12 +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +-- See the License for the specific language governing permissions and
  14 +-- limitations under the License.
  15 +--
  16 +
  17 +-- call create_partition_ts_kv_table();
  18 +
  19 +CREATE OR REPLACE PROCEDURE create_partition_ts_kv_table() LANGUAGE plpgsql AS $$
  20 +
  21 +BEGIN
  22 + ALTER TABLE ts_kv
  23 + RENAME TO ts_kv_old;
  24 + ALTER TABLE ts_kv_old
  25 + RENAME CONSTRAINT ts_kv_pkey TO ts_kv_pkey_old;
  26 + CREATE TABLE IF NOT EXISTS ts_kv
  27 + (
  28 + LIKE ts_kv_old
  29 + )
  30 + PARTITION BY RANGE (ts);
  31 + ALTER TABLE ts_kv
  32 + DROP COLUMN entity_type;
  33 + ALTER TABLE ts_kv
  34 + ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid;
  35 + ALTER TABLE ts_kv
  36 + ALTER COLUMN key TYPE integer USING key::integer;
  37 + ALTER TABLE ts_kv
  38 + ADD CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts);
  39 +END;
  40 +$$;
  41 +
  42 +-- call create_new_ts_kv_latest_table();
  43 +
  44 +CREATE OR REPLACE PROCEDURE create_new_ts_kv_latest_table() LANGUAGE plpgsql AS $$
  45 +
  46 +BEGIN
  47 + ALTER TABLE ts_kv_latest
  48 + RENAME TO ts_kv_latest_old;
  49 + ALTER TABLE ts_kv_latest_old
  50 + RENAME CONSTRAINT ts_kv_latest_pkey TO ts_kv_latest_pkey_old;
  51 + CREATE TABLE IF NOT EXISTS ts_kv_latest
  52 + (
  53 + LIKE ts_kv_latest_old
  54 + );
  55 + ALTER TABLE ts_kv_latest
  56 + DROP COLUMN entity_type;
  57 + ALTER TABLE ts_kv_latest
  58 + ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid;
  59 + ALTER TABLE ts_kv_latest
  60 + ALTER COLUMN key TYPE integer USING key::integer;
  61 + ALTER TABLE ts_kv_latest
  62 + ADD CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key);
  63 +END;
  64 +$$;
  65 +
  66 +CREATE OR REPLACE FUNCTION get_partitions_data(IN partition_type varchar)
  67 + RETURNS
  68 + TABLE
  69 + (
  70 + partition_date text,
  71 + from_ts bigint,
  72 + to_ts bigint
  73 + )
  74 +AS
  75 +$$
  76 +BEGIN
  77 + CASE
  78 + WHEN partition_type = 'DAYS' THEN
  79 + RETURN QUERY SELECT day_date.day AS partition_date,
  80 + (extract(epoch from (day_date.day)::timestamp) * 1000)::bigint AS from_ts,
  81 + (extract(epoch from (day_date.day::date + INTERVAL '1 DAY')::timestamp) *
  82 + 1000)::bigint AS to_ts
  83 + FROM (SELECT DISTINCT TO_CHAR(TO_TIMESTAMP(ts / 1000), 'YYYY_MM_DD') AS day
  84 + FROM ts_kv_old) AS day_date;
  85 + WHEN partition_type = 'MONTHS' THEN
  86 + RETURN QUERY SELECT SUBSTRING(month_date.first_date, 1, 7) AS partition_date,
  87 + (extract(epoch from (month_date.first_date)::timestamp) * 1000)::bigint AS from_ts,
  88 + (extract(epoch from (month_date.first_date::date + INTERVAL '1 MONTH')::timestamp) *
  89 + 1000)::bigint AS to_ts
  90 + FROM (SELECT DISTINCT TO_CHAR(TO_TIMESTAMP(ts / 1000), 'YYYY_MM_01') AS first_date
  91 + FROM ts_kv_old) AS month_date;
  92 + WHEN partition_type = 'YEARS' THEN
  93 + RETURN QUERY SELECT SUBSTRING(year_date.year, 1, 4) AS partition_date,
  94 + (extract(epoch from (year_date.year)::timestamp) * 1000)::bigint AS from_ts,
  95 + (extract(epoch from (year_date.year::date + INTERVAL '1 YEAR')::timestamp) *
  96 + 1000)::bigint AS to_ts
  97 + FROM (SELECT DISTINCT TO_CHAR(TO_TIMESTAMP(ts / 1000), 'YYYY_01_01') AS year FROM ts_kv_old) AS year_date;
  98 + ELSE
  99 + RAISE EXCEPTION 'Failed to parse partitioning property: % !', partition_type;
  100 + END CASE;
  101 +END;
  102 +$$ LANGUAGE plpgsql;
  103 +
  104 +-- call create_partitions();
  105 +
  106 +CREATE OR REPLACE PROCEDURE create_partitions(IN partition_type varchar) LANGUAGE plpgsql AS $$
  107 +
  108 +DECLARE
  109 + partition_date varchar;
  110 + from_ts bigint;
  111 + to_ts bigint;
  112 + partitions_cursor CURSOR FOR SELECT * FROM get_partitions_data(partition_type);
  113 +BEGIN
  114 + OPEN partitions_cursor;
  115 + LOOP
  116 + FETCH partitions_cursor INTO partition_date, from_ts, to_ts;
  117 + EXIT WHEN NOT FOUND;
  118 + EXECUTE 'CREATE TABLE IF NOT EXISTS ts_kv_' || partition_date ||
  119 + ' PARTITION OF ts_kv FOR VALUES FROM (' || from_ts ||
  120 + ') TO (' || to_ts || ');';
  121 + RAISE NOTICE 'A partition % has been created!',CONCAT('ts_kv_', partition_date);
  122 + END LOOP;
  123 +
  124 + CLOSE partitions_cursor;
  125 +END;
  126 +$$;
  127 +
  128 +-- call create_ts_kv_dictionary_table();
  129 +
  130 +CREATE OR REPLACE PROCEDURE create_ts_kv_dictionary_table() LANGUAGE plpgsql AS $$
  131 +
  132 +BEGIN
  133 + CREATE TABLE IF NOT EXISTS ts_kv_dictionary
  134 + (
  135 + key varchar(255) NOT NULL,
  136 + key_id serial UNIQUE,
  137 + CONSTRAINT ts_key_id_pkey PRIMARY KEY (key)
  138 + );
  139 +END;
  140 +$$;
  141 +
  142 +-- call insert_into_dictionary();
  143 +
  144 +CREATE OR REPLACE PROCEDURE insert_into_dictionary() LANGUAGE plpgsql AS $$
  145 +
  146 +DECLARE
  147 + insert_record RECORD;
  148 + key_cursor CURSOR FOR SELECT DISTINCT key
  149 + FROM ts_kv_old
  150 + ORDER BY key;
  151 +BEGIN
  152 + OPEN key_cursor;
  153 + LOOP
  154 + FETCH key_cursor INTO insert_record;
  155 + EXIT WHEN NOT FOUND;
  156 + IF NOT EXISTS(SELECT key FROM ts_kv_dictionary WHERE key = insert_record.key) THEN
  157 + INSERT INTO ts_kv_dictionary(key) VALUES (insert_record.key);
  158 + RAISE NOTICE 'Key: % has been inserted into the dictionary!',insert_record.key;
  159 + ELSE
  160 + RAISE NOTICE 'Key: % already exists in the dictionary!',insert_record.key;
  161 + END IF;
  162 + END LOOP;
  163 + CLOSE key_cursor;
  164 +END;
  165 +$$;
  166 +
  167 +-- call insert_into_ts_kv();
  168 +
  169 +CREATE OR REPLACE PROCEDURE insert_into_ts_kv() LANGUAGE plpgsql AS $$
  170 +DECLARE
  171 + insert_size CONSTANT integer := 10000;
  172 + insert_counter integer DEFAULT 0;
  173 + insert_record RECORD;
  174 + insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id,
  175 + ts_kv_records.key AS key,
  176 + ts_kv_records.ts AS ts,
  177 + ts_kv_records.bool_v AS bool_v,
  178 + ts_kv_records.str_v AS str_v,
  179 + ts_kv_records.long_v AS long_v,
  180 + ts_kv_records.dbl_v AS dbl_v
  181 + FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part,
  182 + SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part,
  183 + SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part,
  184 + SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part,
  185 + SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part,
  186 + key_id AS key,
  187 + ts,
  188 + bool_v,
  189 + str_v,
  190 + long_v,
  191 + dbl_v
  192 + FROM ts_kv_old
  193 + INNER JOIN ts_kv_dictionary ON (ts_kv_old.key = ts_kv_dictionary.key)) AS ts_kv_records;
  194 +BEGIN
  195 + OPEN insert_cursor;
  196 + LOOP
  197 + insert_counter := insert_counter + 1;
  198 + FETCH insert_cursor INTO insert_record;
  199 + IF NOT FOUND THEN
  200 + RAISE NOTICE '% records have been inserted into the partitioned ts_kv!',insert_counter - 1;
  201 + EXIT;
  202 + END IF;
  203 + INSERT INTO ts_kv(entity_id, key, ts, bool_v, str_v, long_v, dbl_v)
  204 + VALUES (insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v,
  205 + insert_record.long_v, insert_record.dbl_v);
  206 + IF MOD(insert_counter, insert_size) = 0 THEN
  207 + RAISE NOTICE '% records have been inserted into the partitioned ts_kv!',insert_counter;
  208 + END IF;
  209 + END LOOP;
  210 + CLOSE insert_cursor;
  211 +END;
  212 +$$;
  213 +
  214 +-- call insert_into_ts_kv_latest();
  215 +
  216 +CREATE OR REPLACE PROCEDURE insert_into_ts_kv_latest() LANGUAGE plpgsql AS $$
  217 +DECLARE
  218 + insert_size CONSTANT integer := 10000;
  219 + insert_counter integer DEFAULT 0;
  220 + insert_record RECORD;
  221 + insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id,
  222 + ts_kv_latest_records.key AS key,
  223 + ts_kv_latest_records.ts AS ts,
  224 + ts_kv_latest_records.bool_v AS bool_v,
  225 + ts_kv_latest_records.str_v AS str_v,
  226 + ts_kv_latest_records.long_v AS long_v,
  227 + ts_kv_latest_records.dbl_v AS dbl_v
  228 + FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part,
  229 + SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part,
  230 + SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part,
  231 + SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part,
  232 + SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part,
  233 + key_id AS key,
  234 + ts,
  235 + bool_v,
  236 + str_v,
  237 + long_v,
  238 + dbl_v
  239 + FROM ts_kv_latest_old
  240 + INNER JOIN ts_kv_dictionary ON (ts_kv_latest_old.key = ts_kv_dictionary.key)) AS ts_kv_latest_records;
  241 +BEGIN
  242 + OPEN insert_cursor;
  243 + LOOP
  244 + insert_counter := insert_counter + 1;
  245 + FETCH insert_cursor INTO insert_record;
  246 + IF NOT FOUND THEN
  247 + RAISE NOTICE '% records have been inserted into the ts_kv_latest!',insert_counter - 1;
  248 + EXIT;
  249 + END IF;
  250 + INSERT INTO ts_kv_latest(entity_id, key, ts, bool_v, str_v, long_v, dbl_v)
  251 + VALUES (insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v,
  252 + insert_record.long_v, insert_record.dbl_v);
  253 + IF MOD(insert_counter, insert_size) = 0 THEN
  254 + RAISE NOTICE '% records have been inserted into the ts_kv_latest!',insert_counter;
  255 + END IF;
  256 + END LOOP;
  257 + CLOSE insert_cursor;
  258 +END;
  259 +$$;
  260 +
  261 +
... ...
  1 +--
  2 +-- Copyright © 2016-2020 The Thingsboard Authors
  3 +--
  4 +-- Licensed under the Apache License, Version 2.0 (the "License");
  5 +-- you may not use this file except in compliance with the License.
  6 +-- You may obtain a copy of the License at
  7 +--
  8 +-- http://www.apache.org/licenses/LICENSE-2.0
  9 +--
  10 +-- Unless required by applicable law or agreed to in writing, software
  11 +-- distributed under the License is distributed on an "AS IS" BASIS,
  12 +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +-- See the License for the specific language governing permissions and
  14 +-- limitations under the License.
  15 +--
  16 +
  17 +-- call create_new_ts_kv_table();
  18 +
  19 +CREATE OR REPLACE PROCEDURE create_new_ts_kv_table() LANGUAGE plpgsql AS $$
  20 +
  21 +BEGIN
  22 + ALTER TABLE tenant_ts_kv
  23 + RENAME TO tenant_ts_kv_old;
  24 + CREATE TABLE IF NOT EXISTS ts_kv
  25 + (
  26 + LIKE tenant_ts_kv_old
  27 + );
  28 + ALTER TABLE ts_kv ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid;
  29 + ALTER TABLE ts_kv ALTER COLUMN key TYPE integer USING key::integer;
  30 + ALTER INDEX ts_kv_pkey RENAME TO tenant_ts_kv_pkey_old;
  31 + ALTER INDEX idx_tenant_ts_kv RENAME TO idx_tenant_ts_kv_old;
  32 + ALTER INDEX tenant_ts_kv_ts_idx RENAME TO tenant_ts_kv_ts_idx_old;
  33 + ALTER TABLE ts_kv ADD CONSTRAINT ts_kv_pkey PRIMARY KEY(entity_id, key, ts);
  34 +-- CREATE INDEX IF NOT EXISTS ts_kv_ts_idx ON ts_kv(ts DESC);
  35 + ALTER TABLE ts_kv DROP COLUMN IF EXISTS tenant_id;
  36 +END;
  37 +$$;
  38 +
  39 +
  40 +-- call create_ts_kv_latest_table();
  41 +
  42 +CREATE OR REPLACE PROCEDURE create_ts_kv_latest_table() LANGUAGE plpgsql AS $$
  43 +
  44 +BEGIN
  45 + CREATE TABLE IF NOT EXISTS ts_kv_latest
  46 + (
  47 + entity_id uuid NOT NULL,
  48 + key int NOT NULL,
  49 + ts bigint NOT NULL,
  50 + bool_v boolean,
  51 + str_v varchar(10000000),
  52 + long_v bigint,
  53 + dbl_v double precision,
  54 + CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key)
  55 + );
  56 +END;
  57 +$$;
  58 +
  59 +
  60 +-- call create_ts_kv_dictionary_table();
  61 +
  62 +CREATE OR REPLACE PROCEDURE create_ts_kv_dictionary_table() LANGUAGE plpgsql AS $$
  63 +
  64 +BEGIN
  65 + CREATE TABLE IF NOT EXISTS ts_kv_dictionary
  66 + (
  67 + key varchar(255) NOT NULL,
  68 + key_id serial UNIQUE,
  69 + CONSTRAINT ts_key_id_pkey PRIMARY KEY (key)
  70 + );
  71 +END;
  72 +$$;
  73 +
  74 +-- call insert_into_dictionary();
  75 +
  76 +CREATE OR REPLACE PROCEDURE insert_into_dictionary() LANGUAGE plpgsql AS $$
  77 +
  78 +DECLARE
  79 + insert_record RECORD;
  80 + key_cursor CURSOR FOR SELECT DISTINCT key
  81 + FROM tenant_ts_kv_old
  82 + ORDER BY key;
  83 +BEGIN
  84 + OPEN key_cursor;
  85 + LOOP
  86 + FETCH key_cursor INTO insert_record;
  87 + EXIT WHEN NOT FOUND;
  88 + IF NOT EXISTS(SELECT key FROM ts_kv_dictionary WHERE key = insert_record.key) THEN
  89 + INSERT INTO ts_kv_dictionary(key) VALUES (insert_record.key);
  90 + RAISE NOTICE 'Key: % has been inserted into the dictionary!',insert_record.key;
  91 + ELSE
  92 + RAISE NOTICE 'Key: % already exists in the dictionary!',insert_record.key;
  93 + END IF;
  94 + END LOOP;
  95 + CLOSE key_cursor;
  96 +END;
  97 +$$;
  98 +
  99 +-- call insert_into_ts_kv();
  100 +
  101 +CREATE OR REPLACE PROCEDURE insert_into_ts_kv() LANGUAGE plpgsql AS $$
  102 +
  103 +DECLARE
  104 + insert_size CONSTANT integer := 10000;
  105 + insert_counter integer DEFAULT 0;
  106 + insert_record RECORD;
  107 + insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id,
  108 + new_ts_kv_records.key AS key,
  109 + new_ts_kv_records.ts AS ts,
  110 + new_ts_kv_records.bool_v AS bool_v,
  111 + new_ts_kv_records.str_v AS str_v,
  112 + new_ts_kv_records.long_v AS long_v,
  113 + new_ts_kv_records.dbl_v AS dbl_v
  114 + FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part,
  115 + SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part,
  116 + SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part,
  117 + SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part,
  118 + SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part,
  119 + key_id AS key,
  120 + ts,
  121 + bool_v,
  122 + str_v,
  123 + long_v,
  124 + dbl_v
  125 + FROM tenant_ts_kv_old
  126 + INNER JOIN ts_kv_dictionary ON (tenant_ts_kv_old.key = ts_kv_dictionary.key)) AS new_ts_kv_records;
  127 +BEGIN
  128 + OPEN insert_cursor;
  129 + LOOP
  130 + insert_counter := insert_counter + 1;
  131 + FETCH insert_cursor INTO insert_record;
  132 + IF NOT FOUND THEN
  133 + RAISE NOTICE '% records have been inserted into the new ts_kv table!',insert_counter - 1;
  134 + EXIT;
  135 + END IF;
  136 + INSERT INTO ts_kv(entity_id, key, ts, bool_v, str_v, long_v, dbl_v)
  137 + VALUES (insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v,
  138 + insert_record.long_v, insert_record.dbl_v);
  139 + IF MOD(insert_counter, insert_size) = 0 THEN
  140 + RAISE NOTICE '% records have been inserted into the new ts_kv table!',insert_counter;
  141 + END IF;
  142 + END LOOP;
  143 + CLOSE insert_cursor;
  144 +END;
  145 +$$;
  146 +
  147 +-- call insert_into_ts_kv_latest();
  148 +
  149 +CREATE OR REPLACE PROCEDURE insert_into_ts_kv_latest() LANGUAGE plpgsql AS $$
  150 +
  151 +DECLARE
  152 + insert_size CONSTANT integer := 10000;
  153 + insert_counter integer DEFAULT 0;
  154 + latest_record RECORD;
  155 + insert_record RECORD;
  156 + insert_cursor CURSOR FOR SELECT
  157 + latest_records.key AS key,
  158 + latest_records.entity_id AS entity_id,
  159 + latest_records.ts AS ts
  160 + FROM (SELECT DISTINCT key AS key, entity_id AS entity_id, MAX(ts) AS ts FROM ts_kv GROUP BY key, entity_id) AS latest_records;
  161 +BEGIN
  162 + OPEN insert_cursor;
  163 + LOOP
  164 + insert_counter := insert_counter + 1;
  165 + FETCH insert_cursor INTO latest_record;
  166 + IF NOT FOUND THEN
  167 + RAISE NOTICE '% records have been inserted into the ts_kv_latest table!',insert_counter - 1;
  168 + EXIT;
  169 + END IF;
  170 + SELECT entity_id AS entity_id, key AS key, ts AS ts, bool_v AS bool_v, str_v AS str_v, long_v AS long_v, dbl_v AS dbl_v INTO insert_record FROM ts_kv WHERE entity_id = latest_record.entity_id AND key = latest_record.key AND ts = latest_record.ts;
  171 + INSERT INTO ts_kv_latest(entity_id, key, ts, bool_v, str_v, long_v, dbl_v)
  172 + VALUES (insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v, insert_record.long_v, insert_record.dbl_v);
  173 + IF MOD(insert_counter, insert_size) = 0 THEN
  174 + RAISE NOTICE '% records have been inserted into the ts_kv_latest table!',insert_counter;
  175 + END IF;
  176 + END LOOP;
  177 + CLOSE insert_cursor;
  178 +END;
  179 +$$;
... ...
  1 +--
  2 +-- Copyright © 2016-2020 The Thingsboard Authors
  3 +--
  4 +-- Licensed under the Apache License, Version 2.0 (the "License");
  5 +-- you may not use this file except in compliance with the License.
  6 +-- You may obtain a copy of the License at
  7 +--
  8 +-- http://www.apache.org/licenses/LICENSE-2.0
  9 +--
  10 +-- Unless required by applicable law or agreed to in writing, software
  11 +-- distributed under the License is distributed on an "AS IS" BASIS,
  12 +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +-- See the License for the specific language governing permissions and
  14 +-- limitations under the License.
  15 +--
  16 +
  17 +CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS
  18 +$$
  19 +BEGIN
  20 + uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) ||
  21 + '-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12);
  22 +END;
  23 +$$ LANGUAGE plpgsql;
  24 +
  25 +CREATE OR REPLACE FUNCTION delete_device_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint,
  26 + OUT deleted bigint) AS
  27 +$$
  28 +BEGIN
  29 + EXECUTE format(
  30 + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(device.id) as entity_id FROM device WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted',
  31 + tenant_id, customer_id, ttl) into deleted;
  32 +END;
  33 +$$ LANGUAGE plpgsql;
  34 +
  35 +CREATE OR REPLACE FUNCTION delete_asset_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint,
  36 + OUT deleted bigint) AS
  37 +$$
  38 +BEGIN
  39 + EXECUTE format(
  40 + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(asset.id) as entity_id FROM asset WHERE tenant_id = %L and customer_id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted',
  41 + tenant_id, customer_id, ttl) into deleted;
  42 +END;
  43 +$$ LANGUAGE plpgsql;
  44 +
  45 +CREATE OR REPLACE FUNCTION delete_customer_records_from_ts_kv(tenant_id varchar, customer_id varchar, ttl bigint,
  46 + OUT deleted bigint) AS
  47 +$$
  48 +BEGIN
  49 + EXECUTE format(
  50 + 'WITH deleted AS (DELETE FROM ts_kv WHERE entity_id IN (SELECT to_uuid(customer.id) as entity_id FROM customer WHERE tenant_id = %L and id = %L) AND ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted',
  51 + tenant_id, customer_id, ttl) into deleted;
  52 +END;
  53 +$$ LANGUAGE plpgsql;
  54 +
  55 +CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid varchar(31),
  56 + IN system_ttl bigint, INOUT deleted bigint)
  57 + LANGUAGE plpgsql AS
  58 +$$
  59 +DECLARE
  60 + tenant_cursor CURSOR FOR select tenant.id as tenant_id
  61 + from tenant;
  62 + tenant_id_record varchar;
  63 + customer_id_record varchar;
  64 + tenant_ttl bigint;
  65 + customer_ttl bigint;
  66 + deleted_for_entities bigint;
  67 + tenant_ttl_ts bigint;
  68 + customer_ttl_ts bigint;
  69 +BEGIN
  70 + OPEN tenant_cursor;
  71 + FETCH tenant_cursor INTO tenant_id_record;
  72 + WHILE FOUND
  73 + LOOP
  74 + EXECUTE format(
  75 + 'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L',
  76 + tenant_id_record, 'TTL') INTO tenant_ttl;
  77 + if tenant_ttl IS NULL THEN
  78 + tenant_ttl := system_ttl;
  79 + END IF;
  80 + IF tenant_ttl > 0 THEN
  81 + tenant_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - tenant_ttl::bigint * 1000)::bigint;
  82 + deleted_for_entities := delete_device_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts);
  83 + deleted := deleted + deleted_for_entities;
  84 + RAISE NOTICE '% telemetry removed for devices where tenant_id = %', deleted_for_entities, tenant_id_record;
  85 + deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record, null_uuid, tenant_ttl_ts);
  86 + deleted := deleted + deleted_for_entities;
  87 + RAISE NOTICE '% telemetry removed for assets where tenant_id = %', deleted_for_entities, tenant_id_record;
  88 + END IF;
  89 + FOR customer_id_record IN
  90 + SELECT customer.id AS customer_id FROM customer WHERE customer.tenant_id = tenant_id_record
  91 + LOOP
  92 + EXECUTE format(
  93 + 'select attribute_kv.long_v from attribute_kv where attribute_kv.entity_id = %L and attribute_kv.attribute_key = %L',
  94 + customer_id_record, 'TTL') INTO customer_ttl;
  95 + IF customer_ttl IS NULL THEN
  96 + customer_ttl_ts := tenant_ttl_ts;
  97 + ELSE
  98 + IF customer_ttl > 0 THEN
  99 + customer_ttl_ts :=
  100 + (EXTRACT(EPOCH FROM current_timestamp) * 1000 -
  101 + customer_ttl::bigint * 1000)::bigint;
  102 + END IF;
  103 + END IF;
  104 + IF customer_ttl_ts IS NOT NULL AND customer_ttl_ts > 0 THEN
  105 + deleted_for_entities :=
  106 + delete_customer_records_from_ts_kv(tenant_id_record, customer_id_record,
  107 + customer_ttl_ts);
  108 + deleted := deleted + deleted_for_entities;
  109 + RAISE NOTICE '% telemetry removed for customer with id = % where tenant_id = %', deleted_for_entities, customer_id_record, tenant_id_record;
  110 + deleted_for_entities :=
  111 + delete_device_records_from_ts_kv(tenant_id_record, customer_id_record,
  112 + customer_ttl_ts);
  113 + deleted := deleted + deleted_for_entities;
  114 + RAISE NOTICE '% telemetry removed for devices where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record;
  115 + deleted_for_entities := delete_asset_records_from_ts_kv(tenant_id_record,
  116 + customer_id_record,
  117 + customer_ttl_ts);
  118 + deleted := deleted + deleted_for_entities;
  119 + RAISE NOTICE '% telemetry removed for assets where tenant_id = % and customer_id = %', deleted_for_entities, tenant_id_record, customer_id_record;
  120 + END IF;
  121 + END LOOP;
  122 + FETCH tenant_cursor INTO tenant_id_record;
  123 + END LOOP;
  124 +END
  125 +$$;
  126 +
  127 +CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint)
  128 + LANGUAGE plpgsql AS
  129 +$$
  130 +DECLARE
  131 + ttl_ts bigint;
  132 + debug_ttl_ts bigint;
  133 + ttl_deleted_count bigint DEFAULT 0;
  134 + debug_ttl_deleted_count bigint DEFAULT 0;
  135 +BEGIN
  136 + IF ttl > 0 THEN
  137 + ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - ttl::bigint * 1000)::bigint;
  138 + EXECUTE format(
  139 + 'WITH deleted AS (DELETE FROM event WHERE ts < %L::bigint AND (event_type != %L::varchar AND event_type != %L::varchar) RETURNING *) SELECT count(*) FROM deleted', ttl_ts, 'DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') into ttl_deleted_count;
  140 + END IF;
  141 + IF debug_ttl > 0 THEN
  142 + debug_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - debug_ttl::bigint * 1000)::bigint;
  143 + EXECUTE format(
  144 + 'WITH deleted AS (DELETE FROM event WHERE ts < %L::bigint AND (event_type = %L::varchar OR event_type = %L::varchar) RETURNING *) SELECT count(*) FROM deleted', debug_ttl_ts, 'DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') into debug_ttl_deleted_count;
  145 + END IF;
  146 + RAISE NOTICE 'Events removed by ttl: %', ttl_deleted_count;
  147 + RAISE NOTICE 'Debug Events removed by ttl: %', debug_ttl_deleted_count;
  148 + deleted := ttl_deleted_count + debug_ttl_deleted_count;
  149 +END
  150 +$$;
... ...
... ... @@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
24 24 import com.google.common.util.concurrent.FutureCallback;
25 25 import com.google.common.util.concurrent.Futures;
26 26 import com.google.common.util.concurrent.ListenableFuture;
  27 +import com.google.common.util.concurrent.MoreExecutors;
27 28 import com.typesafe.config.Config;
28 29 import com.typesafe.config.ConfigFactory;
29 30 import lombok.Getter;
... ... @@ -36,7 +37,6 @@ import org.springframework.data.redis.core.RedisTemplate;
36 37 import org.springframework.scheduling.annotation.Scheduled;
37 38 import org.springframework.stereotype.Component;
38 39 import org.thingsboard.rule.engine.api.MailService;
39   -import org.thingsboard.rule.engine.api.RuleChainTransactionService;
40 40 import org.thingsboard.server.actors.service.ActorService;
41 41 import org.thingsboard.server.actors.tenant.DebugTbRateLimits;
42 42 import org.thingsboard.server.common.data.DataConstants;
... ... @@ -44,10 +44,11 @@ import org.thingsboard.server.common.data.Event;
44 44 import org.thingsboard.server.common.data.id.EntityId;
45 45 import org.thingsboard.server.common.data.id.TenantId;
46 46 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
  47 +import org.thingsboard.server.common.msg.TbActorMsg;
47 48 import org.thingsboard.server.common.msg.TbMsg;
48   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
  49 +import org.thingsboard.server.common.msg.queue.ServiceType;
  50 +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
49 51 import org.thingsboard.server.common.msg.tools.TbRateLimits;
50   -import org.thingsboard.server.common.transport.auth.DeviceAuthService;
51 52 import org.thingsboard.server.dao.alarm.AlarmService;
52 53 import org.thingsboard.server.dao.asset.AssetService;
53 54 import org.thingsboard.server.dao.attributes.AttributesService;
... ... @@ -64,24 +65,23 @@ import org.thingsboard.server.dao.rule.RuleChainService;
64 65 import org.thingsboard.server.dao.tenant.TenantService;
65 66 import org.thingsboard.server.dao.timeseries.TimeseriesService;
66 67 import org.thingsboard.server.dao.user.UserService;
67   -import org.thingsboard.server.kafka.TbNodeIdProvider;
68   -import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
69   -import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
70   -import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
  68 +import org.thingsboard.server.queue.discovery.PartitionService;
  69 +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
71 70 import org.thingsboard.server.service.component.ComponentDiscoveryService;
72 71 import org.thingsboard.server.service.encoding.DataDecodingEncodingService;
73   -import org.thingsboard.server.service.executors.ClusterRpcCallbackExecutorService;
74 72 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
75 73 import org.thingsboard.server.service.executors.ExternalCallExecutorService;
76 74 import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
77 75 import org.thingsboard.server.service.mail.MailExecutorService;
78   -import org.thingsboard.server.service.rpc.DeviceRpcService;
  76 +import org.thingsboard.server.service.queue.TbClusterService;
  77 +import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
  78 +import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
79 79 import org.thingsboard.server.service.script.JsExecutorService;
80 80 import org.thingsboard.server.service.script.JsInvokeService;
81 81 import org.thingsboard.server.service.session.DeviceSessionCacheService;
82 82 import org.thingsboard.server.service.state.DeviceStateService;
83 83 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
84   -import org.thingsboard.server.service.transport.RuleEngineTransportService;
  84 +import org.thingsboard.server.service.transport.TbCoreToTransportService;
85 85
86 86 import javax.annotation.Nullable;
87 87 import java.io.IOException;
... ... @@ -105,13 +105,14 @@ public class ActorSystemContext {
105 105 return debugPerTenantLimits;
106 106 }
107 107
  108 + @Autowired
108 109 @Getter
109 110 @Setter
110   - private ActorService actorService;
  111 + private TbServiceInfoProvider serviceInfoProvider;
111 112
112   - @Autowired
113 113 @Getter
114   - private DiscoveryService discoveryService;
  114 + @Setter
  115 + private ActorService actorService;
115 116
116 117 @Autowired
117 118 @Getter
... ... @@ -120,22 +121,10 @@ public class ActorSystemContext {
120 121
121 122 @Autowired
122 123 @Getter
123   - private ClusterRoutingService routingService;
124   -
125   - @Autowired
126   - @Getter
127   - private ClusterRpcService rpcService;
128   -
129   - @Autowired
130   - @Getter
131 124 private DataDecodingEncodingService encodingService;
132 125
133 126 @Autowired
134 127 @Getter
135   - private DeviceAuthService deviceAuthService;
136   -
137   - @Autowired
138   - @Getter
139 128 private DeviceService deviceService;
140 129
141 130 @Autowired
... ... @@ -163,6 +152,13 @@ public class ActorSystemContext {
163 152 private RuleChainService ruleChainService;
164 153
165 154 @Autowired
  155 + private PartitionService partitionService;
  156 +
  157 + @Autowired
  158 + @Getter
  159 + private TbClusterService clusterService;
  160 +
  161 + @Autowired
166 162 @Getter
167 163 private TimeseriesService tsService;
168 164
... ... @@ -196,10 +192,6 @@ public class ActorSystemContext {
196 192
197 193 @Autowired
198 194 @Getter
199   - private DeviceRpcService deviceRpcService;
200   -
201   - @Autowired
202   - @Getter
203 195 private JsInvokeService jsSandbox;
204 196
205 197 @Autowired
... ... @@ -212,10 +204,6 @@ public class ActorSystemContext {
212 204
213 205 @Autowired
214 206 @Getter
215   - private ClusterRpcCallbackExecutorService clusterRpcCallbackExecutor;
216   -
217   - @Autowired
218   - @Getter
219 207 private DbCallbackExecutorService dbCallbackExecutor;
220 208
221 209 @Autowired
... ... @@ -230,27 +218,34 @@ public class ActorSystemContext {
230 218 @Getter
231 219 private MailService mailService;
232 220
233   - @Autowired
  221 + //TODO: separate context for TbCore and TbRuleEngine
  222 + @Autowired(required = false)
234 223 @Getter
235 224 private DeviceStateService deviceStateService;
236 225
237   - @Autowired
  226 + @Autowired(required = false)
238 227 @Getter
239 228 private DeviceSessionCacheService deviceSessionCacheService;
240 229
241   - @Lazy
242   - @Autowired
  230 + @Autowired(required = false)
243 231 @Getter
244   - private RuleEngineTransportService ruleEngineTransportService;
  232 + private TbCoreToTransportService tbCoreToTransportService;
245 233
  234 + /**
  235 + * The following Service will be null if we operate in tb-core mode
  236 + */
246 237 @Lazy
247   - @Autowired
  238 + @Autowired(required = false)
248 239 @Getter
249   - private RuleChainTransactionService ruleChainTransactionService;
  240 + private TbRuleEngineDeviceRpcService tbRuleEngineDeviceRpcService;
250 241
251   - @Value("${cluster.partition_id}")
  242 + /**
  243 + * The following Service will be null if we operate in tb-rule-engine mode
  244 + */
  245 + @Lazy
  246 + @Autowired(required = false)
252 247 @Getter
253   - private long queuePartitionId;
  248 + private TbCoreDeviceRpcService tbCoreDeviceRpcService;
254 249
255 250 @Value("${actors.session.max_concurrent_sessions_per_device:1}")
256 251 @Getter
... ... @@ -268,10 +263,6 @@ public class ActorSystemContext {
268 263 @Getter
269 264 private long queuePersistenceTimeout;
270 265
271   - @Value("${actors.client_side_rpc.timeout}")
272   - @Getter
273   - private long clientSideRpcTimeout;
274   -
275 266 @Value("${actors.rule.chain.error_persist_frequency}")
276 267 @Getter
277 268 private long ruleChainErrorPersistFrequency;
... ... @@ -295,7 +286,7 @@ public class ActorSystemContext {
295 286 @Getter
296 287 private final AtomicInteger jsInvokeFailuresCount = new AtomicInteger(0);
297 288
298   - @Scheduled(fixedDelayString = "${js.remote.stats.print_interval_ms}")
  289 + @Scheduled(fixedDelayString = "${actors.statistics.js_print_interval_ms}")
299 290 public void printStats() {
300 291 if (statisticsEnabled) {
301 292 if (jsInvokeRequestsCount.get() > 0 || jsInvokeResponsesCount.get() > 0 || jsInvokeFailuresCount.get() > 0) {
... ... @@ -333,11 +324,6 @@ public class ActorSystemContext {
333 324 @Setter
334 325 private ActorSystem actorSystem;
335 326
336   - @Autowired
337   - @Getter
338   - private TbNodeIdProvider nodeIdProvider;
339   -
340   - @Getter
341 327 @Setter
342 328 private ActorRef appActor;
343 329
... ... @@ -364,6 +350,8 @@ public class ActorSystemContext {
364 350 config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load());
365 351 }
366 352
  353 +
  354 +
367 355 public Scheduler getScheduler() {
368 356 return actorSystem.scheduler();
369 357 }
... ... @@ -373,7 +361,7 @@ public class ActorSystemContext {
373 361 event.setTenantId(tenantId);
374 362 event.setEntityId(entityId);
375 363 event.setType(DataConstants.ERROR);
376   - event.setBody(toBodyJson(discoveryService.getCurrentServer().getServerAddress(), method, toString(e)));
  364 + event.setBody(toBodyJson(serviceInfoProvider.getServiceInfo().getServiceId(), method, toString(e)));
377 365 persistEvent(event);
378 366 }
379 367
... ... @@ -382,7 +370,7 @@ public class ActorSystemContext {
382 370 event.setTenantId(tenantId);
383 371 event.setEntityId(entityId);
384 372 event.setType(DataConstants.LC_EVENT);
385   - event.setBody(toBodyJson(discoveryService.getCurrentServer().getServerAddress(), lcEvent, Optional.ofNullable(e)));
  373 + event.setBody(toBodyJson(serviceInfoProvider.getServiceInfo().getServiceId(), lcEvent, Optional.ofNullable(e)));
386 374 persistEvent(event);
387 375 }
388 376
... ... @@ -396,8 +384,8 @@ public class ActorSystemContext {
396 384 return sw.toString();
397 385 }
398 386
399   - private JsonNode toBodyJson(ServerAddress server, ComponentLifecycleEvent event, Optional<Exception> e) {
400   - ObjectNode node = mapper.createObjectNode().put("server", server.toString()).put("event", event.name());
  387 + private JsonNode toBodyJson(String serviceId, ComponentLifecycleEvent event, Optional<Exception> e) {
  388 + ObjectNode node = mapper.createObjectNode().put("server", serviceId).put("event", event.name());
401 389 if (e.isPresent()) {
402 390 node = node.put("success", false);
403 391 node = node.put("error", toString(e.get()));
... ... @@ -407,12 +395,21 @@ public class ActorSystemContext {
407 395 return node;
408 396 }
409 397
410   - private JsonNode toBodyJson(ServerAddress server, String method, String body) {
411   - return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body);
  398 + private JsonNode toBodyJson(String serviceId, String method, String body) {
  399 + return mapper.createObjectNode().put("server", serviceId).put("method", method).put("error", body);
412 400 }
413 401
414   - public String getServerAddress() {
415   - return discoveryService.getCurrentServer().getServerAddress().toString();
  402 + public TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId) {
  403 + return partitionService.resolve(serviceType, tenantId, entityId);
  404 + }
  405 +
  406 + public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) {
  407 + return partitionService.resolve(serviceType, queueName, tenantId, entityId);
  408 + }
  409 +
  410 +
  411 + public String getServiceId() {
  412 + return serviceInfoProvider.getServiceId();
416 413 }
417 414
418 415 public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType) {
... ... @@ -443,7 +440,7 @@ public class ActorSystemContext {
443 440
444 441 ObjectNode node = mapper.createObjectNode()
445 442 .put("type", type)
446   - .put("server", getServerAddress())
  443 + .put("server", getServiceId())
447 444 .put("entityId", tbMsg.getOriginator().getId().toString())
448 445 .put("entityName", tbMsg.getOriginator().getEntityType().name())
449 446 .put("msgId", tbMsg.getId().toString())
... ... @@ -469,7 +466,7 @@ public class ActorSystemContext {
469 466 public void onFailure(Throwable th) {
470 467 log.error("Could not save debug Event for Node", th);
471 468 }
472   - });
  469 + }, MoreExecutors.directExecutor());
473 470 } catch (IOException ex) {
474 471 log.warn("Failed to persist rule node debug message", ex);
475 472 }
... ... @@ -503,7 +500,7 @@ public class ActorSystemContext {
503 500
504 501 ObjectNode node = mapper.createObjectNode()
505 502 //todo: what fields are needed here?
506   - .put("server", getServerAddress())
  503 + .put("server", getServiceId())
507 504 .put("message", "Reached debug mode rate limit!");
508 505
509 506 if (error != null) {
... ... @@ -522,11 +519,14 @@ public class ActorSystemContext {
522 519 public void onFailure(Throwable th) {
523 520 log.error("Could not save debug Event for Rule Chain", th);
524 521 }
525   - });
  522 + }, MoreExecutors.directExecutor());
526 523 }
527 524
528 525 public static Exception toException(Throwable error) {
529 526 return Exception.class.isInstance(error) ? (Exception) error : new Exception(error);
530 527 }
531 528
  529 + public void tell(TbActorMsg tbActorMsg, ActorRef sender) {
  530 + appActor.tell(tbActorMsg, sender);
  531 + }
532 532 }
... ...
... ... @@ -20,19 +20,13 @@ import akka.actor.LocalActorRef;
20 20 import akka.actor.OneForOneStrategy;
21 21 import akka.actor.Props;
22 22 import akka.actor.SupervisorStrategy;
23   -import akka.actor.SupervisorStrategy.Directive;
24 23 import akka.actor.Terminated;
25   -import akka.event.Logging;
26   -import akka.event.LoggingAdapter;
27   -import akka.japi.Function;
28 24 import com.google.common.collect.BiMap;
29 25 import com.google.common.collect.HashBiMap;
30   -import lombok.extern.slf4j.Slf4j;
31 26 import org.thingsboard.server.actors.ActorSystemContext;
32   -import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
  27 +import org.thingsboard.server.actors.service.ContextAwareActor;
33 28 import org.thingsboard.server.actors.service.ContextBasedCreator;
34 29 import org.thingsboard.server.actors.service.DefaultActorService;
35   -import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager;
36 30 import org.thingsboard.server.actors.tenant.TenantActor;
37 31 import org.thingsboard.server.common.data.EntityType;
38 32 import org.thingsboard.server.common.data.Tenant;
... ... @@ -42,29 +36,32 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
42 36 import org.thingsboard.server.common.msg.MsgType;
43 37 import org.thingsboard.server.common.msg.TbActorMsg;
44 38 import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
45   -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
46   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
47 39 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
48   -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
  40 +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
  41 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  42 +import org.thingsboard.server.common.msg.queue.ServiceType;
49 43 import org.thingsboard.server.dao.model.ModelConstants;
50 44 import org.thingsboard.server.dao.tenant.TenantService;
  45 +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
51 46 import scala.concurrent.duration.Duration;
52 47
53   -import java.util.HashMap;
54   -import java.util.Map;
  48 +import java.util.HashSet;
55 49 import java.util.Optional;
  50 +import java.util.Set;
56 51
57   -public class AppActor extends RuleChainManagerActor {
  52 +public class AppActor extends ContextAwareActor {
58 53
59 54 private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
60 55 private final TenantService tenantService;
61 56 private final BiMap<TenantId, ActorRef> tenantActors;
  57 + private final Set<TenantId> deletedTenants;
62 58 private boolean ruleChainsInitialized;
63 59
64 60 private AppActor(ActorSystemContext systemContext) {
65   - super(systemContext, new SystemRuleChainManager(systemContext));
  61 + super(systemContext);
66 62 this.tenantService = systemContext.getTenantService();
67 63 this.tenantActors = HashBiMap.create();
  64 + this.deletedTenants = new HashSet<>();
68 65 }
69 66
70 67 @Override
... ... @@ -79,7 +76,7 @@ public class AppActor extends RuleChainManagerActor {
79 76 @Override
80 77 protected boolean process(TbActorMsg msg) {
81 78 if (!ruleChainsInitialized) {
82   - initRuleChainsAndTenantActors();
  79 + initTenantActors();
83 80 ruleChainsInitialized = true;
84 81 if (msg.getMsgType() != MsgType.APP_INIT_MSG) {
85 82 log.warn("Rule Chains initialized by unexpected message: {}", msg);
... ... @@ -88,17 +85,14 @@ public class AppActor extends RuleChainManagerActor {
88 85 switch (msg.getMsgType()) {
89 86 case APP_INIT_MSG:
90 87 break;
91   - case SEND_TO_CLUSTER_MSG:
92   - onPossibleClusterMsg((SendToClusterMsg) msg);
93   - break;
94   - case CLUSTER_EVENT_MSG:
  88 + case PARTITION_CHANGE_MSG:
95 89 broadcast(msg);
96 90 break;
97 91 case COMPONENT_LIFE_CYCLE_MSG:
98 92 onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
99 93 break;
100   - case SERVICE_TO_RULE_ENGINE_MSG:
101   - onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);
  94 + case QUEUE_TO_RULE_ENGINE_MSG:
  95 + onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg);
102 96 break;
103 97 case TRANSPORT_TO_DEVICE_ACTOR_MSG:
104 98 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
... ... @@ -106,7 +100,6 @@ public class AppActor extends RuleChainManagerActor {
106 100 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
107 101 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
108 102 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
109   - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG:
110 103 onToDeviceActorMsg((TenantAwareMsg) msg);
111 104 break;
112 105 default:
... ... @@ -115,16 +108,30 @@ public class AppActor extends RuleChainManagerActor {
115 108 return true;
116 109 }
117 110
118   - private void initRuleChainsAndTenantActors() {
  111 + private void initTenantActors() {
119 112 log.info("Starting main system actor.");
120 113 try {
121   - initRuleChains();
122   - if (systemContext.isTenantComponentsInitEnabled()) {
123   - PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT);
124   - for (Tenant tenant : tenantIterator) {
  114 + // This Service may be started for specific tenant only.
  115 + Optional<TenantId> isolatedTenantId = systemContext.getServiceInfoProvider().getIsolatedTenant();
  116 + if (isolatedTenantId.isPresent()) {
  117 + Tenant tenant = systemContext.getTenantService().findTenantById(isolatedTenantId.get());
  118 + if (tenant != null) {
125 119 log.debug("[{}] Creating tenant actor", tenant.getId());
126 120 getOrCreateTenantActor(tenant.getId());
127 121 log.debug("Tenant actor created.");
  122 + } else {
  123 + log.error("[{}] Tenant with such ID does not exist", isolatedTenantId.get());
  124 + }
  125 + } else if (systemContext.isTenantComponentsInitEnabled()) {
  126 + PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT);
  127 + boolean isRuleEngine = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE);
  128 + boolean isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE);
  129 + for (Tenant tenant : tenantIterator) {
  130 + if (isCore || (isRuleEngine && !tenant.isIsolatedTbRuleEngine())) {
  131 + log.debug("[{}] Creating tenant actor", tenant.getId());
  132 + getOrCreateTenantActor(tenant.getId());
  133 + log.debug("[{}] Tenant actor created.", tenant.getId());
  134 + }
128 135 }
129 136 }
130 137 log.info("Main system actor started.");
... ... @@ -133,40 +140,33 @@ public class AppActor extends RuleChainManagerActor {
133 140 }
134 141 }
135 142
136   - private void onPossibleClusterMsg(SendToClusterMsg msg) {
137   - Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(msg.getEntityId());
138   - if (address.isPresent()) {
139   - systemContext.getRpcService().tell(
140   - systemContext.getEncodingService().convertToProtoDataMessage(address.get(), msg.getMsg()));
141   - } else {
142   - self().tell(msg.getMsg(), ActorRef.noSender());
143   - }
144   - }
145   -
146   - private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) {
  143 + private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) {
147 144 if (SYSTEM_TENANT.equals(msg.getTenantId())) {
148   -// this may be a notification about system entities created.
149   -// log.warn("[{}] Invalid service to rule engine msg called. System messages are not supported yet: {}", SYSTEM_TENANT, msg);
  145 + msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!"));
150 146 } else {
151   - getOrCreateTenantActor(msg.getTenantId()).tell(msg, self());
  147 + if (!deletedTenants.contains(msg.getTenantId())) {
  148 + getOrCreateTenantActor(msg.getTenantId()).tell(msg, self());
  149 + } else {
  150 + msg.getTbMsg().getCallback().onSuccess();
  151 + }
152 152 }
153 153 }
154 154
155   - @Override
156 155 protected void broadcast(Object msg) {
157   - super.broadcast(msg);
158 156 tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
159 157 }
160 158
161 159 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
162 160 ActorRef target = null;
163 161 if (SYSTEM_TENANT.equals(msg.getTenantId())) {
164   - target = getEntityActorRef(msg.getEntityId());
  162 + log.warn("Message has system tenant id: {}", msg);
165 163 } else {
166 164 if (msg.getEntityId().getEntityType() == EntityType.TENANT
167 165 && msg.getEvent() == ComponentLifecycleEvent.DELETED) {
168   - log.debug("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg);
169   - ActorRef tenantActor = tenantActors.remove(new TenantId(msg.getEntityId().getId()));
  166 + log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg);
  167 + TenantId tenantId = new TenantId(msg.getEntityId().getId());
  168 + deletedTenants.add(tenantId);
  169 + ActorRef tenantActor = tenantActors.get(tenantId);
170 170 if (tenantActor != null) {
171 171 log.debug("[{}] Deleting tenant actor: {}", msg.getTenantId(), tenantActor);
172 172 context().stop(tenantActor);
... ... @@ -183,16 +183,22 @@ public class AppActor extends RuleChainManagerActor {
183 183 }
184 184
185 185 private void onToDeviceActorMsg(TenantAwareMsg msg) {
186   - getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender());
  186 + if (!deletedTenants.contains(msg.getTenantId())) {
  187 + getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender());
  188 + } else {
  189 + if (msg instanceof TransportToDeviceActorMsgWrapper) {
  190 + ((TransportToDeviceActorMsgWrapper) msg).getCallback().onSuccess();
  191 + }
  192 + }
187 193 }
188 194
189 195 private ActorRef getOrCreateTenantActor(TenantId tenantId) {
190 196 return tenantActors.computeIfAbsent(tenantId, k -> {
191   - log.debug("[{}] Creating tenant actor.", tenantId);
  197 + log.info("[{}] Creating tenant actor.", tenantId);
192 198 ActorRef tenantActor = context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId))
193 199 .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString());
194 200 context().watch(tenantActor);
195   - log.debug("[{}] Created tenant actor: {}.", tenantId, tenantActor);
  201 + log.info("[{}] Created tenant actor: {}.", tenantId, tenantActor);
196 202 return tenantActor;
197 203 });
198 204 }
... ...
... ... @@ -22,10 +22,8 @@ import org.thingsboard.server.actors.service.ContextAwareActor;
22 22 import org.thingsboard.server.common.data.id.DeviceId;
23 23 import org.thingsboard.server.common.data.id.TenantId;
24 24 import org.thingsboard.server.common.msg.TbActorMsg;
25   -import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg;
26 25 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
27 26 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
28   -import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;
29 27 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
30 28
31 29 public class DeviceActor extends ContextAwareActor {
... ... @@ -49,6 +47,11 @@ public class DeviceActor extends ContextAwareActor {
49 47 }
50 48
51 49 @Override
  50 + public void postStop() {
  51 +
  52 + }
  53 +
  54 + @Override
52 55 protected boolean process(TbActorMsg msg) {
53 56 switch (msg.getMsgType()) {
54 57 case TRANSPORT_TO_DEVICE_ACTOR_MSG:
... ... @@ -66,15 +69,9 @@ public class DeviceActor extends ContextAwareActor {
66 69 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
67 70 processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg);
68 71 break;
69   - case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
70   - processor.processToServerRPCResponse(context(), (ToServerRpcResponseActorMsg) msg);
71   - break;
72 72 case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG:
73 73 processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg);
74 74 break;
75   - case DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG:
76   - processor.processClientSideRpcTimeout(context(), (DeviceActorClientSideRpcTimeoutMsg) msg);
77   - break;
78 75 case SESSION_TIMEOUT_MSG:
79 76 processor.checkSessionsTimeout();
80 77 break;
... ...