[4114] Added Modbus version mapping and OPC initial mapping

This commit is contained in:
mpetrov 2024-09-10 18:05:59 +03:00
parent 339f2c3e8f
commit b142c72247
27 changed files with 1395 additions and 539 deletions

View File

@ -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<InputBasicConfig, OutputBasicConfig>
implements ControlValueAccessor, Validator, OnDestroy {
@Input() generalTabContent: TemplateRef<any>;
basicFormGroup: FormGroup;
protected fb = inject(FormBuilder);
protected onChange!: (value: OutputBasicConfig) => void;
protected onTouched!: () => void;
protected destroy$ = new Subject<void>();
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;
}

View File

@ -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<BasicConfig> {
gatewayVersion: number;
@ -48,7 +49,7 @@ export abstract class GatewayConnectorVersionProcessor<BasicConfig> {
}
private parseVersion(version: string): number {
return Number(version?.replace(/\./g, ''));
return isString(version) ? Number(version.replace(/\./g, '')) : 0;
}
protected abstract getDowngradedVersion(): GatewayConnector<BasicConfig>;

View File

@ -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<any> {
constructor(
protected gatewayVersionStr: string,
protected connector: GatewayConnector<ModbusBasicConfig>
) {
super(gatewayVersionStr, connector);
}
getUpgradedVersion(): GatewayConnector<ModbusBasicConfig_v3_5_2> {
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<ModbusBasicConfig_v3_5_2>;
}
getDowngradedVersion(): GatewayConnector<ModbusLegacyBasicConfig> {
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<ModbusLegacyBasicConfig>;
}
}

View File

@ -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<OPCBasicConfig> {
constructor(
protected gatewayVersionStr: string,
protected connector: GatewayConnector<OPCBasicConfig>
) {
super(gatewayVersionStr, connector);
}
getUpgradedVersion(): GatewayConnector<OPCBasicConfig_v3_5_2> {
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<OPCBasicConfig_v3_5_2>;
}
getDowngradedVersion(): GatewayConnector<OPCLegacyBasicConfig> {
return {
...this.connector,
configurationJson: {
server: OpcVersionMappingUtil.mapServerToDowngradedVersion(this.connector.configurationJson as OPCBasicConfig_v3_5_2)
},
configVersion: this.gatewayVersionStr
} as GatewayConnector<OPCLegacyBasicConfig>;
}
}

View File

@ -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<BasicConfig>
extends GatewayConnectorBasicConfigDirective<ModbusBasicConfig_v3_5_2, BasicConfig> {
enableSlaveControl: FormControl<boolean> = 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, {}));
}
}

View File

@ -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<ModbusBasicConfig_v3_5_2> {
export class ModbusBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy {
@Input() generalTabContent: TemplateRef<any>;
basicFormGroup: FormGroup;
enableSlaveControl: FormControl<boolean>;
onChange: (value: ModbusBasicConfig) => void;
onTouched: () => void;
private destroy$ = new Subject<void>();
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,
};
}
}

View File

@ -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<ModbusLegacyBasicConfig> {
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,
};
}
}

View File

@ -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<BasicConfig> implements ControlValueAccessor, Validator, OnDestroy {
export abstract class MqttBasicConfigDirective<BasicConfig>
extends GatewayConnectorBasicConfigDirective<MQTTBasicConfig_v3_5_2, BasicConfig> {
basicFormGroup: FormGroup;
MappingType = MappingType;
private destroy$ = new Subject<void>();
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<RequestType, RequestMappingData[]>): RequestMappingData[] {
@ -103,6 +73,10 @@ export abstract class AbstractMqttBasicConfigComponent<BasicConfig> 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;
}

View File

@ -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<MQTTBasicConfig_v3_5_2> {
export class MqttBasicConfigComponent extends MqttBasicConfigDirective<MQTTBasicConfig_v3_5_2> {
@Input()
generalTabContent: TemplateRef<any>;
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<RequestType, RequestMappingData[]>),
};
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)) {

View File

@ -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<MQTTLegacyBasicConfig> {
export class MqttLegacyBasicConfigComponent extends MqttBasicConfigDirective<MQTTLegacyBasicConfig> {
@Input()
generalTabContent: TemplateRef<any>;
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)) {

View File

@ -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<any>;
export class OpcUaBasicConfigComponent extends GatewayConnectorBasicConfigDirective<OPCBasicConfig_v3_5_2, OPCBasicConfig_v3_5_2> {
mappingTypes = MappingType;
basicFormGroup: FormGroup;
onChange!: (value: string) => void;
onTouched!: () => void;
protected readonly connectorType = ConnectorType;
private destroy$ = new Subject<void>();
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,
};
}
}

View File

@ -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<OPCBasicConfig_v3_5_2, OPCLegacyBasicConfig> {
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),
};
}
}

View File

@ -186,14 +186,26 @@
<tb-mqtt-legacy-basic-config formControlName="basicConfig" [generalTabContent]="generalTabContent"/>
</ng-template>
</ng-container>
<tb-opc-ua-basic-config *ngSwitchCase="ConnectorType.OPCUA"
formControlName="basicConfig"
[generalTabContent]="generalTabContent">
</tb-opc-ua-basic-config>
<tb-modbus-basic-config *ngSwitchCase="ConnectorType.MODBUS"
formControlName="basicConfig"
[generalTabContent]="generalTabContent">
</tb-modbus-basic-config>
<ng-container *ngSwitchCase="ConnectorType.OPCUA">
<tb-opc-ua-basic-config
*ngIf="connectorForm.get('configVersion').value === GatewayVersion.Current else legacy"
formControlName="basicConfig"
[generalTabContent]="generalTabContent"
/>
<ng-template #legacy>
<tb-opc-ua-legacy-basic-config formControlName="basicConfig" [generalTabContent]="generalTabContent"/>
</ng-template>
</ng-container>
<ng-container *ngSwitchCase="ConnectorType.MODBUS">
<tb-modbus-basic-config
*ngIf="connectorForm.get('configVersion').value === GatewayVersion.Current else legacy"
formControlName="basicConfig"
[generalTabContent]="generalTabContent"
/>
<ng-template #legacy>
<tb-modbus-legacy-basic-config formControlName="basicConfig" [generalTabContent]="generalTabContent"/>
</ng-template>
</ng-container>
</ng-container>
</ng-container>
<ng-template #defaultConfig>

View File

@ -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<ServerConfig, 'enableSubscriptions'> {
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<ModbusSlave, 'values'> {
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;

View File

@ -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<MQTTBasicConfig>).getProcessedByVersion();
case ConnectorType.OPCUA:
return new OpcVersionProcessor(gatewayVersion, connector as GatewayConnector<OPCBasicConfig>).getProcessedByVersion();
case ConnectorType.MODBUS:
return new ModbusVersionProcessor(gatewayVersion, connector as GatewayConnector<ModbusBasicConfig>).getProcessedByVersion();
default:
return connector;
}

View File

@ -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);
}
}

View File

@ -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';
}
}
}

View File

@ -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,

View File

@ -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"
}
],
"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
"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
}
]
}
]
},
"coils_initializer": {
"attributes": [
{
"address": 5,
"type": "string",
"tag": "sm",
"objectsCount": 1,
"value": "12"
"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": []
}
],
"timeseries": [],
"attributeUpdates": [],
"rpc": []
}
}
},
"legacy": {
"master": {
"slaves": [
{
"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
}
]
}
]
},
"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": []
}
]
}
}
}
}
}

View File

@ -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"
}
]
}
]
}
}
}