Commit 1430fe27dbee4af5600aa934ec76111b10a3a57d
Committed by
GitHub
Merge pull request #223 from thingsboard/feature/TB-70
TB-70: RPC widgets: improve led indicator widget behavior.
Showing
2 changed files
with
91 additions
and
23 deletions
@@ -96,9 +96,9 @@ | @@ -96,9 +96,9 @@ | ||
96 | "templateHtml": "<tb-led-indicator ctx='ctx'></tb-led-indicator>", | 96 | "templateHtml": "<tb-led-indicator ctx='ctx'></tb-led-indicator>", |
97 | "templateCss": "", | 97 | "templateCss": "", |
98 | "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", | 98 | "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", |
99 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"getValueMethod\": {\n \"title\": \"Get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"valuePollingInterval\": {\n \"title\": \"Value polling interval (ms)\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"getValueMethod\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"getValueMethod\",\n \"valuePollingInterval\",\n \"requestTimeout\"\n ]\n}", | 99 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"scheckStatusMethod\": {\n \"title\": \"Check device status method\",\n \"type\": \"string\",\n \"default\": \"checkStatus\"\n },\n \"valueAttribute\": {\n \"title\": \"Device attribute containing led status value\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"scheckStatusMethod\", \"valueAttribute\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"scheckStatusMethod\",\n \"valueAttribute\",\n \"requestTimeout\"\n ]\n}", |
100 | "dataKeySettingsSchema": "{}\n", | 100 | "dataKeySettingsSchema": "{}\n", |
101 | - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"getValueMethod\":\"getValue\",\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valuePollingInterval\":500},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" | 101 | + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"scheckStatusMethod\":\"checkStatus\",\"valueAttribute\":\"value\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" |
102 | } | 102 | } |
103 | } | 103 | } |
104 | ] | 104 | ] |
@@ -43,13 +43,23 @@ function LedIndicator() { | @@ -43,13 +43,23 @@ function LedIndicator() { | ||
43 | } | 43 | } |
44 | 44 | ||
45 | /*@ngInject*/ | 45 | /*@ngInject*/ |
46 | -function LedIndicatorController($element, $scope, $timeout) { | 46 | +function LedIndicatorController($element, $scope, $timeout, utils, types) { |
47 | let vm = this; | 47 | let vm = this; |
48 | 48 | ||
49 | vm.showTitle = false; | 49 | vm.showTitle = false; |
50 | vm.value = false; | 50 | vm.value = false; |
51 | vm.error = ''; | 51 | vm.error = ''; |
52 | 52 | ||
53 | + const checkStatusPollingInterval = 10000; | ||
54 | + | ||
55 | + vm.subscriptionOptions = { | ||
56 | + callbacks: { | ||
57 | + onDataUpdated: onDataUpdated, | ||
58 | + onDataUpdateError: onDataUpdateError, | ||
59 | + dataLoading: () => {} | ||
60 | + } | ||
61 | + }; | ||
62 | + | ||
53 | var led = angular.element('.led', $element), | 63 | var led = angular.element('.led', $element), |
54 | ledContainer = angular.element('#led-container', $element), | 64 | ledContainer = angular.element('#led-container', $element), |
55 | textMeasure = angular.element('#text-measure', $element), | 65 | textMeasure = angular.element('#text-measure', $element), |
@@ -66,8 +76,11 @@ function LedIndicatorController($element, $scope, $timeout) { | @@ -66,8 +76,11 @@ function LedIndicatorController($element, $scope, $timeout) { | ||
66 | 76 | ||
67 | $scope.$on('$destroy', () => { | 77 | $scope.$on('$destroy', () => { |
68 | vm.destroyed = true; | 78 | vm.destroyed = true; |
69 | - if (vm.requestValueTimeoutHandle) { | ||
70 | - $timeout.cancel(vm.requestValueTimeoutHandle); | 79 | + if (vm.checkStatusTimeoutHandle) { |
80 | + $timeout.cancel(vm.checkStatusTimeoutHandle); | ||
81 | + } | ||
82 | + if (vm.subscription) { | ||
83 | + vm.ctx.subscriptionApi.removeSubscription(vm.subscription.id); | ||
71 | } | 84 | } |
72 | }); | 85 | }); |
73 | 86 | ||
@@ -80,6 +93,8 @@ function LedIndicatorController($element, $scope, $timeout) { | @@ -80,6 +93,8 @@ function LedIndicatorController($element, $scope, $timeout) { | ||
80 | 93 | ||
81 | var origColor = angular.isDefined(vm.ctx.settings.ledColor) ? vm.ctx.settings.ledColor : 'green'; | 94 | var origColor = angular.isDefined(vm.ctx.settings.ledColor) ? vm.ctx.settings.ledColor : 'green'; |
82 | 95 | ||
96 | + vm.valueAttribute = angular.isDefined(vm.ctx.settings.valueAttribute) ? vm.ctx.settings.valueAttribute : 'value'; | ||
97 | + | ||
83 | vm.ledColor = tinycolor(origColor).brighten(30).toHexString(); | 98 | vm.ledColor = tinycolor(origColor).brighten(30).toHexString(); |
84 | vm.ledMiddleColor = tinycolor(origColor).toHexString(); | 99 | vm.ledMiddleColor = tinycolor(origColor).toHexString(); |
85 | vm.disabledColor = tinycolor(origColor).darken(40).toHexString(); | 100 | vm.disabledColor = tinycolor(origColor).darken(40).toHexString(); |
@@ -101,19 +116,15 @@ function LedIndicatorController($element, $scope, $timeout) { | @@ -101,19 +116,15 @@ function LedIndicatorController($element, $scope, $timeout) { | ||
101 | if (vm.ctx.settings.requestTimeout) { | 116 | if (vm.ctx.settings.requestTimeout) { |
102 | vm.requestTimeout = vm.ctx.settings.requestTimeout; | 117 | vm.requestTimeout = vm.ctx.settings.requestTimeout; |
103 | } | 118 | } |
104 | - vm.valuePollingInterval = 500; | ||
105 | - if (vm.ctx.settings.valuePollingInterval) { | ||
106 | - vm.valuePollingInterval = vm.ctx.settings.valuePollingInterval; | ||
107 | - } | ||
108 | - vm.getValueMethod = 'getValue'; | ||
109 | - if (vm.ctx.settings.getValueMethod && vm.ctx.settings.getValueMethod.length) { | ||
110 | - vm.getValueMethod = vm.ctx.settings.getValueMethod; | 119 | + vm.checkStatusMethod = 'checkStatus'; |
120 | + if (vm.ctx.settings.checkStatusMethod && vm.ctx.settings.checkStatusMethod.length) { | ||
121 | + vm.checkStatusMethod = vm.ctx.settings.checkStatusMethod; | ||
111 | } | 122 | } |
112 | if (!rpcEnabled) { | 123 | if (!rpcEnabled) { |
113 | onError('Target device is not set!'); | 124 | onError('Target device is not set!'); |
114 | } else { | 125 | } else { |
115 | if (!vm.isSimulated) { | 126 | if (!vm.isSimulated) { |
116 | - rpcRequestValue(); | 127 | + rpcCheckStatus(); |
117 | } | 128 | } |
118 | } | 129 | } |
119 | } | 130 | } |
@@ -173,29 +184,86 @@ function LedIndicatorController($element, $scope, $timeout) { | @@ -173,29 +184,86 @@ function LedIndicatorController($element, $scope, $timeout) { | ||
173 | return textMeasure.width(); | 184 | return textMeasure.width(); |
174 | } | 185 | } |
175 | 186 | ||
176 | - function rpcRequestValue() { | 187 | + function rpcCheckStatus() { |
177 | if (vm.destroyed) { | 188 | if (vm.destroyed) { |
178 | return; | 189 | return; |
179 | } | 190 | } |
180 | vm.error = ''; | 191 | vm.error = ''; |
181 | - vm.ctx.controlApi.sendTwoWayCommand(vm.getValueMethod, null, vm.requestTimeout).then( | 192 | + vm.ctx.controlApi.sendTwoWayCommand(vm.checkStatusMethod, null, vm.requestTimeout).then( |
182 | (responseBody) => { | 193 | (responseBody) => { |
183 | - var newValue = responseBody ? true : false; | ||
184 | - setValue(newValue); | ||
185 | - if (vm.requestValueTimeoutHandle) { | ||
186 | - $timeout.cancel(vm.requestValueTimeoutHandle); | 194 | + var status = responseBody ? true : false; |
195 | + if (status) { | ||
196 | + if (vm.checkStatusTimeoutHandle) { | ||
197 | + $timeout.cancel(vm.checkStatusTimeoutHandle); | ||
198 | + vm.checkStatusTimeoutHandle = null; | ||
199 | + } | ||
200 | + subscribeForValue(); | ||
201 | + } else { | ||
202 | + var errorText = 'Unknown device status!'; | ||
203 | + onError(errorText); | ||
204 | + if (vm.checkStatusTimeoutHandle) { | ||
205 | + $timeout.cancel(vm.checkStatusTimeoutHandle); | ||
206 | + } | ||
207 | + vm.checkStatusTimeoutHandle = $timeout(rpcCheckStatus, checkStatusPollingInterval); | ||
187 | } | 208 | } |
188 | - vm.requestValueTimeoutHandle = $timeout(rpcRequestValue, vm.valuePollingInterval); | ||
189 | }, | 209 | }, |
190 | () => { | 210 | () => { |
191 | var errorText = vm.ctx.defaultSubscription.rpcErrorText; | 211 | var errorText = vm.ctx.defaultSubscription.rpcErrorText; |
192 | onError(errorText); | 212 | onError(errorText); |
193 | - if (vm.requestValueTimeoutHandle) { | ||
194 | - $timeout.cancel(vm.requestValueTimeoutHandle); | 213 | + if (vm.checkStatusTimeoutHandle) { |
214 | + $timeout.cancel(vm.checkStatusTimeoutHandle); | ||
195 | } | 215 | } |
196 | - vm.requestValueTimeoutHandle = $timeout(rpcRequestValue, vm.valuePollingInterval); | 216 | + vm.checkStatusTimeoutHandle = $timeout(rpcCheckStatus, checkStatusPollingInterval); |
217 | + } | ||
218 | + ); | ||
219 | + } | ||
220 | + | ||
221 | + function subscribeForValue() { | ||
222 | + var subscriptionsInfo = [{ | ||
223 | + type: types.datasourceType.entity, | ||
224 | + entityType: types.entityType.device, | ||
225 | + entityId: vm.ctx.defaultSubscription.targetDeviceId, | ||
226 | + attributes: [ | ||
227 | + {name: vm.valueAttribute} | ||
228 | + ] | ||
229 | + }]; | ||
230 | + vm.ctx.subscriptionApi.createSubscriptionFromInfo ( | ||
231 | + types.widgetType.latest.value, subscriptionsInfo, vm.subscriptionOptions, false, true).then( | ||
232 | + function(subscription) { | ||
233 | + vm.subscription = subscription; | ||
197 | } | 234 | } |
198 | ); | 235 | ); |
199 | } | 236 | } |
200 | 237 | ||
238 | + function onDataUpdated(subscription, apply) { | ||
239 | + var value = false; | ||
240 | + var data = subscription.data; | ||
241 | + if (data.length) { | ||
242 | + var keyData = data[0]; | ||
243 | + if (keyData && keyData.data && keyData.data[0]) { | ||
244 | + var attrValue = keyData.data[0][1]; | ||
245 | + if (attrValue) { | ||
246 | + var parsed = null; | ||
247 | + try { | ||
248 | + parsed = angular.fromJson(attrValue); | ||
249 | + } catch (e){/**/} | ||
250 | + value = parsed ? true : false; | ||
251 | + } | ||
252 | + } | ||
253 | + } | ||
254 | + setValue(value); | ||
255 | + if (apply) { | ||
256 | + $scope.$digest(); | ||
257 | + } | ||
258 | + } | ||
259 | + | ||
260 | + function onDataUpdateError(subscription, e) { | ||
261 | + var exceptionData = utils.parseException(e); | ||
262 | + var errorText = exceptionData.name; | ||
263 | + if (exceptionData.message) { | ||
264 | + errorText += ': ' + exceptionData.message; | ||
265 | + } | ||
266 | + onError(errorText); | ||
267 | + } | ||
268 | + | ||
201 | } | 269 | } |