Merge branch 'task/4081-update-modbus-rpc-templates' into improvements/050824-gateway
This commit is contained in:
commit
09f20a2e32
@ -102,7 +102,7 @@
|
|||||||
name="value"
|
name="value"
|
||||||
formControlName="objectsCount"
|
formControlName="objectsCount"
|
||||||
placeholder="{{ 'gateway.set' | translate }}"
|
placeholder="{{ 'gateway.set' | translate }}"
|
||||||
[readonly]="!editableDataTypes.includes(keyControl.get('type').value)"
|
[readonly]="!ModbusEditableDataTypes.includes(keyControl.get('type').value)"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import {
|
|||||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||||
import {
|
import {
|
||||||
ModbusDataType,
|
ModbusDataType,
|
||||||
|
ModbusEditableDataTypes,
|
||||||
ModbusFunctionCodeTranslationsMap,
|
ModbusFunctionCodeTranslationsMap,
|
||||||
ModbusObjectCountByDataType,
|
ModbusObjectCountByDataType,
|
||||||
ModbusValue,
|
ModbusValue,
|
||||||
@ -74,7 +75,7 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
functionCodesMap = new Map();
|
functionCodesMap = new Map();
|
||||||
defaultFunctionCodes = [];
|
defaultFunctionCodes = [];
|
||||||
|
|
||||||
readonly editableDataTypes = [ModbusDataType.BYTES, ModbusDataType.BITS, ModbusDataType.STRING];
|
readonly ModbusEditableDataTypes = ModbusEditableDataTypes;
|
||||||
readonly ModbusFunctionCodeTranslationsMap = ModbusFunctionCodeTranslationsMap;
|
readonly ModbusFunctionCodeTranslationsMap = ModbusFunctionCodeTranslationsMap;
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
@ -164,7 +165,7 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private observeKeyDataType(keyFormGroup: FormGroup): void {
|
private observeKeyDataType(keyFormGroup: FormGroup): void {
|
||||||
keyFormGroup.get('type').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(dataType => {
|
keyFormGroup.get('type').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(dataType => {
|
||||||
if (!this.editableDataTypes.includes(dataType)) {
|
if (!this.ModbusEditableDataTypes.includes(dataType)) {
|
||||||
keyFormGroup.get('objectsCount').patchValue(ModbusObjectCountByDataType[dataType], {emitEvent: false});
|
keyFormGroup.get('objectsCount').patchValue(ModbusObjectCountByDataType[dataType], {emitEvent: false});
|
||||||
}
|
}
|
||||||
this.updateFunctionCodes(keyFormGroup, dataType);
|
this.updateFunctionCodes(keyFormGroup, dataType);
|
||||||
|
|||||||
@ -0,0 +1,92 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright © 2016-2024 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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<ng-container [formGroup]="rpcParametersFormGroup">
|
||||||
|
<div fxFlex fxLayout="row">
|
||||||
|
<mat-form-field fxFlex="100">
|
||||||
|
<mat-label>{{ 'gateway.key' | translate }}</mat-label>
|
||||||
|
<input matInput name="value" formControlName="tag" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||||
|
<mat-icon matSuffix
|
||||||
|
matTooltipPosition="above"
|
||||||
|
matTooltipClass="tb-error-tooltip"
|
||||||
|
[matTooltip]="('gateway.key-required') | translate"
|
||||||
|
*ngIf="rpcParametersFormGroup.get('tag').hasError('required') &&
|
||||||
|
rpcParametersFormGroup.get('tag').touched"
|
||||||
|
class="tb-error">
|
||||||
|
warning
|
||||||
|
</mat-icon>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||||
|
<mat-form-field fxFlex="50" class="mat-block">
|
||||||
|
<mat-label>{{ 'gateway.rpc.type' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="type">
|
||||||
|
<mat-option *ngFor="let type of modbusDataTypes" [value]="type">{{ type }}</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field fxFlex="50" class="mat-block">
|
||||||
|
<mat-label>{{ 'gateway.rpc.functionCode' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="functionCode">
|
||||||
|
<mat-option *ngFor="let code of functionCodes" [value]="code">{{ ModbusFunctionCodeTranslationsMap.get(code) | translate}}</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div fxFlex fxLayout="row">
|
||||||
|
<mat-form-field fxFlex="100" *ngIf="writeFunctionCodes.includes(rpcParametersFormGroup.get('functionCode').value)">
|
||||||
|
<mat-label>{{ 'gateway.rpc.value' | translate }}</mat-label>
|
||||||
|
<input matInput name="value" formControlName="value" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||||
|
<mat-icon matSuffix
|
||||||
|
matTooltipPosition="above"
|
||||||
|
matTooltipClass="tb-error-tooltip"
|
||||||
|
[matTooltip]="('gateway.value-required') | translate"
|
||||||
|
*ngIf="rpcParametersFormGroup.get('value').hasError('required') &&
|
||||||
|
rpcParametersFormGroup.get('value').touched"
|
||||||
|
class="tb-error">
|
||||||
|
warning
|
||||||
|
</mat-icon>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||||
|
<mat-form-field fxFlex="50">
|
||||||
|
<mat-label>{{ 'gateway.rpc.address' | translate }}</mat-label>
|
||||||
|
<input matInput type="number" min="0" max="50000" name="value" formControlName="address" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||||
|
<mat-icon matSuffix
|
||||||
|
matTooltipPosition="above"
|
||||||
|
matTooltipClass="tb-error-tooltip"
|
||||||
|
[matTooltip]="('gateway.address-required') | translate"
|
||||||
|
*ngIf="rpcParametersFormGroup.get('address').hasError('required') &&
|
||||||
|
rpcParametersFormGroup.get('address').touched"
|
||||||
|
class="tb-error">
|
||||||
|
warning
|
||||||
|
</mat-icon>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field fxFlex="50">
|
||||||
|
<mat-label>{{ 'gateway.rpc.objectsCount' | translate }}</mat-label>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="50000"
|
||||||
|
name="value"
|
||||||
|
formControlName="objectsCount"
|
||||||
|
placeholder="{{ 'gateway.set' | translate }}"
|
||||||
|
[readonly]="!ModbusEditableDataTypes.includes(rpcParametersFormGroup.get('type').value)"
|
||||||
|
/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
@ -0,0 +1,166 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2024 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 {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
forwardRef,
|
||||||
|
OnDestroy,
|
||||||
|
} from '@angular/core';
|
||||||
|
import {
|
||||||
|
ControlValueAccessor,
|
||||||
|
FormBuilder,
|
||||||
|
NG_VALIDATORS,
|
||||||
|
NG_VALUE_ACCESSOR,
|
||||||
|
UntypedFormGroup,
|
||||||
|
ValidationErrors,
|
||||||
|
Validator,
|
||||||
|
Validators
|
||||||
|
} from '@angular/forms';
|
||||||
|
import { SharedModule } from '@shared/shared.module';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
import {
|
||||||
|
ModbusDataType,
|
||||||
|
ModbusEditableDataTypes,
|
||||||
|
ModbusFunctionCodeTranslationsMap,
|
||||||
|
ModbusObjectCountByDataType,
|
||||||
|
ModbusValue,
|
||||||
|
noLeadTrailSpacesRegex,
|
||||||
|
} from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-modbus-rpc-parameters',
|
||||||
|
templateUrl: './modbus-rpc-parameters.component.html',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => ModbusRpcParametersComponent),
|
||||||
|
multi: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: NG_VALIDATORS,
|
||||||
|
useExisting: forwardRef(() => ModbusRpcParametersComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
SharedModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class ModbusRpcParametersComponent implements ControlValueAccessor, Validator, OnDestroy {
|
||||||
|
|
||||||
|
rpcParametersFormGroup: UntypedFormGroup;
|
||||||
|
functionCodes: Array<number>;
|
||||||
|
|
||||||
|
readonly ModbusEditableDataTypes = ModbusEditableDataTypes;
|
||||||
|
readonly ModbusFunctionCodeTranslationsMap = ModbusFunctionCodeTranslationsMap;
|
||||||
|
|
||||||
|
readonly modbusDataTypes = Object.values(ModbusDataType) as ModbusDataType[];
|
||||||
|
readonly writeFunctionCodes = [5, 6, 15, 16];
|
||||||
|
|
||||||
|
private readonly defaultFunctionCodes = [3, 4, 6, 16];
|
||||||
|
private readonly readFunctionCodes = [1, 2, 3, 4];
|
||||||
|
private readonly bitsFunctionCodes = [...this.readFunctionCodes, ...this.writeFunctionCodes];
|
||||||
|
|
||||||
|
private onChange: (value: ModbusValue) => void;
|
||||||
|
private onTouched: () => void;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
constructor(private fb: FormBuilder) {
|
||||||
|
this.rpcParametersFormGroup = this.fb.group({
|
||||||
|
tag: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||||
|
type: [ModbusDataType.BYTES, [Validators.required]],
|
||||||
|
functionCode: [this.defaultFunctionCodes[0], [Validators.required]],
|
||||||
|
value: [{value: '', disabled: true}, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||||
|
address: [null, [Validators.required]],
|
||||||
|
objectsCount: [1, [Validators.required]],
|
||||||
|
});
|
||||||
|
|
||||||
|
this.updateFunctionCodes(this.rpcParametersFormGroup.get('type').value);
|
||||||
|
this.observeValueChanges();
|
||||||
|
this.observeKeyDataType();
|
||||||
|
this.observeFunctionCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: (value: ModbusValue) => void): void {
|
||||||
|
this.onChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: () => void): void {
|
||||||
|
this.onTouched = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(): ValidationErrors | null {
|
||||||
|
return this.rpcParametersFormGroup.valid ? null : {
|
||||||
|
rpcParametersFormGroup: { valid: false }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(value: ModbusValue): void {
|
||||||
|
this.rpcParametersFormGroup.patchValue(value, {emitEvent: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
private observeValueChanges(): void {
|
||||||
|
this.rpcParametersFormGroup.valueChanges.pipe(
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
).subscribe((value) => {
|
||||||
|
this.onChange(value);
|
||||||
|
this.onTouched();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private observeKeyDataType(): void {
|
||||||
|
this.rpcParametersFormGroup.get('type').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(dataType => {
|
||||||
|
if (!this.ModbusEditableDataTypes.includes(dataType)) {
|
||||||
|
this.rpcParametersFormGroup.get('objectsCount').patchValue(ModbusObjectCountByDataType[dataType], {emitEvent: false});
|
||||||
|
}
|
||||||
|
this.updateFunctionCodes(dataType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private observeFunctionCode(): void {
|
||||||
|
this.rpcParametersFormGroup.get('functionCode').valueChanges
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(code => this.updateValueEnabling(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateValueEnabling(code: number): void {
|
||||||
|
if (this.writeFunctionCodes.includes(code)) {
|
||||||
|
this.rpcParametersFormGroup.get('value').enable({emitEvent: false});
|
||||||
|
} else {
|
||||||
|
this.rpcParametersFormGroup.get('value').setValue(null);
|
||||||
|
this.rpcParametersFormGroup.get('value').disable({emitEvent: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateFunctionCodes(dataType: ModbusDataType): void {
|
||||||
|
this.functionCodes = dataType === ModbusDataType.BITS ? this.bitsFunctionCodes : this.defaultFunctionCodes;
|
||||||
|
if (!this.functionCodes.includes(this.rpcParametersFormGroup.get('functionCode').value)) {
|
||||||
|
this.rpcParametersFormGroup.get('functionCode').patchValue(this.functionCodes[0], {emitEvent: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -50,46 +50,6 @@
|
|||||||
placeholder="${params}"/>
|
placeholder="${params}"/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngSwitchCase]="ConnectorType.MODBUS">
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label>{{ 'gateway.rpc.tag' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="tag" placeholder="setValue"/>
|
|
||||||
</mat-form-field>
|
|
||||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
|
||||||
<mat-form-field fxFlex="50" class="mat-block">
|
|
||||||
<mat-label>{{ 'gateway.rpc.type' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="type">
|
|
||||||
<mat-option *ngFor="let type of modbusCommandTypes" [value]="type">
|
|
||||||
{{ type }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field fxFlex="50" class="mat-block">
|
|
||||||
<mat-label>{{ 'gateway.rpc.functionCode' | translate }}</mat-label>
|
|
||||||
<mat-select formControlName="functionCode">
|
|
||||||
<mat-option *ngFor="let code of codesArray" [value]="code">
|
|
||||||
{{ modbusCodesTranslate.get(code) | translate}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<mat-form-field *ngIf="commandForm.get('functionCode').value>4">
|
|
||||||
<mat-label>{{ 'gateway.rpc.value' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="value" placeholder="value"/>
|
|
||||||
</mat-form-field>
|
|
||||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
|
||||||
<mat-form-field fxFlex="50">
|
|
||||||
<mat-label>{{ 'gateway.rpc.address' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="address" type="number" min="0"
|
|
||||||
placeholder="1" step="1"/>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field fxFlex="50">
|
|
||||||
<mat-label>{{ 'gateway.rpc.objectsCount' | translate }}</mat-label>
|
|
||||||
<input matInput formControlName="objectsCount" type="number" min="0"
|
|
||||||
placeholder="31" step="1"/>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template [ngSwitchCase]="ConnectorType.BACNET">
|
<ng-template [ngSwitchCase]="ConnectorType.BACNET">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
|
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
|
||||||
|
|||||||
@ -35,8 +35,6 @@ import {
|
|||||||
ConnectorType,
|
ConnectorType,
|
||||||
GatewayConnectorDefaultTypesTranslatesMap,
|
GatewayConnectorDefaultTypesTranslatesMap,
|
||||||
HTTPMethods,
|
HTTPMethods,
|
||||||
ModbusCodesTranslate,
|
|
||||||
ModbusCommandTypes,
|
|
||||||
noLeadTrailSpacesRegex,
|
noLeadTrailSpacesRegex,
|
||||||
RPCCommand,
|
RPCCommand,
|
||||||
RPCTemplateConfig,
|
RPCTemplateConfig,
|
||||||
@ -53,7 +51,7 @@ import {
|
|||||||
} from '@shared/components/dialog/json-object-edit-dialog.component';
|
} from '@shared/components/dialog/json-object-edit-dialog.component';
|
||||||
import { jsonRequired } from '@shared/components/json-object-edit.component';
|
import { jsonRequired } from '@shared/components/json-object-edit.component';
|
||||||
import { deepClone } from '@core/utils';
|
import { deepClone } from '@core/utils';
|
||||||
import { filter, takeUntil, tap } from "rxjs/operators";
|
import { takeUntil, tap } from "rxjs/operators";
|
||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -80,9 +78,7 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C
|
|||||||
saveTemplate: EventEmitter<RPCTemplateConfig> = new EventEmitter();
|
saveTemplate: EventEmitter<RPCTemplateConfig> = new EventEmitter();
|
||||||
|
|
||||||
commandForm: FormGroup;
|
commandForm: FormGroup;
|
||||||
codesArray: Array<number> = [1, 2, 3, 4, 5, 6, 15, 16];
|
|
||||||
ConnectorType = ConnectorType;
|
ConnectorType = ConnectorType;
|
||||||
modbusCommandTypes = Object.values(ModbusCommandTypes) as ModbusCommandTypes[];
|
|
||||||
bACnetRequestTypes = Object.values(BACnetRequestTypes) as BACnetRequestTypes[];
|
bACnetRequestTypes = Object.values(BACnetRequestTypes) as BACnetRequestTypes[];
|
||||||
bACnetObjectTypes = Object.values(BACnetObjectTypes) as BACnetObjectTypes[];
|
bACnetObjectTypes = Object.values(BACnetObjectTypes) as BACnetObjectTypes[];
|
||||||
bLEMethods = Object.values(BLEMethods) as BLEMethods[];
|
bLEMethods = Object.values(BLEMethods) as BLEMethods[];
|
||||||
@ -98,7 +94,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C
|
|||||||
SocketMethodProcessingsTranslates = SocketMethodProcessingsTranslates;
|
SocketMethodProcessingsTranslates = SocketMethodProcessingsTranslates;
|
||||||
SNMPMethodsTranslations = SNMPMethodsTranslations;
|
SNMPMethodsTranslations = SNMPMethodsTranslations;
|
||||||
gatewayConnectorDefaultTypesTranslates = GatewayConnectorDefaultTypesTranslatesMap;
|
gatewayConnectorDefaultTypesTranslates = GatewayConnectorDefaultTypesTranslatesMap;
|
||||||
modbusCodesTranslate = ModbusCodesTranslate;
|
|
||||||
|
|
||||||
urlPattern = /^[-a-zA-Zd_$:{}?~+=\/.0-9-]*$/;
|
urlPattern = /^[-a-zA-Zd_$:{}?~+=\/.0-9-]*$/;
|
||||||
numbersOnlyPattern = /^[0-9]*$/;
|
numbersOnlyPattern = /^[0-9]*$/;
|
||||||
@ -156,26 +151,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C
|
|||||||
withResponse: [false, []],
|
withResponse: [false, []],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ConnectorType.MODBUS:
|
|
||||||
formGroup = this.fb.group({
|
|
||||||
tag: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
|
||||||
type: [null, [Validators.required]],
|
|
||||||
functionCode: [null, [Validators.required]],
|
|
||||||
value: [null, []],
|
|
||||||
address: [null, [Validators.required, Validators.min(0), Validators.pattern(this.numbersOnlyPattern)]],
|
|
||||||
objectsCount: [null, [Validators.required, Validators.min(0), Validators.pattern(this.numbersOnlyPattern)]]
|
|
||||||
})
|
|
||||||
const valueForm = formGroup.get('value');
|
|
||||||
formGroup.get('functionCode').valueChanges.subscribe(value => {
|
|
||||||
if (value > 4) {
|
|
||||||
valueForm.addValidators([Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]);
|
|
||||||
} else {
|
|
||||||
valueForm.clearValidators();
|
|
||||||
valueForm.setValue(null);
|
|
||||||
}
|
|
||||||
valueForm.updateValueAndValidity();
|
|
||||||
})
|
|
||||||
break;
|
|
||||||
case ConnectorType.BACNET:
|
case ConnectorType.BACNET:
|
||||||
formGroup = this.fb.group({
|
formGroup = this.fb.group({
|
||||||
method: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
method: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||||
|
|||||||
@ -41,8 +41,32 @@
|
|||||||
</button>
|
</button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template #connectorForm>
|
<ng-template #connectorForm>
|
||||||
<tb-gateway-service-rpc-connector formControlName="params" [connectorType]="connectorType"
|
<tb-gateway-service-rpc-connector
|
||||||
(sendCommand)="sendCommand()" (saveTemplate)="saveTemplate()"/>
|
*ngIf="connectorType !== ConnectorType.MODBUS else modbusParameters"
|
||||||
|
formControlName="params"
|
||||||
|
[connectorType]="connectorType"
|
||||||
|
(sendCommand)="sendCommand()"
|
||||||
|
(saveTemplate)="saveTemplate()"
|
||||||
|
/>
|
||||||
|
<ng-template #modbusParameters>
|
||||||
|
<div fxLayout="column" class="rpc-parameters">
|
||||||
|
<div class="mat-subtitle-1 tb-form-panel-title">{{ 'gateway.rpc.title' | translate: {type: gatewayConnectorDefaultTypesTranslates.get(connectorType)} }}</div>
|
||||||
|
<tb-modbus-rpc-parameters formControlName="params"/>
|
||||||
|
<div class="template-actions" fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="10px">
|
||||||
|
<button mat-raised-button
|
||||||
|
(click)="saveTemplate()"
|
||||||
|
[disabled]="commandForm.get('params').invalid">
|
||||||
|
{{ 'gateway.rpc-command-save-template' | translate }}
|
||||||
|
</button>
|
||||||
|
<button mat-raised-button
|
||||||
|
color="primary"
|
||||||
|
(click)="sendCommand()"
|
||||||
|
[disabled]="commandForm.get('params').invalid">
|
||||||
|
{{ 'gateway.rpc-command-send' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
<section class="result-block" [formGroup]="commandForm">
|
<section class="result-block" [formGroup]="commandForm">
|
||||||
|
|||||||
@ -40,6 +40,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rpc-parameters {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.result-block {
|
.result-block {
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { ContentType } from '@shared/models/constants';
|
|||||||
import { jsonRequired } from '@shared/components/json-object-edit.component';
|
import { jsonRequired } from '@shared/components/json-object-edit.component';
|
||||||
import {
|
import {
|
||||||
ConnectorType,
|
ConnectorType,
|
||||||
|
GatewayConnectorDefaultTypesTranslatesMap,
|
||||||
RPCCommand,
|
RPCCommand,
|
||||||
RPCTemplate,
|
RPCTemplate,
|
||||||
RPCTemplateConfig,
|
RPCTemplateConfig,
|
||||||
@ -71,6 +72,9 @@ export class GatewayServiceRPCComponent implements OnInit {
|
|||||||
public connectorType: ConnectorType;
|
public connectorType: ConnectorType;
|
||||||
public templates: Array<RPCTemplate> = [];
|
public templates: Array<RPCTemplate> = [];
|
||||||
|
|
||||||
|
readonly ConnectorType = ConnectorType;
|
||||||
|
readonly gatewayConnectorDefaultTypesTranslates = GatewayConnectorDefaultTypesTranslatesMap;
|
||||||
|
|
||||||
private subscription: IWidgetSubscription;
|
private subscription: IWidgetSubscription;
|
||||||
private subscriptionOptions: WidgetSubscriptionOptions = {
|
private subscriptionOptions: WidgetSubscriptionOptions = {
|
||||||
callbacks: {
|
callbacks: {
|
||||||
|
|||||||
@ -319,35 +319,15 @@ export interface RPCCommand {
|
|||||||
time: number;
|
time: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ModbusFunctionCodeTranslationsMap = new Map<number, string>([
|
||||||
export enum ModbusCommandTypes {
|
[1, 'gateway.function-codes.read-coils'],
|
||||||
Bits = 'bits',
|
[2, 'gateway.function-codes.read-discrete-inputs'],
|
||||||
Bit = 'bit',
|
[3, 'gateway.function-codes.read-multiple-holding-registers'],
|
||||||
// eslint-disable-next-line id-blacklist
|
[4, 'gateway.function-codes.read-input-registers'],
|
||||||
String = 'string',
|
[5, 'gateway.function-codes.write-single-coil'],
|
||||||
Bytes = 'bytes',
|
[6, 'gateway.function-codes.write-single-holding-register'],
|
||||||
Int8 = '8int',
|
[15, 'gateway.function-codes.write-multiple-coils'],
|
||||||
Uint8 = '8uint',
|
[16, 'gateway.function-codes.write-multiple-holding-registers']
|
||||||
Int16 = '16int',
|
|
||||||
Uint16 = '16uint',
|
|
||||||
Float16 = '16float',
|
|
||||||
Int32 = '32int',
|
|
||||||
Uint32 = '32uint',
|
|
||||||
Float32 = '32float',
|
|
||||||
Int64 = '64int',
|
|
||||||
Uint64 = '64uint',
|
|
||||||
Float64 = '64float'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ModbusCodesTranslate = new Map<number, string>([
|
|
||||||
[1, 'gateway.rpc.read-coils'],
|
|
||||||
[2, 'gateway.rpc.read-discrete-inputs'],
|
|
||||||
[3, 'gateway.rpc.read-multiple-holding-registers'],
|
|
||||||
[4, 'gateway.rpc.read-input-registers'],
|
|
||||||
[5, 'gateway.rpc.write-single-coil'],
|
|
||||||
[6, 'gateway.rpc.write-single-holding-register'],
|
|
||||||
[15, 'gateway.rpc.write-multiple-coils'],
|
|
||||||
[16, 'gateway.rpc.write-multiple-holding-registers']
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export enum BACnetRequestTypes {
|
export enum BACnetRequestTypes {
|
||||||
@ -870,6 +850,8 @@ export enum ModbusDataType {
|
|||||||
FLOAT64 = '64float'
|
FLOAT64 = '64float'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ModbusEditableDataTypes = [ModbusDataType.BYTES, ModbusDataType.BITS, ModbusDataType.STRING];
|
||||||
|
|
||||||
export enum ModbusObjectCountByDataType {
|
export enum ModbusObjectCountByDataType {
|
||||||
'8int' = 1,
|
'8int' = 1,
|
||||||
'8uint' = 1,
|
'8uint' = 1,
|
||||||
@ -928,19 +910,6 @@ export const ModbusKeysNoKeysTextTranslationsMap = new Map<ModbusValueKey, strin
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
export const ModbusFunctionCodeTranslationsMap = new Map<number, string>(
|
|
||||||
[
|
|
||||||
[1, 'gateway.read-coils'],
|
|
||||||
[2, 'gateway.read-discrete-inputs'],
|
|
||||||
[3, 'gateway.read-multiple-holding-registers'],
|
|
||||||
[4, 'gateway.read-input-registers'],
|
|
||||||
[5, 'gateway.write-coil'],
|
|
||||||
[6, 'gateway.write-register'],
|
|
||||||
[15, 'gateway.write-coils'],
|
|
||||||
[16, 'gateway.write-registers'],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
export interface ModbusMasterConfig {
|
export interface ModbusMasterConfig {
|
||||||
slaves: SlaveConfig[];
|
slaves: SlaveConfig[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,6 +141,9 @@ import {
|
|||||||
import {
|
import {
|
||||||
TypeValuePanelComponent
|
TypeValuePanelComponent
|
||||||
} from '@home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component';
|
} from '@home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component';
|
||||||
|
import {
|
||||||
|
ModbusRpcParametersComponent
|
||||||
|
} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -227,6 +230,7 @@ import {
|
|||||||
KeyValueIsNotEmptyPipe,
|
KeyValueIsNotEmptyPipe,
|
||||||
ModbusBasicConfigComponent,
|
ModbusBasicConfigComponent,
|
||||||
EllipsisChipListDirective,
|
EllipsisChipListDirective,
|
||||||
|
ModbusRpcParametersComponent,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
EntitiesTableWidgetComponent,
|
EntitiesTableWidgetComponent,
|
||||||
|
|||||||
@ -2914,6 +2914,16 @@
|
|||||||
"from-device-request-settings": "Input request parsing",
|
"from-device-request-settings": "Input request parsing",
|
||||||
"from-device-request-settings-hint": "These fields support JSONPath expressions to extract a name from incoming message.",
|
"from-device-request-settings-hint": "These fields support JSONPath expressions to extract a name from incoming message.",
|
||||||
"function-code": "Function code",
|
"function-code": "Function code",
|
||||||
|
"function-codes": {
|
||||||
|
"read-coils": "01 - Read Coils",
|
||||||
|
"read-discrete-inputs": "02 - Read Discrete Inputs",
|
||||||
|
"read-multiple-holding-registers": "03 - Read Multiple Holding Registers",
|
||||||
|
"read-input-registers": "04 - Read Input Registers",
|
||||||
|
"write-single-coil": "05 - Write Single Coil",
|
||||||
|
"write-single-holding-register": "06 - Write Single Holding Register",
|
||||||
|
"write-multiple-coils": "15 - Write Multiple Coils",
|
||||||
|
"write-multiple-holding-registers": "16 - Write Multiple Holding Registers"
|
||||||
|
},
|
||||||
"to-device-response-settings": "Output request processing",
|
"to-device-response-settings": "Output request processing",
|
||||||
"to-device-response-settings-hint": "For these fields you can use the following variables and they will be replaced with actual values: ${deviceName}, ${attributeKey}, ${attributeValue}",
|
"to-device-response-settings-hint": "For these fields you can use the following variables and they will be replaced with actual values: ${deviceName}, ${attributeKey}, ${attributeValue}",
|
||||||
"gateway": "Gateway",
|
"gateway": "Gateway",
|
||||||
@ -3120,14 +3130,6 @@
|
|||||||
"template-name-duplicate": "Template with such name already exists, it will be updated.",
|
"template-name-duplicate": "Template with such name already exists, it will be updated.",
|
||||||
"command": "Command",
|
"command": "Command",
|
||||||
"params": "Params",
|
"params": "Params",
|
||||||
"read-coils": "01: Read Coils",
|
|
||||||
"read-discrete-inputs": "02: Read Discrete Inputs",
|
|
||||||
"read-multiple-holding-registers": "03: Read Multiple Holding Registers",
|
|
||||||
"read-input-registers": "04: Read Input Registers",
|
|
||||||
"write-single-coil": "05: Write Single Coil",
|
|
||||||
"write-single-holding-register": "06: Write Single Holding Register",
|
|
||||||
"write-multiple-coils": "15: Write Multiple Coils",
|
|
||||||
"write-multiple-holding-registers": "16: Write Multiple Holding Registers",
|
|
||||||
"json-value-invalid": "JSON value has an invalid format"
|
"json-value-invalid": "JSON value has an invalid format"
|
||||||
},
|
},
|
||||||
"rpc-methods": "RPC methods",
|
"rpc-methods": "RPC methods",
|
||||||
@ -3317,10 +3319,6 @@
|
|||||||
"username": "Username",
|
"username": "Username",
|
||||||
"username-required": "Username is required.",
|
"username-required": "Username is required.",
|
||||||
"unit-id-required": "Unit ID is required.",
|
"unit-id-required": "Unit ID is required.",
|
||||||
"read-coils": "Read Coils",
|
|
||||||
"read-discrete-inputs": "Read Discrete Inputs",
|
|
||||||
"read-multiple-holding-registers": "Read Multiple Holding Register",
|
|
||||||
"read-input-registers": "Read Input Registers",
|
|
||||||
"write-coil": "Write Coil",
|
"write-coil": "Write Coil",
|
||||||
"write-coils": "Write Coils",
|
"write-coils": "Write Coils",
|
||||||
"write-register": "Write Register",
|
"write-register": "Write Register",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user