From 69aca15b9b281c4deb74732d802315e46c3fb346 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Fri, 20 Sep 2024 18:29:08 +0300 Subject: [PATCH 1/7] RPC templates update for MQTT/MODBUS/OPC --- .../modbus-rpc-parameters.component.html | 47 ++--- .../modbus-rpc-parameters.component.scss | 20 +++ .../modbus-rpc-parameters.component.ts | 10 +- .../mqtt-rpc-parameters.component.html | 48 +++++ .../mqtt-rpc-parameters.component.scss | 24 +++ .../mqtt-rpc-parameters.component.ts | 136 ++++++++++++++ .../opc-rpc-parameters.component.html | 90 ++++++++++ .../opc-rpc-parameters.component.scss | 28 +++ .../opc-rpc-parameters.component.ts | 166 ++++++++++++++++++ .../type-value-panel.component.html | 4 +- .../type-value-panel.component.ts | 2 +- ...ice-rpc-connector-templates.component.html | 6 +- ...ice-rpc-connector-templates.component.scss | 4 + ...rvice-rpc-connector-templates.component.ts | 3 +- ...teway-service-rpc-connector.component.html | 55 ------ ...gateway-service-rpc-connector.component.ts | 56 ------ .../gateway-service-rpc.component.html | 10 +- .../gateway/gateway-service-rpc.component.ts | 5 + .../lib/gateway/gateway-widget.models.ts | 33 +++- .../pipes/rpc-template-array-view.pipe.ts | 28 +++ .../widget/widget-components.module.ts | 17 +- .../assets/locale/locale.constant-en_US.json | 5 +- 22 files changed, 638 insertions(+), 159 deletions(-) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{modbus => rpc-parameters}/modbus-rpc-parameters/modbus-rpc-parameters.component.html (77%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.scss rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{modbus => rpc-parameters}/modbus-rpc-parameters/modbus-rpc-parameters.component.ts (94%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/rpc-template-array-view.pipe.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.html similarity index 77% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.html index c2dead1abc..9f27d4a1a1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.html @@ -16,20 +16,9 @@ --> -
- - {{ 'gateway.key' | translate }} - - - warning - - +
+ RPC response will return all subtracted values from all connected devices when the reading functions are selected.
+ RPC will write a filled value to all connected devices when the writing functions are selected.
@@ -45,21 +34,6 @@
-
- - {{ 'gateway.rpc.value' | translate }} - - - warning - - -
{{ 'gateway.rpc.address' | translate }} @@ -88,5 +62,20 @@ />
+
+ + {{ 'gateway.rpc.value' | translate }} + + + warning + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.scss new file mode 100644 index 0000000000..62eaca664f --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.scss @@ -0,0 +1,20 @@ +/** + * 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. + */ +:host { + .hint-container { + margin-bottom: 12px; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.ts similarity index 94% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.ts index 17c48cc595..ae110b9418 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component.ts @@ -39,13 +39,14 @@ import { ModbusEditableDataTypes, ModbusFunctionCodeTranslationsMap, ModbusObjectCountByDataType, - ModbusValue, noLeadTrailSpacesRegex, + RPCTemplateConfigModbus, } from '@home/components/widget/lib/gateway/gateway-widget.models'; @Component({ selector: 'tb-modbus-rpc-parameters', templateUrl: './modbus-rpc-parameters.component.html', + styleUrls: ['./modbus-rpc-parameters.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, providers: [ { @@ -80,14 +81,13 @@ export class ModbusRpcParametersComponent implements ControlValueAccessor, Valid private readonly readFunctionCodes = [1, 2, 3, 4]; private readonly bitsFunctionCodes = [...this.readFunctionCodes, ...this.writeFunctionCodes]; - private onChange: (value: ModbusValue) => void; + private onChange: (value: RPCTemplateConfigModbus) => void; private onTouched: () => void; private destroy$ = new Subject(); 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)]], @@ -106,7 +106,7 @@ export class ModbusRpcParametersComponent implements ControlValueAccessor, Valid this.destroy$.complete(); } - registerOnChange(fn: (value: ModbusValue) => void): void { + registerOnChange(fn: (value: RPCTemplateConfigModbus) => void): void { this.onChange = fn; } @@ -120,7 +120,7 @@ export class ModbusRpcParametersComponent implements ControlValueAccessor, Valid }; } - writeValue(value: ModbusValue): void { + writeValue(value: RPCTemplateConfigModbus): void { this.rpcParametersFormGroup.patchValue(value, {emitEvent: false}); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.html new file mode 100644 index 0000000000..eb66a6df8c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.html @@ -0,0 +1,48 @@ + + + + {{ 'gateway.rpc.method-name' | translate }} + + + + {{ 'gateway.rpc.requestTopicExpression' | translate }} + + + + {{ 'gateway.rpc.withResponse' | translate }} + + + {{ 'gateway.rpc.responseTopicExpression' | translate }} + + + + {{ 'gateway.rpc.responseTimeout' | translate }} + + + + {{ 'gateway.rpc.valueExpression' | translate }} + + + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.scss new file mode 100644 index 0000000000..a2dddebc47 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.scss @@ -0,0 +1,24 @@ +/** + * 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. + */ +:host { + display: flex; + flex-direction: column; + + .mat-mdc-slide-toggle.margin { + margin-bottom: 10px; + margin-left: 10px; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts new file mode 100644 index 0000000000..13f366f09b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts @@ -0,0 +1,136 @@ +/// +/// 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, tap } from 'rxjs/operators'; +import { + integerRegex, + noLeadTrailSpacesRegex, + RPCTemplateConfigMQTT +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +@Component({ + selector: 'tb-mqtt-rpc-parameters', + templateUrl: './mqtt-rpc-parameters.component.html', + styleUrls: ['./mqtt-rpc-parameters.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MqttRpcParametersComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => MqttRpcParametersComponent), + multi: true + } + ], + standalone: true, + imports: [ + CommonModule, + SharedModule, + ], +}) +export class MqttRpcParametersComponent implements ControlValueAccessor, Validator, OnDestroy { + + rpcParametersFormGroup: UntypedFormGroup; + + private onChange: (value: RPCTemplateConfigMQTT) => void; + private onTouched: () => void; + + private destroy$ = new Subject(); + + constructor(private fb: FormBuilder) { + this.rpcParametersFormGroup = this.fb.group({ + methodFilter: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], + requestTopicExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], + responseTopicExpression: [{ value: null, disabled: true }, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], + responseTimeout: [{ value: null, disabled: true }, [Validators.min(10), Validators.pattern(integerRegex)]], + valueExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], + withResponse: [false, []], + }); + + this.observeValueChanges(); + this.observeWithResponse(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + registerOnChange(fn: (value: RPCTemplateConfigMQTT) => 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: RPCTemplateConfigMQTT): 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 observeWithResponse(): void { + this.rpcParametersFormGroup.get('withResponse').valueChanges.pipe( + tap((isActive: boolean) => { + const responseTopicControl = this.rpcParametersFormGroup.get('responseTopicExpression'); + const responseTimeoutControl = this.rpcParametersFormGroup.get('responseTimeout'); + if (isActive) { + responseTopicControl.enable(); + responseTimeoutControl.enable(); + } else { + responseTopicControl.disable(); + responseTimeoutControl.disable(); + } + }), + takeUntil(this.destroy$), + ).subscribe(); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.html new file mode 100644 index 0000000000..06f98668c4 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.html @@ -0,0 +1,90 @@ + + + + {{ 'gateway.rpc.method' | translate }} + + +
+ + {{ 'gateway.rpc.arguments' | translate }} + +
+
+
gateway.type
+
+ + + +
+ + + {{ valueTypes.get(argumentFormGroup.get('type').value)?.name | translate }} +
+
+ + + + {{ valueTypes.get(valueType).name | translate }} + +
+
+
+
+
+
gateway.value
+ + + + + + + true + false + + + + warning + + +
+ +
+ +
+
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.scss new file mode 100644 index 0000000000..1ff651a032 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.scss @@ -0,0 +1,28 @@ +/** + * 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. + */ +:host { + .arguments-container { + margin-bottom: 10px; + } + + .type-container { + width: 40%; + } + + .value-container { + width: 50%; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.ts new file mode 100644 index 0000000000..4409fdcf6f --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.ts @@ -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, + ChangeDetectorRef, + Component, + forwardRef, + OnDestroy, +} from '@angular/core'; +import { + ControlValueAccessor, + FormArray, + FormBuilder, + FormGroup, + 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 { + integerRegex, + MappingValueType, + mappingValueTypesMap, + noLeadTrailSpacesRegex, + OPCTypeValue, + RPCTemplateConfigOPC +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { isEqual } from '@core/utils'; + +@Component({ + selector: 'tb-opc-rpc-parameters', + templateUrl: './opc-rpc-parameters.component.html', + styleUrls: ['./opc-rpc-parameters.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => OpcRpcParametersComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => OpcRpcParametersComponent), + multi: true + } + ], + standalone: true, + imports: [ + CommonModule, + SharedModule, + ], +}) +export class OpcRpcParametersComponent implements ControlValueAccessor, Validator, OnDestroy { + + rpcParametersFormGroup: UntypedFormGroup; + + readonly valueTypeKeys: MappingValueType[] = Object.values(MappingValueType); + readonly MappingValueType = MappingValueType; + readonly valueTypes = mappingValueTypesMap; + + private onChange: (value: RPCTemplateConfigOPC) => void; + private onTouched: () => void; + + private destroy$ = new Subject(); + + constructor(private fb: FormBuilder, private cdr: ChangeDetectorRef) { + this.rpcParametersFormGroup = this.fb.group({ + method: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], + arguments: this.fb.array([]), + }); + + this.observeValueChanges(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + registerOnChange(fn: (value: RPCTemplateConfigOPC) => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + validate(): ValidationErrors | null { + return this.rpcParametersFormGroup.valid ? null : { + rpcParametersFormGroup: { valid: false } + }; + } + + writeValue(params: RPCTemplateConfigOPC): void { + this.clearFromArrayByName('arguments'); + params.arguments?.map(({type, value}) => ({type, [type]: value })) + .forEach(argument => this.addOCPUAArguments(argument as OPCTypeValue)); + this.cdr.markForCheck(); + this.rpcParametersFormGroup.get('method').patchValue(params.method, {emitEvent: false}); + } + + private observeValueChanges(): void { + this.rpcParametersFormGroup.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(params => { + const updatedArguments = params.arguments.map(({type, ...config}) => ({type, value: config[type]})); + this.onChange({method: params.method, arguments: updatedArguments}); + this.onTouched(); + }); + } + + removeOCPUAArguments(index: number): void { + (this.rpcParametersFormGroup.get('arguments') as FormArray).removeAt(index); + } + + addOCPUAArguments(value: OPCTypeValue = {} as OPCTypeValue): void { + const fromGroup = this.fb.group({ + type: [value.type ?? MappingValueType.STRING], + string: [ + value.string ?? { value: '', disabled: !(isEqual(value, {}) || value.string)}, + [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)] + ], + integer: [{value: value.integer ?? 0, disabled: !value.integer}, [Validators.required, Validators.pattern(integerRegex)]], + double: [{value: value.double ?? 0, disabled: !value.double}, [Validators.required]], + boolean: [{value: value.boolean ?? false, disabled: !value.boolean}, [Validators.required]], + }); + this.observeTypeChange(fromGroup); + (this.rpcParametersFormGroup.get('arguments') as FormArray).push(fromGroup, {emitEvent: false}); + } + + clearFromArrayByName(name: string): void { + const formArray = this.rpcParametersFormGroup.get(name) as FormArray; + while (formArray.length !== 0) { + formArray.removeAt(0); + } + } + + private observeTypeChange(dataKeyFormGroup: FormGroup): void { + dataKeyFormGroup.get('type').valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(type => { + dataKeyFormGroup.disable({emitEvent: false}); + dataKeyFormGroup.get('type').enable({emitEvent: false}); + dataKeyFormGroup.get(type).enable({emitEvent: false}); + }); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component.html index f72a2c18af..f40914f3d0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component.html @@ -70,8 +70,8 @@ matTooltipPosition="above" matTooltipClass="tb-error-tooltip" [matTooltip]="('gateway.value-required') | translate" - *ngIf="keyControl.get(keyControl.get('type').value).hasError('required') - && keyControl.get(keyControl.get('type').value).touched" + *ngIf="keyControl.get(keyControl.get('value').value).hasError('required') + && keyControl.get(keyControl.get('value').value).touched" class="tb-error"> warning diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component.ts index 8e1c6fdb57..27096ea25a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component.ts @@ -104,7 +104,7 @@ export class TypeValuePanelComponent implements ControlValueAccessor, Validator, dataKeyFormGroup.disable({emitEvent: false}); dataKeyFormGroup.get('type').enable({emitEvent: false}); dataKeyFormGroup.get(type).enable({emitEvent: false}); - }) + }); } deleteKey($event: Event, index: number): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.html index ee644c54c7..0d01a1c1d7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.html @@ -44,7 +44,11 @@
{{!innerValue ? ('gateway.rpc.' + config.key | translate) : config.key}}
-
+ {{ config.value | getRpcTemplateArrayView }} +
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.scss index 27ff7843ee..bf037a7249 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.scss @@ -104,6 +104,10 @@ flex: 1; margin: 0; } + + .array-value { + margin-left: 10px; + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.ts index 466ab5fdb5..9c2e551a22 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector-templates.component.ts @@ -49,7 +49,8 @@ export class GatewayServiceRPCConnectorTemplatesComponent implements OnInit { rpcTemplates: Array; public readonly originalOrder = (): number => 0; - public readonly isObject = (value: any) => isLiteralObject(value); + public readonly isObject = (value: unknown) => isLiteralObject(value); + public readonly isArray = (value: unknown) => Array.isArray(value); public readonly SNMPMethodsTranslations = SNMPMethodsTranslations; constructor(private attributeService: AttributeService) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.html index 3e94ae96d7..fde4ab28ac 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.html @@ -20,36 +20,6 @@ class="mat-subtitle-1 title">{{ 'gateway.rpc.title' | translate: {type: gatewayConnectorDefaultTypesTranslates.get(connectorType)} }}
- - - {{ 'gateway.rpc.methodFilter' | translate }} - - - - {{ 'gateway.rpc.requestTopicExpression' | translate }} - - - - {{ 'gateway.rpc.withResponse' | translate }} - - - {{ 'gateway.rpc.responseTopicExpression' | translate }} - - - - {{ 'gateway.rpc.responseTimeout' | translate }} - - - - {{ 'gateway.rpc.valueExpression' | translate }} - - - {{ 'gateway.rpc.methodRPC' | translate }} @@ -407,31 +377,6 @@ - - - {{ 'gateway.rpc.method' | translate }} - - -
- {{ 'gateway.rpc.arguments' | translate }} -
- - - - delete - -
- -
-
{{ 'gateway.statistics.command' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.ts index 989f9daeed..f77e877aea 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.ts @@ -51,7 +51,6 @@ import { } from '@shared/components/dialog/json-object-edit-dialog.component'; import { jsonRequired } from '@shared/components/json-object-edit.component'; import { deepClone } from '@core/utils'; -import { takeUntil, tap } from "rxjs/operators"; import { Subject } from "rxjs"; @Component({ @@ -129,7 +128,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C this.propagateChange({...this.commandForm.value, ...value}); } }); - this.observeMQTTWithResponse(); } ngOnDestroy(): void { @@ -141,16 +139,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C let formGroup: FormGroup; switch (type) { - case ConnectorType.MQTT: - formGroup = this.fb.group({ - methodFilter: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], - requestTopicExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], - responseTopicExpression: [{ value: null, disabled: true }, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], - responseTimeout: [{ value: null, disabled: true }, [Validators.min(10), Validators.pattern(this.numbersOnlyPattern)]], - valueExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], - withResponse: [false, []], - }); - break; case ConnectorType.BACNET: formGroup = this.fb.group({ method: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], @@ -246,12 +234,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C httpHeaders: this.fb.array([]), }) break; - case ConnectorType.OPCUA: - formGroup = this.fb.group({ - method: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], - arguments: this.fb.array([]), - }) - break; default: formGroup = this.fb.group({ command: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], @@ -293,18 +275,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C return (this.commandForm.get(path) as FormArray).controls as FormControl[]; } - addOCPUAArguments(value: string = null) { - const oidsFA = this.commandForm.get('arguments') as FormArray; - if (oidsFA) { - oidsFA.push(this.fb.control(value, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]), {emitEvent: false}); - } - } - - removeOCPUAArguments(index: number) { - const oidsFA = this.commandForm.get('arguments') as FormArray; - oidsFA.removeAt(index); - } - openEditJSONDialog($event: Event) { if ($event) { $event.stopPropagation(); @@ -368,34 +338,8 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C }) delete value.httpHeaders; break; - case ConnectorType.OPCUA: - this.clearFromArrayByName("arguments"); - value.arguments.forEach(value => { - this.addOCPUAArguments(value) - }) - delete value.arguments; - break; } this.commandForm.patchValue(value, {onlySelf: false}); } } - - private observeMQTTWithResponse(): void { - if (this.connectorType === ConnectorType.MQTT) { - this.commandForm.get('withResponse').valueChanges.pipe( - tap((isActive: boolean) => { - const responseTopicControl = this.commandForm.get('responseTopicExpression'); - const responseTimeoutControl = this.commandForm.get('responseTimeout'); - if (isActive) { - responseTopicControl.enable(); - responseTimeoutControl.enable(); - } else { - responseTopicControl.disable(); - responseTimeoutControl.disable(); - } - }), - takeUntil(this.destroy$), - ).subscribe(); - } - } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.html index 41dea0b656..41a655d93e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.html @@ -42,16 +42,20 @@
- +
{{ 'gateway.rpc.title' | translate: {type: gatewayConnectorDefaultTypesTranslates.get(connectorType)} }}
- + + + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.ts index 4409fdcf6f..0c0dbea3bd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.ts @@ -44,7 +44,7 @@ import { OPCTypeValue, RPCTemplateConfigOPC } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { isEqual } from '@core/utils'; +import { isDefinedAndNotNull, isEqual } from '@core/utils'; @Component({ selector: 'tb-opc-rpc-parameters', @@ -77,8 +77,8 @@ export class OpcRpcParametersComponent implements ControlValueAccessor, Validato readonly MappingValueType = MappingValueType; readonly valueTypes = mappingValueTypesMap; - private onChange: (value: RPCTemplateConfigOPC) => void; - private onTouched: () => void; + private onChange: (value: RPCTemplateConfigOPC) => void = (_) => {} ; + private onTouched: () => void = () => {}; private destroy$ = new Subject(); @@ -111,11 +111,11 @@ export class OpcRpcParametersComponent implements ControlValueAccessor, Validato } writeValue(params: RPCTemplateConfigOPC): void { - this.clearFromArrayByName('arguments'); + this.clearArguments(); params.arguments?.map(({type, value}) => ({type, [type]: value })) - .forEach(argument => this.addOCPUAArguments(argument as OPCTypeValue)); + .forEach(argument => this.addArgument(argument as OPCTypeValue)); this.cdr.markForCheck(); - this.rpcParametersFormGroup.get('method').patchValue(params.method, {emitEvent: false}); + this.rpcParametersFormGroup.get('method').patchValue(params.method); } private observeValueChanges(): void { @@ -128,27 +128,30 @@ export class OpcRpcParametersComponent implements ControlValueAccessor, Validato }); } - removeOCPUAArguments(index: number): void { + removeArgument(index: number): void { (this.rpcParametersFormGroup.get('arguments') as FormArray).removeAt(index); } - addOCPUAArguments(value: OPCTypeValue = {} as OPCTypeValue): void { + addArgument(value: OPCTypeValue = {} as OPCTypeValue): void { const fromGroup = this.fb.group({ type: [value.type ?? MappingValueType.STRING], string: [ value.string ?? { value: '', disabled: !(isEqual(value, {}) || value.string)}, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)] ], - integer: [{value: value.integer ?? 0, disabled: !value.integer}, [Validators.required, Validators.pattern(integerRegex)]], - double: [{value: value.double ?? 0, disabled: !value.double}, [Validators.required]], - boolean: [{value: value.boolean ?? false, disabled: !value.boolean}, [Validators.required]], + integer: [ + {value: value.integer ?? 0, disabled: !isDefinedAndNotNull(value.integer)}, + [Validators.required, Validators.pattern(integerRegex)] + ], + double: [{value: value.double ?? 0, disabled: !isDefinedAndNotNull(value.double)}, [Validators.required]], + boolean: [{value: value.boolean ?? false, disabled: !isDefinedAndNotNull(value.boolean)}, [Validators.required]], }); this.observeTypeChange(fromGroup); (this.rpcParametersFormGroup.get('arguments') as FormArray).push(fromGroup, {emitEvent: false}); } - clearFromArrayByName(name: string): void { - const formArray = this.rpcParametersFormGroup.get(name) as FormArray; + clearArguments(): void { + const formArray = this.rpcParametersFormGroup.get('arguments') as FormArray; while (formArray.length !== 0) { formArray.removeAt(0); } From 7171ea8f189c11a1006fc30de83a42350a44c62a Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 23 Sep 2024 12:28:47 +0300 Subject: [PATCH 6/7] [4143] default onChange mqtt --- .../mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts index 6675baeef9..56d9510e7d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component.ts @@ -66,8 +66,8 @@ export class MqttRpcParametersComponent implements ControlValueAccessor, Validat rpcParametersFormGroup: UntypedFormGroup; - private onChange: (value: RPCTemplateConfigMQTT) => void; - private onTouched: () => void; + private onChange: (value: RPCTemplateConfigMQTT) => void = (_) => {}; + private onTouched: () => void = () => {}; private destroy$ = new Subject(); From 5fbabf842872a9b7a7c27700b3f84a2716881261 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 23 Sep 2024 12:41:05 +0300 Subject: [PATCH 7/7] [4143] added opc hint --- .../opc-rpc-parameters/opc-rpc-parameters.component.html | 3 +++ .../opc-rpc-parameters/opc-rpc-parameters.component.scss | 4 ++++ ui-ngx/src/assets/locale/locale.constant-en_US.json | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.html index 507d42d43e..ec5c20cfb1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.html @@ -16,6 +16,9 @@ --> +
+ {{ 'gateway.rpc.hint.opc-method' | translate }} +
{{ 'gateway.rpc.method' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.scss index 1ff651a032..5108cc70b1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component.scss @@ -25,4 +25,8 @@ .value-container { width: 50%; } + + .hint-container { + margin-bottom: 12px; + } } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 3f75d5edc9..df03032dea 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3187,7 +3187,8 @@ "header-name": "Header name", "hint": { "modbus-response-reading": "RPC response will return all subtracted values from all connected devices when the reading functions are selected.", - "modbus-writing-functions": "RPC will write a filled value to all connected devices when the writing functions are selected." + "modbus-writing-functions": "RPC will write a filled value to all connected devices when the writing functions are selected.", + "opc-method": "A filled method name is the OPC-UA method that will processed on the server side (make sure your node has the requested method)." }, "security-name": "Security name", "value": "Value",