Implemented GUI configuration for MODBUS gateway extension.
This commit is contained in:
parent
a6661147be
commit
cfcd71adb3
@ -384,7 +384,8 @@ export default angular.module('thingsboard.types', [])
|
||||
extensionType: {
|
||||
http: "HTTP",
|
||||
mqtt: "MQTT",
|
||||
opc: "OPC UA"
|
||||
opc: "OPC UA",
|
||||
modbus: "MODBUS"
|
||||
},
|
||||
extensionValueType: {
|
||||
string: 'value.string',
|
||||
@ -428,6 +429,26 @@ export default angular.module('thingsboard.types', [])
|
||||
PKCS12: "PKCS12",
|
||||
JKS: "JKS"
|
||||
},
|
||||
extensionModbusFunctionCodes: {
|
||||
1: "Read Coils (1)",
|
||||
2: "Read Discrete Inputs (2)",
|
||||
3: "Read Multiple Holding Registers (3)",
|
||||
4: "Read Input Registers (4)"
|
||||
},
|
||||
extensionModbusTransports: {
|
||||
tcp: "TCP",
|
||||
udp: "UDP",
|
||||
rtu: "RTU"
|
||||
},
|
||||
extensionModbusRtuParities: {
|
||||
none: "none",
|
||||
even: "even",
|
||||
odd: "odd"
|
||||
},
|
||||
extensionModbusRtuEncodings: {
|
||||
ascii: "ascii",
|
||||
rtu: "rtu"
|
||||
},
|
||||
latestTelemetry: {
|
||||
value: "LATEST_TELEMETRY",
|
||||
name: "attribute.scope-latest-telemetry",
|
||||
|
||||
@ -49,7 +49,7 @@ export default function ExtensionDialogController($scope, $mdDialog, $translate,
|
||||
"brokers": []
|
||||
};
|
||||
}
|
||||
if (vm.extension.type === "OPC UA") {
|
||||
if (vm.extension.type === "OPC UA" || vm.extension.type === "MODBUS") {
|
||||
vm.extension.configuration = {
|
||||
"servers": []
|
||||
};
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
<div tb-extension-form-http config="vm.extension.configuration" is-add="vm.isAdd" ng-if="vm.extension.type && vm.extension.type == vm.types.extensionType.http"></div>
|
||||
<div tb-extension-form-mqtt config="vm.extension.configuration" is-add="vm.isAdd" ng-if="vm.extension.type && vm.extension.type == vm.types.extensionType.mqtt"></div>
|
||||
<div tb-extension-form-opc configuration="vm.extension.configuration" ng-if="vm.extension.type && vm.extension.type == vm.types.extensionType.opc"></div>
|
||||
<div tb-extension-form-modbus configuration="vm.extension.configuration" ng-if="vm.extension.type && vm.extension.type == vm.types.extensionType.modbus"></div>
|
||||
</fieldset>
|
||||
</md-content>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 'brace/ext/language_tools';
|
||||
import 'brace/mode/json';
|
||||
import 'brace/theme/github';
|
||||
|
||||
import './extension-form.scss';
|
||||
|
||||
/* eslint-disable angular/log */
|
||||
|
||||
import extensionFormModbusTemplate from './extension-form-modbus.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
/*@ngInject*/
|
||||
export default function ExtensionFormModbusDirective($compile, $templateCache, $translate, types) {
|
||||
|
||||
|
||||
var linker = function(scope, element) {
|
||||
|
||||
|
||||
function Server() {
|
||||
this.transport = {
|
||||
"type": "tcp",
|
||||
"host": "localhost",
|
||||
"port": 502,
|
||||
"timeout": 3000
|
||||
};
|
||||
this.devices = []
|
||||
}
|
||||
|
||||
function Device() {
|
||||
this.unitId = 1;
|
||||
this.deviceName = "";
|
||||
this.attributesPollPeriod = 1000;
|
||||
this.timeseriesPollPeriod = 1000;
|
||||
this.attributes = [];
|
||||
this.timeseries = [];
|
||||
}
|
||||
|
||||
function Tag(globalPollPeriod) {
|
||||
this.tag = "";
|
||||
this.type = "long";
|
||||
this.pollPeriod = globalPollPeriod;
|
||||
this.functionCode = 3;
|
||||
this.address = 0;
|
||||
this.registerCount = 1;
|
||||
this.bit = 0;
|
||||
this.byteOrder = "BIG";
|
||||
}
|
||||
|
||||
|
||||
var template = $templateCache.get(extensionFormModbusTemplate);
|
||||
element.html(template);
|
||||
|
||||
scope.types = types;
|
||||
scope.theForm = scope.$parent.theForm;
|
||||
|
||||
|
||||
if (!scope.configuration.servers.length) {
|
||||
scope.configuration.servers.push(new Server());
|
||||
}
|
||||
|
||||
scope.addServer = function(serversList) {
|
||||
serversList.push(new Server());
|
||||
scope.theForm.$setDirty();
|
||||
};
|
||||
|
||||
scope.addDevice = function(deviceList) {
|
||||
deviceList.push(new Device());
|
||||
scope.theForm.$setDirty();
|
||||
};
|
||||
|
||||
scope.addNewAttribute = function(device) {
|
||||
device.attributes.push(new Tag(device.attributesPollPeriod));
|
||||
scope.theForm.$setDirty();
|
||||
};
|
||||
|
||||
scope.addNewTimeseries = function(device) {
|
||||
device.timeseries.push(new Tag(device.timeseriesPollPeriod));
|
||||
scope.theForm.$setDirty();
|
||||
};
|
||||
|
||||
scope.removeItem = (item, itemList) => {
|
||||
var index = itemList.indexOf(item);
|
||||
if (index > -1) {
|
||||
itemList.splice(index, 1);
|
||||
}
|
||||
scope.theForm.$setDirty();
|
||||
};
|
||||
|
||||
|
||||
$compile(element.contents())(scope);
|
||||
|
||||
|
||||
scope.collapseValidation = function(index, id) {
|
||||
var invalidState = angular.element('#'+id+':has(.ng-invalid)');
|
||||
if(invalidState.length) {
|
||||
invalidState.addClass('inner-invalid');
|
||||
}
|
||||
};
|
||||
|
||||
scope.expandValidation = function (index, id) {
|
||||
var invalidState = angular.element('#'+id);
|
||||
invalidState.removeClass('inner-invalid');
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
restrict: "A",
|
||||
link: linker,
|
||||
scope: {
|
||||
configuration: "=",
|
||||
isAdd: "="
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,818 @@
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<md-card class="extension-form extension-modbus">
|
||||
<md-card-title>
|
||||
<md-card-title-text>
|
||||
<span translate class="md-headline">extension.configuration</span>
|
||||
</md-card-title-text>
|
||||
</md-card-title>
|
||||
|
||||
<md-card-content>
|
||||
<v-accordion id="modbus-server-configs-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
|
||||
<v-pane id="modbus-servers-pane" expanded="true">
|
||||
<v-pane-header>
|
||||
{{ 'extension.modbus-server' | translate }}
|
||||
</v-pane-header>
|
||||
|
||||
<v-pane-content>
|
||||
<div ng-if="configuration.servers.length === 0">
|
||||
<span translate layout-align="center center" class="tb-prompt">extension.modbus-add-server-prompt</span>
|
||||
</div>
|
||||
|
||||
<div ng-if="configuration.servers.length > 0">
|
||||
<ol class="list-group">
|
||||
<li class="list-group-item" ng-repeat="(serverIndex, server) in configuration.servers">
|
||||
<md-button aria-label="{{ 'action.remove' | translate }}"
|
||||
class="md-icon-button"
|
||||
ng-click="removeItem(server, configuration.servers)"
|
||||
ng-hide="configuration.servers.length < 2"
|
||||
>
|
||||
<ng-md-icon icon="close" aria-label="{{ 'action.remove' | translate }}"></ng-md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.remove' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
|
||||
<md-card>
|
||||
<md-card-content>
|
||||
|
||||
<div layout="row">
|
||||
|
||||
<md-input-container flex="50" class="md-block tb-container-for-select">
|
||||
<label translate>extension.modbus-transport</label>
|
||||
<md-select required
|
||||
name="transportType_{{serverIndex}}"
|
||||
ng-model="server.transport.type"
|
||||
>
|
||||
<md-option ng-value="transportType"
|
||||
ng-repeat="(transportType, transportValue) in types.extensionModbusTransports"
|
||||
><span ng-bind="transportValue"></span></md-option>
|
||||
</md-select>
|
||||
<div ng-messages="theForm['transportType_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
</div>
|
||||
|
||||
<div layout="row" ng-if="server.transport.type == 'tcp'">
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.host</label>
|
||||
<input required name="transportHost_{{serverIndex}}" ng-model="server.transport.host">
|
||||
<div ng-messages="theForm['transportHost_' + serverIndex].$error">
|
||||
<div translate ng-message="required">extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.port</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="transportPort_{{serverIndex}}"
|
||||
ng-model="server.transport.port"
|
||||
min="1"
|
||||
max="65535"
|
||||
>
|
||||
<div ng-messages="theForm['transportPort_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.port-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.port-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.timeout</label>
|
||||
<input type="number"
|
||||
required name="transportTimeout_{{serverIndex}}"
|
||||
ng-model="server.transport.timeout"
|
||||
>
|
||||
<div ng-messages="theForm['transportTimeout_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<div layout="row" ng-if="server.transport.type == 'udp'">
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.host</label>
|
||||
<input required name="transportHost_{{serverIndex}}" ng-model="server.transport.host">
|
||||
<div ng-messages="theForm['transportHost_' + serverIndex].$error">
|
||||
<div translate ng-message="required">extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.port</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="transportPort_{{serverIndex}}"
|
||||
ng-model="server.transport.port"
|
||||
min="1"
|
||||
max="65535"
|
||||
>
|
||||
<div ng-messages="theForm['transportPort_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.port-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.port-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.timeout</label>
|
||||
<input type="number"
|
||||
required name="transportTimeout_{{serverIndex}}"
|
||||
ng-model="server.transport.timeout"
|
||||
>
|
||||
<div ng-messages="theForm['transportTimeout_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<div ng-if="server.transport.type == 'rtu'">
|
||||
|
||||
<div layout="row">
|
||||
<md-input-container flex="70" class="md-block">
|
||||
<label translate>extension.modbus-port-name</label>
|
||||
<input required name="transportPortName_{{serverIndex}}" ng-model="server.transport.portName">
|
||||
<div ng-messages="theForm['transportPortName_' + serverIndex].$error">
|
||||
<div translate ng-message="required">extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="30" class="md-block">
|
||||
<label translate>extension.timeout</label>
|
||||
<input type="number"
|
||||
required name="transportTimeout_{{serverIndex}}"
|
||||
ng-model="server.transport.timeout"
|
||||
>
|
||||
<div ng-messages="theForm['transportTimeout_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<div layout="row">
|
||||
<md-input-container flex="50" class="md-block tb-container-for-select">
|
||||
<label translate>extension.modbus-encoding</label>
|
||||
<md-select required
|
||||
name="transportEncoding_{{serverIndex}}"
|
||||
ng-model="server.transport.encoding"
|
||||
>
|
||||
<md-option ng-value="encodingType"
|
||||
ng-repeat="(encodingType, encodingValue) in types.extensionModbusRtuEncodings"
|
||||
><span ng-bind="encodingValue"></span></md-option>
|
||||
</md-select>
|
||||
<div ng-messages="theForm['transportEncoding_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="50" class="md-block tb-container-for-select">
|
||||
<label translate>extension.modbus-parity</label>
|
||||
<md-select name="transportParity_{{serverIndex}}" ng-model="server.transport.parity">
|
||||
<md-option ng-repeat="(parityKey, parityValue) in types.extensionModbusRtuParities"
|
||||
ng-value="parityValue"
|
||||
>
|
||||
{{parityValue}}
|
||||
</md-option>
|
||||
</md-select>
|
||||
<div ng-messages="theForm['transportParity_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
</div>
|
||||
|
||||
<div layout="row">
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.modbus-baudrate</label>
|
||||
<input type="number"
|
||||
required name="transportBaudRate_{{serverIndex}}"
|
||||
ng-model="server.transport.baudRate"
|
||||
>
|
||||
<div ng-messages="theForm['transportBaudRate_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.modbus-databits</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="transportDataBits_{{serverIndex}}"
|
||||
ng-model="server.transport.dataBits"
|
||||
min="7"
|
||||
max="8"
|
||||
>
|
||||
<div ng-messages="theForm['transportDataBits_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-databits-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.modbus-databits-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="33" class="md-block">
|
||||
<label translate>extension.modbus-stopbits</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="transportStopBits_{{serverIndex}}"
|
||||
ng-model="server.transport.stopBits"
|
||||
min="1"
|
||||
max="2"
|
||||
>
|
||||
<div ng-messages="theForm['transportStopBits_' + serverIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-stopbits-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.modbus-stopbits-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-accordion id="modbus-mapping-accordion"
|
||||
class="vAccordion--default"
|
||||
onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
|
||||
<v-pane id="modbus-mapping-pane_{{serverIndex}}">
|
||||
<v-pane-header>
|
||||
{{ 'extension.mapping' | translate }}
|
||||
</v-pane-header>
|
||||
<v-pane-content>
|
||||
<div ng-if="server.devices.length > 0">
|
||||
<ol class="list-group">
|
||||
<li class="list-group-item"
|
||||
ng-repeat="(deviceIndex, device) in server.devices"
|
||||
>
|
||||
<md-button aria-label="{{ 'action.remove' | translate }}"
|
||||
class="md-icon-button"
|
||||
ng-click="removeItem(device, server.devices)"
|
||||
>
|
||||
<ng-md-icon icon="close" aria-label="{{ 'action.remove' | translate }}"></ng-md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.remove' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
|
||||
<md-card>
|
||||
<md-card-content>
|
||||
<div flex layout="row">
|
||||
<md-input-container flex="80" class="md-block">
|
||||
<label translate>extension.modbus-device-name</label>
|
||||
<input required
|
||||
name="deviceName_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="device.deviceName"
|
||||
>
|
||||
<div ng-messages="theForm['deviceName_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="20" class="md-block">
|
||||
<label translate>extension.modbus-unit-id</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="unitId_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="device.unitId"
|
||||
min="1"
|
||||
max="247"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['unitId_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-unit-id-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.modbus-unit-id-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<div flex layout="row">
|
||||
<md-input-container flex="50" class="md-block">
|
||||
<label translate>extension.modbus-attributes-poll-period</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="attributesPollPeriod_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="device.attributesPollPeriod"
|
||||
min="1"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['attributesPollPeriod_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-poll-period-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="50" class="md-block">
|
||||
<label translate>extension.modbus-timeseries-poll-period</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="timeseriesPollPeriod_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="device.timeseriesPollPeriod"
|
||||
min="1"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['timeseriesPollPeriod_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-poll-period-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<v-accordion id="modbus-attributes-accordion"
|
||||
class="vAccordion--default"
|
||||
onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
|
||||
<v-pane id="modbus-attributes-pane_{{serverIndex}}{{deviceIndex}}">
|
||||
<v-pane-header>
|
||||
{{ 'extension.attributes' | translate }}
|
||||
</v-pane-header>
|
||||
<v-pane-content>
|
||||
<div ng-show="device.attributes.length > 0">
|
||||
<ol class="list-group">
|
||||
<li class="list-group-item"
|
||||
ng-repeat="(attributeIndex, attribute) in device.attributes"
|
||||
>
|
||||
<md-button aria-label="{{ 'action.remove' | translate }}"
|
||||
class="md-icon-button"
|
||||
ng-click="removeItem(attribute, device.attributes)">
|
||||
<ng-md-icon icon="close"
|
||||
aria-label="{{ 'action.remove' | translate }}"
|
||||
></ng-md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.remove' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
<md-card>
|
||||
<md-card-content>
|
||||
|
||||
<section flex layout="row">
|
||||
<md-input-container flex="50" class="md-block">
|
||||
<label translate>extension.modbus-tag</label>
|
||||
<input required
|
||||
name="modbusAttributeTag_{{serverIndex}}{{deviceIndex}}{{attributeIndex}}"
|
||||
ng-model="attribute.tag"
|
||||
>
|
||||
<div ng-messages="theForm['modbusAttributeTag_' + serverIndex + deviceIndex + attributeIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="30" class="md-block tb-container-for-select">
|
||||
<label translate>extension.type</label>
|
||||
<md-select required name="modbusAttributeType_{{serverIndex}}{{deviceIndex}}{{attributeIndex}}"
|
||||
ng-model="attribute.type"
|
||||
>
|
||||
<md-option ng-repeat="(attrType, attrTypeValue) in types.extensionValueType"
|
||||
ng-value="attrType"
|
||||
>
|
||||
{{attrTypeValue | translate}}
|
||||
</md-option>
|
||||
</md-select>
|
||||
<div ng-messages="theForm['modbusAttributeType_' + serverIndex + deviceIndex + attributeIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="20" class="md-block">
|
||||
<label translate>extension.modbus-poll-period</label>
|
||||
<input type="number"
|
||||
name="pollPeriod_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="attribute.pollPeriod"
|
||||
min="1"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['pollPeriod_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-poll-period-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</section>
|
||||
|
||||
<section flex layout="row">
|
||||
<md-input-container flex="50" class="md-block tb-container-for-select">
|
||||
<label translate>extension.type</label>
|
||||
<md-select required name="modbusAttributeFunctionCode_{{serverIndex}}{{deviceIndex}}{{attributeIndex}}"
|
||||
ng-model="attribute.functionCode"
|
||||
>
|
||||
<md-option ng-repeat="(functionCode, functionName) in types.extensionModbusFunctionCodes"
|
||||
ng-value="functionCode"
|
||||
>
|
||||
{{functionName}}
|
||||
</md-option>
|
||||
</md-select>
|
||||
<div ng-messages="theForm['modbusAttributeFunctionCode_' + serverIndex + deviceIndex + attributeIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="50" class="md-block">
|
||||
<label translate>extension.modbus-register-address</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="address_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="attribute.address"
|
||||
min="0"
|
||||
max="65535"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['address_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-register-address-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.modbus-register-address-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
</section>
|
||||
|
||||
<section flex layout="row">
|
||||
<md-input-container flex="50" class="md-block" ng-if="attribute.type != 'boolean'">
|
||||
<label translate>extension.modbus-register-count</label>
|
||||
<input type="number"
|
||||
name="registerCount_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="attribute.registerCount"
|
||||
min="1"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['registerCount_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-register-count-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="50" class="md-block" ng-if="attribute.type == 'boolean' && attribute.functionCode >= 3">
|
||||
<label translate>extension.modbus-register-bit-index</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="bit_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="attribute.bit"
|
||||
min="0"
|
||||
max="15"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['bit_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-register-bit-index-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.modbus-register-bit-index-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</section>
|
||||
|
||||
<section flex layout="row">
|
||||
<md-input-container flex="100" class="md-block" ng-if="attribute.functionCode >= 3">
|
||||
<label translate>extension.modbus-byte-order</label>
|
||||
<input required
|
||||
name="modbusByteOrder_{{serverIndex}}{{deviceIndex}}{{attributeIndex}}"
|
||||
ng-model="attribute.byteOrder"
|
||||
>
|
||||
<div ng-messages="theForm['modbusByteOrder_' + serverIndex + deviceIndex + attributeIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div flex layout="row" layout-align="start center">
|
||||
<md-button class="md-primary md-raised"
|
||||
ng-click="addNewAttribute(device)"
|
||||
aria-label="{{ 'action.add' | translate }}"
|
||||
>
|
||||
<md-icon class="material-icons">add</md-icon>
|
||||
<span translate>extension.add-attribute</span>
|
||||
</md-button>
|
||||
</div>
|
||||
</v-pane-content>
|
||||
</v-pane>
|
||||
</v-accordion>
|
||||
|
||||
<v-accordion id="modbus-timeseries-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
|
||||
<v-pane id="modbus-timeseries-pane_{{serverIndex}}{{deviceIndex}}">
|
||||
<v-pane-header>
|
||||
{{ 'extension.timeseries' | translate }}
|
||||
</v-pane-header>
|
||||
<v-pane-content>
|
||||
<div ng-show="device.timeseries.length > 0">
|
||||
<ol class="list-group">
|
||||
<li class="list-group-item"
|
||||
ng-repeat="(timeseriesIndex, timeserie) in device.timeseries"
|
||||
>
|
||||
<md-button aria-label="{{ 'action.remove' | translate }}"
|
||||
class="md-icon-button"
|
||||
ng-click="removeItem(timeserie, device.timeseries)">
|
||||
<ng-md-icon icon="close"
|
||||
aria-label="{{ 'action.remove' | translate }}"
|
||||
></ng-md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.remove' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
<md-card>
|
||||
<md-card-content>
|
||||
|
||||
<section flex layout="row">
|
||||
<md-input-container flex="50" class="md-block">
|
||||
<label translate>extension.modbus-tag</label>
|
||||
<input required
|
||||
name="modbusTimeserieTag_{{serverIndex}}{{deviceIndex}}{{timeseriesIndex}}"
|
||||
ng-model="timeserie.tag"
|
||||
>
|
||||
<div ng-messages="theForm['modbusTimeserieTag_' + serverIndex + deviceIndex + timeseriesIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="30" class="md-block tb-container-for-select">
|
||||
<label translate>extension.type</label>
|
||||
<md-select required name="modbusTimeserieType_{{serverIndex}}{{deviceIndex}}{{timeseriesIndex}}"
|
||||
ng-model="timeserie.type"
|
||||
>
|
||||
<md-option ng-repeat="(attrType, attrTypeValue) in types.extensionValueType"
|
||||
ng-value="attrType"
|
||||
>
|
||||
{{attrTypeValue | translate}}
|
||||
</md-option>
|
||||
</md-select>
|
||||
<div ng-messages="theForm['modbusTimeserieType_' + serverIndex + deviceIndex + timeseriesIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="20" class="md-block">
|
||||
<label translate>extension.modbus-poll-period</label>
|
||||
<input type="number"
|
||||
name="pollPeriod_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="timeserie.pollPeriod"
|
||||
min="1"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['pollPeriod_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-poll-period-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</section>
|
||||
|
||||
<section flex layout="row">
|
||||
<md-input-container flex="50" class="md-block tb-container-for-select">
|
||||
<label translate>extension.type</label>
|
||||
<md-select required name="modbusTimeserieFunctionCode_{{serverIndex}}{{deviceIndex}}{{timeseriesIndex}}"
|
||||
ng-model="timeserie.functionCode"
|
||||
>
|
||||
<md-option ng-repeat="(functionCode, functionName) in types.extensionModbusFunctionCodes"
|
||||
ng-value="functionCode"
|
||||
>
|
||||
{{functionName}}
|
||||
</md-option>
|
||||
</md-select>
|
||||
<div ng-messages="theForm['modbusTimeserieFunctionCode_' + serverIndex + deviceIndex + timeseriesIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="50" class="md-block">
|
||||
<label translate>extension.modbus-register-address</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="address_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="timeserie.address"
|
||||
min="0"
|
||||
max="65535"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['address_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-register-address-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.modbus-register-address-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</section>
|
||||
|
||||
<section flex layout="row">
|
||||
<md-input-container flex="50" class="md-block" ng-if="timeserie.type != 'boolean'">
|
||||
<label translate>extension.modbus-register-count</label>
|
||||
<input type="number"
|
||||
name="registerCount_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="timeserie.registerCount"
|
||||
min="1"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['registerCount_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-register-count-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
<md-input-container flex="50" class="md-block" ng-if="timeserie.type == 'boolean' && timeserie.functionCode >= 3">
|
||||
<label translate>extension.modbus-register-bit-index</label>
|
||||
<input type="number"
|
||||
required
|
||||
name="bit_{{serverIndex}}{{deviceIndex}}"
|
||||
ng-model="timeserie.bit"
|
||||
min="0"
|
||||
max="15"
|
||||
>
|
||||
|
||||
<div ng-messages="theForm['bit_' + serverIndex + deviceIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
<div translate
|
||||
ng-message="min"
|
||||
>extension.modbus-register-bit-index-range</div>
|
||||
<div translate
|
||||
ng-message="max"
|
||||
>extension.modbus-register-bit-index-range</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
</section>
|
||||
|
||||
<section flex layout="row">
|
||||
<md-input-container flex="100" class="md-block" ng-if="timeserie.functionCode >= 3">
|
||||
<label translate>extension.modbus-byte-order</label>
|
||||
<input required
|
||||
name="modbusByteOrder_{{serverIndex}}{{deviceIndex}}{{timeseriesIndex}}"
|
||||
ng-model="timeserie.byteOrder"
|
||||
>
|
||||
<div ng-messages="theForm['modbusByteOrder_' + serverIndex + deviceIndex + timeseriesIndex].$error">
|
||||
<div translate
|
||||
ng-message="required"
|
||||
>extension.field-required</div>
|
||||
</div>
|
||||
</md-input-container>
|
||||
|
||||
</section>
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div flex layout="row" layout-align="start center">
|
||||
<md-button class="md-primary md-raised"
|
||||
ng-click="addNewTimeseries(device)"
|
||||
aria-label="{{ 'action.add' | translate }}"
|
||||
>
|
||||
<md-icon class="material-icons">add</md-icon>
|
||||
<span translate>extension.add-timeseries</span>
|
||||
</md-button>
|
||||
</div>
|
||||
</v-pane-content>
|
||||
</v-pane>
|
||||
</v-accordion>
|
||||
|
||||
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div flex
|
||||
layout="row"
|
||||
layout-align="start center"
|
||||
>
|
||||
<md-button class="md-primary md-raised"
|
||||
ng-click="addDevice(server.devices)"
|
||||
aria-label="{{ 'action.add' | translate }}"
|
||||
>
|
||||
<md-icon class="material-icons">add</md-icon>
|
||||
<span translate>extension.add-device</span>
|
||||
</md-button>
|
||||
</div>
|
||||
</v-pane-content>
|
||||
</v-pane>
|
||||
</v-accordion>
|
||||
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div flex
|
||||
layout="row"
|
||||
layout-align="start center"
|
||||
>
|
||||
<md-button class="md-primary md-raised"
|
||||
ng-click="addServer(configuration.servers)"
|
||||
aria-label="{{ 'action.add' | translate }}"
|
||||
>
|
||||
<md-icon class="material-icons">add</md-icon>
|
||||
<span translate>extension.modbus-add-server</span>
|
||||
</md-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</v-pane-content>
|
||||
</v-pane>
|
||||
</v-accordion>
|
||||
<!--{{config}}-->
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
@ -17,6 +17,8 @@ import ExtensionTableDirective from './extension-table.directive';
|
||||
import ExtensionFormHttpDirective from './extensions-forms/extension-form-http.directive';
|
||||
import ExtensionFormMqttDirective from './extensions-forms/extension-form-mqtt.directive'
|
||||
import ExtensionFormOpcDirective from './extensions-forms/extension-form-opc.directive';
|
||||
import ExtensionFormModbusDirective from './extensions-forms/extension-form-modbus.directive';
|
||||
|
||||
import {ParseToNull} from './extension-dialog.controller';
|
||||
|
||||
export default angular.module('thingsboard.extension', [])
|
||||
@ -24,5 +26,6 @@ export default angular.module('thingsboard.extension', [])
|
||||
.directive('tbExtensionFormHttp', ExtensionFormHttpDirective)
|
||||
.directive('tbExtensionFormMqtt', ExtensionFormMqttDirective)
|
||||
.directive('tbExtensionFormOpc', ExtensionFormOpcDirective)
|
||||
.directive('tbExtensionFormModbus', ExtensionFormModbusDirective)
|
||||
.directive('parseToNull', ParseToNull)
|
||||
.name;
|
||||
@ -866,8 +866,10 @@ export default angular.module('thingsboard.locale', [])
|
||||
"response-timeout": "Response timeout in milliseconds",
|
||||
"topic-expression": "Topic expression",
|
||||
"client-scope": "Client scope",
|
||||
"add-device": "Add device",
|
||||
"opc-server": "Servers",
|
||||
"opc-add-server": "Add server",
|
||||
"opc-add-server-prompt": "Please add server",
|
||||
"opc-application-name": "Application name",
|
||||
"opc-application-uri": "Application uri",
|
||||
"opc-scan-period-in-seconds": "Scan period in seconds",
|
||||
@ -882,6 +884,34 @@ export default angular.module('thingsboard.locale', [])
|
||||
"opc-keystore-key-password":"Key password",
|
||||
"opc-device-node-pattern":"Device node pattern",
|
||||
"opc-device-name-pattern":"Device name pattern",
|
||||
"modbus-server": "Servers/slaves",
|
||||
"modbus-add-server": "Add server/slave",
|
||||
"modbus-add-server-prompt": "Please add server/slave",
|
||||
"modbus-transport": "Transport",
|
||||
"modbus-port-name": "Serial port name",
|
||||
"modbus-encoding": "Encoding",
|
||||
"modbus-parity": "Parity",
|
||||
"modbus-baudrate": "Baud rate",
|
||||
"modbus-databits": "Data bits",
|
||||
"modbus-stopbits": "Stop bits",
|
||||
"modbus-databits-range": "Data bits should be in a range from 7 to 8.",
|
||||
"modbus-stopbits-range": "Stop bits should be in a range from 1 to 2.",
|
||||
"modbus-unit-id": "Unit ID",
|
||||
"modbus-unit-id-range": "Unit ID should be in a range from 1 to 247.",
|
||||
"modbus-device-name":"Device name",
|
||||
"modbus-poll-period": "Poll period (ms)",
|
||||
"modbus-attributes-poll-period": "Attributes poll period (ms)",
|
||||
"modbus-timeseries-poll-period": "Timeseries poll period (ms)",
|
||||
"modbus-poll-period-range": "Poll period should be positive value.",
|
||||
"modbus-tag": "Tag",
|
||||
"modbus-function": "Function",
|
||||
"modbus-register-address": "Register address",
|
||||
"modbus-register-address-range": "Register address should be in a range from 0 to 65535.",
|
||||
"modbus-register-bit-index": "Bit index",
|
||||
"modbus-register-bit-index-range": "Bit index should be in a range from 0 to 15.",
|
||||
"modbus-register-count": "Register count",
|
||||
"modbus-register-count-range": "Register count should be a positive value.",
|
||||
"modbus-byte-order": "Byte order",
|
||||
|
||||
"sync": {
|
||||
"status": "Status",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user