62 changed files with 3139 additions and 1076 deletions
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -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; |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
///
|
|||
/// 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'; |
|||
import { isNumber, isString } from '@core/utils'; |
|||
|
|||
export abstract class GatewayConnectorVersionProcessor<BasicConfig> { |
|||
gatewayVersion: number; |
|||
configVersion: number; |
|||
|
|||
protected constructor(protected gatewayVersionIn: string | number, protected connector: GatewayConnector<BasicConfig>) { |
|||
this.gatewayVersion = this.parseVersion(this.gatewayVersionIn); |
|||
this.configVersion = this.parseVersion(connector.configVersion); |
|||
} |
|||
|
|||
getProcessedByVersion(): GatewayConnector<BasicConfig> { |
|||
if (this.isVersionUpdateNeeded()) { |
|||
return this.isVersionUpgradeNeeded() |
|||
? this.getUpgradedVersion() |
|||
: this.getDowngradedVersion(); |
|||
} |
|||
|
|||
return this.connector; |
|||
} |
|||
|
|||
private isVersionUpdateNeeded(): boolean { |
|||
if (!this.gatewayVersion) { |
|||
return false; |
|||
} |
|||
|
|||
return this.configVersion !== this.gatewayVersion; |
|||
} |
|||
|
|||
private isVersionUpgradeNeeded(): boolean { |
|||
return this.gatewayVersionIn === GatewayVersion.Current && (!this.configVersion || this.configVersion < this.gatewayVersion); |
|||
} |
|||
|
|||
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<BasicConfig>; |
|||
protected abstract getUpgradedVersion(): GatewayConnector<BasicConfig>; |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
///
|
|||
/// 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 gatewayVersionIn: string, |
|||
protected connector: GatewayConnector<ModbusBasicConfig> |
|||
) { |
|||
super(gatewayVersionIn, 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.gatewayVersionIn |
|||
} 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.gatewayVersionIn |
|||
} as GatewayConnector<ModbusLegacyBasicConfig>; |
|||
} |
|||
} |
|||
@ -0,0 +1,101 @@ |
|||
///
|
|||
/// 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, |
|||
MQTTBasicConfig, |
|||
MQTTBasicConfig_v3_5_2, |
|||
MQTTLegacyBasicConfig, |
|||
RequestMappingData, |
|||
RequestType, |
|||
} 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<MQTTBasicConfig> { |
|||
|
|||
private readonly mqttRequestTypeKeys = Object.values(RequestType); |
|||
|
|||
constructor( |
|||
protected gatewayVersionIn: string, |
|||
protected connector: GatewayConnector<MQTTBasicConfig> |
|||
) { |
|||
super(gatewayVersionIn, connector); |
|||
} |
|||
|
|||
getUpgradedVersion(): GatewayConnector<MQTTBasicConfig_v3_5_2> { |
|||
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]: removedValue, ...rest } = configurationJson as MQTTLegacyBasicConfig; |
|||
configurationJson = { ...rest } as any; |
|||
}); |
|||
|
|||
this.cleanUpConfigJson(configurationJson as MQTTBasicConfig_v3_5_2); |
|||
|
|||
return { |
|||
...this.connector, |
|||
configurationJson, |
|||
configVersion: this.gatewayVersionIn |
|||
} as GatewayConnector<MQTTBasicConfig_v3_5_2>; |
|||
} |
|||
|
|||
getDowngradedVersion(): GatewayConnector<MQTTLegacyBasicConfig> { |
|||
const { requestsMapping, mapping, ...restConfig } = this.connector.configurationJson as MQTTBasicConfig_v3_5_2; |
|||
|
|||
const updatedRequestsMapping = |
|||
MqttVersionMappingUtil.mapRequestsToDowngradedVersion(requestsMapping as Record<RequestType, RequestMappingData[]>); |
|||
const updatedMapping = MqttVersionMappingUtil.mapMappingToDowngradedVersion(mapping); |
|||
|
|||
return { |
|||
...this.connector, |
|||
configurationJson: { |
|||
...restConfig, |
|||
...updatedRequestsMapping, |
|||
mapping: updatedMapping, |
|||
}, |
|||
configVersion: this.gatewayVersionIn |
|||
} as GatewayConnector<MQTTLegacyBasicConfig>; |
|||
} |
|||
|
|||
private cleanUpConfigJson(configurationJson: MQTTBasicConfig_v3_5_2): void { |
|||
if (isEqual(configurationJson.requestsMapping, {})) { |
|||
delete configurationJson.requestsMapping; |
|||
} |
|||
|
|||
if (isEqual(configurationJson.mapping, [])) { |
|||
delete configurationJson.mapping; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
///
|
|||
/// 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 gatewayVersionIn: string, |
|||
protected connector: GatewayConnector<OPCBasicConfig> |
|||
) { |
|||
super(gatewayVersionIn, 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.gatewayVersionIn |
|||
} 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.gatewayVersionIn |
|||
} as GatewayConnector<OPCLegacyBasicConfig>; |
|||
} |
|||
} |
|||
@ -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, {})); |
|||
} |
|||
} |
|||
@ -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, |
|||
}; |
|||
} |
|||
} |
|||
@ -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<any>; |
|||
|
|||
mappingTypes = MappingType; |
|||
basicFormGroup: FormGroup; |
|||
|
|||
private onChange: (value: MQTTBasicConfig) => void; |
|||
private onTouched: () => void; |
|||
|
|||
private destroy$ = new Subject<void>(); |
|||
|
|||
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<RequestType, RequestMappingData[]>): 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<RequestType, RequestMappingData[]> { |
|||
return array.reduce((result, { requestType, requestValue }) => { |
|||
result[requestType].push(requestValue); |
|||
return result; |
|||
}, { |
|||
connectRequests: [], |
|||
disconnectRequests: [], |
|||
attributeRequests: [], |
|||
attributeUpdates: [], |
|||
serverSideRpc: [], |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
///
|
|||
/// 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 { FormGroup } from '@angular/forms'; |
|||
import { |
|||
MappingType, |
|||
MQTTBasicConfig, MQTTBasicConfig_v3_5_2, |
|||
RequestMappingData, |
|||
RequestMappingValue, |
|||
RequestType |
|||
} from '@home/components/widget/lib/gateway/gateway-widget.models'; |
|||
import { isObject } from '@core/utils'; |
|||
import { |
|||
GatewayConnectorBasicConfigDirective |
|||
} from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; |
|||
|
|||
@Directive() |
|||
export abstract class MqttBasicConfigDirective<BasicConfig> |
|||
extends GatewayConnectorBasicConfigDirective<MQTTBasicConfig_v3_5_2, BasicConfig> { |
|||
|
|||
MappingType = MappingType; |
|||
|
|||
protected override initBasicFormGroup(): FormGroup { |
|||
return this.fb.group({ |
|||
mapping: [], |
|||
requestsMapping: [], |
|||
broker: [], |
|||
workers: [], |
|||
}); |
|||
} |
|||
|
|||
protected getRequestDataArray(value: Record<RequestType, RequestMappingData[]>): 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<RequestType, RequestMappingValue[]> { |
|||
return array.reduce((result, { requestType, requestValue }) => { |
|||
result[requestType].push(requestValue); |
|||
return result; |
|||
}, { |
|||
connectRequests: [], |
|||
disconnectRequests: [], |
|||
attributeRequests: [], |
|||
attributeUpdates: [], |
|||
serverSideRpc: [], |
|||
}); |
|||
} |
|||
|
|||
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; |
|||
} |
|||
@ -0,0 +1,103 @@ |
|||
///
|
|||
/// 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, ChangeDetectionStrategy } from '@angular/core'; |
|||
import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; |
|||
import { |
|||
BrokerConfig, |
|||
MQTTBasicConfig_v3_5_2, |
|||
RequestMappingData, |
|||
RequestMappingValue, |
|||
RequestType, WorkersConfig |
|||
} from '@home/components/widget/lib/gateway/gateway-widget.models'; |
|||
import { |
|||
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'; |
|||
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/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'; |
|||
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 MqttBasicConfigDirective<MQTTBasicConfig_v3_5_2> { |
|||
|
|||
protected override mapConfigToFormValue(basicConfig: MQTTBasicConfig_v3_5_2): MQTTBasicConfig_v3_5_2 { |
|||
const { broker, mapping = [], requestsMapping } = basicConfig; |
|||
return{ |
|||
workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { |
|||
maxNumberOfWorkers: broker.maxNumberOfWorkers, |
|||
maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, |
|||
} : {} as WorkersConfig, |
|||
mapping: mapping ?? [], |
|||
broker: broker ?? {} as BrokerConfig, |
|||
requestsMapping: this.getRequestDataArray(requestsMapping as Record<RequestType, RequestMappingData[]>), |
|||
}; |
|||
} |
|||
|
|||
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)) { |
|||
broker = { |
|||
...broker, |
|||
...workers, |
|||
}; |
|||
} |
|||
|
|||
if ((requestsMapping as RequestMappingData[])?.length) { |
|||
requestsMapping = this.getRequestDataObject(requestsMapping as RequestMappingValue[]); |
|||
} |
|||
|
|||
return { broker, mapping, requestsMapping }; |
|||
} |
|||
} |
|||
@ -0,0 +1,124 @@ |
|||
///
|
|||
/// 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, ChangeDetectionStrategy } from '@angular/core'; |
|||
import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; |
|||
import { |
|||
BrokerConfig, |
|||
MQTTBasicConfig_v3_5_2, |
|||
MQTTLegacyBasicConfig, |
|||
RequestMappingData, |
|||
RequestMappingValue, |
|||
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 { |
|||
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'; |
|||
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/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'; |
|||
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 MqttBasicConfigDirective<MQTTLegacyBasicConfig> { |
|||
|
|||
protected override mapConfigToFormValue(config: MQTTLegacyBasicConfig): MQTTBasicConfig_v3_5_2 { |
|||
const { |
|||
broker, |
|||
mapping = [], |
|||
connectRequests = [], |
|||
disconnectRequests = [], |
|||
attributeRequests = [], |
|||
attributeUpdates = [], |
|||
serverSideRpc = [] |
|||
} = config as MQTTLegacyBasicConfig; |
|||
const updatedRequestMapping = MqttVersionMappingUtil.mapRequestsToUpgradedVersion({ |
|||
connectRequests, |
|||
disconnectRequests, |
|||
attributeRequests, |
|||
attributeUpdates, |
|||
serverSideRpc |
|||
}); |
|||
return { |
|||
workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { |
|||
maxNumberOfWorkers: broker.maxNumberOfWorkers, |
|||
maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, |
|||
} : {} as WorkersConfig, |
|||
mapping: MqttVersionMappingUtil.mapMappingToUpgradedVersion(mapping) || [], |
|||
broker: broker || {} as BrokerConfig, |
|||
requestsMapping: this.getRequestDataArray(updatedRequestMapping), |
|||
}; |
|||
} |
|||
|
|||
protected override getMappedValue(basicConfig: MQTTBasicConfig_v3_5_2): 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.mapMappingToDowngradedVersion(mapping), |
|||
...(MqttVersionMappingUtil.mapRequestsToDowngradedVersion(requestsMapping as Record<RequestType, RequestMappingData[]>)) |
|||
}; |
|||
} |
|||
} |
|||
@ -1,134 +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 { |
|||
ConnectorType, |
|||
MappingType, |
|||
OPCBasicConfig, |
|||
} 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 { |
|||
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 { |
|||
OpcServerConfigComponent |
|||
} from '@home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-opc-ua-basic-config', |
|||
templateUrl: './opc-ua-basic-config.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => OpcUaBasicConfigComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => OpcUaBasicConfigComponent), |
|||
multi: true |
|||
} |
|||
], |
|||
standalone: true, |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
SecurityConfigComponent, |
|||
WorkersConfigControlComponent, |
|||
BrokerConfigControlComponent, |
|||
MappingTableComponent, |
|||
OpcServerConfigComponent, |
|||
], |
|||
styleUrls: ['./opc-ua-basic-config.component.scss'] |
|||
}) |
|||
|
|||
export class OpcUaBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { |
|||
@Input() generalTabContent: TemplateRef<any>; |
|||
|
|||
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({ |
|||
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 || [], |
|||
}; |
|||
|
|||
this.basicFormGroup.setValue(editedBase, {emitEvent: false}); |
|||
} |
|||
|
|||
validate(): ValidationErrors | null { |
|||
return this.basicFormGroup.valid ? null : { |
|||
basicFormGroup: {valid: false} |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
///
|
|||
/// 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, |
|||
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'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-opc-ua-basic-config', |
|||
templateUrl: './opc-ua-basic-config.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => OpcUaBasicConfigComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => OpcUaBasicConfigComponent), |
|||
multi: true |
|||
} |
|||
], |
|||
standalone: true, |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
SecurityConfigComponent, |
|||
MappingTableComponent, |
|||
OpcServerConfigComponent, |
|||
], |
|||
styleUrls: ['./opc-ua-basic-config.component.scss'] |
|||
}) |
|||
export class OpcUaBasicConfigComponent extends GatewayConnectorBasicConfigDirective<OPCBasicConfig_v3_5_2, OPCBasicConfig_v3_5_2> { |
|||
|
|||
mappingTypes = MappingType; |
|||
isLegacy = false; |
|||
|
|||
protected override initBasicFormGroup(): FormGroup { |
|||
return this.fb.group({ |
|||
mapping: [], |
|||
server: [], |
|||
}); |
|||
} |
|||
|
|||
protected override mapConfigToFormValue(config: OPCBasicConfig_v3_5_2): OPCBasicConfig_v3_5_2 { |
|||
return { |
|||
server: config.server ?? {} as ServerConfig, |
|||
mapping: config.mapping ?? [], |
|||
}; |
|||
} |
|||
|
|||
protected override getMappedValue(value: OPCBasicConfig_v3_5_2): OPCBasicConfig_v3_5_2 { |
|||
return { |
|||
server: value.server, |
|||
mapping: value.mapping, |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
///
|
|||
/// 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; |
|||
isLegacy = true; |
|||
|
|||
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), |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
///
|
|||
/// 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, |
|||
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 { |
|||
|
|||
static getConfig(connector: GatewayConnector, gatewayVersion: string): GatewayConnector { |
|||
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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
///
|
|||
/// 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); |
|||
} |
|||
} |
|||
@ -0,0 +1,217 @@ |
|||
///
|
|||
/// 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 } from '@core/utils'; |
|||
import { |
|||
AttributeRequest, |
|||
ConnectorDeviceInfo, |
|||
Converter, |
|||
ConverterConnectorMapping, |
|||
ConvertorType, |
|||
LegacyConverter, |
|||
LegacyConverterConnectorMapping, |
|||
LegacyRequestMappingData, |
|||
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 mapMappingToUpgradedVersion( |
|||
mapping: LegacyConverterConnectorMapping[] |
|||
): 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 }; |
|||
}) as ConverterConnectorMapping[]; |
|||
} |
|||
|
|||
static mapRequestsToUpgradedVersion( |
|||
requestMapping: Record<RequestType, |
|||
LegacyRequestMappingData[]> |
|||
): Record<RequestType, RequestMappingData[]> { |
|||
return this.mqttRequestTypeKeys.reduce((acc, key: RequestType) => { |
|||
if (!requestMapping[key]) { |
|||
return acc; |
|||
} |
|||
|
|||
acc[key] = requestMapping[key].map(value => { |
|||
const newValue = this.mapRequestToUpgradedVersion(value as LegacyRequestMappingData, key); |
|||
|
|||
this.cleanUpOldFields(newValue as {}); |
|||
|
|||
return newValue; |
|||
}); |
|||
|
|||
return acc; |
|||
}, {}) as Record<RequestType, RequestMappingData[]>; |
|||
} |
|||
|
|||
static mapRequestsToDowngradedVersion( |
|||
requestsMapping: Record<RequestType, RequestMappingData[]> |
|||
): Record<RequestType, LegacyRequestMappingData[]> { |
|||
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<RequestType, LegacyRequestMappingData[]>; |
|||
} |
|||
|
|||
static mapMappingToDowngradedVersion( |
|||
mapping: ConverterConnectorMapping[] |
|||
): LegacyConverterConnectorMapping[] { |
|||
return mapping?.map((converterMapping: ConverterConnectorMapping) => { |
|||
const converter = this.mapConverterToDowngradedVersion(converterMapping.converter); |
|||
|
|||
this.cleanUpNewFields(converter as {}); |
|||
|
|||
return { converter, topicFilter: converterMapping.topicFilter }; |
|||
}); |
|||
} |
|||
|
|||
private static mapConverterToDowngradedVersion(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<string, unknown>): void { |
|||
this.mqttRequestMappingOldFields.forEach(field => delete obj[field]); |
|||
deleteNullProperties(obj); |
|||
} |
|||
|
|||
private static cleanUpNewFields(obj: Record<string, unknown>): 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 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 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; |
|||
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 |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,134 @@ |
|||
///
|
|||
/// 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 { |
|||
Attribute, |
|||
AttributesUpdate, |
|||
DeviceConnectorMapping, |
|||
LegacyAttribute, |
|||
LegacyDeviceAttributeUpdate, |
|||
LegacyDeviceConnectorMapping, |
|||
LegacyRpcMethod, |
|||
LegacyServerConfig, |
|||
LegacyTimeseries, |
|||
OPCBasicConfig_v3_5_2, |
|||
OPCUaSourceType, |
|||
RpcArgument, |
|||
RpcMethod, |
|||
ServerConfig, |
|||
Timeseries |
|||
} 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((legacyMapping: LegacyDeviceConnectorMapping) => ({ |
|||
...legacyMapping, |
|||
deviceNodeSource: this.getTypeSourceByValue(legacyMapping.deviceNodePattern), |
|||
deviceInfo: { |
|||
deviceNameExpression: legacyMapping.deviceNamePattern, |
|||
deviceNameExpressionSource: this.getTypeSourceByValue(legacyMapping.deviceNamePattern), |
|||
deviceProfileExpression: legacyMapping.deviceTypePattern ?? 'default', |
|||
deviceProfileExpressionSource: this.getTypeSourceByValue(legacyMapping.deviceTypePattern ?? 'default'), |
|||
}, |
|||
attributes: legacyMapping.attributes.map((attribute: LegacyAttribute) => ({ |
|||
key: attribute.key, |
|||
type: this.getTypeSourceByValue(attribute.path), |
|||
value: attribute.path, |
|||
})), |
|||
attributes_updates: legacyMapping.attributes_updates.map((attributeUpdate: LegacyDeviceAttributeUpdate) => ({ |
|||
key: attributeUpdate.attributeOnThingsBoard, |
|||
type: this.getTypeSourceByValue(attributeUpdate.attributeOnDevice), |
|||
value: attributeUpdate.attributeOnDevice, |
|||
})), |
|||
timeseries: legacyMapping.timeseries.map((timeseries: LegacyTimeseries) => ({ |
|||
key: timeseries.key, |
|||
type: this.getTypeSourceByValue(timeseries.path), |
|||
value: timeseries.path, |
|||
})), |
|||
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((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: upgradedMapping.attributes_updates.map((attributeUpdate: AttributesUpdate) => ({ |
|||
attributeOnThingsBoard: attributeUpdate.key, |
|||
attributeOnDevice: attributeUpdate.value, |
|||
})), |
|||
timeseries: upgradedMapping.timeseries.map((timeseries: Timeseries) => ({ |
|||
key: timeseries.key, |
|||
path: timeseries.value, |
|||
})), |
|||
rpc_methods: upgradedMapping.rpc_methods.map((rpcMethod: RpcMethod) => ({ |
|||
method: rpcMethod.method, |
|||
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': |
|||
return 'boolean'; |
|||
case 'number': |
|||
return Number.isInteger(arg) ? 'integer' : 'float'; |
|||
default: |
|||
return 'string'; |
|||
} |
|||
} |
|||
} |
|||
@ -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.2": { |
|||
"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": [] |
|||
} |
|||
] |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,217 +1,398 @@ |
|||
{ |
|||
"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}" |
|||
"3.5.2": { |
|||
"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}" |
|||
} |
|||
] |
|||
} |
|||
} |
|||
|
|||
@ -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.2": { |
|||
"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" |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue