Added posibility to configure modifier type for timeseries and attributes of Modbus Connector slaves
This commit is contained in:
parent
05a813a2c8
commit
bbbc6fd558
@ -148,6 +148,62 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="showModifiersMap.get(keyControl.get('id').value)" class="tb-form-panel stroked tb-slide-toggle">
|
||||||
|
<mat-expansion-panel class="tb-settings" [expanded]="enableModifiersControlMap.get(keyControl.get('id').value).value">
|
||||||
|
<mat-expansion-panel-header fxLayout="row wrap">
|
||||||
|
<mat-panel-title>
|
||||||
|
<mat-slide-toggle
|
||||||
|
fxLayoutAlign="center"
|
||||||
|
[formControl]="enableModifiersControlMap.get(keyControl.get('id').value)"
|
||||||
|
class="mat-slide"
|
||||||
|
(click)="$event.stopPropagation()"
|
||||||
|
>
|
||||||
|
<mat-label tb-hint-tooltip-icon="{{ 'gateway.hints.modbus.modifier' | translate }}">
|
||||||
|
{{ 'gateway.modifier' | translate }}
|
||||||
|
</mat-label>
|
||||||
|
</mat-slide-toggle>
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<div class="tb-flex no-gap">
|
||||||
|
<div class="tb-form-row column-xs tb-flex full-width" fxLayoutAlign="space-between center">
|
||||||
|
<div class="fixed-title-width" translate>gateway.type</div>
|
||||||
|
<div class="tb-flex no-gap">
|
||||||
|
<mat-form-field class="tb-flex no-gap fill-width" appearance="outline" subscriptSizing="dynamic">
|
||||||
|
<mat-select formControlName="modifierType">
|
||||||
|
<mat-select-trigger>
|
||||||
|
<div class="tb-flex align-center">
|
||||||
|
<mat-icon class="tb-mat-18" [svgIcon]="ModifierTypesMap.get(keyControl.get('modifierType').value)?.icon"></mat-icon>
|
||||||
|
<span>{{ ModifierTypesMap.get(keyControl.get('modifierType').value)?.name | translate}}</span>
|
||||||
|
</div>
|
||||||
|
</mat-select-trigger>
|
||||||
|
<mat-option *ngFor="let modifierType of modifierTypes" [value]="modifierType">
|
||||||
|
<mat-icon class="tb-mat-20" svgIcon="{{ ModifierTypesMap.get(modifierType).icon }}">
|
||||||
|
</mat-icon>
|
||||||
|
<span>{{ ModifierTypesMap.get(modifierType).name | translate }}</span>
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
||||||
|
<div class="fixed-title-width" translate>gateway.value</div>
|
||||||
|
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute">
|
||||||
|
<input matInput required formControlName="modifierValue" step="0.1" type="number"
|
||||||
|
placeholder="{{ 'gateway.set' | translate }}" />
|
||||||
|
<mat-icon matSuffix
|
||||||
|
matTooltipPosition="above"
|
||||||
|
matTooltipClass="tb-error-tooltip"
|
||||||
|
[matTooltip]="('gateway.modifier-invalid') | translate"
|
||||||
|
*ngIf="keyControl.get('modifierValue').hasError('pattern') &&
|
||||||
|
keyControl.get('modifierValue').touched"
|
||||||
|
class="tb-error">
|
||||||
|
warning
|
||||||
|
</mat-icon>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</div>
|
||||||
<div *ngIf="isMaster" class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
<div *ngIf="isMaster" class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
||||||
<div class="fixed-title-width tb-required" translate>gateway.value</div>
|
<div class="fixed-title-width tb-required" translate>gateway.value</div>
|
||||||
<div class="tb-flex no-gap">
|
<div class="tb-flex no-gap">
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angu
|
|||||||
import {
|
import {
|
||||||
AbstractControl,
|
AbstractControl,
|
||||||
FormArray,
|
FormArray,
|
||||||
|
FormControl,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
UntypedFormArray,
|
UntypedFormArray,
|
||||||
UntypedFormBuilder,
|
UntypedFormBuilder,
|
||||||
@ -32,7 +33,10 @@ import {
|
|||||||
ModbusObjectCountByDataType,
|
ModbusObjectCountByDataType,
|
||||||
ModbusValue,
|
ModbusValue,
|
||||||
ModbusValueKey,
|
ModbusValueKey,
|
||||||
|
ModifierType,
|
||||||
|
ModifierTypesMap,
|
||||||
noLeadTrailSpacesRegex,
|
noLeadTrailSpacesRegex,
|
||||||
|
nonZeroFloat,
|
||||||
} from '@home/components/widget/lib/gateway/gateway-widget.models';
|
} from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { SharedModule } from '@shared/shared.module';
|
import { SharedModule } from '@shared/shared.module';
|
||||||
@ -69,12 +73,17 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
keysListFormArray: FormArray<UntypedFormGroup>;
|
keysListFormArray: FormArray<UntypedFormGroup>;
|
||||||
modbusDataTypes = Object.values(ModbusDataType);
|
modbusDataTypes = Object.values(ModbusDataType);
|
||||||
|
modifierTypes: ModifierType[] = Object.values(ModifierType);
|
||||||
withFunctionCode = true;
|
withFunctionCode = true;
|
||||||
|
|
||||||
|
enableModifiersControlMap = new Map<string, FormControl<boolean>>();
|
||||||
|
showModifiersMap = new Map<string, boolean>();
|
||||||
functionCodesMap = new Map();
|
functionCodesMap = new Map();
|
||||||
defaultFunctionCodes = [];
|
defaultFunctionCodes = [];
|
||||||
|
|
||||||
readonly ModbusEditableDataTypes = ModbusEditableDataTypes;
|
readonly ModbusEditableDataTypes = ModbusEditableDataTypes;
|
||||||
readonly ModbusFunctionCodeTranslationsMap = ModbusFunctionCodeTranslationsMap;
|
readonly ModbusFunctionCodeTranslationsMap = ModbusFunctionCodeTranslationsMap;
|
||||||
|
readonly ModifierTypesMap = ModifierTypesMap;
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
@ -101,6 +110,7 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addKey(): void {
|
addKey(): void {
|
||||||
|
const id = generateSecret(5);
|
||||||
const dataKeyFormGroup = this.fb.group({
|
const dataKeyFormGroup = this.fb.group({
|
||||||
tag: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
tag: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||||
value: [{value: '', disabled: !this.isMaster}, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
value: [{value: '', disabled: !this.isMaster}, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||||
@ -108,9 +118,14 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
address: [null, [Validators.required]],
|
address: [null, [Validators.required]],
|
||||||
objectsCount: [1, [Validators.required]],
|
objectsCount: [1, [Validators.required]],
|
||||||
functionCode: [{ value: this.getDefaultFunctionCodes()[0], disabled: !this.withFunctionCode }, [Validators.required]],
|
functionCode: [{ value: this.getDefaultFunctionCodes()[0], disabled: !this.withFunctionCode }, [Validators.required]],
|
||||||
id: [{value: generateSecret(5), disabled: true}],
|
modifierType: [{ value: ModifierType.MULTIPLIER, disabled: true }],
|
||||||
|
modifierValue: [{ value: 1, disabled: true }, [Validators.pattern(nonZeroFloat)]],
|
||||||
|
id: [{value: id, disabled: true}],
|
||||||
});
|
});
|
||||||
|
this.showModifiersMap.set(id, false);
|
||||||
|
this.enableModifiersControlMap.set(id, this.fb.control(false));
|
||||||
this.observeKeyDataType(dataKeyFormGroup);
|
this.observeKeyDataType(dataKeyFormGroup);
|
||||||
|
this.observeEnableModifier(dataKeyFormGroup);
|
||||||
|
|
||||||
this.keysListFormArray.push(dataKeyFormGroup);
|
this.keysListFormArray.push(dataKeyFormGroup);
|
||||||
}
|
}
|
||||||
@ -128,7 +143,17 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyKeysData(): void {
|
applyKeysData(): void {
|
||||||
this.keysDataApplied.emit(this.keysListFormArray.value);
|
this.keysDataApplied.emit(this.mapKeysWithModifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapKeysWithModifier(): Array<ModbusValue> {
|
||||||
|
return this.keysListFormArray.value.map((keyData, i) => {
|
||||||
|
if (this.showModifiersMap.get(this.keysListFormArray.controls[i].get('id').value)) {
|
||||||
|
const { modifierType, modifierValue, ...value } = keyData;
|
||||||
|
return modifierType ? { ...value, [modifierType]: modifierValue } : value;
|
||||||
|
}
|
||||||
|
return keyData;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private prepareKeysFormArray(values: ModbusValue[]): UntypedFormArray {
|
private prepareKeysFormArray(values: ModbusValue[]): UntypedFormArray {
|
||||||
@ -138,6 +163,7 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
values.forEach(value => {
|
values.forEach(value => {
|
||||||
const dataKeyFormGroup = this.createDataKeyFormGroup(value);
|
const dataKeyFormGroup = this.createDataKeyFormGroup(value);
|
||||||
this.observeKeyDataType(dataKeyFormGroup);
|
this.observeKeyDataType(dataKeyFormGroup);
|
||||||
|
this.observeEnableModifier(dataKeyFormGroup);
|
||||||
this.functionCodesMap.set(dataKeyFormGroup.get('id').value, this.getFunctionCodes(value.type));
|
this.functionCodesMap.set(dataKeyFormGroup.get('id').value, this.getFunctionCodes(value.type));
|
||||||
|
|
||||||
keysControlGroups.push(dataKeyFormGroup);
|
keysControlGroups.push(dataKeyFormGroup);
|
||||||
@ -148,7 +174,12 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createDataKeyFormGroup(modbusValue: ModbusValue): FormGroup {
|
private createDataKeyFormGroup(modbusValue: ModbusValue): FormGroup {
|
||||||
const { tag, value, type, address, objectsCount, functionCode } = modbusValue;
|
const { tag, value, type, address, objectsCount, functionCode, multiplier, divider } = modbusValue;
|
||||||
|
const id = generateSecret(5);
|
||||||
|
|
||||||
|
const showModifier = this.shouldShowModifier(type);
|
||||||
|
this.showModifiersMap.set(id, showModifier);
|
||||||
|
this.enableModifiersControlMap.set(id, this.fb.control((multiplier || divider) && showModifier));
|
||||||
|
|
||||||
return this.fb.group({
|
return this.fb.group({
|
||||||
tag: [tag, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
tag: [tag, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||||
@ -157,19 +188,54 @@ export class ModbusDataKeysPanelComponent implements OnInit, OnDestroy {
|
|||||||
address: [address, [Validators.required]],
|
address: [address, [Validators.required]],
|
||||||
objectsCount: [objectsCount, [Validators.required]],
|
objectsCount: [objectsCount, [Validators.required]],
|
||||||
functionCode: [{ value: functionCode, disabled: !this.withFunctionCode }, [Validators.required]],
|
functionCode: [{ value: functionCode, disabled: !this.withFunctionCode }, [Validators.required]],
|
||||||
id: [{ value: generateSecret(5), disabled: true }],
|
modifierType: [{
|
||||||
|
value: divider ? ModifierType.DIVIDER : ModifierType.MULTIPLIER,
|
||||||
|
disabled: !this.enableModifiersControlMap.get(id).value
|
||||||
|
}],
|
||||||
|
modifierValue: [
|
||||||
|
{ value: multiplier ?? divider ?? 1, disabled: !this.enableModifiersControlMap.get(id).value },
|
||||||
|
[Validators.pattern(nonZeroFloat)]
|
||||||
|
],
|
||||||
|
id: [{ value: id, disabled: true }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private shouldShowModifier(type: ModbusDataType): boolean {
|
||||||
|
return !this.isMaster
|
||||||
|
&& (this.keysType === ModbusValueKey.ATTRIBUTES || this.keysType === ModbusValueKey.TIMESERIES)
|
||||||
|
&& (!this.ModbusEditableDataTypes.includes(type));
|
||||||
|
}
|
||||||
|
|
||||||
private observeKeyDataType(keyFormGroup: FormGroup): void {
|
private observeKeyDataType(keyFormGroup: FormGroup): void {
|
||||||
keyFormGroup.get('type').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(dataType => {
|
keyFormGroup.get('type').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(dataType => {
|
||||||
if (!this.ModbusEditableDataTypes.includes(dataType)) {
|
if (!this.ModbusEditableDataTypes.includes(dataType)) {
|
||||||
keyFormGroup.get('objectsCount').patchValue(ModbusObjectCountByDataType[dataType], {emitEvent: false});
|
keyFormGroup.get('objectsCount').patchValue(ModbusObjectCountByDataType[dataType], {emitEvent: false});
|
||||||
}
|
}
|
||||||
|
const withModifier = this.shouldShowModifier(dataType);
|
||||||
|
this.showModifiersMap.set(keyFormGroup.get('id').value, withModifier);
|
||||||
this.updateFunctionCodes(keyFormGroup, dataType);
|
this.updateFunctionCodes(keyFormGroup, dataType);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private observeEnableModifier(keyFormGroup: FormGroup): void {
|
||||||
|
this.enableModifiersControlMap.get(keyFormGroup.get('id').value).valueChanges
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(showModifier => this.toggleModifierControls(keyFormGroup, showModifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
private toggleModifierControls(keyFormGroup: FormGroup, enable: boolean): void {
|
||||||
|
const modifierTypeControl = keyFormGroup.get('modifierType');
|
||||||
|
const modifierValueControl = keyFormGroup.get('modifierValue');
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
modifierTypeControl.enable();
|
||||||
|
modifierValueControl.enable();
|
||||||
|
} else {
|
||||||
|
modifierTypeControl.disable();
|
||||||
|
modifierValueControl.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private updateFunctionCodes(keyFormGroup: FormGroup, dataType: ModbusDataType): void {
|
private updateFunctionCodes(keyFormGroup: FormGroup, dataType: ModbusDataType): void {
|
||||||
const functionCodes = this.getFunctionCodes(dataType);
|
const functionCodes = this.getFunctionCodes(dataType);
|
||||||
this.functionCodesMap.set(keyFormGroup.get('id').value, functionCodes);
|
this.functionCodesMap.set(keyFormGroup.get('id').value, functionCodes);
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { AttributeData } from '@shared/models/telemetry/telemetry.models';
|
|||||||
|
|
||||||
export const noLeadTrailSpacesRegex = /^\S+(?: \S+)*$/;
|
export const noLeadTrailSpacesRegex = /^\S+(?: \S+)*$/;
|
||||||
export const integerRegex = /^[-+]?\d+$/;
|
export const integerRegex = /^[-+]?\d+$/;
|
||||||
|
export const nonZeroFloat = /^-?(?!0(\.0+)?$)\d+(\.\d+)?$/;
|
||||||
|
|
||||||
export enum StorageTypes {
|
export enum StorageTypes {
|
||||||
MEMORY = 'memory',
|
MEMORY = 'memory',
|
||||||
@ -897,6 +898,30 @@ export enum MappingValueType {
|
|||||||
BOOLEAN = 'boolean'
|
BOOLEAN = 'boolean'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ModifierType {
|
||||||
|
DIVIDER = 'divider',
|
||||||
|
MULTIPLIER = 'multiplier',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ModifierTypesMap = new Map<ModifierType, ValueTypeData>(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
ModifierType.DIVIDER,
|
||||||
|
{
|
||||||
|
name: 'gateway.divider',
|
||||||
|
icon: 'mdi:division'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ModifierType.MULTIPLIER,
|
||||||
|
{
|
||||||
|
name: 'gateway.multiplier',
|
||||||
|
icon: 'mdi:multiplication'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
export const mappingValueTypesMap = new Map<MappingValueType, ValueTypeData>(
|
export const mappingValueTypesMap = new Map<MappingValueType, ValueTypeData>(
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
@ -1141,6 +1166,8 @@ export interface ModbusValue {
|
|||||||
objectsCount: number;
|
objectsCount: number;
|
||||||
address: number;
|
address: number;
|
||||||
value?: string;
|
value?: string;
|
||||||
|
multiplier?: number;
|
||||||
|
divider?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModbusSecurity {
|
export interface ModbusSecurity {
|
||||||
|
|||||||
@ -2934,6 +2934,7 @@
|
|||||||
"details": "Details",
|
"details": "Details",
|
||||||
"delete-mapping-title": "Delete mapping?",
|
"delete-mapping-title": "Delete mapping?",
|
||||||
"delete-slave-title": "Delete slave?",
|
"delete-slave-title": "Delete slave?",
|
||||||
|
"divider": "Divider",
|
||||||
"download-configuration-file": "Download configuration file",
|
"download-configuration-file": "Download configuration file",
|
||||||
"download-docker-compose": "Download docker-compose.yml for your gateway",
|
"download-docker-compose": "Download docker-compose.yml for your gateway",
|
||||||
"enable-remote-logging": "Enable remote logging",
|
"enable-remote-logging": "Enable remote logging",
|
||||||
@ -3089,8 +3090,11 @@
|
|||||||
"min-pack-send-delay-required": "Min pack send delay is required",
|
"min-pack-send-delay-required": "Min pack send delay is required",
|
||||||
"min-pack-send-delay-min": "Min pack send delay can not be less then 10",
|
"min-pack-send-delay-min": "Min pack send delay can not be less then 10",
|
||||||
"min-pack-send-delay-pattern": "Min pack send delay is not valid",
|
"min-pack-send-delay-pattern": "Min pack send delay is not valid",
|
||||||
|
"multiplier": "Multiplier",
|
||||||
"mode": "Mode",
|
"mode": "Mode",
|
||||||
"model-name": "Model name",
|
"model-name": "Model name",
|
||||||
|
"modifier": "Modifier",
|
||||||
|
"modifier-invalid": "Modifier is not valid",
|
||||||
"mqtt-version": "MQTT version",
|
"mqtt-version": "MQTT version",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"name-required": "Name is required.",
|
"name-required": "Name is required.",
|
||||||
@ -3493,7 +3497,8 @@
|
|||||||
"objects-count": "Depends on the selected type.",
|
"objects-count": "Depends on the selected type.",
|
||||||
"address": "Register address to verify.",
|
"address": "Register address to verify.",
|
||||||
"key": "Key to be used as the attribute key for the platform instance.",
|
"key": "Key to be used as the attribute key for the platform instance.",
|
||||||
"data-keys": "For more information about function codes and data types click on help icon"
|
"data-keys": "For more information about function codes and data types click on help icon",
|
||||||
|
"modifier": "The retrieved value will be adjusted (by multiplying or dividing it) based on the specified modifier value."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user