From adf8ec31c5f1e3000bd061386a90644e3dfa1cec Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 28 Aug 2024 19:18:23 +0300 Subject: [PATCH 01/14] Added workaround for version compatibility of Gateway MQTT Connectors --- .../device-info-table.component.ts | 6 +- .../mapping-data-keys-panel.component.ts | 4 +- .../mapping-table/mapping-table.component.ts | 23 +- .../mqtt-basic-config.component.ts | 191 ------ .../mqtt-basic-config.abstract.ts | 107 ++++ .../mqtt-basic-config.component.html | 2 +- .../mqtt-basic-config.component.scss | 0 .../mqtt-basic-config.component.ts | 107 ++++ .../mqtt-legacy-basic-config.component.ts | 128 ++++ .../broker-config-control.component.html | 0 .../broker-config-control.component.ts | 2 +- .../opc-ua-basic-config.component.ts | 8 - .../dialog/add-connector-dialog.component.ts | 16 +- .../dialog/mapping-dialog.component.ts | 27 +- .../gateway/gateway-connectors.component.html | 15 +- .../gateway/gateway-connectors.component.scss | 5 + .../gateway/gateway-connectors.component.ts | 27 +- .../lib/gateway/gateway-widget.models.ts | 215 +++++-- .../gateway/pipes/gateway-help-link.pipe.ts | 10 +- .../gateway-connector-version-mapping.util.ts | 66 ++ .../utils/mqtt-version-mapping.util.ts | 279 ++++++++ .../widget/widget-components.module.ts | 8 +- .../connector-default-configs/mqtt.json | 597 ++++++++++++------ 23 files changed, 1341 insertions(+), 502 deletions(-) delete mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{mqtt-basic-config => mqtt/basic-config}/mqtt-basic-config.component.html (93%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{mqtt-basic-config => mqtt/basic-config}/mqtt-basic-config.component.scss (100%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => mqtt}/broker-config-control/broker-config-control.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => mqtt}/broker-config-control/broker-config-control.component.ts (97%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table/device-info-table.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table/device-info-table.component.ts index 569f40b185..91432b7353 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table/device-info-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table/device-info-table.component.ts @@ -42,8 +42,8 @@ import { import { DeviceInfoType, noLeadTrailSpacesRegex, - OPCUaSourceTypes, - SourceTypes, + OPCUaSourceType, + SourceType, SourceTypeTranslationsMap } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { coerceBoolean } from '@shared/decorators/coercion'; @@ -81,7 +81,7 @@ export class DeviceInfoTableComponent extends PageComponent implements ControlVa required = false; @Input() - sourceTypes: Array = Object.values(SourceTypes); + sourceTypes: Array = Object.values(SourceType); deviceInfoTypeValue: any; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.ts index 7867a7213f..de289dde2e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.ts @@ -42,7 +42,7 @@ import { MappingValueType, mappingValueTypesMap, noLeadTrailSpacesRegex, - OPCUaSourceTypes, + OPCUaSourceType, RpcMethodsMapping, } from '@home/components/widget/lib/gateway/gateway-widget.models'; @@ -73,7 +73,7 @@ export class MappingDataKeysPanelComponent extends PageComponent implements OnIn keysType: MappingKeysType; @Input() - valueTypeKeys: Array = Object.values(MappingValueType); + valueTypeKeys: Array = Object.values(MappingValueType); @Input() valueTypeEnum = MappingValueType; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component.ts index 05dcfa88ba..fa8dfa6466 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component.ts @@ -40,17 +40,21 @@ import { Validator, } from '@angular/forms'; import { + AttributeUpdate, ConnectorMapping, + ConnectRequest, ConverterConnectorMapping, ConvertorTypeTranslationsMap, DeviceConnectorMapping, + DisconnectRequest, MappingInfo, MappingType, MappingTypeTranslationsMap, MappingValue, - RequestMappingData, + RequestMappingValue, RequestType, - RequestTypesTranslationsMap + RequestTypesTranslationsMap, + ServerSideRpc } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { MappingDialogComponent } from '@home/components/widget/lib/gateway/dialog/mapping-dialog.component'; import { isDefinedAndNotNull, isUndefinedOrNull } from '@core/utils'; @@ -259,16 +263,17 @@ export class MappingTableComponent implements ControlValueAccessor, Validator, A }; case MappingType.REQUESTS: let details: string; - if ((value as RequestMappingData).requestType === RequestType.ATTRIBUTE_UPDATE) { - details = (value as RequestMappingData).requestValue.attributeFilter; - } else if ((value as RequestMappingData).requestType === RequestType.SERVER_SIDE_RPC) { - details = (value as RequestMappingData).requestValue.methodFilter; + const requestValue = value as RequestMappingValue; + if (requestValue.requestType === RequestType.ATTRIBUTE_UPDATE) { + details = (requestValue.requestValue as AttributeUpdate).attributeFilter; + } else if (requestValue.requestType === RequestType.SERVER_SIDE_RPC) { + details = (requestValue.requestValue as ServerSideRpc).methodFilter; } else { - details = (value as RequestMappingData).requestValue.topicFilter; + details = (requestValue.requestValue as ConnectRequest | DisconnectRequest).topicFilter; } return { - requestType: (value as RequestMappingData).requestType, - type: this.translate.instant(RequestTypesTranslationsMap.get((value as RequestMappingData).requestType)), + requestType: (value as RequestMappingValue).requestType, + type: this.translate.instant(RequestTypesTranslationsMap.get((value as RequestMappingValue).requestType)), details }; case MappingType.OPCUA: diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.ts deleted file mode 100644 index 25f8671201..0000000000 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.ts +++ /dev/null @@ -1,191 +0,0 @@ -/// -/// 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, Input, OnDestroy, TemplateRef } from '@angular/core'; -import { - ControlValueAccessor, - FormBuilder, - FormGroup, - NG_VALIDATORS, - NG_VALUE_ACCESSOR, - ValidationErrors, - Validator, -} from '@angular/forms'; -import { - MappingType, - MQTTBasicConfig, - RequestMappingData, - RequestType, -} from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { SharedModule } from '@shared/shared.module'; -import { CommonModule } from '@angular/common'; -import { takeUntil } from 'rxjs/operators'; -import { Subject } from 'rxjs'; -import { isObject } from 'lodash'; -import { - SecurityConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; -import { - WorkersConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; -import { - BrokerConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component'; -import { - MappingTableComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; -import { isDefinedAndNotNull } from '@core/utils'; - -@Component({ - selector: 'tb-mqtt-basic-config', - templateUrl: './mqtt-basic-config.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MqttBasicConfigComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => MqttBasicConfigComponent), - multi: true - } - ], - standalone: true, - imports: [ - CommonModule, - SharedModule, - SecurityConfigComponent, - WorkersConfigControlComponent, - BrokerConfigControlComponent, - MappingTableComponent, - ], - styleUrls: ['./mqtt-basic-config.component.scss'] -}) - -export class MqttBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { - - @Input() - generalTabContent: TemplateRef; - - mappingTypes = MappingType; - basicFormGroup: FormGroup; - - private onChange: (value: MQTTBasicConfig) => void; - private onTouched: () => void; - - private destroy$ = new Subject(); - - constructor(private fb: FormBuilder) { - this.basicFormGroup = this.fb.group({ - dataMapping: [], - requestsMapping: [], - broker: [], - workers: [], - }); - - this.basicFormGroup.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(value => { - this.onChange(this.getMappedMQTTConfig(value)); - this.onTouched(); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - registerOnChange(fn: (value: MQTTBasicConfig) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - writeValue(basicConfig: MQTTBasicConfig): void { - const { broker, dataMapping = [], requestsMapping } = basicConfig; - const editedBase = { - workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { - maxNumberOfWorkers: broker.maxNumberOfWorkers, - maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, - } : {}, - dataMapping: dataMapping || [], - broker: broker || {}, - requestsMapping: Array.isArray(requestsMapping) - ? requestsMapping - : this.getRequestDataArray(requestsMapping), - }; - - this.basicFormGroup.setValue(editedBase, {emitEvent: false}); - } - - private getMappedMQTTConfig(basicConfig: MQTTBasicConfig): MQTTBasicConfig { - let { broker, workers, dataMapping, requestsMapping } = basicConfig || {}; - - if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { - broker = { - ...broker, - ...workers, - }; - } - - if ((requestsMapping as RequestMappingData[])?.length) { - requestsMapping = this.getRequestDataObject(requestsMapping as RequestMappingData[]); - } - - return { broker, workers, dataMapping, requestsMapping }; - } - - validate(): ValidationErrors | null { - return this.basicFormGroup.valid ? null : { - basicFormGroup: {valid: false} - }; - } - - private getRequestDataArray(value: Record): RequestMappingData[] { - const mappingConfigs = []; - - if (isObject(value)) { - Object.keys(value).forEach((configKey: string) => { - for (const mapping of value[configKey]) { - mappingConfigs.push({ - requestType: configKey, - requestValue: mapping - }); - } - }); - } - - return mappingConfigs; - } - - private getRequestDataObject(array: RequestMappingData[]): Record { - return array.reduce((result, { requestType, requestValue }) => { - result[requestType].push(requestValue); - return result; - }, { - connectRequests: [], - disconnectRequests: [], - attributeRequests: [], - attributeUpdates: [], - serverSideRpc: [], - }); - } -} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts new file mode 100644 index 0000000000..12529d942f --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts @@ -0,0 +1,107 @@ +/// +/// 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 { ControlValueAccessor, FormBuilder, FormGroup, ValidationErrors, Validator } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { isObject } from 'lodash'; +import { + MappingType, + MQTTBasicConfig, + MQTTLegacyBasicConfig, + RequestMappingData, + RequestMappingValue, + RequestType +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { Directive, OnDestroy } from '@angular/core'; + +@Directive() +export abstract class AbstractMqttBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { + + basicFormGroup: FormGroup; + mappingTypes = MappingType; + private destroy$ = new Subject(); + private onChange: (value: MQTTBasicConfig | MQTTLegacyBasicConfig) => void; + private onTouched: () => void; + + constructor(protected fb: FormBuilder) { + this.basicFormGroup = this.fb.group({ + mapping: [], + requestsMapping: [], + broker: [], + workers: [], + }); + + this.basicFormGroup.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(value => { + this.onChange(this.getMappedMQTTConfig(value)); + this.onTouched(); + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + registerOnChange(fn: (value: MQTTBasicConfig | MQTTLegacyBasicConfig) => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + validate(): ValidationErrors | null { + return this.basicFormGroup.valid ? null : { + basicFormGroup: {valid: false} + }; + } + + protected getRequestDataArray(value: Record): RequestMappingData[] { + const mappingConfigs = []; + + if (isObject(value)) { + Object.keys(value).forEach((configKey: string) => { + for (const mapping of value[configKey]) { + mappingConfigs.push({ + requestType: configKey, + requestValue: mapping + }); + } + }); + } + + return mappingConfigs; + } + + protected getRequestDataObject(array: RequestMappingValue[]): Record { + return array.reduce((result, { requestType, requestValue }) => { + result[requestType].push(requestValue); + return result; + }, { + connectRequests: [], + disconnectRequests: [], + attributeRequests: [], + attributeUpdates: [], + serverSideRpc: [], + }); + } + + abstract writeValue(basicConfig: MQTTBasicConfig | MQTTLegacyBasicConfig): void; + protected abstract getMappedMQTTConfig(basicConfig: MQTTBasicConfig): MQTTBasicConfig | MQTTLegacyBasicConfig; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html similarity index 93% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html index 9849923218..9ad25aa851 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html @@ -24,7 +24,7 @@
- +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts new file mode 100644 index 0000000000..c4ebadb03d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts @@ -0,0 +1,107 @@ +/// +/// 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 { Component, forwardRef, Input, TemplateRef, ChangeDetectionStrategy } from '@angular/core'; +import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; +import { + MQTTBasicConfig, + RequestMappingData, + RequestMappingValue, + RequestType +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { + AbstractMqttBasicConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract'; +import { isDefinedAndNotNull } from '@core/utils'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { + SecurityConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; +import { + WorkersConfigControlComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; +import { + BrokerConfigControlComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; +import { + MappingTableComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; + +@Component({ + selector: 'tb-mqtt-basic-config', + templateUrl: './mqtt-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MqttBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => MqttBasicConfigComponent), + multi: true + } + ], + styleUrls: ['./mqtt-basic-config.component.scss'], + standalone: true, + imports: [ + CommonModule, + SharedModule, + SecurityConfigComponent, + WorkersConfigControlComponent, + BrokerConfigControlComponent, + MappingTableComponent, + ], +}) +export class MqttBasicConfigComponent extends AbstractMqttBasicConfigComponent { + + @Input() + generalTabContent: TemplateRef; + + writeValue(basicConfig: MQTTBasicConfig): void { + const { broker, mapping = [], requestsMapping } = basicConfig; + const editedBase = { + workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { + maxNumberOfWorkers: broker.maxNumberOfWorkers, + maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, + } : {}, + mapping: mapping || [], + broker: broker || {}, + requestsMapping: this.getRequestDataArray(requestsMapping as Record), + }; + + this.basicFormGroup.setValue(editedBase, {emitEvent: false}); + } + + protected getMappedMQTTConfig(basicConfig: MQTTBasicConfig): MQTTBasicConfig { + let { broker, workers, mapping, requestsMapping } = basicConfig || {}; + + if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { + broker = { + ...broker, + ...workers, + }; + } + + if ((requestsMapping as RequestMappingData[])?.length) { + requestsMapping = this.getRequestDataObject(requestsMapping as RequestMappingValue[]); + } + + return { broker, mapping, requestsMapping }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts new file mode 100644 index 0000000000..f499199739 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts @@ -0,0 +1,128 @@ +/// +/// 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 { Component, forwardRef, Input, TemplateRef, ChangeDetectionStrategy } from '@angular/core'; +import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; +import { + MQTTBasicConfig, + MQTTLegacyBasicConfig, + RequestMappingData, + RequestMappingValue, + RequestType +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { MqttVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/mqtt-version-mapping.util'; +import { + AbstractMqttBasicConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract'; +import { isDefinedAndNotNull } from '@core/utils'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { + SecurityConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; +import { + WorkersConfigControlComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; +import { + BrokerConfigControlComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; +import { + MappingTableComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; + +@Component({ + selector: 'tb-mqtt-legacy-basic-config', + templateUrl: './mqtt-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MqttLegacyBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => MqttLegacyBasicConfigComponent), + multi: true + } + ], + styleUrls: ['./mqtt-basic-config.component.scss'], + standalone: true, + imports: [ + CommonModule, + SharedModule, + SecurityConfigComponent, + WorkersConfigControlComponent, + BrokerConfigControlComponent, + MappingTableComponent, + ], +}) +export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigComponent { + + @Input() + generalTabContent: TemplateRef; + + writeValue(basicConfig: any): void { + const { + broker, + mapping = [], + connectRequests = [], + disconnectRequests = [], + attributeRequests = [], + attributeUpdates = [], + serverSideRpc = [] + } = basicConfig; + const updatedRequestMapping = MqttVersionMappingUtil.mapRequestsToNewestVersion({ + connectRequests, + disconnectRequests, + attributeRequests, + attributeUpdates, + serverSideRpc + }); + const editedBase = { + workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { + maxNumberOfWorkers: broker.maxNumberOfWorkers, + maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, + } : {}, + mapping: MqttVersionMappingUtil.mapMappingToNewestVersion(mapping) || [], + broker: broker || {}, + requestsMapping: this.getRequestDataArray(updatedRequestMapping), + }; + + this.basicFormGroup.setValue(editedBase, {emitEvent: false}); + } + + protected getMappedMQTTConfig(basicConfig: MQTTBasicConfig): MQTTLegacyBasicConfig { + let { broker, workers, mapping, requestsMapping } = basicConfig || {}; + + if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { + broker = { + ...broker, + ...workers, + }; + } + + if ((requestsMapping as RequestMappingData[])?.length) { + requestsMapping = this.getRequestDataObject(requestsMapping as RequestMappingValue[]); + } + + return { + broker, + mapping: MqttVersionMappingUtil.mapMappingToLegacyVersion(mapping), + ...(MqttVersionMappingUtil.mapRequestsToLegacyVersion(requestsMapping as Record)) + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.ts similarity index 97% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.ts index d4bfdd4694..6f0eadd55f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.ts @@ -37,7 +37,7 @@ import { TranslateService } from '@ngx-translate/core'; import { generateSecret } from '@core/utils'; import { Subject } from 'rxjs'; import { GatewayPortTooltipPipe } from '@home/components/widget/lib/gateway/pipes/gateway-port-tooltip.pipe'; -import { SecurityConfigComponent } from '../security-config/security-config.component'; +import { SecurityConfigComponent } from '../../security-config/security-config.component'; @Component({ selector: 'tb-broker-config-control', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts index 39198c9696..b6cf4a4081 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts @@ -36,12 +36,6 @@ import { Subject } from 'rxjs'; import { SecurityConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; -import { - WorkersConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; -import { - BrokerConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component'; import { MappingTableComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; @@ -70,8 +64,6 @@ import { CommonModule, SharedModule, SecurityConfigComponent, - WorkersConfigControlComponent, - BrokerConfigControlComponent, MappingTableComponent, OpcServerConfigComponent, ], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts index eca1497d22..d79a1d3fec 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts @@ -26,12 +26,13 @@ import { AddConnectorConfigData, ConnectorType, CreatedConnectorConfigData, + GatewayConnector, GatewayConnectorDefaultTypesTranslatesMap, GatewayLogLevel, - getDefaultConfig, + GatewayVersionedDefaultConfig, noLeadTrailSpacesRegex } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { Subject } from 'rxjs'; +import { Observable, Subject } from 'rxjs'; import { ResourcesService } from '@core/services/resources.service'; import { takeUntil, tap } from 'rxjs/operators'; import { helpBaseUrl } from '@shared/models/constants'; @@ -42,7 +43,8 @@ import { helpBaseUrl } from '@shared/models/constants'; styleUrls: ['./add-connector-dialog.component.scss'], providers: [], }) -export class AddConnectorDialogComponent extends DialogComponent> implements OnInit, OnDestroy { +export class AddConnectorDialogComponent + extends DialogComponent> implements OnInit, OnDestroy { connectorForm: UntypedFormGroup; @@ -95,8 +97,8 @@ export class AddConnectorDialogComponent extends DialogComponent { - value.configurationJson = defaultConfig; + this.getDefaultConfig(value.type).subscribe(({current, legacy, ...defaultConfig}: GatewayVersionedDefaultConfig) => { + value.configurationJson = (this.data.gatewayVersion ? current : legacy) ?? defaultConfig; if (this.connectorForm.valid) { this.dialogRef.close(value); } @@ -130,4 +132,8 @@ export class AddConnectorDialogComponent extends DialogComponent { + return this.resourcesService.loadJsonResource(`/assets/metadata/connector-default-configs/${type}.json`); + }; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts index 9e5a43bc17..ef8d7ed7ce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts @@ -43,15 +43,16 @@ import { MappingType, MappingTypeTranslationsMap, noLeadTrailSpacesRegex, - OPCUaSourceTypes, + OPCUaSourceType, QualityTypes, QualityTypeTranslationsMap, + RequestMappingData, RequestMappingFormValue, RequestType, RequestTypesTranslationsMap, RpcMethod, ServerSideRPCType, - SourceTypes, + SourceType, SourceTypeTranslationsMap, Timeseries } from '@home/components/widget/lib/gateway/gateway-widget.models'; @@ -82,10 +83,10 @@ export class MappingDialogComponent extends DialogComponent; - OPCUaSourceTypesEnum = OPCUaSourceTypes; - sourceTypesEnum = SourceTypes; + sourceTypes: SourceType[] = Object.values(SourceType); + OPCUaSourceTypes = Object.values(OPCUaSourceType) as Array; + OPCUaSourceTypesEnum = OPCUaSourceType; + sourceTypesEnum = SourceType; SourceTypeTranslationsMap = SourceTypeTranslationsMap; requestTypes: RequestType[] = Object.values(RequestType); @@ -230,8 +231,8 @@ export class MappingDialogComponent extends DialogComponent + }; default: return this.data.value as DeviceConnectorMapping; } @@ -349,10 +350,10 @@ export class MappingDialogComponent extends DialogComponent {{ initialConnector?.type ? GatewayConnectorTypesTranslatesMap.get(initialConnector.type) : '' }} {{ 'gateway.configuration' | translate }} + v{{connectorForm.get('configVersion').value}} @@ -175,10 +176,16 @@
- - + + + + + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss index f151887c92..5d8c6aad5b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss @@ -22,6 +22,11 @@ overflow-x: auto; padding: 0; + .version-placeholder { + color: gray; + font-size: 12px + } + .connector-container { height: 100%; width: 100%; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index e7e4d05e45..0da917312b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -65,6 +65,7 @@ import { AddConnectorDialogComponent } from '@home/components/widget/lib/gateway import { debounceTime, filter, switchMap, take, takeUntil, tap } from 'rxjs/operators'; import { ErrorStateMatcher } from '@angular/material/core'; import { PageData } from '@shared/models/page/page-data'; +import { GatewayConnectorVersionMappingUtil } from './utils/gateway-connector-version-mapping.util'; export class ForceErrorStateMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null): boolean { @@ -106,6 +107,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie mode: ConnectorConfigurationModes = this.ConnectorConfigurationModes.BASIC; initialConnector: GatewayConnector; + private gatewayVersion: string; private inactiveConnectors: Array; private attributeDataSource: AttributeDatasource; private inactiveConnectorsDataSource: AttributeDatasource; @@ -241,9 +243,13 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie delete value.class; } + if (this.gatewayVersion && !value.configVersion) { + value.configVersion = this.gatewayVersion; + } + value.ts = Date.now(); - return value; + return GatewayConnectorVersionMappingUtil.getMappedByVersion(value, this.gatewayVersion); } private updateData(reload: boolean = false): void { @@ -265,7 +271,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie }); } - isConnectorSynced(attribute: GatewayAttributeData) { + isConnectorSynced(attribute: GatewayAttributeData): boolean { const connectorData = attribute.value; if (!connectorData.ts || attribute.skipSync) { return false; @@ -342,7 +348,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie class: '', configuration: '', configurationJson: {}, - basicConfig: {} + basicConfig: {}, + configVersion: '' }, {emitEvent: false}); this.connectorForm.markAsPristine(); } @@ -475,7 +482,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie value.configurationJson = {} as ConnectorBaseConfig; } value.basicConfig = value.configurationJson; - this.updateConnector(value); + this.updateConnector({...value, configVersion: this.gatewayVersion ?? ''}); this.generate('basicConfig.broker.clientId'); setTimeout(() => this.saveConnector()); }); @@ -485,7 +492,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie return this.dialog.open(AddConnectorDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], - data: { dataSourceData: this.dataSource.data } + data: { + dataSourceData: this.dataSource.data, + gatewayVersion: this.gatewayVersion, + } }).afterClosed(); } @@ -528,7 +538,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie class: [''], configuration: [''], configurationJson: [{}, [Validators.required]], - basicConfig: [{}] + basicConfig: [{}], + configVersion: [''], }); this.connectorForm.disable(); } @@ -571,10 +582,12 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie forkJoin([ this.attributeService.getEntityAttributes(this.device, AttributeScope.SHARED_SCOPE, ['active_connectors']), - this.attributeService.getEntityAttributes(this.device, AttributeScope.SERVER_SCOPE, ['inactive_connectors']) + this.attributeService.getEntityAttributes(this.device, AttributeScope.SERVER_SCOPE, ['inactive_connectors']), + this.attributeService.getEntityAttributes(this.device, AttributeScope.CLIENT_SCOPE, ['Version']) ]).pipe(takeUntil(this.destroy$)).subscribe(attributes => { this.activeConnectors = this.parseConnectors(attributes[0]); this.inactiveConnectors = this.parseConnectors(attributes[1]); + this.gatewayVersion = attributes[2][0]?.value; this.updateData(true); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index 2dde0b8f54..64cdc8e39b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -14,8 +14,6 @@ /// limitations under the License. /// -import { ResourcesService } from '@core/services/resources.service'; -import { Observable } from 'rxjs'; import { helpBaseUrl, ValueTypeData } from '@shared/models/constants'; import { AttributeData } from '@shared/models/telemetry/telemetry.models'; @@ -114,21 +112,37 @@ export interface GatewayAttributeData extends AttributeData { skipSync?: boolean; } -export interface GatewayConnector { +export interface GatewayConnectorBase { name: string; type: ConnectorType; configuration?: string; - configurationJson: ConnectorBaseConfig; - basicConfig?: ConnectorBaseConfig; logLevel: string; key?: string; class?: string; mode?: ConnectorConfigurationModes; + configVersion?: string; +} + +export type GatewayConnector = CurrentGatewayConnector | LegacyGatewayConnector; + +export interface CurrentGatewayConnector extends GatewayConnectorBase { + configurationJson: ConnectorBaseConfig; + basicConfig?: ConnectorBaseConfig; +} + +export interface LegacyGatewayConnector extends GatewayConnectorBase { + configurationJson: ConnectorLegacyBaseConfig; + basicConfig?: ConnectorLegacyBaseConfig; +} + +export interface GatewayVersionedDefaultConfig { + legacy: LegacyGatewayConnector; + current: GatewayConnector; } export interface DataMapping { topicFilter: string; - QoS: string; + QoS: string | number; converter: Converter; } @@ -180,12 +194,14 @@ export interface ConnectorSecurity { mode?: ModeType; } -export type ConnectorMapping = DeviceConnectorMapping | RequestMappingData | ConverterConnectorMapping; +export type ConnectorMapping = DeviceConnectorMapping | RequestMappingValue | ConverterConnectorMapping; export type ConnectorMappingFormValue = DeviceConnectorMapping | RequestMappingFormValue | ConverterMappingFormValue; export type ConnectorBaseConfig = ConnectorBaseInfo | MQTTBasicConfig | OPCBasicConfig | ModbusBasicConfig; +export type ConnectorLegacyBaseConfig = ConnectorBaseInfo | MQTTLegacyBasicConfig; + export interface ConnectorBaseInfo { name: string; id: string; @@ -194,10 +210,21 @@ export interface ConnectorBaseInfo { } export interface MQTTBasicConfig { - dataMapping: ConverterConnectorMapping[]; - requestsMapping: Record | RequestMappingData[]; + mapping: ConverterConnectorMapping[]; + requestsMapping: Record | RequestMappingData[] | RequestMappingValue[]; + broker: BrokerConfig; + workers?: WorkersConfig; +} + +export interface MQTTLegacyBasicConfig { + mapping: LegacyConverterConnectorMapping[]; broker: BrokerConfig; workers?: WorkersConfig; + connectRequests: LegacyRequestMappingData[]; + disconnectRequests: LegacyRequestMappingData[]; + attributeRequests: LegacyRequestMappingData[]; + attributeUpdates: LegacyRequestMappingData[]; + serverSideRpc: LegacyRequestMappingData[]; } export interface OPCBasicConfig { @@ -215,11 +242,11 @@ export interface WorkersConfig { maxMessageNumberPerWorker: number; } -interface DeviceInfo { +export interface ConnectorDeviceInfo { deviceNameExpression: string; - deviceNameExpressionSource: string; + deviceNameExpressionSource: SourceType; deviceProfileExpression: string; - deviceProfileExpressionSource: string; + deviceProfileExpressionSource: SourceType; } export interface Attribute { @@ -252,20 +279,41 @@ export interface AttributesUpdate { export interface Converter { type: ConvertorType; - deviceNameJsonExpression: string; - deviceTypeJsonExpression: string; + deviceInfo?: ConnectorDeviceInfo; sendDataOnlyOnChange: boolean; timeout: number; - attributes: Attribute[]; - timeseries: Timeseries[]; + attributes?: Attribute[]; + timeseries?: Timeseries[]; + extension?: string; + cached?: boolean; + extensionConfig?: Record; +} + +export interface LegacyConverter extends Converter { + deviceNameJsonExpression?: string; + deviceTypeJsonExpression?: string; + deviceNameTopicExpression?: string; + deviceTypeTopicExpression?: string; + deviceNameExpression?: string; + deviceNameExpressionSource?: string; + deviceTypeExpression?: string; + deviceProfileExpression?: string; + deviceProfileExpressionSource?: string; + ['extension-config']?: Record; } export interface ConverterConnectorMapping { topicFilter: string; - subscriptionQos?: string; + subscriptionQos?: string | number; converter: Converter; } +export interface LegacyConverterConnectorMapping { + topicFilter: string; + subscriptionQos?: string | number; + converter: LegacyConverter; +} + export type ConverterMappingFormValue = Omit & { converter: { type: ConvertorType; @@ -274,8 +322,8 @@ export type ConverterMappingFormValue = Omit; + gatewayVersion: string; } export interface CreatedConnectorConfigData { @@ -590,13 +639,13 @@ export const ConvertorTypeTranslationsMap = new Map( ] ); -export enum SourceTypes { +export enum SourceType { MSG = 'message', TOPIC = 'topic', CONST = 'constant' } -export enum OPCUaSourceTypes { +export enum OPCUaSourceType { PATH = 'path', IDENTIFIER = 'identifier', CONST = 'constant' @@ -607,33 +656,116 @@ export enum DeviceInfoType { PARTIAL = 'partial' } -export const SourceTypeTranslationsMap = new Map( +export const SourceTypeTranslationsMap = new Map( [ - [SourceTypes.MSG, 'gateway.source-type.msg'], - [SourceTypes.TOPIC, 'gateway.source-type.topic'], - [SourceTypes.CONST, 'gateway.source-type.const'], - [OPCUaSourceTypes.PATH, 'gateway.source-type.path'], - [OPCUaSourceTypes.IDENTIFIER, 'gateway.source-type.identifier'], - [OPCUaSourceTypes.CONST, 'gateway.source-type.const'] + [SourceType.MSG, 'gateway.source-type.msg'], + [SourceType.TOPIC, 'gateway.source-type.topic'], + [SourceType.CONST, 'gateway.source-type.const'], + [OPCUaSourceType.PATH, 'gateway.source-type.path'], + [OPCUaSourceType.IDENTIFIER, 'gateway.source-type.identifier'], + [OPCUaSourceType.CONST, 'gateway.source-type.const'] ] ); -export interface RequestMappingData { +export interface RequestMappingValue { requestType: RequestType; - requestValue: RequestDataItem; + requestValue: RequestMappingData; } -export type RequestMappingFormValue = Omit & { - requestValue: Record; -}; - -export interface RequestDataItem { - type: string; - details: string; +export interface RequestMappingFormValue { requestType: RequestType; - methodFilter?: string; - attributeFilter?: string; - topicFilter?: string; + requestValue: Record; +} + +export type RequestMappingData = ConnectRequest | DisconnectRequest | AttributeRequest | AttributeUpdate | ServerSideRpc; + +export type LegacyRequestMappingData = + LegacyConnectRequest + | LegacyDisconnectRequest + | LegacyAttributeRequest + | LegacyAttributeUpdate + | LegacyServerSideRpc; + +export interface ConnectRequest { + topicFilter: string; + deviceInfo: ConnectorDeviceInfo; +} + +export interface DisconnectRequest { + topicFilter: string; + deviceInfo: ConnectorDeviceInfo; +} + +export interface AttributeRequest { + retain: boolean; + topicFilter: string; + deviceInfo: ConnectorDeviceInfo; + attributeNameExpressionSource: SourceType; + attributeNameExpression: string; + topicExpression: string; + valueExpression: string; +} + +export interface AttributeUpdate { + retain: boolean; + deviceNameFilter: string; + attributeFilter: string; + topicExpression: string; + valueExpression: string; +} + +export interface ServerSideRpc { + type: ServerSideRpcType; + deviceNameFilter: string; + methodFilter: string; + requestTopicExpression: string; + responseTopicExpression?: string; + responseTopicQoS?: number; + responseTimeout?: number; + valueExpression: string; +} + +export enum ServerSideRpcType { + WithResponse = 'twoWay', + WithoutResponse = 'oneWay' +} + +export interface LegacyConnectRequest { + topicFilter: string; + deviceNameJsonExpression?: string; + deviceNameTopicExpression?: string; +} + +interface LegacyDisconnectRequest { + topicFilter: string; + deviceNameJsonExpression?: string; + deviceNameTopicExpression?: string; +} + +interface LegacyAttributeRequest { + retain: boolean; + topicFilter: string; + deviceNameJsonExpression: string; + attributeNameJsonExpression: string; + topicExpression: string; + valueExpression: string; +} + +interface LegacyAttributeUpdate { + retain: boolean; + deviceNameFilter: string; + attributeFilter: string; + topicExpression: string; + valueExpression: string; +} + +interface LegacyServerSideRpc { + deviceNameFilter: string; + methodFilter: string; + requestTopicExpression: string; + responseTopicExpression?: string; + responseTimeout?: number; + valueExpression: string; } export enum RequestType { @@ -707,9 +839,6 @@ export enum ServerSideRPCType { TWO_WAY = 'twoWay' } -export const getDefaultConfig = (resourcesService: ResourcesService, type: string): Observable => - resourcesService.loadJsonResource(`/assets/metadata/connector-default-configs/${type}.json`); - export enum MappingValueType { STRING = 'string', INTEGER = 'integer', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/gateway-help-link.pipe.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/gateway-help-link.pipe.ts index 0fec377860..06526ce08e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/gateway-help-link.pipe.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/gateway-help-link.pipe.ts @@ -17,8 +17,8 @@ import { Pipe, PipeTransform } from '@angular/core'; import { MappingValueType, - OPCUaSourceTypes, - SourceTypes + OPCUaSourceType, + SourceType } from '@home/components/widget/lib/gateway/gateway-widget.models'; @Pipe({ @@ -26,9 +26,9 @@ import { standalone: true, }) export class GatewayHelpLinkPipe implements PipeTransform { - transform(field: string, sourceType: SourceTypes | OPCUaSourceTypes, sourceTypes?: Array ): string { - if (!sourceTypes || sourceTypes?.includes(OPCUaSourceTypes.PATH)) { - if (sourceType !== OPCUaSourceTypes.CONST) { + transform(field: string, sourceType: SourceType | OPCUaSourceType, sourceTypes?: Array ): string { + if (!sourceTypes || sourceTypes?.includes(OPCUaSourceType.PATH)) { + if (sourceType !== OPCUaSourceType.CONST) { return `widget/lib/gateway/${field}-${sourceType}_fn`; } else { return; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts new file mode 100644 index 0000000000..6a48b5e64b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts @@ -0,0 +1,66 @@ +/// +/// 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 { + ConnectorType, + GatewayConnector, + LegacyGatewayConnector, +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { MqttVersionMappingUtil } from './mqtt-version-mapping.util'; + +export class GatewayConnectorVersionMappingUtil { + + static getMappedByVersion(connector: GatewayConnector, gatewayVersion: string): GatewayConnector { + switch (connector.type) { + case ConnectorType.MQTT: + return this.getMappedMQTTByVersion(connector, gatewayVersion); + default: + return connector; + } + } + + private static getMappedMQTTByVersion( + connector: GatewayConnector | LegacyGatewayConnector, + gatewayVersion: string + ): GatewayConnector | LegacyGatewayConnector { + if (this.isVersionUpdateNeeded(gatewayVersion, connector.configVersion)) { + return this.isGatewayOutdated(gatewayVersion, connector.configVersion) + ? MqttVersionMappingUtil.getLegacyVersion(connector) + : MqttVersionMappingUtil.getNewestVersion(connector); + } + return connector; + } + + private static isGatewayOutdated(gatewayVersion: string, configVersion: string): boolean { + if (!gatewayVersion || !configVersion) { + return false; + } + + return this.parseVersion(configVersion) > this.parseVersion(gatewayVersion); + } + + private static isVersionUpdateNeeded(configVersion: string, gatewayVersion: string): boolean { + if (!gatewayVersion || !configVersion) { + return false; + } + + return this.parseVersion(configVersion) !== this.parseVersion(gatewayVersion); + } + + private static parseVersion(version: string): number { + return Number(version?.replace(/\./g, '')); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts new file mode 100644 index 0000000000..e32d020730 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts @@ -0,0 +1,279 @@ +/// +/// 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 { deleteNullProperties, isEqual } from '@core/utils'; +import { + AttributeRequest, + ConnectorDeviceInfo, + Converter, + ConverterConnectorMapping, + ConvertorType, + CurrentGatewayConnector, + GatewayConnector, + LegacyConverter, + LegacyConverterConnectorMapping, + LegacyGatewayConnector, + LegacyRequestMappingData, + MQTTBasicConfig, + MQTTLegacyBasicConfig, + RequestMappingData, + RequestType, + ServerSideRpc, + ServerSideRpcType, + SourceType +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +export class MqttVersionMappingUtil { + + static readonly mqttRequestTypeKeys = Object.values(RequestType); + static readonly mqttRequestMappingOldFields = + ['attributeNameJsonExpression', 'deviceNameJsonExpression', 'deviceNameTopicExpression', 'extension-config']; + static readonly mqttRequestMappingNewFields = + ['attributeNameExpressionSource', 'responseTopicQoS', 'extensionConfig']; + + static getNewestVersion(mqttConnector: GatewayConnector): CurrentGatewayConnector { + const { + connectRequests, + disconnectRequests, + attributeRequests, + attributeUpdates, + serverSideRpc + } = mqttConnector.configurationJson as MQTTLegacyBasicConfig; + let configurationJson = { + ...mqttConnector.configurationJson, + requestsMapping: this.mapRequestsToNewestVersion({ + connectRequests, + disconnectRequests, + attributeRequests, + attributeUpdates, + serverSideRpc + }), + mapping: this.mapMappingToNewestVersion((mqttConnector.configurationJson as MQTTLegacyBasicConfig).mapping), + }; + + this.mqttRequestTypeKeys.forEach((key: RequestType) => { + const { [key]: removedKey, ...rest } = configurationJson as MQTTLegacyBasicConfig; + configurationJson = { ...rest } as any; + }); + + this.cleanUpConfigJson(configurationJson as MQTTBasicConfig); + + return { + ...mqttConnector, + configurationJson + } as CurrentGatewayConnector; + } + + static getLegacyVersion(mqttConnector: GatewayConnector): LegacyGatewayConnector { + const { requestsMapping, mapping, ...restConfig } = mqttConnector.configurationJson as MQTTBasicConfig; + + const updatedRequestsMapping = this.mapRequestsToLegacyVersion(requestsMapping as Record); + const updatedMapping = this.mapMappingToLegacyVersion(mapping); + + return { + ...mqttConnector, + configurationJson: { + ...restConfig, + ...updatedRequestsMapping, + mapping: updatedMapping, + }, + } as LegacyGatewayConnector; + } + + static mapMappingToNewestVersion(mapping: LegacyConverterConnectorMapping[] | ConverterConnectorMapping[]): ConverterConnectorMapping[] { + return mapping?.map(({ converter, topicFilter, subscriptionQos = 1 }) => { + const deviceInfo = converter.deviceInfo ?? this.extractConverterDeviceInfo(converter); + + const newConverter = { + ...converter, + deviceInfo, + extensionConfig: converter.extensionConfig || converter['extension-config'] || null + }; + + this.cleanUpOldFields(newConverter); + + return { converter: newConverter, topicFilter, subscriptionQos }; + }); + } + + static mapRequestsToNewestVersion( + requestMapping: Record + ): Record { + return this.mqttRequestTypeKeys.reduce((acc, key: RequestType) => { + if (!requestMapping[key]) { + return acc; + } + + acc[key] = requestMapping[key].map(value => { + const newValue = this.mapRequestToNewest(value as LegacyRequestMappingData, key); + + this.cleanUpOldFields(newValue as {}); + + return newValue; + }); + + return acc; + }, {}) as Record; + } + + static mapRequestsToLegacyVersion( + requestsMapping: Record + ): Record { + return this.mqttRequestTypeKeys.reduce((acc, key) => { + if (!requestsMapping[key]) { + return acc; + } + + acc[key] = requestsMapping[key].map((value: RequestMappingData) => { + if (key === RequestType.SERVER_SIDE_RPC) { + delete (value as ServerSideRpc).type; + } + + const { attributeNameExpression, deviceInfo, ...rest } = value as AttributeRequest; + + const newValue = { + ...rest, + attributeNameJsonExpression: attributeNameExpression || null, + deviceNameJsonExpression: deviceInfo?.deviceNameExpressionSource !== SourceType.TOPIC ? deviceInfo?.deviceNameExpression : null, + deviceNameTopicExpression: deviceInfo?.deviceNameExpressionSource === SourceType.TOPIC ? deviceInfo?.deviceNameExpression : null, + }; + + this.cleanUpNewFields(newValue); + + return newValue; + }); + + return acc; + }, {}) as Record; + } + + static mapMappingToLegacyVersion( + mapping: ConverterConnectorMapping[] + ): LegacyConverterConnectorMapping[] { + return mapping?.map((converterMapping: ConverterConnectorMapping) => { + const converter = this.mapConverterToLegacy(converterMapping.converter); + + this.cleanUpNewFields(converter as {}); + + return { converter, topicFilter: converterMapping.topicFilter }; + }); + } + + private static mapConverterToLegacy(converter: Converter): LegacyConverter { + const { deviceInfo, ...restConverter } = converter; + + return converter.type !== ConvertorType.BYTES ? { + ...restConverter, + deviceNameJsonExpression: deviceInfo?.deviceNameExpressionSource === SourceType.MSG ? deviceInfo.deviceNameExpression : null, + deviceTypeJsonExpression: + deviceInfo?.deviceProfileExpressionSource === SourceType.MSG ? deviceInfo.deviceProfileExpression : null, + deviceNameTopicExpression: + deviceInfo?.deviceNameExpressionSource !== SourceType.MSG + ? deviceInfo?.deviceNameExpression + : null, + deviceTypeTopicExpression: deviceInfo?.deviceProfileExpressionSource !== SourceType.MSG + ? deviceInfo?.deviceProfileExpression + : null, + } : { + ...restConverter, + deviceNameExpression: deviceInfo.deviceNameExpression, + deviceTypeExpression: deviceInfo.deviceProfileExpression, + ['extension-config']: converter.extensionConfig, + }; + } + + private static cleanUpOldFields(obj: Record): void { + this.mqttRequestMappingOldFields.forEach(field => delete obj[field]); + deleteNullProperties(obj); + } + + private static cleanUpNewFields(obj: Record): void { + this.mqttRequestMappingNewFields.forEach(field => delete obj[field]); + deleteNullProperties(obj); + } + + private static getTypeSourceByValue(value: string): SourceType { + if (value.includes('${')) { + return SourceType.MSG; + } + if (value.includes(`/`)) { + return SourceType.TOPIC; + } + return SourceType.CONST; + } + + private static cleanUpConfigJson(configurationJson: MQTTBasicConfig): void { + if (isEqual(configurationJson.requestsMapping, {})) { + delete configurationJson.requestsMapping; + } + + if (isEqual(configurationJson.mapping, [])) { + delete configurationJson.mapping; + } + } + + private static extractConverterDeviceInfo(converter: LegacyConverter): ConnectorDeviceInfo { + const deviceNameExpression = converter.deviceNameExpression + || converter.deviceNameJsonExpression + || converter.deviceNameTopicExpression + || null; + const deviceNameExpressionSource = converter.deviceNameExpressionSource + ? converter.deviceNameExpressionSource as SourceType + : deviceNameExpression ? this.getTypeSourceByValue(deviceNameExpression) : null; + const deviceProfileExpression = converter.deviceProfileExpression + || converter.deviceTypeTopicExpression + || converter.deviceTypeJsonExpression + || 'default'; + const deviceProfileExpressionSource = converter.deviceProfileExpressionSource + ? converter.deviceProfileExpressionSource as SourceType + : deviceProfileExpression ? this.getTypeSourceByValue(deviceProfileExpression) : null; + + return deviceNameExpression || deviceProfileExpression ? { + deviceNameExpression, + deviceNameExpressionSource, + deviceProfileExpression, + deviceProfileExpressionSource + } : null; + } + + private static mapRequestToNewest(value, key: RequestType): RequestMappingData { + const deviceNameExpression = value.deviceNameJsonExpression || value.deviceNameTopicExpression || null; + const deviceProfileExpression = value.deviceTypeTopicExpression || value.deviceTypeJsonExpression || 'default'; + const deviceProfileExpressionSource = deviceProfileExpression ? this.getTypeSourceByValue(deviceProfileExpression) : null; + const attributeNameExpression = value.attributeNameExpressionSource || value.attributeNameJsonExpression || null; + const responseTopicQoS = key === RequestType.SERVER_SIDE_RPC ? 1 : null; + const type = key === RequestType.SERVER_SIDE_RPC + ? (value as ServerSideRpc).responseTopicExpression + ? ServerSideRpcType.WithResponse + : ServerSideRpcType.WithoutResponse + : null; + + return { + ...value, + attributeNameExpression, + attributeNameExpressionSource: attributeNameExpression ? this.getTypeSourceByValue(attributeNameExpression) : null, + deviceInfo: value.deviceInfo ? value.deviceInfo : deviceNameExpression ? { + deviceNameExpression, + deviceNameExpressionSource: this.getTypeSourceByValue(deviceNameExpression), + deviceProfileExpression, + deviceProfileExpressionSource + } : null, + responseTopicQoS, + type + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts index 955fd1ecf6..f5f6614962 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts @@ -113,7 +113,7 @@ import { GatewayHelpLinkPipe } from '@home/components/widget/lib/gateway/pipes/g import { EllipsisChipListDirective } from '@shared/directives/ellipsis-chip-list.directive'; import { BrokerConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; import { WorkersConfigControlComponent } from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; @@ -122,7 +122,7 @@ import { } from '@home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component'; import { MqttBasicConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component'; import { MappingTableComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; @@ -145,6 +145,9 @@ import { ModbusRpcParametersComponent } from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component'; import { ScadaSymbolWidgetComponent } from '@home/components/widget/lib/scada/scada-symbol-widget.component'; +import { + MqttLegacyBasicConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component'; @NgModule({ declarations: [ @@ -233,6 +236,7 @@ import { ScadaSymbolWidgetComponent } from '@home/components/widget/lib/scada/sc ModbusBasicConfigComponent, EllipsisChipListDirective, ModbusRpcParametersComponent, + MqttLegacyBasicConfigComponent, ], exports: [ EntitiesTableWidgetComponent, diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json b/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json index c60e1dd956..17ddbd1285 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json @@ -1,218 +1,399 @@ { - "broker": { - "name": "Default Local Broker", - "host": "127.0.0.1", - "port": 1883, - "clientId": "ThingsBoard_gateway", - "version": 5, - "maxMessageNumberPerWorker": 10, - "maxNumberOfWorkers": 100, - "sendDataOnlyOnChange": false, - "security": { - "type": "anonymous" - } - }, - "dataMapping": [ - { - "topicFilter": "sensor/data", - "subscriptionQos": 1, - "converter": { - "type": "json", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "${serialNumber}", - "deviceProfileExpressionSource": "message", - "deviceProfileExpression": "${sensorType}" + "current": { + "broker": { + "name": "Default Local Broker", + "host": "127.0.0.1", + "port": 1883, + "clientId": "ThingsBoard_gateway", + "version": 5, + "maxMessageNumberPerWorker": 10, + "maxNumberOfWorkers": 100, + "sendDataOnlyOnChange": false, + "security": { + "type": "anonymous" + } }, - "sendDataOnlyOnChange": false, - "timeout": 60000, - "attributes": [ - { - "type": "string", - "key": "model", - "value": "${sensorModel}" - }, - { - "type": "string", - "key": "${sensorModel}", - "value": "on" - } + "mapping": [ + { + "topicFilter": "sensor/data", + "subscriptionQos": 1, + "converter": { + "type": "json", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "${serialNumber}", + "deviceProfileExpressionSource": "message", + "deviceProfileExpression": "${sensorType}" + }, + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "string", + "key": "model", + "value": "${sensorModel}" + }, + { + "type": "string", + "key": "${sensorModel}", + "value": "on" + } + ], + "timeseries": [ + { + "type": "string", + "key": "temperature", + "value": "${temp}" + }, + { + "type": "double", + "key": "humidity", + "value": "${hum}" + }, + { + "type": "string", + "key": "combine", + "value": "${hum}:${temp}" + } + ] + } + }, + { + "topicFilter": "sensor/+/data", + "subscriptionQos": 1, + "converter": { + "type": "json", + "deviceInfo": { + "deviceNameExpressionSource": "topic", + "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/data)", + "deviceProfileExpressionSource": "constant", + "deviceProfileExpression": "Thermometer" + }, + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "string", + "key": "model", + "value": "${sensorModel}" + } + ], + "timeseries": [ + { + "type": "double", + "key": "temperature", + "value": "${temp}" + }, + { + "type": "string", + "key": "humidity", + "value": "${hum}" + } + ] + } + }, + { + "topicFilter": "sensor/raw_data", + "subscriptionQos": 1, + "converter": { + "type": "bytes", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "[0:4]", + "deviceProfileExpressionSource": "constant", + "deviceProfileExpression": "default" + }, + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "raw", + "key": "rawData", + "value": "[:]" + } + ], + "timeseries": [ + { + "type": "raw", + "key": "temp", + "value": "[4:]" + } + ] + } + }, + { + "topicFilter": "custom/sensors/+", + "subscriptionQos": 1, + "converter": { + "type": "custom", + "extension": "CustomMqttUplinkConverter", + "cached": true, + "extensionConfig": { + "temperature": 2, + "humidity": 2, + "batteryLevel": 1 + } + } + } ], - "timeseries": [ - { - "type": "string", - "key": "temperature", - "value": "${temp}" - }, - { - "type": "double", - "key": "humidity", - "value": "${hum}" - }, - { - "type": "string", - "key": "combine", - "value": "${hum}:${temp}" - } - ] - } + "requestsMapping": { + "connectRequests": [ + { + "topicFilter": "sensor/connect", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "${serialNumber}", + "deviceProfileExpressionSource": "constant", + "deviceProfileExpression": "Thermometer" + } + }, + { + "topicFilter": "sensor/+/connect", + "deviceInfo": { + "deviceNameExpressionSource": "topic", + "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/connect)", + "deviceProfileExpressionSource": "constant", + "deviceProfileExpression": "Thermometer" + } + } + ], + "disconnectRequests": [ + { + "topicFilter": "sensor/disconnect", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "${serialNumber}" + } + }, + { + "topicFilter": "sensor/+/disconnect", + "deviceInfo": { + "deviceNameExpressionSource": "topic", + "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/connect)" + } + } + ], + "attributeRequests": [ + { + "retain": false, + "topicFilter": "v1/devices/me/attributes/request", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "${serialNumber}" + }, + "attributeNameExpressionSource": "message", + "attributeNameExpression": "${versionAttribute}, ${pduAttribute}", + "topicExpression": "devices/${deviceName}/attrs", + "valueExpression": "${attributeKey}: ${attributeValue}" + } + ], + "attributeUpdates": [ + { + "retain": true, + "deviceNameFilter": ".*", + "attributeFilter": "firmwareVersion", + "topicExpression": "sensor/${deviceName}/${attributeKey}", + "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}" + } + ], + "serverSideRpc": [ + { + "type": "twoWay", + "deviceNameFilter": ".*", + "methodFilter": "echo", + "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", + "responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}", + "responseTopicQoS": 1, + "responseTimeout": 10000, + "valueExpression": "${params}" + }, + { + "type": "oneWay", + "deviceNameFilter": ".*", + "methodFilter": "no-reply", + "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", + "valueExpression": "${params}" + } + ] + } }, - { - "topicFilter": "sensor/+/data", - "subscriptionQos": 1, - "converter": { - "type": "json", - "deviceInfo": { - "deviceNameExpressionSource": "topic", - "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/data)", - "deviceProfileExpressionSource": "constant", - "deviceProfileExpression": "Thermometer" + "legacy": { + "broker": { + "name": "Default Local Broker", + "host": "127.0.0.1", + "port": 1883, + "clientId": "ThingsBoard_gateway", + "version": 5, + "maxMessageNumberPerWorker": 10, + "maxNumberOfWorkers": 100, + "sendDataOnlyOnChange": false, + "security": { + "type": "basic", + "username": "user", + "password": "password" + } }, - "sendDataOnlyOnChange": false, - "timeout": 60000, - "attributes": [ - { - "type": "string", - "key": "model", - "value": "${sensorModel}" - } + "mapping": [ + { + "topicFilter": "sensor/data", + "converter": { + "type": "json", + "deviceNameJsonExpression": "${serialNumber}", + "deviceTypeJsonExpression": "${sensorType}", + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "string", + "key": "model", + "value": "${sensorModel}" + }, + { + "type": "string", + "key": "${sensorModel}", + "value": "on" + } + ], + "timeseries": [ + { + "type": "double", + "key": "temperature", + "value": "${temp}" + }, + { + "type": "double", + "key": "humidity", + "value": "${hum}" + }, + { + "type": "string", + "key": "combine", + "value": "${hum}:${temp}" + } + ] + } + }, + { + "topicFilter": "sensor/+/data", + "converter": { + "type": "json", + "deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/data)", + "deviceTypeTopicExpression": "Thermometer", + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "string", + "key": "model", + "value": "${sensorModel}" + } + ], + "timeseries": [ + { + "type": "double", + "key": "temperature", + "value": "${temp}" + }, + { + "type": "double", + "key": "humidity", + "value": "${hum}" + } + ] + } + }, + { + "topicFilter": "sensor/raw_data", + "converter": { + "type": "bytes", + "deviceNameExpression": "[0:4]", + "deviceTypeExpression": "default", + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "raw", + "key": "rawData", + "value": "[:]" + } + ], + "timeseries": [ + { + "type": "raw", + "key": "temp", + "value": "[4:]" + } + ] + } + }, + { + "topicFilter": "custom/sensors/+", + "converter": { + "type": "custom", + "extension": "CustomMqttUplinkConverter", + "cached": true, + "extension-config": { + "temperatureBytes": 2, + "humidityBytes": 2, + "batteryLevelBytes": 1 + } + } + } ], - "timeseries": [ - { - "type": "double", - "key": "temperature", - "value": "${temp}" - }, - { - "type": "string", - "key": "humidity", - "value": "${hum}" - } - ] - } - }, - { - "topicFilter": "sensor/raw_data", - "subscriptionQos": 1, - "converter": { - "type": "bytes", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "[0:4]", - "deviceProfileExpressionSource": "constant", - "deviceProfileExpression": "default" - }, - "sendDataOnlyOnChange": false, - "timeout": 60000, - "attributes": [ - { - "type": "raw", - "key": "rawData", - "value": "[:]" - } + "connectRequests": [ + { + "topicFilter": "sensor/connect", + "deviceNameJsonExpression": "${serialNumber}" + }, + { + "topicFilter": "sensor/+/connect", + "deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/connect)" + } + ], + "disconnectRequests": [ + { + "topicFilter": "sensor/disconnect", + "deviceNameJsonExpression": "${serialNumber}" + }, + { + "topicFilter": "sensor/+/disconnect", + "deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/disconnect)" + } + ], + "attributeRequests": [ + { + "retain": false, + "topicFilter": "v1/devices/me/attributes/request", + "deviceNameJsonExpression": "${serialNumber}", + "attributeNameJsonExpression": "${versionAttribute}, ${pduAttribute}", + "topicExpression": "devices/${deviceName}/attrs", + "valueExpression": "${attributeKey}: ${attributeValue}" + } ], - "timeseries": [ - { - "type": "raw", - "key": "temp", - "value": "[4:]" - } + "attributeUpdates": [ + { + "retain": true, + "deviceNameFilter": ".*", + "attributeFilter": "firmwareVersion", + "topicExpression": "sensor/${deviceName}/${attributeKey}", + "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}" + } + ], + "serverSideRpc": [ + { + "deviceNameFilter": ".*", + "methodFilter": "echo", + "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", + "responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}", + "responseTimeout": 10000, + "valueExpression": "${params}" + }, + { + "deviceNameFilter": ".*", + "methodFilter": "no-reply", + "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", + "valueExpression": "${params}" + } ] - } - }, - { - "topicFilter": "custom/sensors/+", - "subscriptionQos": 1, - "converter": { - "type": "custom", - "extension": "CustomMqttUplinkConverter", - "cached": true, - "extensionConfig": { - "temperature": 2, - "humidity": 2, - "batteryLevel": 1 - } - } - } - ], - "requestsMapping": { - "connectRequests": [ - { - "topicFilter": "sensor/connect", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "${serialNumber}", - "deviceProfileExpressionSource": "constant", - "deviceProfileExpression": "Thermometer" - } - }, - { - "topicFilter": "sensor/+/connect", - "deviceInfo": { - "deviceNameExpressionSource": "topic", - "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/connect)", - "deviceProfileExpressionSource": "constant", - "deviceProfileExpression": "Thermometer" - } - } - ], - "disconnectRequests": [ - { - "topicFilter": "sensor/disconnect", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "${serialNumber}" - } - }, - { - "topicFilter": "sensor/+/disconnect", - "deviceInfo": { - "deviceNameExpressionSource": "topic", - "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/connect)" - } - } - ], - "attributeRequests": [ - { - "retain": false, - "topicFilter": "v1/devices/me/attributes/request", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "${serialNumber}" - }, - "attributeNameExpressionSource": "message", - "attributeNameExpression": "${versionAttribute}, ${pduAttribute}", - "topicExpression": "devices/${deviceName}/attrs", - "valueExpression": "${attributeKey}: ${attributeValue}" - } - ], - "attributeUpdates": [ - { - "retain": true, - "deviceNameFilter": ".*", - "attributeFilter": "firmwareVersion", - "topicExpression": "sensor/${deviceName}/${attributeKey}", - "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}" - } - ], - "serverSideRpc": [ - { - "type": "twoWay", - "deviceNameFilter": ".*", - "methodFilter": "echo", - "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", - "responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}", - "responseTopicQoS": 1, - "responseTimeout": 10000, - "valueExpression": "${params}" - }, - { - "type": "oneWay", - "deviceNameFilter": ".*", - "methodFilter": "no-reply", - "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", - "valueExpression": "${params}" } - ] - } } From 33c8cc405058f1a9f42cb90adb7a8ef20d8a4829 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 28 Aug 2024 19:27:44 +0300 Subject: [PATCH 02/14] refactoring --- .../mqtt/basic-config/mqtt-legacy-basic-config.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts index f499199739..92e4e5b4b5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts @@ -75,7 +75,7 @@ export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigCompo @Input() generalTabContent: TemplateRef; - writeValue(basicConfig: any): void { + writeValue(basicConfig: MQTTLegacyBasicConfig): void { const { broker, mapping = [], From a6f79b51def3379519d38a5687fe8e44daef8ee3 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Thu, 29 Aug 2024 11:47:57 +0300 Subject: [PATCH 03/14] refactoring --- .../widget/lib/gateway/gateway-connectors.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index 0da917312b..c2ee0c8d62 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -763,6 +763,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie case ConnectorType.OPCUA: case ConnectorType.MODBUS: this.connectorForm.get('mode').setValue(connector.mode || ConnectorConfigurationModes.BASIC, {emitEvent: false}); + this.connectorForm.get('configVersion').setValue(connector.configVersion, {emitEvent: false}); setTimeout(() => { this.connectorForm.patchValue(connector, {emitEvent: false}); this.connectorForm.markAsPristine(); From c4441eba72c05c683bca9e1516efde3b998312b2 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 9 Sep 2024 15:30:57 +0300 Subject: [PATCH 04/14] changed approach to abstract class for mapping --- ...ay-connector-version-processor.abstract.ts | 36 ++++++++ .../mqtt-version-processor.abstract.ts | 76 +++++++++++++++++ .../mqtt-basic-config.abstract.ts | 13 ++- .../mqtt-basic-config.component.ts | 8 +- .../mqtt-legacy-basic-config.component.ts | 14 ++-- .../dialog/add-connector-dialog.component.ts | 11 ++- .../gateway/gateway-connectors.component.ts | 8 +- .../lib/gateway/gateway-widget.models.ts | 19 ++--- .../gateway-connector-version-mapping.util.ts | 46 ++-------- .../utils/mqtt-version-mapping.util.ts | 84 +++---------------- .../connector-default-configs/mqtt.json | 2 +- 11 files changed, 168 insertions(+), 149 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts new file mode 100644 index 0000000000..1a1c4f05bc --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -0,0 +1,36 @@ +import { GatewayConnector } from '@home/components/widget/lib/gateway/gateway-widget.models'; + +export abstract class GatewayConnectorVersionProcessor { + gatewayVersion: number; + configVersion: number; + + protected constructor(protected gatewayVersionStr: string, protected connector: GatewayConnector) { + this.gatewayVersion = this.parseVersion(this.gatewayVersionStr); + this.configVersion = this.parseVersion(connector.configVersion); + } + + getProcessedByVersion(): BasicConfig { + if (this.isVersionUpdateNeeded()) { + return this.configVersion > this.gatewayVersion + ? this.getDowngradedVersion() + : this.getUpgradedVersion(); + } + + return this.connector.configurationJson as unknown as BasicConfig; + } + + private isVersionUpdateNeeded(): boolean { + if (!this.gatewayVersion || !this.configVersion) { + return false; + } + + return this.configVersion !== this.gatewayVersion; + } + + private parseVersion(version: string): number { + return Number(version?.replace(/\./g, '')); + } + + abstract getDowngradedVersion(): BasicConfig; + abstract getUpgradedVersion(): BasicConfig; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts new file mode 100644 index 0000000000..2a7bea0e1b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts @@ -0,0 +1,76 @@ +import { + GatewayConnectorVersionProcessor +} from '@home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract'; +import { + GatewayConnector, + MQTTBasicConfig, MQTTBasicConfig_v3_5_2, + MQTTLegacyBasicConfig, + RequestMappingData, + RequestType, +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { isEqual } from '@core/utils'; +import { MqttVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/mqtt-version-mapping.util'; + +export class MqttVersionProcessor extends GatewayConnectorVersionProcessor { + private readonly mqttRequestTypeKeys = Object.values(RequestType); + + constructor( + protected gatewayVersionStr: string, + protected connector: GatewayConnector + ) { + super(gatewayVersionStr, connector); + } + getUpgradedVersion(): MQTTBasicConfig { + const { + connectRequests, + disconnectRequests, + attributeRequests, + attributeUpdates, + serverSideRpc + } = this.connector.configurationJson as MQTTLegacyBasicConfig; + let configurationJson = { + ...this.connector.configurationJson, + requestsMapping: MqttVersionMappingUtil.mapRequestsToUpgradedVersion({ + connectRequests, + disconnectRequests, + attributeRequests, + attributeUpdates, + serverSideRpc + }), + mapping: MqttVersionMappingUtil.mapMappingToUpgradedVersion((this.connector.configurationJson as MQTTLegacyBasicConfig).mapping), + }; + + this.mqttRequestTypeKeys.forEach((key: RequestType) => { + const { [key]: removedKey, ...rest } = configurationJson as MQTTLegacyBasicConfig; + configurationJson = { ...rest } as any; + }); + + this.cleanUpConfigJson(configurationJson as MQTTBasicConfig_v3_5_2); + + return configurationJson as MQTTBasicConfig; + } + + getDowngradedVersion(): MQTTLegacyBasicConfig { + const { requestsMapping, mapping, ...restConfig } = this.connector.configurationJson as MQTTBasicConfig_v3_5_2; + + const updatedRequestsMapping = + MqttVersionMappingUtil.mapRequestsToDowngradedVersion(requestsMapping as Record); + const updatedMapping = MqttVersionMappingUtil.mapMappingToDowngradedVersion(mapping); + + return { + ...restConfig, + ...updatedRequestsMapping, + mapping: updatedMapping, + }; + } + + private cleanUpConfigJson(configurationJson: MQTTBasicConfig_v3_5_2): void { + if (isEqual(configurationJson.requestsMapping, {})) { + delete configurationJson.requestsMapping; + } + + if (isEqual(configurationJson.mapping, [])) { + delete configurationJson.mapping; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts index 12529d942f..072d8ba834 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts @@ -17,24 +17,23 @@ import { ControlValueAccessor, FormBuilder, FormGroup, ValidationErrors, Validator } from '@angular/forms'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { isObject } from 'lodash'; import { MappingType, MQTTBasicConfig, - MQTTLegacyBasicConfig, RequestMappingData, RequestMappingValue, RequestType } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { Directive, OnDestroy } from '@angular/core'; +import { isObject } from '@core/utils'; @Directive() -export abstract class AbstractMqttBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { +export abstract class AbstractMqttBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { basicFormGroup: FormGroup; mappingTypes = MappingType; private destroy$ = new Subject(); - private onChange: (value: MQTTBasicConfig | MQTTLegacyBasicConfig) => void; + private onChange: (value: BasicConfig) => void; private onTouched: () => void; constructor(protected fb: FormBuilder) { @@ -58,7 +57,7 @@ export abstract class AbstractMqttBasicConfigComponent implements ControlValueAc this.destroy$.complete(); } - registerOnChange(fn: (value: MQTTBasicConfig | MQTTLegacyBasicConfig) => void): void { + registerOnChange(fn: (value: BasicConfig) => void): void { this.onChange = fn; } @@ -102,6 +101,6 @@ export abstract class AbstractMqttBasicConfigComponent implements ControlValueAc }); } - abstract writeValue(basicConfig: MQTTBasicConfig | MQTTLegacyBasicConfig): void; - protected abstract getMappedMQTTConfig(basicConfig: MQTTBasicConfig): MQTTBasicConfig | MQTTLegacyBasicConfig; + abstract writeValue(basicConfig: BasicConfig): void; + protected abstract getMappedMQTTConfig(basicConfig: MQTTBasicConfig): BasicConfig; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts index c4ebadb03d..e2c9918179 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts @@ -17,7 +17,7 @@ import { Component, forwardRef, Input, TemplateRef, ChangeDetectionStrategy } from '@angular/core'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; import { - MQTTBasicConfig, + MQTTBasicConfig_v3_5_2, RequestMappingData, RequestMappingValue, RequestType @@ -68,12 +68,12 @@ import { MappingTableComponent, ], }) -export class MqttBasicConfigComponent extends AbstractMqttBasicConfigComponent { +export class MqttBasicConfigComponent extends AbstractMqttBasicConfigComponent { @Input() generalTabContent: TemplateRef; - writeValue(basicConfig: MQTTBasicConfig): void { + writeValue(basicConfig: MQTTBasicConfig_v3_5_2): void { const { broker, mapping = [], requestsMapping } = basicConfig; const editedBase = { workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { @@ -88,7 +88,7 @@ export class MqttBasicConfigComponent extends AbstractMqttBasicConfigComponent { this.basicFormGroup.setValue(editedBase, {emitEvent: false}); } - protected getMappedMQTTConfig(basicConfig: MQTTBasicConfig): MQTTBasicConfig { + protected getMappedMQTTConfig(basicConfig: MQTTBasicConfig_v3_5_2): MQTTBasicConfig_v3_5_2 { let { broker, workers, mapping, requestsMapping } = basicConfig || {}; if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts index 92e4e5b4b5..2ca5eba000 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts @@ -17,7 +17,7 @@ import { Component, forwardRef, Input, TemplateRef, ChangeDetectionStrategy } from '@angular/core'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; import { - MQTTBasicConfig, + MQTTBasicConfig_v3_5_2, MQTTLegacyBasicConfig, RequestMappingData, RequestMappingValue, @@ -70,7 +70,7 @@ import { MappingTableComponent, ], }) -export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigComponent { +export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigComponent { @Input() generalTabContent: TemplateRef; @@ -85,7 +85,7 @@ export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigCompo attributeUpdates = [], serverSideRpc = [] } = basicConfig; - const updatedRequestMapping = MqttVersionMappingUtil.mapRequestsToNewestVersion({ + const updatedRequestMapping = MqttVersionMappingUtil.mapRequestsToUpgradedVersion({ connectRequests, disconnectRequests, attributeRequests, @@ -97,7 +97,7 @@ export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigCompo maxNumberOfWorkers: broker.maxNumberOfWorkers, maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, } : {}, - mapping: MqttVersionMappingUtil.mapMappingToNewestVersion(mapping) || [], + mapping: MqttVersionMappingUtil.mapMappingToUpgradedVersion(mapping) || [], broker: broker || {}, requestsMapping: this.getRequestDataArray(updatedRequestMapping), }; @@ -105,7 +105,7 @@ export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigCompo this.basicFormGroup.setValue(editedBase, {emitEvent: false}); } - protected getMappedMQTTConfig(basicConfig: MQTTBasicConfig): MQTTLegacyBasicConfig { + protected getMappedMQTTConfig(basicConfig: MQTTBasicConfig_v3_5_2): MQTTLegacyBasicConfig { let { broker, workers, mapping, requestsMapping } = basicConfig || {}; if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { @@ -121,8 +121,8 @@ export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigCompo return { broker, - mapping: MqttVersionMappingUtil.mapMappingToLegacyVersion(mapping), - ...(MqttVersionMappingUtil.mapRequestsToLegacyVersion(requestsMapping as Record)) + mapping: MqttVersionMappingUtil.mapMappingToDowngradedVersion(mapping), + ...(MqttVersionMappingUtil.mapRequestsToDowngradedVersion(requestsMapping as Record)) }; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts index d79a1d3fec..0168cf86af 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts @@ -97,8 +97,15 @@ export class AddConnectorDialogComponent this.submitted = true; const value = this.connectorForm.getRawValue(); if (value.useDefaults) { - this.getDefaultConfig(value.type).subscribe(({current, legacy, ...defaultConfig}: GatewayVersionedDefaultConfig) => { - value.configurationJson = (this.data.gatewayVersion ? current : legacy) ?? defaultConfig; + this.getDefaultConfig(value.type).subscribe((defaultConfig: GatewayVersionedDefaultConfig) => { + const gatewayVersion = this.data.gatewayVersion; + if (gatewayVersion) { + value.configVersion = gatewayVersion; + } + value.configurationJson = (gatewayVersion + ? defaultConfig[this.data.gatewayVersion] + : defaultConfig.legacy) + ?? defaultConfig; if (this.connectorForm.valid) { this.dialogRef.close(value); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index d7d412f6da..96e15a110f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -65,7 +65,9 @@ import { AddConnectorDialogComponent } from '@home/components/widget/lib/gateway import { debounceTime, filter, switchMap, take, takeUntil, tap } from 'rxjs/operators'; import { ErrorStateMatcher } from '@angular/material/core'; import { PageData } from '@shared/models/page/page-data'; -import { GatewayConnectorVersionMappingUtil } from './utils/gateway-connector-version-mapping.util'; +import { + GatewayConnectorVersionMappingUtil +} from '@home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util'; export class ForceErrorStateMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null): boolean { @@ -247,7 +249,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie value.ts = Date.now(); - return GatewayConnectorVersionMappingUtil.getMappedByVersion(value, this.gatewayVersion); + return value; } private updateData(reload: boolean = false): void { @@ -741,7 +743,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie ...connector, }; - connectorState.basicConfig = connectorState.configurationJson; + connectorState.basicConfig = GatewayConnectorVersionMappingUtil.getConfig(connectorState, this.gatewayVersion); this.initialConnector = connectorState; this.updateConnector(connectorState); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index 4770eeea23..38040f15d3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -124,21 +124,14 @@ export interface GatewayConnectorBase { configVersion?: string; } -export type GatewayConnector = CurrentGatewayConnector | LegacyGatewayConnector; - -export interface CurrentGatewayConnector extends GatewayConnectorBase { +export interface GatewayConnector extends GatewayConnectorBase { configurationJson: ConnectorBaseConfig; basicConfig?: ConnectorBaseConfig; } -export interface LegacyGatewayConnector extends GatewayConnectorBase { - configurationJson: ConnectorLegacyBaseConfig; - basicConfig?: ConnectorLegacyBaseConfig; -} - export interface GatewayVersionedDefaultConfig { - legacy: LegacyGatewayConnector; - current: GatewayConnector; + legacy: GatewayConnector; + '3.5.1': GatewayConnector; } export interface DataMapping { @@ -201,8 +194,6 @@ export type ConnectorMappingFormValue = DeviceConnectorMapping | RequestMappingF export type ConnectorBaseConfig = ConnectorBaseInfo | MQTTBasicConfig | OPCBasicConfig | ModbusBasicConfig; -export type ConnectorLegacyBaseConfig = ConnectorBaseInfo | MQTTLegacyBasicConfig; - export interface ConnectorBaseInfo { name: string; id: string; @@ -210,7 +201,9 @@ export interface ConnectorBaseInfo { logLevel: GatewayLogLevel; } -export interface MQTTBasicConfig { +export type MQTTBasicConfig = MQTTBasicConfig_v3_5_2 | MQTTLegacyBasicConfig; + +export interface MQTTBasicConfig_v3_5_2 { mapping: ConverterConnectorMapping[]; requestsMapping: Record | RequestMappingData[] | RequestMappingValue[]; broker: BrokerConfig; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts index 6a48b5e64b..ab9e393fee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts @@ -15,52 +15,20 @@ /// import { + ConnectorBaseConfig, ConnectorType, GatewayConnector, - LegacyGatewayConnector, } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { MqttVersionMappingUtil } from './mqtt-version-mapping.util'; +import { MqttVersionProcessor } from '@home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract'; -export class GatewayConnectorVersionMappingUtil { +export abstract class GatewayConnectorVersionMappingUtil { - static getMappedByVersion(connector: GatewayConnector, gatewayVersion: string): GatewayConnector { - switch (connector.type) { + static getConfig(connector: GatewayConnector, gatewayVersion: string): ConnectorBaseConfig { + switch(connector.type) { case ConnectorType.MQTT: - return this.getMappedMQTTByVersion(connector, gatewayVersion); + return new MqttVersionProcessor(gatewayVersion, connector).getProcessedByVersion(); default: - return connector; + return connector.configurationJson as ConnectorBaseConfig; } } - - private static getMappedMQTTByVersion( - connector: GatewayConnector | LegacyGatewayConnector, - gatewayVersion: string - ): GatewayConnector | LegacyGatewayConnector { - if (this.isVersionUpdateNeeded(gatewayVersion, connector.configVersion)) { - return this.isGatewayOutdated(gatewayVersion, connector.configVersion) - ? MqttVersionMappingUtil.getLegacyVersion(connector) - : MqttVersionMappingUtil.getNewestVersion(connector); - } - return connector; - } - - private static isGatewayOutdated(gatewayVersion: string, configVersion: string): boolean { - if (!gatewayVersion || !configVersion) { - return false; - } - - return this.parseVersion(configVersion) > this.parseVersion(gatewayVersion); - } - - private static isVersionUpdateNeeded(configVersion: string, gatewayVersion: string): boolean { - if (!gatewayVersion || !configVersion) { - return false; - } - - return this.parseVersion(configVersion) !== this.parseVersion(gatewayVersion); - } - - private static parseVersion(version: string): number { - return Number(version?.replace(/\./g, '')); - } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts index e32d020730..ffd517c3e9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts @@ -14,21 +14,16 @@ /// limitations under the License. /// -import { deleteNullProperties, isEqual } from '@core/utils'; +import { deleteNullProperties } from '@core/utils'; import { AttributeRequest, ConnectorDeviceInfo, Converter, ConverterConnectorMapping, ConvertorType, - CurrentGatewayConnector, - GatewayConnector, LegacyConverter, LegacyConverterConnectorMapping, - LegacyGatewayConnector, LegacyRequestMappingData, - MQTTBasicConfig, - MQTTLegacyBasicConfig, RequestMappingData, RequestType, ServerSideRpc, @@ -44,56 +39,9 @@ export class MqttVersionMappingUtil { static readonly mqttRequestMappingNewFields = ['attributeNameExpressionSource', 'responseTopicQoS', 'extensionConfig']; - static getNewestVersion(mqttConnector: GatewayConnector): CurrentGatewayConnector { - const { - connectRequests, - disconnectRequests, - attributeRequests, - attributeUpdates, - serverSideRpc - } = mqttConnector.configurationJson as MQTTLegacyBasicConfig; - let configurationJson = { - ...mqttConnector.configurationJson, - requestsMapping: this.mapRequestsToNewestVersion({ - connectRequests, - disconnectRequests, - attributeRequests, - attributeUpdates, - serverSideRpc - }), - mapping: this.mapMappingToNewestVersion((mqttConnector.configurationJson as MQTTLegacyBasicConfig).mapping), - }; - - this.mqttRequestTypeKeys.forEach((key: RequestType) => { - const { [key]: removedKey, ...rest } = configurationJson as MQTTLegacyBasicConfig; - configurationJson = { ...rest } as any; - }); - - this.cleanUpConfigJson(configurationJson as MQTTBasicConfig); - - return { - ...mqttConnector, - configurationJson - } as CurrentGatewayConnector; - } - - static getLegacyVersion(mqttConnector: GatewayConnector): LegacyGatewayConnector { - const { requestsMapping, mapping, ...restConfig } = mqttConnector.configurationJson as MQTTBasicConfig; - - const updatedRequestsMapping = this.mapRequestsToLegacyVersion(requestsMapping as Record); - const updatedMapping = this.mapMappingToLegacyVersion(mapping); - - return { - ...mqttConnector, - configurationJson: { - ...restConfig, - ...updatedRequestsMapping, - mapping: updatedMapping, - }, - } as LegacyGatewayConnector; - } - - static mapMappingToNewestVersion(mapping: LegacyConverterConnectorMapping[] | ConverterConnectorMapping[]): ConverterConnectorMapping[] { + static mapMappingToUpgradedVersion( + mapping: LegacyConverterConnectorMapping[] | ConverterConnectorMapping[] + ): ConverterConnectorMapping[] { return mapping?.map(({ converter, topicFilter, subscriptionQos = 1 }) => { const deviceInfo = converter.deviceInfo ?? this.extractConverterDeviceInfo(converter); @@ -109,7 +57,7 @@ export class MqttVersionMappingUtil { }); } - static mapRequestsToNewestVersion( + static mapRequestsToUpgradedVersion( requestMapping: Record ): Record { @@ -119,7 +67,7 @@ export class MqttVersionMappingUtil { } acc[key] = requestMapping[key].map(value => { - const newValue = this.mapRequestToNewest(value as LegacyRequestMappingData, key); + const newValue = this.mapRequestToUpgradedVersion(value as LegacyRequestMappingData, key); this.cleanUpOldFields(newValue as {}); @@ -130,7 +78,7 @@ export class MqttVersionMappingUtil { }, {}) as Record; } - static mapRequestsToLegacyVersion( + static mapRequestsToDowngradedVersion( requestsMapping: Record ): Record { return this.mqttRequestTypeKeys.reduce((acc, key) => { @@ -161,11 +109,11 @@ export class MqttVersionMappingUtil { }, {}) as Record; } - static mapMappingToLegacyVersion( + static mapMappingToDowngradedVersion( mapping: ConverterConnectorMapping[] ): LegacyConverterConnectorMapping[] { return mapping?.map((converterMapping: ConverterConnectorMapping) => { - const converter = this.mapConverterToLegacy(converterMapping.converter); + const converter = this.mapConverterToDowngradedVersion(converterMapping.converter); this.cleanUpNewFields(converter as {}); @@ -173,7 +121,7 @@ export class MqttVersionMappingUtil { }); } - private static mapConverterToLegacy(converter: Converter): LegacyConverter { + private static mapConverterToDowngradedVersion(converter: Converter): LegacyConverter { const { deviceInfo, ...restConverter } = converter; return converter.type !== ConvertorType.BYTES ? { @@ -216,16 +164,6 @@ export class MqttVersionMappingUtil { return SourceType.CONST; } - private static cleanUpConfigJson(configurationJson: MQTTBasicConfig): void { - if (isEqual(configurationJson.requestsMapping, {})) { - delete configurationJson.requestsMapping; - } - - if (isEqual(configurationJson.mapping, [])) { - delete configurationJson.mapping; - } - } - private static extractConverterDeviceInfo(converter: LegacyConverter): ConnectorDeviceInfo { const deviceNameExpression = converter.deviceNameExpression || converter.deviceNameJsonExpression @@ -250,7 +188,7 @@ export class MqttVersionMappingUtil { } : null; } - private static mapRequestToNewest(value, key: RequestType): RequestMappingData { + private static mapRequestToUpgradedVersion(value, key: RequestType): RequestMappingData { const deviceNameExpression = value.deviceNameJsonExpression || value.deviceNameTopicExpression || null; const deviceProfileExpression = value.deviceTypeTopicExpression || value.deviceTypeJsonExpression || 'default'; const deviceProfileExpressionSource = deviceProfileExpression ? this.getTypeSourceByValue(deviceProfileExpression) : null; diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json b/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json index 96ab233ef4..b3ba47215f 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json @@ -1,5 +1,5 @@ { - "current": { + "3.5.1": { "broker": { "host": "127.0.0.1", "port": 1883, From f97598ee081f0244cf83f16e8fc3da4553c83f90 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 9 Sep 2024 16:17:00 +0300 Subject: [PATCH 05/14] refactoring --- ...ay-connector-version-processor.abstract.ts | 6 +++--- .../mqtt-version-processor.abstract.ts | 19 +++++++++---------- .../mqtt-basic-config.abstract.ts | 2 ++ .../mqtt-basic-config.component.ts | 4 ++-- .../gateway/gateway-connectors.component.ts | 6 +----- .../utils/mqtt-version-mapping.util.ts | 6 +++--- 6 files changed, 20 insertions(+), 23 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts index 1a1c4f05bc..31b8ba8cf8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -11,9 +11,9 @@ export abstract class GatewayConnectorVersionProcessor { getProcessedByVersion(): BasicConfig { if (this.isVersionUpdateNeeded()) { - return this.configVersion > this.gatewayVersion - ? this.getDowngradedVersion() - : this.getUpgradedVersion(); + return this.configVersion < this.gatewayVersion + ? this.getUpgradedVersion() + : this.getDowngradedVersion(); } return this.connector.configurationJson as unknown as BasicConfig; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts index 2a7bea0e1b..875b238d7e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts @@ -1,15 +1,14 @@ -import { - GatewayConnectorVersionProcessor -} from '@home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract'; +import { isEqual } from '@core/utils'; import { GatewayConnector, - MQTTBasicConfig, MQTTBasicConfig_v3_5_2, + MQTTBasicConfig, + MQTTBasicConfig_v3_5_2, MQTTLegacyBasicConfig, RequestMappingData, RequestType, -} from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { isEqual } from '@core/utils'; -import { MqttVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/mqtt-version-mapping.util'; +} from '../gateway-widget.models'; +import { MqttVersionMappingUtil } from '../utils/mqtt-version-mapping.util'; +import { GatewayConnectorVersionProcessor } from './gateway-connector-version-processor.abstract'; export class MqttVersionProcessor extends GatewayConnectorVersionProcessor { private readonly mqttRequestTypeKeys = Object.values(RequestType); @@ -20,7 +19,7 @@ export class MqttVersionProcessor extends GatewayConnectorVersionProcessor { - const { [key]: removedKey, ...rest } = configurationJson as MQTTLegacyBasicConfig; + const { [key]: removedValue, ...rest } = configurationJson as MQTTLegacyBasicConfig; configurationJson = { ...rest } as any; }); this.cleanUpConfigJson(configurationJson as MQTTBasicConfig_v3_5_2); - return configurationJson as MQTTBasicConfig; + return configurationJson as MQTTBasicConfig_v3_5_2; } getDowngradedVersion(): MQTTLegacyBasicConfig { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts index 072d8ba834..0394604d42 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts @@ -32,7 +32,9 @@ export abstract class AbstractMqttBasicConfigComponent implements C basicFormGroup: FormGroup; mappingTypes = MappingType; + private destroy$ = new Subject(); + private onChange: (value: BasicConfig) => void; private onTouched: () => void; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts index e2c9918179..541866dab8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts @@ -80,8 +80,8 @@ export class MqttBasicConfigComponent extends AbstractMqttBasicConfigComponent), }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index 96e15a110f..b6e2dfc093 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -243,10 +243,6 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie delete value.class; } - if (this.gatewayVersion && !value.configVersion) { - value.configVersion = this.gatewayVersion; - } - value.ts = Date.now(); return value; @@ -482,7 +478,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie value.configurationJson = {} as ConnectorBaseConfig; } value.basicConfig = value.configurationJson; - this.updateConnector({...value, configVersion: this.gatewayVersion ?? ''}); + this.updateConnector(value); this.generate('basicConfig.broker.clientId'); setTimeout(() => this.saveConnector()); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts index ffd517c3e9..23cc03dc4e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts @@ -40,7 +40,7 @@ export class MqttVersionMappingUtil { ['attributeNameExpressionSource', 'responseTopicQoS', 'extensionConfig']; static mapMappingToUpgradedVersion( - mapping: LegacyConverterConnectorMapping[] | ConverterConnectorMapping[] + mapping: LegacyConverterConnectorMapping[] ): ConverterConnectorMapping[] { return mapping?.map(({ converter, topicFilter, subscriptionQos = 1 }) => { const deviceInfo = converter.deviceInfo ?? this.extractConverterDeviceInfo(converter); @@ -54,12 +54,12 @@ export class MqttVersionMappingUtil { this.cleanUpOldFields(newConverter); return { converter: newConverter, topicFilter, subscriptionQos }; - }); + }) as ConverterConnectorMapping[]; } static mapRequestsToUpgradedVersion( requestMapping: Record + LegacyRequestMappingData[]> ): Record { return this.mqttRequestTypeKeys.reduce((acc, key: RequestType) => { if (!requestMapping[key]) { From 618d82b7ac0385babd566ae97fcb9b8032e4c841 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 9 Sep 2024 17:42:46 +0300 Subject: [PATCH 06/14] Changed approach to GatewayConnector generic --- ...ay-connector-version-processor.abstract.ts | 14 +++++------ .../mqtt-version-processor.abstract.ts | 24 ++++++++++++------- .../models/gateway-configuration.models.ts | 4 +++- .../gateway/gateway-connectors.component.ts | 6 ++--- .../lib/gateway/gateway-widget.models.ts | 16 ++++++++----- .../gateway-connector-version-mapping.util.ts | 8 +++---- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts index 31b8ba8cf8..923cf1920b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -4,23 +4,23 @@ export abstract class GatewayConnectorVersionProcessor { gatewayVersion: number; configVersion: number; - protected constructor(protected gatewayVersionStr: string, protected connector: GatewayConnector) { + protected constructor(protected gatewayVersionStr: string, protected connector: GatewayConnector) { this.gatewayVersion = this.parseVersion(this.gatewayVersionStr); this.configVersion = this.parseVersion(connector.configVersion); } - getProcessedByVersion(): BasicConfig { + getProcessedByVersion(): GatewayConnector { if (this.isVersionUpdateNeeded()) { - return this.configVersion < this.gatewayVersion + return !this.configVersion || this.configVersion < this.gatewayVersion ? this.getUpgradedVersion() : this.getDowngradedVersion(); } - return this.connector.configurationJson as unknown as BasicConfig; + return this.connector; } private isVersionUpdateNeeded(): boolean { - if (!this.gatewayVersion || !this.configVersion) { + if (!this.gatewayVersion) { return false; } @@ -31,6 +31,6 @@ export abstract class GatewayConnectorVersionProcessor { return Number(version?.replace(/\./g, '')); } - abstract getDowngradedVersion(): BasicConfig; - abstract getUpgradedVersion(): BasicConfig; + abstract getDowngradedVersion(): GatewayConnector; + abstract getUpgradedVersion(): GatewayConnector; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts index 875b238d7e..99591130a5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts @@ -15,11 +15,11 @@ export class MqttVersionProcessor extends GatewayConnectorVersionProcessor ) { super(gatewayVersionStr, connector); } - getUpgradedVersion(): MQTTBasicConfig_v3_5_2 { + getUpgradedVersion(): GatewayConnector { const { connectRequests, disconnectRequests, @@ -46,10 +46,14 @@ export class MqttVersionProcessor extends GatewayConnectorVersionProcessor; } - getDowngradedVersion(): MQTTLegacyBasicConfig { + getDowngradedVersion(): GatewayConnector { const { requestsMapping, mapping, ...restConfig } = this.connector.configurationJson as MQTTBasicConfig_v3_5_2; const updatedRequestsMapping = @@ -57,10 +61,14 @@ export class MqttVersionProcessor extends GatewayConnectorVersionProcessor; } private cleanUpConfigJson(configurationJson: MQTTBasicConfig_v3_5_2): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts index a23d8e7900..bfdd46997e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts @@ -16,7 +16,9 @@ import { ConfigurationModes, - GatewayConnector, LocalLogsConfigs, LogSavingPeriod, + GatewayConnector, + LocalLogsConfigs, + LogSavingPeriod, SecurityTypes, StorageTypes } from '@home/components/widget/lib/gateway/gateway-widget.models'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index b6e2dfc093..cbaeed8888 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -732,14 +732,14 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.connectorForm.enable(); } - const connectorState = { + const connectorState = GatewayConnectorVersionMappingUtil.getConfig({ configuration: '', key: 'auto', configurationJson: {} as ConnectorBaseConfig, ...connector, - }; + }, this.gatewayVersion); - connectorState.basicConfig = GatewayConnectorVersionMappingUtil.getConfig(connectorState, this.gatewayVersion); + connectorState.basicConfig = connectorState.configurationJson; this.initialConnector = connectorState; this.updateConnector(connectorState); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index 38040f15d3..94d8ce7d2a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -124,14 +124,14 @@ export interface GatewayConnectorBase { configVersion?: string; } -export interface GatewayConnector extends GatewayConnectorBase { - configurationJson: ConnectorBaseConfig; - basicConfig?: ConnectorBaseConfig; +export interface GatewayConnector extends GatewayConnectorBase { + configurationJson: BaseConfig; + basicConfig?: BaseConfig; } export interface GatewayVersionedDefaultConfig { - legacy: GatewayConnector; - '3.5.1': GatewayConnector; + legacy: GatewayConnector; + '3.5.1': GatewayConnector; } export interface DataMapping { @@ -192,7 +192,11 @@ export type ConnectorMapping = DeviceConnectorMapping | RequestMappingValue | Co export type ConnectorMappingFormValue = DeviceConnectorMapping | RequestMappingFormValue | ConverterMappingFormValue; -export type ConnectorBaseConfig = ConnectorBaseInfo | MQTTBasicConfig | OPCBasicConfig | ModbusBasicConfig; +export type ConnectorBaseConfig = ConnectorBaseConfig_v_3_5_2 | ConnectorLegacyConfig; + +export type ConnectorLegacyConfig = ConnectorBaseInfo | MQTTLegacyBasicConfig | OPCBasicConfig | ModbusBasicConfig; + +export type ConnectorBaseConfig_v_3_5_2 = ConnectorBaseInfo | MQTTBasicConfig_v3_5_2; export interface ConnectorBaseInfo { name: string; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts index ab9e393fee..9de53e506d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts @@ -17,18 +17,18 @@ import { ConnectorBaseConfig, ConnectorType, - GatewayConnector, + GatewayConnector, MQTTBasicConfig, } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { MqttVersionProcessor } from '@home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract'; export abstract class GatewayConnectorVersionMappingUtil { - static getConfig(connector: GatewayConnector, gatewayVersion: string): ConnectorBaseConfig { + static getConfig(connector: GatewayConnector, gatewayVersion: string): GatewayConnector { switch(connector.type) { case ConnectorType.MQTT: - return new MqttVersionProcessor(gatewayVersion, connector).getProcessedByVersion(); + return new MqttVersionProcessor(gatewayVersion, connector as GatewayConnector).getProcessedByVersion(); default: - return connector.configurationJson as ConnectorBaseConfig; + return connector; } } } From 53d86dd31ef098ebfa4a37babcb6fc438f50f98e Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 9 Sep 2024 18:21:33 +0300 Subject: [PATCH 07/14] refactoring --- .../abstract/gateway-connector-version-processor.abstract.ts | 4 ++-- .../mqtt/basic-config/mqtt-basic-config.abstract.ts | 2 +- .../mqtt/basic-config/mqtt-basic-config.component.html | 4 ++-- .../gateway/utils/gateway-connector-version-mapping.util.ts | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts index 923cf1920b..579ad6a45b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -31,6 +31,6 @@ export abstract class GatewayConnectorVersionProcessor { return Number(version?.replace(/\./g, '')); } - abstract getDowngradedVersion(): GatewayConnector; - abstract getUpgradedVersion(): GatewayConnector; + protected abstract getDowngradedVersion(): GatewayConnector; + protected abstract getUpgradedVersion(): GatewayConnector; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts index 0394604d42..aeef688333 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts @@ -31,7 +31,7 @@ import { isObject } from '@core/utils'; export abstract class AbstractMqttBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { basicFormGroup: FormGroup; - mappingTypes = MappingType; + MappingType = MappingType; private destroy$ = new Subject(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html index 9ad25aa851..b602ba20d4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html @@ -24,12 +24,12 @@
- +
- +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts index 9de53e506d..12f3a7c439 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts @@ -15,9 +15,9 @@ /// import { - ConnectorBaseConfig, ConnectorType, - GatewayConnector, MQTTBasicConfig, + GatewayConnector, + MQTTBasicConfig, } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { MqttVersionProcessor } from '@home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract'; From 13e7e4a61d356453900befd5ef77df11f1feda5f Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 9 Sep 2024 18:39:26 +0300 Subject: [PATCH 08/14] [4114] Updated version checks --- .../gateway-connector-version-processor.abstract.ts | 8 ++++++-- .../lib/gateway/dialog/add-connector-dialog.component.ts | 3 ++- .../widget/lib/gateway/gateway-connectors.component.html | 2 +- .../widget/lib/gateway/gateway-connectors.component.ts | 2 ++ .../widget/lib/gateway/gateway-widget.models.ts | 5 +++++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts index 579ad6a45b..b2062e428b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -1,4 +1,4 @@ -import { GatewayConnector } from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { GatewayConnector, GatewayVersion } from '@home/components/widget/lib/gateway/gateway-widget.models'; export abstract class GatewayConnectorVersionProcessor { gatewayVersion: number; @@ -11,7 +11,7 @@ export abstract class GatewayConnectorVersionProcessor { getProcessedByVersion(): GatewayConnector { if (this.isVersionUpdateNeeded()) { - return !this.configVersion || this.configVersion < this.gatewayVersion + return this.isVersionUpgradeNeeded() ? this.getUpgradedVersion() : this.getDowngradedVersion(); } @@ -27,6 +27,10 @@ export abstract class GatewayConnectorVersionProcessor { return this.configVersion !== this.gatewayVersion; } + private isVersionUpgradeNeeded(): boolean { + return (!this.configVersion || this.configVersion < this.gatewayVersion) && this.gatewayVersionStr === GatewayVersion.Current; + } + private parseVersion(version: string): number { return Number(version?.replace(/\./g, '')); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts index 0168cf86af..c8235cb697 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts @@ -29,6 +29,7 @@ import { GatewayConnector, GatewayConnectorDefaultTypesTranslatesMap, GatewayLogLevel, + GatewayVersion, GatewayVersionedDefaultConfig, noLeadTrailSpacesRegex } from '@home/components/widget/lib/gateway/gateway-widget.models'; @@ -102,7 +103,7 @@ export class AddConnectorDialogComponent if (gatewayVersion) { value.configVersion = gatewayVersion; } - value.configurationJson = (gatewayVersion + value.configurationJson = (gatewayVersion === GatewayVersion.Current ? defaultConfig[this.data.gatewayVersion] : defaultConfig.legacy) ?? defaultConfig; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html index 63a18ad3d2..f0459496df 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html @@ -178,7 +178,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index cbaeed8888..9be5b550ce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -59,6 +59,7 @@ import { GatewayConnectorDefaultTypesTranslatesMap, GatewayLogLevel, noLeadTrailSpacesRegex, + GatewayVersion, } from './gateway-widget.models'; import { MatDialog } from '@angular/material/dialog'; import { AddConnectorDialogComponent } from '@home/components/widget/lib/gateway/dialog/add-connector-dialog.component'; @@ -101,6 +102,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie readonly displayedColumns = ['enabled', 'key', 'type', 'syncStatus', 'errors', 'actions']; readonly GatewayConnectorTypesTranslatesMap = GatewayConnectorDefaultTypesTranslatesMap; readonly ConnectorConfigurationModes = ConfigurationModes; + readonly GatewayVersion = GatewayVersion; pageLink: PageLink; dataSource: MatTableDataSource; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index 94d8ce7d2a..f7acac12e6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -188,6 +188,11 @@ export interface ConnectorSecurity { mode?: ModeType; } +export enum GatewayVersion { + Current = '3.5.1', + Legacy = 'legacy' +} + export type ConnectorMapping = DeviceConnectorMapping | RequestMappingValue | ConverterConnectorMapping; export type ConnectorMappingFormValue = DeviceConnectorMapping | RequestMappingFormValue | ConverterMappingFormValue; From 4323c6abd2bc3f911b28a0cb134a8503c9bb06d8 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 9 Sep 2024 19:10:49 +0300 Subject: [PATCH 09/14] [4114] refactoring --- .../abstract/gateway-connector-version-processor.abstract.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts index b2062e428b..cad9300212 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -28,7 +28,7 @@ export abstract class GatewayConnectorVersionProcessor { } private isVersionUpgradeNeeded(): boolean { - return (!this.configVersion || this.configVersion < this.gatewayVersion) && this.gatewayVersionStr === GatewayVersion.Current; + return this.gatewayVersionStr === GatewayVersion.Current && (!this.configVersion || this.configVersion < this.gatewayVersion); } private parseVersion(version: string): number { From 1625f435b380faf1f23f58a02b18d3077d70447f Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 9 Sep 2024 19:11:37 +0300 Subject: [PATCH 10/14] [4114] license headers --- ...teway-connector-version-processor.abstract.ts | 16 ++++++++++++++++ .../abstract/mqtt-version-processor.abstract.ts | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts index cad9300212..e1addf0b71 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -1,3 +1,19 @@ +/// +/// 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 { GatewayConnector, GatewayVersion } from '@home/components/widget/lib/gateway/gateway-widget.models'; export abstract class GatewayConnectorVersionProcessor { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts index 99591130a5..645eb64fa4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts @@ -1,3 +1,19 @@ +/// +/// 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 { isEqual } from '@core/utils'; import { GatewayConnector, From b142c72247f7050427d6ab49789ea40e403b263d Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 10 Sep 2024 18:05:59 +0300 Subject: [PATCH 11/14] [4114] Added Modbus version mapping and OPC initial mapping --- ...gateway-connector-basic-config.abstract.ts | 72 ++ ...ay-connector-version-processor.abstract.ts | 3 +- .../modbus-version-processor.abstract.ts | 67 ++ .../opc-version-processor.abstract.ts | 55 ++ .../modbus-basic-config.abstract.ts | 81 ++ .../modbus-basic-config.component.ts | 110 +-- .../modbus-legacy-basic-config.component.ts | 76 ++ .../mqtt-basic-config.abstract.ts | 58 +- .../mqtt-basic-config.component.ts | 26 +- .../mqtt-legacy-basic-config.component.ts | 28 +- .../workers-config-control.component.html | 0 .../workers-config-control.component.ts | 0 .../opc-server-config.component.html | 0 .../opc-server-config.component.scss | 0 .../opc-server-config.component.ts | 0 .../opc-ua-basic-config.component.html | 0 .../opc-ua-basic-config.component.scss | 0 .../opc-ua-basic-config.component.ts | 81 +- .../opc-ua-legacy-basic-config.component.ts | 87 +++ .../gateway/gateway-connectors.component.html | 28 +- .../lib/gateway/gateway-widget.models.ts | 68 +- .../gateway-connector-version-mapping.util.ts | 8 + .../utils/modbus-version-mapping.util.ts | 77 ++ .../gateway/utils/opc-version-mapping.util.ts | 113 +++ .../widget/widget-components.module.ts | 14 +- .../connector-default-configs/modbus.json | 698 ++++++++++++------ .../connector-default-configs/opcua.json | 180 +++-- 27 files changed, 1393 insertions(+), 537 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component.ts rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => mqtt}/workers-config-control/workers-config-control.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => mqtt}/workers-config-control/workers-config-control.component.ts (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => opc}/opc-server-config/opc-server-config.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => opc}/opc-server-config/opc-server-config.component.scss (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => opc}/opc-server-config/opc-server-config.component.ts (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => opc}/opc-ua-basic-config/opc-ua-basic-config.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => opc}/opc-ua-basic-config/opc-ua-basic-config.component.scss (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/{ => opc}/opc-ua-basic-config/opc-ua-basic-config.component.ts (51%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts new file mode 100644 index 0000000000..d12e647254 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts @@ -0,0 +1,72 @@ +/// +/// 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 { Directive, inject, Input, OnDestroy, TemplateRef } from '@angular/core'; +import { ControlValueAccessor, FormBuilder, FormGroup, ValidationErrors, Validator } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +@Directive() +export abstract class GatewayConnectorBasicConfigDirective + implements ControlValueAccessor, Validator, OnDestroy { + + @Input() generalTabContent: TemplateRef; + + basicFormGroup: FormGroup; + + protected fb = inject(FormBuilder); + protected onChange!: (value: OutputBasicConfig) => void; + protected onTouched!: () => void; + protected destroy$ = new Subject(); + + constructor() { + this.basicFormGroup = this.initBasicFormGroup(); + + this.basicFormGroup.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe((value) => this.onBasicFormGroupChange(value)); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + validate(): ValidationErrors | null { + return this.basicFormGroup.valid ? null : { basicFormGroup: { valid: false } }; + } + + registerOnChange(fn: (value: OutputBasicConfig) => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + writeValue(config: OutputBasicConfig): void { + this.basicFormGroup.setValue(this.mapConfigToFormValue(config), { emitEvent: false }); + } + + protected onBasicFormGroupChange(value: InputBasicConfig): void { + this.onChange(this.getMappedValue(value)); + this.onTouched(); + } + + protected abstract mapConfigToFormValue(config: OutputBasicConfig): InputBasicConfig; + protected abstract getMappedValue(config: InputBasicConfig): OutputBasicConfig; + protected abstract initBasicFormGroup(): FormGroup; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts index e1addf0b71..5f06659823 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -15,6 +15,7 @@ /// import { GatewayConnector, GatewayVersion } from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { isString } from '@core/utils'; export abstract class GatewayConnectorVersionProcessor { gatewayVersion: number; @@ -48,7 +49,7 @@ export abstract class GatewayConnectorVersionProcessor { } private parseVersion(version: string): number { - return Number(version?.replace(/\./g, '')); + return isString(version) ? Number(version.replace(/\./g, '')) : 0; } protected abstract getDowngradedVersion(): GatewayConnector; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts new file mode 100644 index 0000000000..d520a5b1e8 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts @@ -0,0 +1,67 @@ +/// +/// 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 { + GatewayConnector, + ModbusBasicConfig, + ModbusBasicConfig_v3_5_2, + ModbusLegacyBasicConfig, + ModbusLegacySlave, + ModbusMasterConfig, + ModbusSlave, +} from '../gateway-widget.models'; +import { GatewayConnectorVersionProcessor } from './gateway-connector-version-processor.abstract'; +import { ModbusVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/modbus-version-mapping.util'; + +export class ModbusVersionProcessor extends GatewayConnectorVersionProcessor { + + constructor( + protected gatewayVersionStr: string, + protected connector: GatewayConnector + ) { + super(gatewayVersionStr, connector); + } + getUpgradedVersion(): GatewayConnector { + const configurationJson = this.connector.configurationJson; + return { + ...this.connector, + configurationJson: { + master: configurationJson.master + ? ModbusVersionMappingUtil.mapMasterToUpgradedVersion(configurationJson.master) + : {} as ModbusMasterConfig, + slave: configurationJson.slave + ? ModbusVersionMappingUtil.mapSlaveToUpgradedVersion(configurationJson.slave as ModbusLegacySlave) + : {} as ModbusSlave, + }, + configVersion: this.gatewayVersionStr + } as GatewayConnector; + } + + getDowngradedVersion(): GatewayConnector { + const configurationJson = this.connector.configurationJson; + return { + ...this.connector, + configurationJson: { + ...configurationJson, + slave: configurationJson.slave + ? ModbusVersionMappingUtil.mapSlaveToDowngradedVersion(configurationJson.slave as ModbusSlave) + : {} as ModbusLegacySlave, + master: configurationJson.master, + }, + configVersion: this.gatewayVersionStr + } as GatewayConnector; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts new file mode 100644 index 0000000000..11c9908058 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts @@ -0,0 +1,55 @@ +/// +/// 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 { + GatewayConnector, LegacyServerConfig, + OPCBasicConfig, + OPCBasicConfig_v3_5_2, + OPCLegacyBasicConfig, +} from '../gateway-widget.models'; +import { GatewayConnectorVersionProcessor } from './gateway-connector-version-processor.abstract'; +import { OpcVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/opc-version-mapping.util'; + +export class OpcVersionProcessor extends GatewayConnectorVersionProcessor { + + constructor( + protected gatewayVersionStr: string, + protected connector: GatewayConnector + ) { + super(gatewayVersionStr, connector); + } + getUpgradedVersion(): GatewayConnector { + const server = this.connector.configurationJson.server as LegacyServerConfig; + return { + ...this.connector, + configurationJson: { + server: server ? OpcVersionMappingUtil.mapServerToUpgradedVersion(server) : {}, + mapping: server.mapping ? OpcVersionMappingUtil.mapMappingToUpgradedVersion(server.mapping) : [], + }, + configVersion: this.gatewayVersionStr + } as GatewayConnector; + } + + getDowngradedVersion(): GatewayConnector { + return { + ...this.connector, + configurationJson: { + server: OpcVersionMappingUtil.mapServerToDowngradedVersion(this.connector.configurationJson as OPCBasicConfig_v3_5_2) + }, + configVersion: this.gatewayVersionStr + } as GatewayConnector; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract.ts new file mode 100644 index 0000000000..9e7be382d2 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract.ts @@ -0,0 +1,81 @@ +/// +/// 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 { Directive } from '@angular/core'; +import { FormControl, FormGroup, ValidationErrors } from '@angular/forms'; +import { takeUntil } from 'rxjs/operators'; +import { isEqual } from '@core/utils'; +import { GatewayConnectorBasicConfigDirective } from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; +import { + ModbusBasicConfig, + ModbusBasicConfig_v3_5_2, +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +@Directive() +export abstract class ModbusBasicConfigDirective + extends GatewayConnectorBasicConfigDirective { + + enableSlaveControl: FormControl = new FormControl(false); + + constructor() { + super(); + + this.enableSlaveControl.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(enable => { + this.updateSlaveEnabling(enable); + this.basicFormGroup.get('slave').updateValueAndValidity({ emitEvent: !!this.onChange }); + }); + } + + override writeValue(basicConfig: BasicConfig & ModbusBasicConfig): void { + super.writeValue(basicConfig); + this.onEnableSlaveControl(basicConfig); + } + + override validate(): ValidationErrors | null { + const { master, slave } = this.basicFormGroup.value; + const isEmpty = !master?.slaves?.length && (isEqual(slave, {}) || !slave); + if (!this.basicFormGroup.valid || isEmpty) { + return { basicFormGroup: { valid: false } }; + } + return null; + } + + protected override initBasicFormGroup(): FormGroup { + return this.fb.group({ + master: [], + slave: [], + }); + } + + protected override onBasicFormGroupChange(value: ModbusBasicConfig_v3_5_2): void { + super.onBasicFormGroupChange(value); + this.basicFormGroup.get('slave').updateValueAndValidity({ emitEvent: !!this.onChange }); + } + + private updateSlaveEnabling(isEnabled: boolean): void { + if (isEnabled) { + this.basicFormGroup.get('slave').enable({ emitEvent: false }); + } else { + this.basicFormGroup.get('slave').disable({ emitEvent: false }); + } + } + + private onEnableSlaveControl(basicConfig: ModbusBasicConfig): void { + this.enableSlaveControl.setValue(!!basicConfig.slave && !isEqual(basicConfig.slave, {})); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component.ts index aa0424da93..21c37ed147 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component.ts @@ -14,28 +14,21 @@ /// limitations under the License. /// -import { ChangeDetectionStrategy, Component, forwardRef, Input, OnDestroy, TemplateRef } from '@angular/core'; +import { ChangeDetectionStrategy, Component, forwardRef } from '@angular/core'; +import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; import { - ControlValueAccessor, - FormBuilder, - FormControl, - FormGroup, - NG_VALIDATORS, - NG_VALUE_ACCESSOR, - UntypedFormControl, - ValidationErrors, - Validator, -} from '@angular/forms'; -import { ModbusBasicConfig } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { SharedModule } from '@shared/shared.module'; + ModbusBasicConfig_v3_5_2, + ModbusMasterConfig, + ModbusSlave +} from '@home/components/widget/lib/gateway/gateway-widget.models'; import { CommonModule } from '@angular/common'; -import { takeUntil } from 'rxjs/operators'; -import { Subject } from 'rxjs'; - -import { EllipsisChipListDirective } from '@shared/directives/ellipsis-chip-list.directive'; +import { SharedModule } from '@shared/shared.module'; import { ModbusSlaveConfigComponent } from '../modbus-slave-config/modbus-slave-config.component'; import { ModbusMasterTableComponent } from '../modbus-master-table/modbus-master-table.component'; -import { isEqual } from '@core/utils'; +import { EllipsisChipListDirective } from '@shared/directives/ellipsis-chip-list.directive'; +import { + ModbusBasicConfigDirective +} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract'; @Component({ selector: 'tb-modbus-basic-config', @@ -63,80 +56,19 @@ import { isEqual } from '@core/utils'; ], styleUrls: ['./modbus-basic-config.component.scss'], }) +export class ModbusBasicConfigComponent extends ModbusBasicConfigDirective { -export class ModbusBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { - - @Input() generalTabContent: TemplateRef; - - basicFormGroup: FormGroup; - enableSlaveControl: FormControl; - - onChange: (value: ModbusBasicConfig) => void; - onTouched: () => void; - - private destroy$ = new Subject(); - - constructor(private fb: FormBuilder) { - this.basicFormGroup = this.fb.group({ - master: [], - slave: [], - }); - this.enableSlaveControl = new FormControl(false); - - this.basicFormGroup.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ master, slave }) => { - this.onChange({ master, slave: slave ?? {} }); - this.onTouched(); - }); - - this.enableSlaveControl.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(enable => { - this.updateSlaveEnabling(enable); - this.basicFormGroup.get('slave').updateValueAndValidity({emitEvent: !!this.onChange}); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - registerOnChange(fn: (value: ModbusBasicConfig) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - writeValue(basicConfig: ModbusBasicConfig): void { - const editedBase = { - slave: basicConfig.slave ?? {}, - master: basicConfig.master ?? {}, + protected override mapConfigToFormValue(config: ModbusBasicConfig_v3_5_2): ModbusBasicConfig_v3_5_2 { + return { + master: config.master ?? {} as ModbusMasterConfig, + slave: config.slave ?? {} as ModbusSlave, }; - - this.basicFormGroup.setValue(editedBase, {emitEvent: false}); - this.enableSlaveControl.setValue(!!basicConfig.slave && !isEqual(basicConfig.slave, {})); - } - - validate(basicFormControl: UntypedFormControl): ValidationErrors | null { - const { master, slave } = basicFormControl.value; - const isEmpty = !master?.slaves?.length && (isEqual(slave, {}) || !slave); - if (!this.basicFormGroup.valid || isEmpty) { - return { - basicFormGroup: {valid: false} - }; - } - return null; } - private updateSlaveEnabling(isEnabled: boolean): void { - if (isEnabled) { - this.basicFormGroup.get('slave').enable({emitEvent: false}); - } else { - this.basicFormGroup.get('slave').disable({emitEvent: false}); - } + protected override getMappedValue(value: ModbusBasicConfig_v3_5_2): ModbusBasicConfig_v3_5_2 { + return { + master: value.master, + slave: value.slave, + }; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component.ts new file mode 100644 index 0000000000..50f7d833fa --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component.ts @@ -0,0 +1,76 @@ +/// +/// 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 } from '@angular/core'; +import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + ModbusBasicConfig_v3_5_2, + ModbusLegacyBasicConfig, ModbusLegacySlave, + ModbusMasterConfig, + ModbusSlave +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { ModbusSlaveConfigComponent } from '../modbus-slave-config/modbus-slave-config.component'; +import { ModbusMasterTableComponent } from '../modbus-master-table/modbus-master-table.component'; +import { EllipsisChipListDirective } from '@shared/directives/ellipsis-chip-list.directive'; +import { ModbusVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/modbus-version-mapping.util'; +import { + ModbusBasicConfigDirective +} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract'; + +@Component({ + selector: 'tb-modbus-legacy-basic-config', + templateUrl: './modbus-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ModbusLegacyBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => ModbusLegacyBasicConfigComponent), + multi: true + } + ], + standalone: true, + imports: [ + CommonModule, + SharedModule, + ModbusSlaveConfigComponent, + ModbusMasterTableComponent, + EllipsisChipListDirective, + ], + styleUrls: ['./modbus-basic-config.component.scss'], +}) +export class ModbusLegacyBasicConfigComponent extends ModbusBasicConfigDirective { + + protected override mapConfigToFormValue(config: ModbusLegacyBasicConfig): ModbusBasicConfig_v3_5_2 { + return { + master: config.master ? ModbusVersionMappingUtil.mapMasterToUpgradedVersion(config.master) : {} as ModbusMasterConfig, + slave: config.slave ? ModbusVersionMappingUtil.mapSlaveToUpgradedVersion(config.slave) : {} as ModbusSlave, + }; + } + + protected override getMappedValue(value: ModbusBasicConfig_v3_5_2): ModbusLegacyBasicConfig { + return { + master: value.master, + slave: value.slave ? ModbusVersionMappingUtil.mapSlaveToDowngradedVersion(value.slave) : {} as ModbusLegacySlave, + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts index aeef688333..ce87d80a75 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts @@ -14,63 +14,33 @@ /// limitations under the License. /// -import { ControlValueAccessor, FormBuilder, FormGroup, ValidationErrors, Validator } from '@angular/forms'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { Directive } from '@angular/core'; +import { FormGroup } from '@angular/forms'; import { MappingType, - MQTTBasicConfig, + MQTTBasicConfig, MQTTBasicConfig_v3_5_2, RequestMappingData, RequestMappingValue, RequestType } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { Directive, OnDestroy } from '@angular/core'; import { isObject } from '@core/utils'; +import { + GatewayConnectorBasicConfigDirective +} from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; @Directive() -export abstract class AbstractMqttBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { +export abstract class MqttBasicConfigDirective + extends GatewayConnectorBasicConfigDirective { - basicFormGroup: FormGroup; MappingType = MappingType; - private destroy$ = new Subject(); - - private onChange: (value: BasicConfig) => void; - private onTouched: () => void; - - constructor(protected fb: FormBuilder) { - this.basicFormGroup = this.fb.group({ + protected override initBasicFormGroup(): FormGroup { + return this.fb.group({ mapping: [], requestsMapping: [], broker: [], workers: [], }); - - this.basicFormGroup.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(value => { - this.onChange(this.getMappedMQTTConfig(value)); - this.onTouched(); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - registerOnChange(fn: (value: BasicConfig) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - validate(): ValidationErrors | null { - return this.basicFormGroup.valid ? null : { - basicFormGroup: {valid: false} - }; } protected getRequestDataArray(value: Record): RequestMappingData[] { @@ -103,6 +73,10 @@ export abstract class AbstractMqttBasicConfigComponent implements C }); } - abstract writeValue(basicConfig: BasicConfig): void; - protected abstract getMappedMQTTConfig(basicConfig: MQTTBasicConfig): BasicConfig; + writeValue(basicConfig: BasicConfig): void { + this.basicFormGroup.setValue(this.mapConfigToFormValue(basicConfig), { emitEvent: false }); + } + + protected abstract override mapConfigToFormValue(config: BasicConfig): MQTTBasicConfig_v3_5_2; + protected abstract override getMappedValue(config: MQTTBasicConfig): BasicConfig; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts index 541866dab8..9af627352a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts @@ -14,16 +14,17 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, TemplateRef, ChangeDetectionStrategy } from '@angular/core'; +import { Component, forwardRef, ChangeDetectionStrategy } from '@angular/core'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; import { + BrokerConfig, MQTTBasicConfig_v3_5_2, RequestMappingData, RequestMappingValue, - RequestType + RequestType, WorkersConfig } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { - AbstractMqttBasicConfigComponent + MqttBasicConfigDirective } from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract'; import { isDefinedAndNotNull } from '@core/utils'; import { CommonModule } from '@angular/common'; @@ -33,7 +34,7 @@ import { } from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; import { WorkersConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component'; import { BrokerConfigControlComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; @@ -68,27 +69,22 @@ import { MappingTableComponent, ], }) -export class MqttBasicConfigComponent extends AbstractMqttBasicConfigComponent { +export class MqttBasicConfigComponent extends MqttBasicConfigDirective { - @Input() - generalTabContent: TemplateRef; - - writeValue(basicConfig: MQTTBasicConfig_v3_5_2): void { + protected override mapConfigToFormValue(basicConfig: MQTTBasicConfig_v3_5_2): MQTTBasicConfig_v3_5_2 { const { broker, mapping = [], requestsMapping } = basicConfig; - const editedBase = { + return{ workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { maxNumberOfWorkers: broker.maxNumberOfWorkers, maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, - } : {}, + } : {} as WorkersConfig, mapping: mapping ?? [], - broker: broker ?? {}, + broker: broker ?? {} as BrokerConfig, requestsMapping: this.getRequestDataArray(requestsMapping as Record), }; - - this.basicFormGroup.setValue(editedBase, {emitEvent: false}); } - protected getMappedMQTTConfig(basicConfig: MQTTBasicConfig_v3_5_2): MQTTBasicConfig_v3_5_2 { + protected override getMappedValue(basicConfig: MQTTBasicConfig_v3_5_2): MQTTBasicConfig_v3_5_2 { let { broker, workers, mapping, requestsMapping } = basicConfig || {}; if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts index 2ca5eba000..e4577c653e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts @@ -14,18 +14,19 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, TemplateRef, ChangeDetectionStrategy } from '@angular/core'; +import { Component, forwardRef, ChangeDetectionStrategy } from '@angular/core'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; import { + BrokerConfig, MQTTBasicConfig_v3_5_2, MQTTLegacyBasicConfig, RequestMappingData, RequestMappingValue, - RequestType + RequestType, WorkersConfig } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { MqttVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/mqtt-version-mapping.util'; import { - AbstractMqttBasicConfigComponent + MqttBasicConfigDirective } from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract'; import { isDefinedAndNotNull } from '@core/utils'; import { CommonModule } from '@angular/common'; @@ -35,7 +36,7 @@ import { } from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; import { WorkersConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component'; import { BrokerConfigControlComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; @@ -70,12 +71,9 @@ import { MappingTableComponent, ], }) -export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigComponent { +export class MqttLegacyBasicConfigComponent extends MqttBasicConfigDirective { - @Input() - generalTabContent: TemplateRef; - - writeValue(basicConfig: MQTTLegacyBasicConfig): void { + protected override mapConfigToFormValue(config: MQTTLegacyBasicConfig): MQTTBasicConfig_v3_5_2 { const { broker, mapping = [], @@ -84,7 +82,7 @@ export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigCompo attributeRequests = [], attributeUpdates = [], serverSideRpc = [] - } = basicConfig; + } = config as MQTTLegacyBasicConfig; const updatedRequestMapping = MqttVersionMappingUtil.mapRequestsToUpgradedVersion({ connectRequests, disconnectRequests, @@ -92,20 +90,18 @@ export class MqttLegacyBasicConfigComponent extends AbstractMqttBasicConfigCompo attributeUpdates, serverSideRpc }); - const editedBase = { + return { workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { maxNumberOfWorkers: broker.maxNumberOfWorkers, maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, - } : {}, + } : {} as WorkersConfig, mapping: MqttVersionMappingUtil.mapMappingToUpgradedVersion(mapping) || [], - broker: broker || {}, + broker: broker || {} as BrokerConfig, requestsMapping: this.getRequestDataArray(updatedRequestMapping), }; - - this.basicFormGroup.setValue(editedBase, {emitEvent: false}); } - protected getMappedMQTTConfig(basicConfig: MQTTBasicConfig_v3_5_2): MQTTLegacyBasicConfig { + protected override getMappedValue(basicConfig: MQTTBasicConfig_v3_5_2): MQTTLegacyBasicConfig { let { broker, workers, mapping, requestsMapping } = basicConfig || {}; if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts similarity index 51% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts index b6cf4a4081..1a45e74c7a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts @@ -14,34 +14,25 @@ /// limitations under the License. /// -import { ChangeDetectionStrategy, Component, forwardRef, Input, OnDestroy, TemplateRef } from '@angular/core'; +import { ChangeDetectionStrategy, Component, forwardRef } from '@angular/core'; +import { FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; import { - ControlValueAccessor, - FormBuilder, - FormGroup, - NG_VALIDATORS, - NG_VALUE_ACCESSOR, - ValidationErrors, - Validator, -} from '@angular/forms'; -import { - ConnectorType, MappingType, - OPCBasicConfig, + OPCBasicConfig_v3_5_2, + ServerConfig } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { SharedModule } from '@shared/shared.module'; import { CommonModule } from '@angular/common'; -import { takeUntil } from 'rxjs/operators'; -import { Subject } from 'rxjs'; +import { SharedModule } from '@shared/shared.module'; +import { MappingTableComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; import { SecurityConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; -import { - MappingTableComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; import { OpcServerConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component'; +import { + GatewayConnectorBasicConfigDirective +} from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; @Component({ selector: 'tb-opc-ua-basic-config', @@ -69,58 +60,28 @@ import { ], styleUrls: ['./opc-ua-basic-config.component.scss'] }) - -export class OpcUaBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { - @Input() generalTabContent: TemplateRef; +export class OpcUaBasicConfigComponent extends GatewayConnectorBasicConfigDirective { mappingTypes = MappingType; - basicFormGroup: FormGroup; - - onChange!: (value: string) => void; - onTouched!: () => void; - - protected readonly connectorType = ConnectorType; - private destroy$ = new Subject(); - constructor(private fb: FormBuilder) { - this.basicFormGroup = this.fb.group({ + protected override initBasicFormGroup(): FormGroup { + return this.fb.group({ mapping: [], server: [], }); - - this.basicFormGroup.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(value => { - this.onChange(value); - this.onTouched(); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - registerOnChange(fn: (value: string) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; } - writeValue(basicConfig: OPCBasicConfig): void { - const editedBase = { - server: basicConfig.server || {}, - mapping: basicConfig.mapping || [], + protected override mapConfigToFormValue(config: OPCBasicConfig_v3_5_2): OPCBasicConfig_v3_5_2 { + return { + server: config.server ?? {} as ServerConfig, + mapping: config.mapping ?? [], }; - - this.basicFormGroup.setValue(editedBase, {emitEvent: false}); } - validate(): ValidationErrors | null { - return this.basicFormGroup.valid ? null : { - basicFormGroup: {valid: false} + protected override getMappedValue(value: OPCBasicConfig_v3_5_2): OPCBasicConfig_v3_5_2 { + return { + server: value.server, + mapping: value.mapping, }; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts new file mode 100644 index 0000000000..12e05205a2 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts @@ -0,0 +1,87 @@ +/// +/// 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 } from '@angular/core'; +import { FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + MappingType, + OPCBasicConfig_v3_5_2, + OPCLegacyBasicConfig, ServerConfig, +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { MappingTableComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; +import { + SecurityConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; +import { + OpcServerConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component'; +import { + GatewayConnectorBasicConfigDirective +} from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; +import { OpcVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/opc-version-mapping.util'; + +@Component({ + selector: 'tb-opc-ua-legacy-basic-config', + templateUrl: './opc-ua-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => OpcUaLegacyBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => OpcUaLegacyBasicConfigComponent), + multi: true + } + ], + standalone: true, + imports: [ + CommonModule, + SharedModule, + SecurityConfigComponent, + MappingTableComponent, + OpcServerConfigComponent, + ], + styleUrls: ['./opc-ua-basic-config.component.scss'] +}) +export class OpcUaLegacyBasicConfigComponent extends GatewayConnectorBasicConfigDirective { + + mappingTypes = MappingType; + + protected override initBasicFormGroup(): FormGroup { + return this.fb.group({ + mapping: [], + server: [], + }); + } + + protected override mapConfigToFormValue(config: OPCLegacyBasicConfig): OPCBasicConfig_v3_5_2 { + return { + server: config.server ? OpcVersionMappingUtil.mapServerToUpgradedVersion(config.server) : {} as ServerConfig, + mapping: config.server?.mapping ? OpcVersionMappingUtil.mapMappingToUpgradedVersion(config.server.mapping) : [], + }; + } + + protected override getMappedValue(value: OPCBasicConfig_v3_5_2): OPCLegacyBasicConfig { + return { + server: OpcVersionMappingUtil.mapServerToDowngradedVersion(value), + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html index f0459496df..7c495d34f1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html @@ -186,14 +186,26 @@ - - - - + + + + + + + + + + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index f7acac12e6..8a0e4005fd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -199,9 +199,9 @@ export type ConnectorMappingFormValue = DeviceConnectorMapping | RequestMappingF export type ConnectorBaseConfig = ConnectorBaseConfig_v_3_5_2 | ConnectorLegacyConfig; -export type ConnectorLegacyConfig = ConnectorBaseInfo | MQTTLegacyBasicConfig | OPCBasicConfig | ModbusBasicConfig; +export type ConnectorLegacyConfig = ConnectorBaseInfo | MQTTLegacyBasicConfig | OPCLegacyBasicConfig | ModbusBasicConfig; -export type ConnectorBaseConfig_v_3_5_2 = ConnectorBaseInfo | MQTTBasicConfig_v3_5_2; +export type ConnectorBaseConfig_v_3_5_2 = ConnectorBaseInfo | MQTTBasicConfig_v3_5_2 | OPCBasicConfig_v3_5_2; export interface ConnectorBaseInfo { name: string; @@ -230,16 +230,34 @@ export interface MQTTLegacyBasicConfig { serverSideRpc: LegacyRequestMappingData[]; } -export interface OPCBasicConfig { +export type OPCBasicConfig = OPCBasicConfig_v3_5_2 | OPCLegacyBasicConfig; + +export interface OPCBasicConfig_v3_5_2 { mapping: DeviceConnectorMapping[]; server: ServerConfig; } -export interface ModbusBasicConfig { +export interface OPCLegacyBasicConfig { + server: LegacyServerConfig; +} + +export interface LegacyServerConfig extends Omit { + mapping: LegacyDeviceConnectorMapping[]; + disableSubscriptions: boolean; +} + +export type ModbusBasicConfig = ModbusBasicConfig_v3_5_2 | ModbusLegacyBasicConfig; + +export interface ModbusBasicConfig_v3_5_2 { master: ModbusMasterConfig; slave: ModbusSlave; } +export interface ModbusLegacyBasicConfig { + master: ModbusMasterConfig; + slave: ModbusLegacySlave; +} + export interface WorkersConfig { maxNumberOfWorkers: number; maxMessageNumberPerWorker: number; @@ -258,12 +276,22 @@ export interface Attribute { value: string; } +export interface LegacyAttribute { + key: string; + path: string; +} + export interface Timeseries { key: string; type: string; value: string; } +export interface LegacyTimeseries { + key: string; + path: string; +} + interface RpcArgument { type: string; value: number; @@ -274,12 +302,22 @@ export interface RpcMethod { arguments: RpcArgument[]; } +export interface LegacyRpcMethod { + method: string; + arguments: unknown[]; +} + export interface AttributesUpdate { key: string; type: string; value: string; } +export interface LegacyDeviceAttributeUpdate { + attributeOnThingsBoard: string; + attributeOnDevice: string; +} + export interface Converter { type: ConvertorType; deviceInfo?: ConnectorDeviceInfo; @@ -333,6 +371,15 @@ export interface DeviceConnectorMapping { attributes_updates?: AttributesUpdate[]; } +export interface LegacyDeviceConnectorMapping { + deviceNamePattern: string; + deviceTypePattern: string; + attributes?: LegacyAttribute[]; + timeseries?: LegacyTimeseries[]; + rpc_methods?: LegacyRpcMethod[]; + attributes_updates?: LegacyDeviceAttributeUpdate[]; +} + export enum ConnectorType { MQTT = 'mqtt', MODBUS = 'modbus', @@ -1069,7 +1116,7 @@ export interface SlaveConfig { pollPeriod: number; unitId: number; deviceName: string; - deviceType: string; + deviceType?: string; sendDataOnlyOnChange: boolean; connectAttemptTimeMs: number; connectAttemptCount: number; @@ -1121,8 +1168,19 @@ export interface ModbusSlave { security: ModbusSecurity; } +export interface ModbusLegacySlave extends Omit { + values: ModbusLegacyRegisterValues; +} + export type ModbusValuesState = ModbusRegisterValues | ModbusValues; +export interface ModbusLegacyRegisterValues { + holding_registers: ModbusValues[]; + coils_initializer: ModbusValues[]; + input_registers: ModbusValues[]; + discrete_inputs: ModbusValues[]; +} + export interface ModbusRegisterValues { holding_registers: ModbusValues; coils_initializer: ModbusValues; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts index 12f3a7c439..90c89ea316 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts @@ -17,9 +17,13 @@ import { ConnectorType, GatewayConnector, + ModbusBasicConfig, MQTTBasicConfig, + OPCBasicConfig, } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { MqttVersionProcessor } from '@home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract'; +import { OpcVersionProcessor } from '@home/components/widget/lib/gateway/abstract/opc-version-processor.abstract'; +import { ModbusVersionProcessor } from '@home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract'; export abstract class GatewayConnectorVersionMappingUtil { @@ -27,6 +31,10 @@ export abstract class GatewayConnectorVersionMappingUtil { switch(connector.type) { case ConnectorType.MQTT: return new MqttVersionProcessor(gatewayVersion, connector as GatewayConnector).getProcessedByVersion(); + case ConnectorType.OPCUA: + return new OpcVersionProcessor(gatewayVersion, connector as GatewayConnector).getProcessedByVersion(); + case ConnectorType.MODBUS: + return new ModbusVersionProcessor(gatewayVersion, connector as GatewayConnector).getProcessedByVersion(); default: return connector; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts new file mode 100644 index 0000000000..b65d3e7449 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts @@ -0,0 +1,77 @@ +/// +/// 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 { + ModbusDataType, + ModbusLegacyRegisterValues, + ModbusLegacySlave, + ModbusMasterConfig, + ModbusRegisterValues, + ModbusSlave, ModbusValue, ModbusValues, + SlaveConfig +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +export class ModbusVersionMappingUtil { + static mapMasterToUpgradedVersion(master: ModbusMasterConfig): ModbusMasterConfig { + return { + slaves: master.slaves.map((slave: SlaveConfig) => ({ + ...slave, + deviceType: slave.deviceType ?? 'default', + })) + }; + } + + static mapSlaveToDowngradedVersion(slave: ModbusSlave): ModbusLegacySlave { + const values = Object.keys(slave.values).reduce((acc, valueKey) => { + acc = { + ...acc, + [valueKey]: [ + slave.values[valueKey] + ] + }; + return acc; + }, {} as ModbusLegacyRegisterValues); + return { + ...slave, + values + }; + } + + static mapSlaveToUpgradedVersion(slave: ModbusLegacySlave): ModbusSlave { + const values = Object.keys(slave.values).reduce((acc, valueKey) => { + acc = { + ...acc, + [valueKey]: this.mapValuesToUpgradedVersion(slave.values[valueKey][0]) + }; + return acc; + }, {} as ModbusRegisterValues); + return { + ...slave, + values + }; + } + + private static mapValuesToUpgradedVersion(registerValues: ModbusValues): ModbusValues { + return Object.keys(registerValues).reduce((acc, valueKey) => { + acc = { + ...acc, + [valueKey]: registerValues[valueKey].map((value: ModbusValue) => + ({ ...value, type: (value.type as string) === 'int' ? ModbusDataType.INT16 : value.type })) + }; + return acc; + }, {} as ModbusValues); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts new file mode 100644 index 0000000000..56eea67ddf --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts @@ -0,0 +1,113 @@ +/// +/// 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 { + DeviceConnectorMapping, + LegacyDeviceConnectorMapping, + LegacyServerConfig, + OPCBasicConfig_v3_5_2, + ServerConfig +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +export class OpcVersionMappingUtil { + static mapServerToUpgradedVersion(server: LegacyServerConfig): ServerConfig { + const { mapping, disableSubscriptions, ...restServer } = server; + return { + ...restServer, + enableSubscriptions: !disableSubscriptions, + }; + } + + static mapServerToDowngradedVersion(config: OPCBasicConfig_v3_5_2): LegacyServerConfig { + const { mapping, server } = config; + const { enableSubscriptions, ...restServer } = server; + return { + ...restServer, + mapping: mapping ? this.mapMappingToDowngradedVersion(mapping) : [], + disableSubscriptions: !enableSubscriptions, + }; + } + + static mapMappingToUpgradedVersion(mapping: LegacyDeviceConnectorMapping[]): DeviceConnectorMapping[] { + return mapping?.map((oldMapping: any) => ({ + ...oldMapping, + deviceNodeSource: 'path', + deviceInfo: { + deviceNameExpression: oldMapping.deviceNamePattern, + deviceNameExpressionSource: 'path', + deviceProfileExpression: oldMapping.deviceTypePattern ?? 'default', + deviceProfileExpressionSource: 'path', + }, + attributes: oldMapping.attributes.map(attribute => ({ + key: attribute.key, + type: 'path', + value: attribute.path, + })), + attributes_updates: oldMapping.attributes_updates.map(attributeUpdate => ({ + key: attributeUpdate.attributeOnThingsBoard, + type: 'path', + value: attributeUpdate.attributeOnDevice, + })), + timeseries: oldMapping.timeseries.map(timeseries => ({ + key: timeseries.key, + type: 'path', + value: timeseries.path, + })), + rpc_methods: oldMapping.rpc_methods.map(rpcMethod => ({ + method: rpcMethod.method, + arguments: rpcMethod.arguments.map(arg => ({ + value: arg, + type: this.getArgumentType(arg), + })) + })) + })); + } + + static mapMappingToDowngradedVersion(mapping: DeviceConnectorMapping[]): LegacyDeviceConnectorMapping[] { + return mapping?.map((newMapping: DeviceConnectorMapping) => ({ + ...newMapping, + deviceNamePattern: newMapping.deviceInfo.deviceNameExpression, + deviceTypePattern: newMapping.deviceInfo.deviceProfileExpression, + attributes: newMapping.attributes.map((attribute: any) => ({ + key: attribute.key, + path: attribute.value, + })), + attributes_updates: newMapping.attributes_updates.map((attributeUpdate: any) => ({ + attributeOnThingsBoard: attributeUpdate.key, + attributeOnDevice: attributeUpdate.value, + })), + timeseries: newMapping.timeseries.map((timeseries: any) => ({ + key: timeseries.key, + path: timeseries.value, + })), + rpc_methods: newMapping.rpc_methods.map((rpcMethod: any) => ({ + method: rpcMethod.method, + arguments: rpcMethod.arguments.map((arg: any) => arg.value) + })) + })); + } + + private static getArgumentType(arg: unknown): string { + switch (typeof arg) { + case 'boolean': + return 'boolean'; + case 'number': + return Number.isInteger(arg) ? 'integer' : 'float'; + default: + return 'string'; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts index b3663c9b48..f241bc91d0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts @@ -116,10 +116,10 @@ import { } from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; import { WorkersConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component'; import { OpcServerConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component'; import { MqttBasicConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component'; @@ -128,7 +128,7 @@ import { } from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; import { OpcUaBasicConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component'; import { ModbusBasicConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component'; @@ -154,6 +154,12 @@ import { import { GatewayAdvancedConfigurationComponent } from '@home/components/widget/lib/gateway/configuration/advanced/gateway-advanced-configuration.component'; +import { + OpcUaLegacyBasicConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component'; +import { + ModbusLegacyBasicConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component'; @NgModule({ declarations: [ @@ -245,6 +251,8 @@ import { MqttLegacyBasicConfigComponent, GatewayBasicConfigurationComponent, GatewayAdvancedConfigurationComponent, + OpcUaLegacyBasicConfigComponent, + ModbusLegacyBasicConfigComponent, ], exports: [ EntitiesTableWidgetComponent, diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json b/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json index 441f63ab5f..96fb59dcf5 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json @@ -1,246 +1,474 @@ { - "master": { - "slaves": [ - { - "name": "Slave 1", - "host": "127.0.0.1", - "port": 5021, - "type": "tcp", - "method": "socket", - "timeout": 35, - "byteOrder": "LITTLE", - "wordOrder": "LITTLE", - "retries": true, - "retryOnEmpty": true, - "retryOnInvalid": true, - "pollPeriod": 5000, - "unitId": 1, - "deviceName": "Temp Sensor", - "deviceType": "default", - "sendDataOnlyOnChange": true, - "connectAttemptTimeMs": 5000, - "connectAttemptCount": 5, - "waitAfterFailedAttemptsMs": 300000, - "attributes": [ - { - "tag": "string_read", - "type": "string", - "functionCode": 4, - "objectsCount": 4, - "address": 1 - }, - { - "tag": "bits_read", - "type": "bits", - "functionCode": 4, - "objectsCount": 1, - "address": 5 - }, - { - "tag": "8int_read", - "type": "8int", - "functionCode": 4, - "objectsCount": 1, - "address": 6 - }, - { - "tag": "16int_read", - "type": "16int", - "functionCode": 4, - "objectsCount": 1, - "address": 7 - }, - { - "tag": "32int_read_divider", - "type": "32int", - "functionCode": 4, - "objectsCount": 2, - "address": 8, - "divider": 10 - }, - { - "tag": "8int_read_multiplier", - "type": "8int", - "functionCode": 4, - "objectsCount": 1, - "address": 10, - "multiplier": 10 - }, - { - "tag": "32int_read", - "type": "32int", - "functionCode": 4, - "objectsCount": 2, - "address": 11 - }, - { - "tag": "64int_read", - "type": "64int", - "functionCode": 4, - "objectsCount": 4, - "address": 13 - } - ], - "timeseries": [ - { - "tag": "8uint_read", - "type": "8uint", - "functionCode": 4, - "objectsCount": 1, - "address": 17 - }, - { - "tag": "16uint_read", - "type": "16uint", - "functionCode": 4, - "objectsCount": 2, - "address": 18 - }, - { - "tag": "32uint_read", - "type": "32uint", - "functionCode": 4, - "objectsCount": 4, - "address": 20 - }, - { - "tag": "64uint_read", - "type": "64uint", - "functionCode": 4, - "objectsCount": 1, - "address": 24 - }, - { - "tag": "16float_read", - "type": "16float", - "functionCode": 4, - "objectsCount": 1, - "address": 25 - }, - { - "tag": "32float_read", - "type": "32float", - "functionCode": 4, - "objectsCount": 2, - "address": 26 - }, - { - "tag": "64float_read", - "type": "64float", - "functionCode": 4, - "objectsCount": 4, - "address": 28 - } - ], - "attributeUpdates": [ - { - "tag": "shared_attribute_write", - "type": "32int", - "functionCode": 6, - "objectsCount": 2, - "address": 29 - } - ], - "rpc": [ - { - "tag": "setValue", - "type": "bits", - "functionCode": 5, - "objectsCount": 1, - "address": 31 - }, - { - "tag": "getValue", - "type": "bits", - "functionCode": 1, - "objectsCount": 1, - "address": 31 - }, - { - "tag": "setCPUFanSpeed", - "type": "32int", - "functionCode": 16, - "objectsCount": 2, - "address": 33 - }, - { - "tag": "getCPULoad", - "type": "32int", - "functionCode": 4, - "objectsCount": 2, - "address": 35 - } - ] - } - ] - }, - "slave": { - "type": "tcp", - "host": "127.0.0.1", - "port": 5026, - "method": "socket", - "deviceName": "Modbus Slave Example", - "deviceType": "default", - "pollPeriod": 5000, - "sendDataToThingsBoard": false, - "byteOrder": "LITTLE", - "wordOrder": "LITTLE", - "unitId": 0, - "values": { - "holding_registers": { - "attributes": [ + "3.5.1": { + "master": { + "slaves": [ { - "address": 1, - "type": "string", - "tag": "sm", - "objectsCount": 1, - "value": "ON" + "name": "Slave 1", + "host": "127.0.0.1", + "port": 5021, + "type": "tcp", + "method": "socket", + "timeout": 35, + "byteOrder": "LITTLE", + "wordOrder": "LITTLE", + "retries": true, + "retryOnEmpty": true, + "retryOnInvalid": true, + "pollPeriod": 5000, + "unitId": 1, + "deviceName": "Temp Sensor", + "deviceType": "default", + "sendDataOnlyOnChange": true, + "connectAttemptTimeMs": 5000, + "connectAttemptCount": 5, + "waitAfterFailedAttemptsMs": 300000, + "attributes": [ + { + "tag": "string_read", + "type": "string", + "functionCode": 4, + "objectsCount": 4, + "address": 1 + }, + { + "tag": "bits_read", + "type": "bits", + "functionCode": 4, + "objectsCount": 1, + "address": 5 + }, + { + "tag": "8int_read", + "type": "8int", + "functionCode": 4, + "objectsCount": 1, + "address": 6 + }, + { + "tag": "16int_read", + "type": "16int", + "functionCode": 4, + "objectsCount": 1, + "address": 7 + }, + { + "tag": "32int_read_divider", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 8, + "divider": 10 + }, + { + "tag": "8int_read_multiplier", + "type": "8int", + "functionCode": 4, + "objectsCount": 1, + "address": 10, + "multiplier": 10 + }, + { + "tag": "32int_read", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 11 + }, + { + "tag": "64int_read", + "type": "64int", + "functionCode": 4, + "objectsCount": 4, + "address": 13 + } + ], + "timeseries": [ + { + "tag": "8uint_read", + "type": "8uint", + "functionCode": 4, + "objectsCount": 1, + "address": 17 + }, + { + "tag": "16uint_read", + "type": "16uint", + "functionCode": 4, + "objectsCount": 2, + "address": 18 + }, + { + "tag": "32uint_read", + "type": "32uint", + "functionCode": 4, + "objectsCount": 4, + "address": 20 + }, + { + "tag": "64uint_read", + "type": "64uint", + "functionCode": 4, + "objectsCount": 1, + "address": 24 + }, + { + "tag": "16float_read", + "type": "16float", + "functionCode": 4, + "objectsCount": 1, + "address": 25 + }, + { + "tag": "32float_read", + "type": "32float", + "functionCode": 4, + "objectsCount": 2, + "address": 26 + }, + { + "tag": "64float_read", + "type": "64float", + "functionCode": 4, + "objectsCount": 4, + "address": 28 + } + ], + "attributeUpdates": [ + { + "tag": "shared_attribute_write", + "type": "32int", + "functionCode": 6, + "objectsCount": 2, + "address": 29 + } + ], + "rpc": [ + { + "tag": "setValue", + "type": "bits", + "functionCode": 5, + "objectsCount": 1, + "address": 31 + }, + { + "tag": "getValue", + "type": "bits", + "functionCode": 1, + "objectsCount": 1, + "address": 31 + }, + { + "tag": "setCPUFanSpeed", + "type": "32int", + "functionCode": 16, + "objectsCount": 2, + "address": 33 + }, + { + "tag": "getCPULoad", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 35 + } + ] } - ], - "timeseries": [ - { - "address": 2, - "type": "8int", - "tag": "smm", - "objectsCount": 1, - "value": "12334" - } - ], - "attributeUpdates": [ - { - "tag": "shared_attribute_write", - "type": "32int", - "functionCode": 6, - "objectsCount": 2, - "address": 29, - "value": 1243 + ] + }, + "slave": { + "type": "tcp", + "host": "127.0.0.1", + "port": 5026, + "method": "socket", + "deviceName": "Modbus Slave Example", + "deviceType": "default", + "pollPeriod": 5000, + "sendDataToThingsBoard": false, + "byteOrder": "LITTLE", + "wordOrder": "LITTLE", + "unitId": 0, + "values": { + "holding_registers": { + "attributes": [ + { + "address": 1, + "type": "string", + "tag": "sm", + "objectsCount": 1, + "value": "ON" + } + ], + "timeseries": [ + { + "address": 2, + "type": "8int", + "tag": "smm", + "objectsCount": 1, + "value": "12334" + } + ], + "attributeUpdates": [ + { + "tag": "shared_attribute_write", + "type": "32int", + "functionCode": 6, + "objectsCount": 2, + "address": 29, + "value": 1243 + } + ], + "rpc": [ + { + "tag": "setValue", + "type": "bits", + "functionCode": 5, + "objectsCount": 1, + "address": 31, + "value": 22 + } + ] + }, + "coils_initializer": { + "attributes": [ + { + "address": 5, + "type": "string", + "tag": "sm", + "objectsCount": 1, + "value": "12" + } + ], + "timeseries": [], + "attributeUpdates": [], + "rpc": [] } - ], - "rpc": [ + } + } + }, + "legacy": { + "master": { + "slaves": [ { - "tag": "setValue", - "type": "bits", - "functionCode": 5, - "objectsCount": 1, - "address": 31, - "value": 22 + "host": "127.0.0.1", + "port": 5021, + "type": "tcp", + "method": "socket", + "timeout": 35, + "byteOrder": "LITTLE", + "wordOrder": "LITTLE", + "retries": true, + "retryOnEmpty": true, + "retryOnInvalid": true, + "pollPeriod": 5000, + "unitId": 1, + "deviceName": "Temp Sensor", + "sendDataOnlyOnChange": true, + "connectAttemptTimeMs": 5000, + "connectAttemptCount": 5, + "waitAfterFailedAttemptsMs": 300000, + "attributes": [ + { + "tag": "string_read", + "type": "string", + "functionCode": 4, + "objectsCount": 4, + "address": 1 + }, + { + "tag": "bits_read", + "type": "bits", + "functionCode": 4, + "objectsCount": 1, + "address": 5 + }, + { + "tag": "16int_read", + "type": "16int", + "functionCode": 4, + "objectsCount": 1, + "address": 7 + }, + { + "tag": "32int_read_divider", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 8, + "divider": 10 + }, + { + "tag": "32int_read", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 11 + }, + { + "tag": "64int_read", + "type": "64int", + "functionCode": 4, + "objectsCount": 4, + "address": 13 + } + ], + "timeseries": [ + { + "tag": "16uint_read", + "type": "16uint", + "functionCode": 4, + "objectsCount": 2, + "address": 18 + }, + { + "tag": "32uint_read", + "type": "32uint", + "functionCode": 4, + "objectsCount": 4, + "address": 20 + }, + { + "tag": "64uint_read", + "type": "64uint", + "functionCode": 4, + "objectsCount": 1, + "address": 24 + }, + { + "tag": "16float_read", + "type": "16float", + "functionCode": 4, + "objectsCount": 1, + "address": 25 + }, + { + "tag": "32float_read", + "type": "32float", + "functionCode": 4, + "objectsCount": 2, + "address": 26 + }, + { + "tag": "64float_read", + "type": "64float", + "functionCode": 4, + "objectsCount": 4, + "address": 28 + } + ], + "attributeUpdates": [ + { + "tag": "shared_attribute_write", + "type": "32int", + "functionCode": 6, + "objectsCount": 2, + "address": 29 + } + ], + "rpc": [ + { + "tag": "setValue", + "type": "bits", + "functionCode": 5, + "objectsCount": 1, + "address": 31 + }, + { + "tag": "getValue", + "type": "bits", + "functionCode": 1, + "objectsCount": 1, + "address": 31 + }, + { + "tag": "setCPUFanSpeed", + "type": "32int", + "functionCode": 16, + "objectsCount": 2, + "address": 33 + }, + { + "tag": "getCPULoad", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 35 + } + ] } ] }, - "coils_initializer": { - "attributes": [ - { - "address": 5, - "type": "string", - "tag": "sm", - "objectsCount": 1, - "value": "12" - } - ], - "timeseries": [], - "attributeUpdates": [], - "rpc": [] + "slave": { + "type": "tcp", + "host": "127.0.0.1", + "port": 5026, + "method": "socket", + "deviceName": "Modbus Slave Example", + "deviceType": "default", + "pollPeriod": 5000, + "sendDataToThingsBoard": false, + "byteOrder": "LITTLE", + "wordOrder": "LITTLE", + "unitId": 0, + "values": { + "holding_registers": [ + { + "attributes": [ + { + "address": 1, + "type": "string", + "tag": "sm", + "objectsCount": 1, + "value": "ON" + } + ], + "timeseries": [ + { + "address": 2, + "type": "int", + "tag": "smm", + "objectsCount": 1, + "value": "12334" + } + ], + "attributeUpdates": [ + { + "tag": "shared_attribute_write", + "type": "32int", + "functionCode": 6, + "objectsCount": 2, + "address": 29, + "value": 1243 + } + ], + "rpc": [ + { + "tag": "setValue", + "type": "bits", + "functionCode": 5, + "objectsCount": 1, + "address": 31, + "value": 22 + } + ] + } + ], + "coils_initializer": [ + { + "attributes": [ + { + "address": 5, + "type": "string", + "tag": "sm", + "objectsCount": 1, + "value": "12" + } + ], + "timeseries": [], + "attributeUpdates": [], + "rpc": [] + } + ] + } } } - } } diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json b/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json index 7ff5b78433..eb33f9235e 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json @@ -1,66 +1,120 @@ { - "server": { - "url": "localhost:4840/freeopcua/server/", - "timeoutInMillis": 5000, - "scanPeriodInMillis": 3600000, - "pollPeriodInMillis": 5000, - "enableSubscriptions": true, - "subCheckPeriodInMillis": 100, - "showMap": false, - "security": "Basic128Rsa15", - "identity": { - "type": "anonymous" - } - }, - "mapping": [{ - "deviceNodePattern": "Root\\.Objects\\.Device1", - "deviceNodeSource": "path", - "deviceInfo": { - "deviceNameExpression": "Device ${Root\\.Objects\\.Device1\\.serialNumber}", - "deviceNameExpressionSource": "path", - "deviceProfileExpression": "Device", - "deviceProfileExpressionSource": "constant" + "3.5.1": { + "server": { + "url": "localhost:4840/freeopcua/server/", + "timeoutInMillis": 5000, + "scanPeriodInMillis": 3600000, + "pollPeriodInMillis": 5000, + "enableSubscriptions": true, + "subCheckPeriodInMillis": 100, + "showMap": false, + "security": "Basic128Rsa15", + "identity": { + "type": "anonymous" + } + }, + "mapping": [{ + "deviceNodePattern": "Root\\.Objects\\.Device1", + "deviceNodeSource": "path", + "deviceInfo": { + "deviceNameExpression": "Device ${Root\\.Objects\\.Device1\\.serialNumber}", + "deviceNameExpressionSource": "path", + "deviceProfileExpression": "Device", + "deviceProfileExpressionSource": "constant" + }, + "attributes": [ + { + "key": "temperature °C", + "type": "path", + "value": "${ns=2;i=5}" + } + ], + "timeseries": [ + { + "key": "humidity", + "type": "path", + "value": "${Root\\.Objects\\.Device1\\.TemperatureAndHumiditySensor\\.Humidity}" + }, + { + "key": "batteryLevel", + "type": "path", + "value": "${Battery\\.batteryLevel}" + } + ], + "rpc_methods": [ + { + "method": "multiply", + "arguments": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 4 + } + ] + } + ], + "attributes_updates": [ + { + "key": "deviceName", + "type": "path", + "value": "Root\\.Objects\\.Device1\\.serialNumber" + } + ] + }] }, - "attributes": [ - { - "key": "temperature °C", - "type": "path", - "value": "${ns=2;i=5}" - } - ], - "timeseries": [ - { - "key": "humidity", - "type": "path", - "value": "${Root\\.Objects\\.Device1\\.TemperatureAndHumiditySensor\\.Humidity}" - }, - { - "key": "batteryLevel", - "type": "path", - "value": "${Battery\\.batteryLevel}" - } - ], - "rpc_methods": [ - { - "method": "multiply", - "arguments": [ - { - "type": "integer", - "value": 2 - }, - { - "type": "integer", - "value": 4 - } - ] - } - ], - "attributes_updates": [ - { - "key": "deviceName", - "type": "path", - "value": "Root\\.Objects\\.Device1\\.serialNumber" - } - ] - }] + "legacy": { + "server": { + "name": "OPC-UA Default Server", + "url": "localhost:4840/freeopcua/server/", + "timeoutInMillis": 5000, + "scanPeriodInMillis": 5000, + "disableSubscriptions": false, + "subCheckPeriodInMillis": 100, + "showMap": false, + "security": "Basic128Rsa15", + "identity": { + "type": "anonymous" + }, + "mapping": [ + { + "deviceNodePattern": "Root\\.Objects\\.Device1", + "deviceNamePattern": "Device ${Root\\.Objects\\.Device1\\.serialNumber}", + "attributes": [ + { + "key": "temperature °C", + "path": "${ns=2;i=5}" + } + ], + "timeseries": [ + { + "key": "humidity", + "path": "${Root\\.Objects\\.Device1\\.TemperatureAndHumiditySensor\\.Humidity}" + }, + { + "key": "batteryLevel", + "path": "${Battery\\.batteryLevel}" + } + ], + "rpc_methods": [ + { + "method": "multiply", + "arguments": [ + 2, + 4 + ] + } + ], + "attributes_updates": [ + { + "attributeOnThingsBoard": "deviceName", + "attributeOnDevice": "Root\\.Objects\\.Device1\\.serialNumber" + } + ] + } + ] + } + } } From 5329fe3aa18a8ca386f0114171242e1ec147afde Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 10 Sep 2024 19:18:21 +0300 Subject: [PATCH 12/14] [4114] Adjusted OPC mapping --- .../lib/gateway/gateway-widget.models.ts | 9 +-- .../gateway/utils/opc-version-mapping.util.ts | 70 ++++++++++++------- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index 8a0e4005fd..b933ff1186 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -265,9 +265,9 @@ export interface WorkersConfig { export interface ConnectorDeviceInfo { deviceNameExpression: string; - deviceNameExpressionSource: SourceType; + deviceNameExpressionSource: SourceType | OPCUaSourceType; deviceProfileExpression: string; - deviceProfileExpressionSource: SourceType; + deviceProfileExpressionSource: SourceType | OPCUaSourceType; } export interface Attribute { @@ -292,7 +292,7 @@ export interface LegacyTimeseries { path: string; } -interface RpcArgument { +export interface RpcArgument { type: string; value: number; } @@ -363,7 +363,7 @@ export type ConverterMappingFormValue = Omit ({ - ...oldMapping, - deviceNodeSource: 'path', + return mapping.map((legacyMapping: LegacyDeviceConnectorMapping) => ({ + ...legacyMapping, + deviceNodeSource: this.getTypeSourceByValue(legacyMapping.deviceNodePattern), deviceInfo: { - deviceNameExpression: oldMapping.deviceNamePattern, - deviceNameExpressionSource: 'path', - deviceProfileExpression: oldMapping.deviceTypePattern ?? 'default', - deviceProfileExpressionSource: 'path', + deviceNameExpression: legacyMapping.deviceNamePattern, + deviceNameExpressionSource: this.getTypeSourceByValue(legacyMapping.deviceNamePattern), + deviceProfileExpression: legacyMapping.deviceTypePattern ?? 'default', + deviceProfileExpressionSource: this.getTypeSourceByValue(legacyMapping.deviceTypePattern ?? 'default'), }, - attributes: oldMapping.attributes.map(attribute => ({ + attributes: legacyMapping.attributes.map((attribute: LegacyAttribute) => ({ key: attribute.key, - type: 'path', + type: this.getTypeSourceByValue(attribute.path), value: attribute.path, })), - attributes_updates: oldMapping.attributes_updates.map(attributeUpdate => ({ + attributes_updates: legacyMapping.attributes_updates.map((attributeUpdate: LegacyDeviceAttributeUpdate) => ({ key: attributeUpdate.attributeOnThingsBoard, - type: 'path', + type: this.getTypeSourceByValue(attributeUpdate.attributeOnDevice), value: attributeUpdate.attributeOnDevice, })), - timeseries: oldMapping.timeseries.map(timeseries => ({ + timeseries: legacyMapping.timeseries.map((timeseries: LegacyTimeseries) => ({ key: timeseries.key, - type: 'path', + type: this.getTypeSourceByValue(timeseries.path), value: timeseries.path, })), - rpc_methods: oldMapping.rpc_methods.map(rpcMethod => ({ + rpc_methods: legacyMapping.rpc_methods.map((rpcMethod: LegacyRpcMethod) => ({ method: rpcMethod.method, arguments: rpcMethod.arguments.map(arg => ({ value: arg, type: this.getArgumentType(arg), - })) + } as RpcArgument)) })) })); } static mapMappingToDowngradedVersion(mapping: DeviceConnectorMapping[]): LegacyDeviceConnectorMapping[] { - return mapping?.map((newMapping: DeviceConnectorMapping) => ({ - ...newMapping, - deviceNamePattern: newMapping.deviceInfo.deviceNameExpression, - deviceTypePattern: newMapping.deviceInfo.deviceProfileExpression, - attributes: newMapping.attributes.map((attribute: any) => ({ + return mapping.map((upgradedMapping: DeviceConnectorMapping) => ({ + ...upgradedMapping, + deviceNamePattern: upgradedMapping.deviceInfo.deviceNameExpression, + deviceTypePattern: upgradedMapping.deviceInfo.deviceProfileExpression, + attributes: upgradedMapping.attributes.map((attribute: Attribute) => ({ key: attribute.key, path: attribute.value, })), - attributes_updates: newMapping.attributes_updates.map((attributeUpdate: any) => ({ + attributes_updates: upgradedMapping.attributes_updates.map((attributeUpdate: AttributesUpdate) => ({ attributeOnThingsBoard: attributeUpdate.key, attributeOnDevice: attributeUpdate.value, })), - timeseries: newMapping.timeseries.map((timeseries: any) => ({ + timeseries: upgradedMapping.timeseries.map((timeseries: Timeseries) => ({ key: timeseries.key, path: timeseries.value, })), - rpc_methods: newMapping.rpc_methods.map((rpcMethod: any) => ({ + rpc_methods: upgradedMapping.rpc_methods.map((rpcMethod: RpcMethod) => ({ method: rpcMethod.method, - arguments: rpcMethod.arguments.map((arg: any) => arg.value) + arguments: rpcMethod.arguments.map((arg: RpcArgument) => arg.value) })) })); } + private static getTypeSourceByValue(value: string): OPCUaSourceType { + if (value.includes('${')) { + return OPCUaSourceType.IDENTIFIER; + } + if (value.includes(`/`) || value.includes('\\')) { + return OPCUaSourceType.PATH; + } + return OPCUaSourceType.CONST; + } + private static getArgumentType(arg: unknown): string { switch (typeof arg) { case 'boolean': From 6104778cd24c1a767cd0193bf689a757b4fc03c7 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 10 Sep 2024 19:34:03 +0300 Subject: [PATCH 13/14] [4114] refactoring --- .../gateway/abstract/modbus-version-processor.abstract.ts | 1 + .../lib/gateway/abstract/mqtt-version-processor.abstract.ts | 2 ++ .../lib/gateway/abstract/opc-version-processor.abstract.ts | 1 + .../widget/lib/gateway/gateway-connectors.component.ts | 4 ++++ .../widget/lib/gateway/utils/modbus-version-mapping.util.ts | 5 ++++- .../widget/lib/gateway/utils/opc-version-mapping.util.ts | 1 + 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts index d520a5b1e8..abcf6ce597 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts @@ -34,6 +34,7 @@ export class ModbusVersionProcessor extends GatewayConnectorVersionProcessor { const configurationJson = this.connector.configurationJson; return { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts index 645eb64fa4..f55269eadf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts @@ -27,6 +27,7 @@ import { MqttVersionMappingUtil } from '../utils/mqtt-version-mapping.util'; import { GatewayConnectorVersionProcessor } from './gateway-connector-version-processor.abstract'; export class MqttVersionProcessor extends GatewayConnectorVersionProcessor { + private readonly mqttRequestTypeKeys = Object.values(RequestType); constructor( @@ -35,6 +36,7 @@ export class MqttVersionProcessor extends GatewayConnectorVersionProcessor { const { connectRequests, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts index 11c9908058..e0337d9fe3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts @@ -31,6 +31,7 @@ export class OpcVersionProcessor extends GatewayConnectorVersionProcessor { const server = this.connector.configurationJson.server as LegacyServerConfig; return { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index 9be5b550ce..03765613da 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -245,6 +245,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie delete value.class; } + if (this.gatewayVersion && !value.configVersion) { + value.configVersion = this.gatewayVersion; + } + value.ts = Date.now(); return value; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts index b65d3e7449..fbb78059e1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts @@ -20,11 +20,14 @@ import { ModbusLegacySlave, ModbusMasterConfig, ModbusRegisterValues, - ModbusSlave, ModbusValue, ModbusValues, + ModbusSlave, + ModbusValue, + ModbusValues, SlaveConfig } from '@home/components/widget/lib/gateway/gateway-widget.models'; export class ModbusVersionMappingUtil { + static mapMasterToUpgradedVersion(master: ModbusMasterConfig): ModbusMasterConfig { return { slaves: master.slaves.map((slave: SlaveConfig) => ({ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts index 161eaf7daa..35807065e9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts @@ -33,6 +33,7 @@ import { } from '@home/components/widget/lib/gateway/gateway-widget.models'; export class OpcVersionMappingUtil { + static mapServerToUpgradedVersion(server: LegacyServerConfig): ServerConfig { const { mapping, disableSubscriptions, ...restServer } = server; return { From 148108006c29fa5537efca6cd02b1830987244e3 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 11 Sep 2024 17:15:20 +0300 Subject: [PATCH 14/14] [4114] fixed number version bug, added hide new field for opc and refactoring --- ...teway-connector-version-processor.abstract.ts | 16 ++++++++++------ .../modbus-version-processor.abstract.ts | 8 ++++---- .../abstract/mqtt-version-processor.abstract.ts | 8 ++++---- .../abstract/opc-version-processor.abstract.ts | 8 ++++---- .../opc-server-config.component.html | 2 +- .../opc-server-config.component.ts | 15 +++++++++++++-- .../opc-ua-basic-config.component.html | 2 +- .../opc-ua-basic-config.component.ts | 1 + .../opc-ua-legacy-basic-config.component.ts | 1 + .../widget/lib/gateway/gateway-widget.models.ts | 8 ++++---- .../connector-default-configs/modbus.json | 2 +- .../metadata/connector-default-configs/mqtt.json | 2 +- .../connector-default-configs/opcua.json | 2 +- 13 files changed, 46 insertions(+), 29 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts index 5f06659823..944b5ffe6c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -15,14 +15,14 @@ /// import { GatewayConnector, GatewayVersion } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { isString } from '@core/utils'; +import { isNumber, isString } from '@core/utils'; export abstract class GatewayConnectorVersionProcessor { gatewayVersion: number; configVersion: number; - protected constructor(protected gatewayVersionStr: string, protected connector: GatewayConnector) { - this.gatewayVersion = this.parseVersion(this.gatewayVersionStr); + protected constructor(protected gatewayVersionIn: string | number, protected connector: GatewayConnector) { + this.gatewayVersion = this.parseVersion(this.gatewayVersionIn); this.configVersion = this.parseVersion(connector.configVersion); } @@ -45,11 +45,15 @@ export abstract class GatewayConnectorVersionProcessor { } private isVersionUpgradeNeeded(): boolean { - return this.gatewayVersionStr === GatewayVersion.Current && (!this.configVersion || this.configVersion < this.gatewayVersion); + return this.gatewayVersionIn === GatewayVersion.Current && (!this.configVersion || this.configVersion < this.gatewayVersion); } - private parseVersion(version: string): number { - return isString(version) ? Number(version.replace(/\./g, '')) : 0; + private parseVersion(version: string | number): number { + if (isNumber(version)) { + return version as number; + } + + return isString(version) ? parseFloat((version as string).replace(/\./g, '').slice(0, 3)) / 100 : 0; } protected abstract getDowngradedVersion(): GatewayConnector; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts index abcf6ce597..6ea8f4516d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts @@ -29,10 +29,10 @@ import { ModbusVersionMappingUtil } from '@home/components/widget/lib/gateway/ut export class ModbusVersionProcessor extends GatewayConnectorVersionProcessor { constructor( - protected gatewayVersionStr: string, + protected gatewayVersionIn: string, protected connector: GatewayConnector ) { - super(gatewayVersionStr, connector); + super(gatewayVersionIn, connector); } getUpgradedVersion(): GatewayConnector { @@ -47,7 +47,7 @@ export class ModbusVersionProcessor extends GatewayConnectorVersionProcessor; } @@ -62,7 +62,7 @@ export class ModbusVersionProcessor extends GatewayConnectorVersionProcessor; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts index f55269eadf..351ad76494 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts @@ -31,10 +31,10 @@ export class MqttVersionProcessor extends GatewayConnectorVersionProcessor ) { - super(gatewayVersionStr, connector); + super(gatewayVersionIn, connector); } getUpgradedVersion(): GatewayConnector { @@ -67,7 +67,7 @@ export class MqttVersionProcessor extends GatewayConnectorVersionProcessor; } @@ -85,7 +85,7 @@ export class MqttVersionProcessor extends GatewayConnectorVersionProcessor; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts index e0337d9fe3..e89c48fc28 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts @@ -26,10 +26,10 @@ import { OpcVersionMappingUtil } from '@home/components/widget/lib/gateway/utils export class OpcVersionProcessor extends GatewayConnectorVersionProcessor { constructor( - protected gatewayVersionStr: string, + protected gatewayVersionIn: string, protected connector: GatewayConnector ) { - super(gatewayVersionStr, connector); + super(gatewayVersionIn, connector); } getUpgradedVersion(): GatewayConnector { @@ -40,7 +40,7 @@ export class OpcVersionProcessor extends GatewayConnectorVersionProcessor; } @@ -50,7 +50,7 @@ export class OpcVersionProcessor extends GatewayConnectorVersionProcessor; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html index 584679fa2c..523705d029 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html @@ -84,7 +84,7 @@ -
+
{{ 'gateway.poll-period' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts index c838121b76..c000139ded 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectionStrategy, Component, forwardRef, OnDestroy } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, forwardRef, Input, OnDestroy } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -39,6 +39,7 @@ import { SecurityConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; import { HOUR } from '@shared/models/time/time.models'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-opc-server-config', @@ -64,7 +65,11 @@ import { HOUR } from '@shared/models/time/time.models'; SecurityConfigComponent, ] }) -export class OpcServerConfigComponent implements ControlValueAccessor, Validator, OnDestroy { +export class OpcServerConfigComponent implements ControlValueAccessor, Validator, AfterViewInit, OnDestroy { + + @Input() + @coerceBoolean() + hideNewFields: boolean = false; securityPolicyTypes = SecurityPolicyTypes; serverConfigFormGroup: UntypedFormGroup; @@ -95,6 +100,12 @@ export class OpcServerConfigComponent implements ControlValueAccessor, Validator }); } + ngAfterViewInit(): void { + if (this.hideNewFields) { + this.serverConfigFormGroup.get('pollPeriodInMillis').disable({emitEvent: false}); + } + } + ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html index 5f8b25af9d..2296a472a4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html @@ -20,7 +20,7 @@ - +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts index 1a45e74c7a..c45eafcc67 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts @@ -63,6 +63,7 @@ import { export class OpcUaBasicConfigComponent extends GatewayConnectorBasicConfigDirective { mappingTypes = MappingType; + isLegacy = false; protected override initBasicFormGroup(): FormGroup { return this.fb.group({ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts index 12e05205a2..9458858cbf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts @@ -64,6 +64,7 @@ import { OpcVersionMappingUtil } from '@home/components/widget/lib/gateway/utils export class OpcUaLegacyBasicConfigComponent extends GatewayConnectorBasicConfigDirective { mappingTypes = MappingType; + isLegacy = true; protected override initBasicFormGroup(): FormGroup { return this.fb.group({ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index b933ff1186..0f940e28ff 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -131,7 +131,7 @@ export interface GatewayConnector extends Gate export interface GatewayVersionedDefaultConfig { legacy: GatewayConnector; - '3.5.1': GatewayConnector; + '3.5.2': GatewayConnector; } export interface DataMapping { @@ -189,7 +189,7 @@ export interface ConnectorSecurity { } export enum GatewayVersion { - Current = '3.5.1', + Current = '3.5.2', Legacy = 'legacy' } @@ -197,11 +197,11 @@ export type ConnectorMapping = DeviceConnectorMapping | RequestMappingValue | Co export type ConnectorMappingFormValue = DeviceConnectorMapping | RequestMappingFormValue | ConverterMappingFormValue; -export type ConnectorBaseConfig = ConnectorBaseConfig_v_3_5_2 | ConnectorLegacyConfig; +export type ConnectorBaseConfig = ConnectorBaseConfig_v3_5_2 | ConnectorLegacyConfig; export type ConnectorLegacyConfig = ConnectorBaseInfo | MQTTLegacyBasicConfig | OPCLegacyBasicConfig | ModbusBasicConfig; -export type ConnectorBaseConfig_v_3_5_2 = ConnectorBaseInfo | MQTTBasicConfig_v3_5_2 | OPCBasicConfig_v3_5_2; +export type ConnectorBaseConfig_v3_5_2 = ConnectorBaseInfo | MQTTBasicConfig_v3_5_2 | OPCBasicConfig_v3_5_2; export interface ConnectorBaseInfo { name: string; diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json b/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json index 96fb59dcf5..38bb44e036 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json @@ -1,5 +1,5 @@ { - "3.5.1": { + "3.5.2": { "master": { "slaves": [ { diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json b/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json index b3ba47215f..5b8b8dbd44 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json @@ -1,5 +1,5 @@ { - "3.5.1": { + "3.5.2": { "broker": { "host": "127.0.0.1", "port": 1883, diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json b/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json index eb33f9235e..c0ef993dd1 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json @@ -1,5 +1,5 @@ { - "3.5.1": { + "3.5.2": { "server": { "url": "localhost:4840/freeopcua/server/", "timeoutInMillis": 5000,