/* * Copyright © 2016-2018 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import './round-switch.scss'; /* eslint-disable import/no-unresolved, import/default */ import roundSwitchTemplate from './round-switch.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ export default angular.module('thingsboard.widgets.rpc.roundSwitch', []) .directive('tbRoundSwitch', RoundSwitch) .name; /*@ngInject*/ function RoundSwitch() { return { restrict: "E", scope: true, bindToController: { ctx: '=' }, controller: RoundSwitchController, controllerAs: 'vm', templateUrl: roundSwitchTemplate }; } /*@ngInject*/ function RoundSwitchController($element, $scope, utils, types) { let vm = this; vm.showTitle = false; vm.value = false; vm.error = ''; vm.checkboxId = 'onoff-' + utils.guid(); var switchElement = angular.element('.switch', $element), switchContainer = angular.element('#switch-container', $element), onoff = angular.element('input', $element), textMeasure = angular.element('#text-measure', $element), switchTitleContainer = angular.element('.title-container', $element), switchTitle = angular.element('.switch-title', $element), switchErrorContainer = angular.element('.error-container', $element), switchError = angular.element('.switch-error', $element); onoff.bind('change', () => { vm.value = onoff.prop('checked') === false; onValue(); }); vm.valueSubscription = null; $scope.$watch('vm.ctx', () => { if (vm.ctx) { init(); } }); $scope.$on('$destroy', () => { if (vm.valueSubscription) { vm.ctx.subscriptionApi.removeSubscription(vm.valueSubscription.id); } }); resize(); function init() { vm.title = angular.isDefined(vm.ctx.settings.title) ? vm.ctx.settings.title : ''; vm.showTitle = vm.title && vm.title.length ? true : false; vm.ctx.resize = resize; $scope.$applyAsync(() => { resize(); }); var initialValue = angular.isDefined(vm.ctx.settings.initialValue) ? vm.ctx.settings.initialValue : false; setValue(initialValue); var subscription = vm.ctx.defaultSubscription; var rpcEnabled = subscription.rpcEnabled; vm.isSimulated = $scope.widgetEditMode; vm.requestTimeout = 500; if (vm.ctx.settings.requestTimeout) { vm.requestTimeout = vm.ctx.settings.requestTimeout; } vm.retrieveValueMethod = 'rpc'; if (vm.ctx.settings.retrieveValueMethod && vm.ctx.settings.retrieveValueMethod.length) { vm.retrieveValueMethod = vm.ctx.settings.retrieveValueMethod; } vm.valueKey = 'value'; if (vm.ctx.settings.valueKey && vm.ctx.settings.valueKey.length) { vm.valueKey = vm.ctx.settings.valueKey; } vm.parseValueFunction = (data) => data ? true : false; if (vm.ctx.settings.parseValueFunction && vm.ctx.settings.parseValueFunction.length) { try { vm.parseValueFunction = new Function('data', vm.ctx.settings.parseValueFunction); } catch (e) { vm.parseValueFunction = (data) => data ? true : false; } } vm.convertValueFunction = (value) => value; if (vm.ctx.settings.convertValueFunction && vm.ctx.settings.convertValueFunction.length) { try { vm.convertValueFunction = new Function('value', vm.ctx.settings.convertValueFunction); } catch (e) { vm.convertValueFunction = (value) => value; } } vm.getValueMethod = 'getValue'; if (vm.ctx.settings.getValueMethod && vm.ctx.settings.getValueMethod.length) { vm.getValueMethod = vm.ctx.settings.getValueMethod; } vm.setValueMethod = 'setValue'; if (vm.ctx.settings.setValueMethod && vm.ctx.settings.setValueMethod.length) { vm.setValueMethod = vm.ctx.settings.setValueMethod; } if (!rpcEnabled) { onError('Target device is not set!'); } else { if (!vm.isSimulated) { if (vm.retrieveValueMethod == 'rpc') { rpcRequestValue(); } else if (vm.retrieveValueMethod == 'attribute' || vm.retrieveValueMethod == 'timeseries') { subscribeForValue(); } } } } function resize() { var width = switchContainer.width(); var height = switchContainer.height(); var size = Math.min(width, height); var scale = size/260; switchElement.css({ '-webkit-transform': `scale(${scale})`, '-moz-transform': `scale(${scale})`, '-ms-transform': `scale(${scale})`, '-o-transform': `scale(${scale})`, transform: `scale(${scale})` }); if (vm.showTitle) { setFontSize(switchTitle, vm.title, switchTitleContainer.height() * 2 / 3, switchTitleContainer.width()); } setFontSize(switchError, vm.error, switchErrorContainer.height(), switchErrorContainer.width()); } function subscribeForValue() { var valueSubscriptionInfo = [{ type: types.datasourceType.entity, entityType: types.entityType.device, entityId: vm.ctx.defaultSubscription.targetDeviceId }]; if (vm.retrieveValueMethod == 'attribute') { valueSubscriptionInfo[0].attributes = [ {name: vm.valueKey} ]; } else { valueSubscriptionInfo[0].timeseries = [ {name: vm.valueKey} ]; } var subscriptionOptions = { callbacks: { onDataUpdated: onDataUpdated, onDataUpdateError: onDataUpdateError } }; vm.ctx.subscriptionApi.createSubscriptionFromInfo ( types.widgetType.latest.value, valueSubscriptionInfo, subscriptionOptions, false, true).then( (subscription) => { vm.valueSubscription = subscription; } ); } function onDataUpdated(subscription, apply) { var value = false; var data = subscription.data; if (data.length) { var keyData = data[0]; if (keyData && keyData.data && keyData.data[0]) { var attrValue = keyData.data[0][1]; if (attrValue) { var parsed = null; try { parsed = vm.parseValueFunction(angular.fromJson(attrValue)); } catch (e){/**/} value = parsed ? true : false; } } } setValue(value); if (apply) { $scope.$digest(); } } function onDataUpdateError(subscription, e) { var exceptionData = utils.parseException(e); var errorText = exceptionData.name; if (exceptionData.message) { errorText += ': ' + exceptionData.message; } onError(errorText); } function setValue(value) { vm.value = value ? true : false; onoff.prop('checked', !vm.value); } function onValue() { rpcUpdateValue(vm.value); } function onError(error) { $scope.$applyAsync(() => { vm.error = error; setFontSize(switchError, vm.error, switchErrorContainer.height(), switchErrorContainer.width()); }); } function setFontSize(element, text, fontSize, maxWidth) { var textWidth = measureTextWidth(text, fontSize); while (textWidth > maxWidth) { fontSize--; textWidth = measureTextWidth(text, fontSize); } element.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'}); } function measureTextWidth(text, fontSize) { textMeasure.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'}); textMeasure.text(text); return textMeasure.width(); } function rpcRequestValue() { vm.error = ''; vm.ctx.controlApi.sendTwoWayCommand(vm.getValueMethod, null, vm.requestTimeout).then( (responseBody) => { setValue(vm.parseValueFunction(responseBody)); }, () => { var errorText = vm.ctx.defaultSubscription.rpcErrorText; onError(errorText); } ); } function rpcUpdateValue(value) { if (vm.executingUpdateValue) { vm.scheduledValue = value; return; } else { vm.scheduledValue = null; vm.rpcValue = value; vm.executingUpdateValue = true; } vm.error = ''; vm.ctx.controlApi.sendOneWayCommand(vm.setValueMethod, vm.convertValueFunction(value), vm.requestTimeout).then( () => { vm.executingUpdateValue = false; if (vm.scheduledValue != null && vm.scheduledValue != vm.rpcValue) { rpcUpdateValue(vm.scheduledValue); } }, () => { vm.executingUpdateValue = false; var errorText = vm.ctx.defaultSubscription.rpcErrorText; onError(errorText); } ); } }