47 changed files with 2736 additions and 686 deletions
@ -0,0 +1,86 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<div class="tb-form-panel no-border no-padding padding-top" [formGroup]="brokerConfigFormGroup"> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width tb-required" translate>gateway.host</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput name="value" formControlName="host" placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="('gateway.host-required') | translate" |
|||
*ngIf="brokerConfigFormGroup.get('host').hasError('required') |
|||
&& brokerConfigFormGroup.get('host').touched" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width tb-required" translate>gateway.port</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput type="number" min="{{portLimits.MIN}}" max="{{portLimits.MAX}}" |
|||
name="value" formControlName="port" placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="portErrorTooltip" |
|||
*ngIf="(brokerConfigFormGroup.get('port').hasError('required') || |
|||
brokerConfigFormGroup.get('port').hasError('min') || |
|||
brokerConfigFormGroup.get('port').hasError('max')) && |
|||
brokerConfigFormGroup.get('port').touched" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width" translate>gateway.mqtt-version</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<mat-select formControlName="version"> |
|||
<mat-option *ngFor="let version of mqttVersions" [value]="version.value">{{ version.name }}</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width" translate>gateway.client-id</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput name="value" formControlName="clientId" placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<button type="button" |
|||
matSuffix |
|||
mat-icon-button |
|||
aria-label="Generate" |
|||
matTooltip="{{ 'gateway.generate-client-id' | translate }}" |
|||
matTooltipPosition="above" |
|||
(click)="generate('clientId')" |
|||
*ngIf="!brokerConfigFormGroup.get('clientId').value"> |
|||
<mat-icon>autorenew</mat-icon> |
|||
</button> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<tb-security-config [formControl]="brokerConfigFormGroup.get('security')"> |
|||
</tb-security-config> |
|||
</div> |
|||
@ -0,0 +1,129 @@ |
|||
///
|
|||
/// 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, |
|||
inject, |
|||
Input, |
|||
OnDestroy, |
|||
OnInit |
|||
} from '@angular/core'; |
|||
import { |
|||
ControlContainer, |
|||
ControlValueAccessor, |
|||
FormBuilder, |
|||
FormGroup, |
|||
NG_VALUE_ACCESSOR, |
|||
UntypedFormGroup, |
|||
Validators |
|||
} from '@angular/forms'; |
|||
import { |
|||
MqttVersions, |
|||
noLeadTrailSpacesRegex, |
|||
PortLimits, |
|||
} from '@home/components/widget/lib/gateway/gateway-widget.models'; |
|||
import { SharedModule } from '@shared/shared.module'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { generateSecret } from '@core/utils'; |
|||
import { SecurityConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-broker-config-control', |
|||
templateUrl: './broker-config-control.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
standalone: true, |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
SecurityConfigComponent, |
|||
], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => BrokerConfigControlComponent), |
|||
multi: true |
|||
} |
|||
] |
|||
}) |
|||
export class BrokerConfigControlComponent implements ControlValueAccessor, OnInit, OnDestroy { |
|||
@Input() controlKey = 'broker'; |
|||
|
|||
brokerConfigFormGroup: UntypedFormGroup; |
|||
mqttVersions = MqttVersions; |
|||
portLimits = PortLimits; |
|||
|
|||
get parentFormGroup(): FormGroup { |
|||
return this.parentContainer.control as FormGroup; |
|||
} |
|||
|
|||
private parentContainer = inject(ControlContainer); |
|||
private translate = inject(TranslateService); |
|||
|
|||
constructor(private fb: FormBuilder) { |
|||
this.brokerConfigFormGroup = this.fb.group({ |
|||
name: ['', []], |
|||
host: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], |
|||
port: [null, [Validators.required, Validators.min(PortLimits.MIN), Validators.max(PortLimits.MAX)]], |
|||
version: [5, []], |
|||
clientId: ['', [Validators.pattern(noLeadTrailSpacesRegex)]], |
|||
maxNumberOfWorkers: [100, [Validators.required, Validators.min(1)]], |
|||
maxMessageNumberPerWorker: [10, [Validators.required, Validators.min(1)]], |
|||
security: [{}, [Validators.required]] |
|||
}); |
|||
} |
|||
|
|||
get portErrorTooltip(): string { |
|||
if (this.brokerConfigFormGroup.get('port').hasError('required')) { |
|||
return this.translate.instant('gateway.port-required'); |
|||
} else if ( |
|||
this.brokerConfigFormGroup.get('port').hasError('min') || |
|||
this.brokerConfigFormGroup.get('port').hasError('max') |
|||
) { |
|||
return this.translate.instant('gateway.port-limits-error', |
|||
{min: PortLimits.MIN, max: PortLimits.MAX}); |
|||
} |
|||
return ''; |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this.addSelfControl(); |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
this.removeSelfControl(); |
|||
} |
|||
|
|||
generate(formControlName: string): void { |
|||
this.brokerConfigFormGroup.get(formControlName)?.patchValue('tb_gw_' + generateSecret(5)); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void {} |
|||
|
|||
registerOnTouched(fn: any): void {} |
|||
|
|||
writeValue(obj: any): void {} |
|||
|
|||
private addSelfControl(): void { |
|||
this.parentFormGroup.addControl(this.controlKey, this.brokerConfigFormGroup); |
|||
} |
|||
|
|||
private removeSelfControl(): void { |
|||
this.parentFormGroup.removeControl(this.controlKey); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
export * from './mapping-table/mapping-table.component'; |
|||
export * from './device-info-table/device-info-table.component'; |
|||
export * from './security-config/security-config.component'; |
|||
export * from './server-config/server-config.component'; |
|||
export * from './mapping-data-keys-panel/mapping-data-keys-panel.component'; |
|||
export * from './type-value-panel/type-value-panel.component'; |
|||
export * from './broker-config-control/broker-config-control.component'; |
|||
export * from './workers-config-control/workers-config-control.component'; |
|||
@ -0,0 +1,125 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<div class="tb-form-panel no-border no-padding padding-top" [formGroup]="serverConfigFormGroup"> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width" translate>gateway.server-url</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput name="value" formControlName="url" placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="('gateway.server-url-required') | translate" |
|||
*ngIf="serverConfigFormGroup.get('url').hasError('required') && |
|||
serverConfigFormGroup.get('url').touched" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width" tb-hint-tooltip-icon="{{ 'gateway.hints.opcua-timeout' | translate }}" translate> |
|||
gateway.timeout |
|||
</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput type="number" min="0" name="value" formControlName="timeoutInMillis" placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="'gateway.timeout-error' | translate: {min: 1000}" |
|||
*ngIf="(serverConfigFormGroup.get('timeoutInMillis').hasError('required') || |
|||
serverConfigFormGroup.get('timeoutInMillis').hasError('min')) && |
|||
serverConfigFormGroup.get('timeoutInMillis').touched" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width" translate>gateway.security</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<mat-select formControlName="security"> |
|||
<mat-option *ngFor="let version of serverSecurityTypes" [value]="version.value">{{ version.name }}</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width" tb-hint-tooltip-icon="{{ 'gateway.hints.scan-period' | translate }}" translate> |
|||
gateway.scan-period |
|||
</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput type="number" min="0" name="value" |
|||
formControlName="scanPeriodInMillis" placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="'gateway.scan-period-error' | translate: {min: 1000}" |
|||
*ngIf="(serverConfigFormGroup.get('scanPeriodInMillis').hasError('required') || |
|||
serverConfigFormGroup.get('scanPeriodInMillis').hasError('min')) && |
|||
serverConfigFormGroup.get('scanPeriodInMillis').touched" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width" tb-hint-tooltip-icon="{{ 'gateway.hints.sub-check-period' | translate }}" translate> |
|||
gateway.sub-check-period |
|||
</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput type="number" min="0" name="value" |
|||
formControlName="subCheckPeriodInMillis" placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="'gateway.sub-check-period-error' | translate: {min: 10}" |
|||
*ngIf="(serverConfigFormGroup.get('subCheckPeriodInMillis').hasError('required') || |
|||
serverConfigFormGroup.get('subCheckPeriodInMillis').hasError('min')) && |
|||
serverConfigFormGroup.get('subCheckPeriodInMillis').touched" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row" fxLayoutAlign="space-between center"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="enableSubscriptions"> |
|||
<mat-label tb-hint-tooltip-icon="{{ 'gateway.hints.enable-subscription' | translate }}"> |
|||
{{ 'gateway.enable-subscription' | translate }} |
|||
</mat-label> |
|||
</mat-slide-toggle> |
|||
</div> |
|||
<div class="tb-form-row" fxLayoutAlign="space-between center"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="showMap"> |
|||
<mat-label tb-hint-tooltip-icon="{{ 'gateway.hints.show-map' | translate }}"> |
|||
{{ 'gateway.show-map' | translate }} |
|||
</mat-label> |
|||
</mat-slide-toggle> |
|||
</div> |
|||
<tb-security-config [formControl]="serverConfigFormGroup.get('identity')" |
|||
[extendCertificatesModel]="true"> |
|||
</tb-security-config> |
|||
</div> |
|||
@ -0,0 +1,20 @@ |
|||
/** |
|||
* Copyright © 2016-2024 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
:host { |
|||
width: 100%; |
|||
height: 100%; |
|||
display: block; |
|||
} |
|||
@ -0,0 +1,106 @@ |
|||
///
|
|||
/// 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, inject, Input, |
|||
OnDestroy, OnInit |
|||
} from '@angular/core'; |
|||
import { |
|||
ControlContainer, |
|||
ControlValueAccessor, |
|||
FormBuilder, FormGroup, |
|||
NG_VALUE_ACCESSOR, |
|||
UntypedFormGroup, |
|||
Validators |
|||
} from '@angular/forms'; |
|||
import { |
|||
noLeadTrailSpacesRegex, |
|||
SecurityType, |
|||
ServerSecurityTypes |
|||
} from '@home/components/widget/lib/gateway/gateway-widget.models'; |
|||
import { SharedModule } from '@shared/shared.module'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SecurityConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-server-config', |
|||
templateUrl: './server-config.component.html', |
|||
styleUrls: ['./server-config.component.scss'], |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => ServerConfigComponent), |
|||
multi: true |
|||
}, |
|||
], |
|||
standalone: true, |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
SecurityConfigComponent, |
|||
] |
|||
}) |
|||
export class ServerConfigComponent implements OnInit, ControlValueAccessor, OnDestroy { |
|||
@Input() controlKey = 'server'; |
|||
|
|||
serverSecurityTypes = ServerSecurityTypes; |
|||
serverConfigFormGroup: UntypedFormGroup; |
|||
|
|||
get parentFormGroup(): FormGroup { |
|||
return this.parentContainer.control as FormGroup; |
|||
} |
|||
|
|||
private parentContainer = inject(ControlContainer); |
|||
|
|||
constructor(private fb: FormBuilder) { |
|||
this.serverConfigFormGroup = this.fb.group({ |
|||
name: ['', []], |
|||
url: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], |
|||
timeoutInMillis: [1000, [Validators.required, Validators.min(1000)]], |
|||
scanPeriodInMillis: [1000, [Validators.required, Validators.min(1000)]], |
|||
enableSubscriptions: [true, []], |
|||
subCheckPeriodInMillis: [10, [Validators.required, Validators.min(10)]], |
|||
showMap: [false, []], |
|||
security: [SecurityType.BASIC128, []], |
|||
identity: [{}, [Validators.required]] |
|||
}); |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this.addSelfControl(); |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
this.removeSelfControl(); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void {} |
|||
|
|||
registerOnTouched(fn: any): void {} |
|||
|
|||
writeValue(obj: any): void {} |
|||
|
|||
private addSelfControl(): void { |
|||
this.parentFormGroup.addControl(this.controlKey, this.serverConfigFormGroup); |
|||
} |
|||
|
|||
private removeSelfControl(): void { |
|||
this.parentFormGroup.removeControl(this.controlKey); |
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<div class="tb-form-panel no-border no-padding"> |
|||
<div class="tb-form-panel no-border no-padding key-panel" *ngIf="valueListFormArray.controls.length; else noKeys"> |
|||
<div class="tb-form-panel no-border no-padding tb-flex no-flex row center fill-width" |
|||
*ngFor="let keyControl of valueListFormArray.controls; trackBy: trackByKey; let $index = index; let last = last;"> |
|||
<div class="tb-form-panel stroked tb-flex"> |
|||
<ng-container [formGroup]="keyControl"> |
|||
<mat-expansion-panel class="tb-settings" [expanded]="last"> |
|||
<mat-expansion-panel-header fxLayout="row wrap"> |
|||
<mat-panel-title> |
|||
<div class="title-container">{{ valueTitle(keyControl.get('value').value) }}</div> |
|||
</mat-panel-title> |
|||
</mat-expansion-panel-header> |
|||
<ng-template matExpansionPanelContent> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width tb-required" 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 name="valueType" formControlName="type"> |
|||
<mat-select-trigger> |
|||
<div class="tb-flex align-center"> |
|||
<mat-icon class="tb-mat-18" [svgIcon]="valueTypes.get(keyControl.get('type').value)?.icon"> |
|||
</mat-icon> |
|||
<span> |
|||
{{ valueTypes.get(keyControl.get('type').value)?.name | translate}} |
|||
</span> |
|||
</div> |
|||
</mat-select-trigger> |
|||
<mat-option *ngFor="let valueType of valueTypeKeys" [value]="valueType"> |
|||
<mat-icon class="tb-mat-20" svgIcon="{{ valueTypes.get(valueType).icon }}"> |
|||
</mat-icon> |
|||
<span>{{ valueTypes.get(valueType).name | translate }}</span> |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width tb-required" translate>gateway.value</div> |
|||
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute"> |
|||
<input matInput required formControlName="value" |
|||
placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="('gateway.value-required') | translate" |
|||
*ngIf="keyControl.get('value').hasError('required') && keyControl.get('value').touched" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</ng-template> |
|||
</mat-expansion-panel> |
|||
</ng-container> |
|||
</div> |
|||
<button type="button" |
|||
mat-icon-button |
|||
(click)="deleteKey($event, $index)" |
|||
[matTooltip]="'gateway.delete-value' | translate" |
|||
matTooltipPosition="above"> |
|||
<mat-icon>delete</mat-icon> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<div> |
|||
<button type="button" mat-stroked-button color="primary" (click)="addKey()"> |
|||
{{ 'gateway.add-value' | translate }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<ng-template #noKeys> |
|||
<div class="tb-flex no-flex center align-center key-panel"> |
|||
<span class="tb-prompt" translate>{{ 'gateway.no-value' }}</span> |
|||
</div> |
|||
</ng-template> |
|||
@ -0,0 +1,52 @@ |
|||
/** |
|||
* Copyright © 2016-2024 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
|
|||
:host { |
|||
|
|||
.title-container { |
|||
max-width: 11vw; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap |
|||
} |
|||
|
|||
.key-panel { |
|||
height: 250px; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.tb-form-panel { |
|||
.mat-mdc-icon-button { |
|||
width: 56px; |
|||
height: 56px; |
|||
padding: 16px; |
|||
color: rgba(0, 0, 0, 0.54); |
|||
} |
|||
} |
|||
|
|||
.see-example { |
|||
width: 32px; |
|||
height: 32px; |
|||
margin: 4px; |
|||
} |
|||
} |
|||
|
|||
:host ::ng-deep { |
|||
.mat-mdc-form-field-icon-suffix { |
|||
display: flex; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,144 @@ |
|||
///
|
|||
/// 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, |
|||
OnDestroy, |
|||
OnInit, |
|||
} from '@angular/core'; |
|||
import { |
|||
AbstractControl, |
|||
ControlValueAccessor, |
|||
NG_VALIDATORS, |
|||
NG_VALUE_ACCESSOR, |
|||
UntypedFormArray, |
|||
UntypedFormBuilder, |
|||
ValidationErrors, |
|||
Validator, |
|||
Validators |
|||
} from '@angular/forms'; |
|||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; |
|||
import { isDefinedAndNotNull } from '@core/utils'; |
|||
import { |
|||
MappingDataKey, |
|||
MappingValueType, |
|||
mappingValueTypesMap, |
|||
noLeadTrailSpacesRegex |
|||
} from '@home/components/widget/lib/gateway/gateway-widget.models'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { Subject } from 'rxjs'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-type-value-panel', |
|||
templateUrl: './type-value-panel.component.html', |
|||
styleUrls: ['./type-value-panel.component.scss'], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => TypeValuePanelComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => TypeValuePanelComponent), |
|||
multi: true |
|||
} |
|||
] |
|||
}) |
|||
export class TypeValuePanelComponent implements ControlValueAccessor, Validator, OnInit, OnDestroy { |
|||
valueTypeKeys = Object.values(MappingValueType); |
|||
valueTypeEnum = MappingValueType; |
|||
valueTypes = mappingValueTypesMap; |
|||
dataKeyType: DataKeyType; |
|||
valueListFormArray: UntypedFormArray; |
|||
errorText = ''; |
|||
|
|||
private destroy$ = new Subject<void>(); |
|||
private propagateChange = (v: any) => {}; |
|||
|
|||
constructor(private fb: UntypedFormBuilder) {} |
|||
|
|||
ngOnInit(): void { |
|||
this.valueListFormArray = this.fb.array([]); |
|||
this.valueListFormArray.valueChanges.pipe( |
|||
takeUntil(this.destroy$) |
|||
).subscribe((value) => { |
|||
this.updateView(value); |
|||
}); |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
this.destroy$.next(); |
|||
this.destroy$.complete(); |
|||
} |
|||
|
|||
trackByKey(_: number, keyControl: AbstractControl): any { |
|||
return keyControl; |
|||
} |
|||
|
|||
addKey(): void { |
|||
const dataKeyFormGroup = this.fb.group({ |
|||
type: [MappingValueType.STRING, []], |
|||
value: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]] |
|||
}); |
|||
this.valueListFormArray.push(dataKeyFormGroup); |
|||
} |
|||
|
|||
deleteKey($event: Event, index: number): void { |
|||
if ($event) { |
|||
$event.stopPropagation(); |
|||
} |
|||
this.valueListFormArray.removeAt(index); |
|||
this.valueListFormArray.markAsDirty(); |
|||
} |
|||
|
|||
valueTitle(value: any): string { |
|||
if (isDefinedAndNotNull(value)) { |
|||
if (typeof value === 'object') { |
|||
return JSON.stringify(value); |
|||
} |
|||
return value; |
|||
} |
|||
return ''; |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void {} |
|||
|
|||
writeValue(deviceInfoArray: Array<MappingDataKey>): void { |
|||
for (const deviceInfo of deviceInfoArray) { |
|||
const dataKeyFormGroup = this.fb.group({ |
|||
type: [deviceInfo.type, []], |
|||
value: [deviceInfo.value, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]] |
|||
}); |
|||
this.valueListFormArray.push(dataKeyFormGroup); |
|||
} |
|||
} |
|||
|
|||
validate(): ValidationErrors | null { |
|||
return this.valueListFormArray.valid ? null : { |
|||
valueListForm: { valid: false } |
|||
}; |
|||
} |
|||
|
|||
updateView(value: any): void { |
|||
this.propagateChange(value); |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<div class="tb-form-panel no-border no-padding padding-top" [formGroup]="workersConfigFormGroup"> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width tb-required" [style.width.%]="50" |
|||
tb-hint-tooltip-icon="{{ 'gateway.max-number-of-workers-hint' | translate }}" translate> |
|||
gateway.max-number-of-workers |
|||
</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput name="value" type="number" min="1" formControlName="maxNumberOfWorkers" |
|||
placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="('gateway.max-number-of-workers-required') | translate" |
|||
*ngIf="workersConfigFormGroup.get('maxNumberOfWorkers').hasError('min') || |
|||
(workersConfigFormGroup.get('maxNumberOfWorkers').hasError('required') && |
|||
workersConfigFormGroup.get('maxNumberOfWorkers').touched)" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> |
|||
<div class="fixed-title-width tb-required" [style.width.%]="50" |
|||
tb-hint-tooltip-icon="{{ 'gateway.max-messages-queue-for-worker-hint' | translate }}" translate> |
|||
gateway.max-messages-queue-for-worker |
|||
</div> |
|||
<div class="tb-flex no-gap"> |
|||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput name="value" type="number" min="1" formControlName="maxMessageNumberPerWorker" |
|||
placeholder="{{ 'gateway.set' | translate }}"/> |
|||
<mat-icon matSuffix |
|||
matTooltipPosition="above" |
|||
matTooltipClass="tb-error-tooltip" |
|||
[matTooltip]="('gateway.max-messages-queue-for-worker-required') | translate" |
|||
*ngIf="workersConfigFormGroup.get('maxMessageNumberPerWorker').hasError('min') || |
|||
(workersConfigFormGroup.get('maxMessageNumberPerWorker').hasError('required') && |
|||
workersConfigFormGroup.get('maxMessageNumberPerWorker').touched)" |
|||
class="tb-error"> |
|||
warning |
|||
</mat-icon> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,94 @@ |
|||
///
|
|||
/// 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, |
|||
inject, |
|||
Input, |
|||
OnDestroy, |
|||
OnInit |
|||
} from '@angular/core'; |
|||
import { |
|||
ControlContainer, |
|||
ControlValueAccessor, |
|||
FormBuilder, |
|||
FormGroup, |
|||
NG_VALUE_ACCESSOR, |
|||
UntypedFormGroup, |
|||
Validators |
|||
} from '@angular/forms'; |
|||
import { SharedModule } from '@shared/shared.module'; |
|||
import { CommonModule } from '@angular/common'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-workers-config-control', |
|||
templateUrl: './workers-config-control.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
standalone: true, |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => WorkersConfigControlComponent), |
|||
multi: true |
|||
} |
|||
] |
|||
}) |
|||
export class WorkersConfigControlComponent implements ControlValueAccessor, OnInit, OnDestroy { |
|||
@Input() controlKey = 'workers'; |
|||
|
|||
workersConfigFormGroup: UntypedFormGroup; |
|||
|
|||
get parentFormGroup(): FormGroup { |
|||
return this.parentContainer.control as FormGroup; |
|||
} |
|||
|
|||
private parentContainer = inject(ControlContainer); |
|||
|
|||
constructor(private fb: FormBuilder) { |
|||
this.workersConfigFormGroup = this.fb.group({ |
|||
maxNumberOfWorkers: [100, [Validators.required, Validators.min(1)]], |
|||
maxMessageNumberPerWorker: [10, [Validators.required, Validators.min(1)]], |
|||
}); |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this.addSelfControl(); |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
this.removeSelfControl(); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void {} |
|||
|
|||
registerOnTouched(fn: any): void {} |
|||
|
|||
writeValue(obj: any): void {} |
|||
|
|||
private addSelfControl(): void { |
|||
this.parentFormGroup.addControl(this.controlKey, this.workersConfigFormGroup); |
|||
} |
|||
|
|||
private removeSelfControl(): void { |
|||
this.parentFormGroup.removeControl(this.controlKey); |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
///
|
|||
/// 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 { Pipe, PipeTransform } from '@angular/core'; |
|||
import { |
|||
MappingValueType, |
|||
OPCUaSourceTypes, |
|||
SourceTypes |
|||
} from '@home/components/widget/lib/gateway/gateway-widget.models'; |
|||
|
|||
@Pipe({ |
|||
name: 'getGatewayHelpLink', |
|||
standalone: true, |
|||
}) |
|||
export class GatewayHelpLinkPipe implements PipeTransform { |
|||
transform(field: string, sourceType: SourceTypes | OPCUaSourceTypes, sourceTypes?: Array<SourceTypes | OPCUaSourceTypes | MappingValueType> ): string { |
|||
if (!sourceTypes || sourceTypes?.includes(OPCUaSourceTypes.PATH)) { |
|||
if (sourceType !== OPCUaSourceTypes.CONST) { |
|||
return `widget/lib/gateway/${field}-${sourceType}_fn`; |
|||
} else { |
|||
return; |
|||
} |
|||
} |
|||
return 'widget/lib/gateway/expressions_fn'; |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
///
|
|||
/// 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.
|
|||
///
|
|||
|
|||
export * from './gateway-help-link/gateway-help-link.pipe'; |
|||
@ -0,0 +1,24 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { UntypedFormArray, ValidatorFn } from '@angular/forms'; |
|||
|
|||
export function validateArrayIsNotEmpty(): ValidatorFn { |
|||
return (formArray: UntypedFormArray): { formArrayIsEmpty: boolean } => { |
|||
const length = formArray.length; |
|||
return length ? null : { formArrayIsEmpty: true }; |
|||
}; |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
An **Identifier** type is a unique ID assigned to a node within the OPC-UA server. It is used to directly reference specific nodes without navigating through the namespace hierarchy. |
|||
The **Identifier** type in the OPC-UA connector configuration can be used in various forms to uniquely reference nodes in the OPC-UA server's address space. Identifiers can be of different types, such as numeric (i), string (s), byte string (b), and GUID (g). Below is an explanation of each identifier type with examples. |
|||
|
|||
- ##### Numeric Identifier (`i`) |
|||
A **numeric identifier** uses an integer value to uniquely reference a node in the OPC-UA server. |
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**ns=2;i=1235**” node is **21.34**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${ns=2;i=1235}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`21.34`** |
|||
|
|||
- ##### String Identifier (`s`) |
|||
A **string identifier** uses a string value to uniquely reference a node in the OPC-UA server. |
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**ns=3;s=TemperatureSensor**” node is **21.34**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${ns=3;s=TemperatureSensor}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`21.34`** |
|||
|
|||
- ##### Byte String Identifier (`b`) |
|||
A **byte string identifier** uses a byte string to uniquely reference a node in the OPC-UA server. This is useful for binary data that can be converted to a byte string. |
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**ns=4;b=Q2xpZW50RGF0YQ==**” node is **21.34**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${ns=4;b=Q2xpZW50RGF0YQ==}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`21.34`** |
|||
|
|||
- ##### GUID Identifier (`g`) |
|||
A **GUID identifier** uses a globally unique identifier (GUID) to uniquely reference a node in the OPC-UA server. |
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**ns=1;g=550e8400-e29b-41d4-a716-446655440000**” node is **21.34**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${ns=1;g=550e8400-e29b-41d4-a716-446655440000}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`21.34`** |
|||
@ -0,0 +1,36 @@ |
|||
A **Path** type refers to the hierarchical address within the OPC-UA server's namespace. It is used to navigate to specific |
|||
nodes in the server. |
|||
|
|||
The path for the attribute value can be absolute or relative. |
|||
|
|||
### Absolute Path |
|||
An **absolute path** specifies the full hierarchical address from the root of the OPC-UA server's namespace to the target node. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of Root\\.Objects\\.TempSensor\\.Temperature is 23.54. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${Root\.Objects\.TempSensor\.Temperature}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`23.54`** |
|||
|
|||
### Relative Path |
|||
A **relative path** specifies the address relative to a predefined starting point in the OPC-UA server's namespace. |
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “Root\\.Objects\\.TempSensor\\.Temperature” is 23.56. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${Temperature}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`23.56`** |
|||
|
|||
Additionally, you can use the node browser name to ensure that your path cannot be altered by the user or server. |
|||
|
|||
###### Example: |
|||
**`Root\.0:Objects\.3:Simulation`** |
|||
@ -0,0 +1,46 @@ |
|||
An **Identifier** type is a unique ID assigned to a node within the OPC-UA server. It is used to directly reference |
|||
specific nodes without navigating through the namespace hierarchy. |
|||
|
|||
The **Identifier** type in the OPC-UA connector configuration can be used in various forms to uniquely reference nodes |
|||
in the OPC-UA server's address space. Identifiers can be of different types, such as numeric (`i`), string (`s`), |
|||
byte string (`b`), and GUID (`g`). Below is an explanation of each identifier type with examples. |
|||
|
|||
- ##### Numeric Identifier (`i`) |
|||
A **numeric identifier** uses an integer value to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`ns=2;i=1236`** |
|||
|
|||
- ##### String Identifier (`s`) |
|||
A **string identifier** uses a string value to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`ns=3;s=TemperatureSensor`** |
|||
|
|||
- ##### Byte String Identifier (`b`) |
|||
A **byte string identifier** uses a byte string to uniquely reference a node in the OPC-UA server. This is useful for binary data that can be converted to a byte string. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`ns=4;b=Q2xpZW50RGF0YQ==`** |
|||
|
|||
- ##### GUID Identifier (`g`) |
|||
A **GUID identifier** uses a globally unique identifier (GUID) to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`ns=1;g=550e8400-e29b-41d4-a716-446655440000`** |
|||
@ -0,0 +1,34 @@ |
|||
A **Path** type refers to the hierarchical address within the OPC-UA server's namespace. It is used to navigate to |
|||
specific nodes in the server. |
|||
|
|||
The path for device name can be absolute or relative. |
|||
|
|||
### Absolute Path |
|||
An **absolute path** specifies the full hierarchical address from the root of the OPC-UA server's namespace to |
|||
the target node. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of **Root\\.Objects\\.TempSensor\\.Version** is “**1.0.3**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Root\.Objects\.TempSensor\.Version`** |
|||
|
|||
In this example, the attribute update request will write the received data to the configured node above. |
|||
|
|||
### Relative Path |
|||
A **relative path** specifies the address relative to a predefined starting point in the OPC-UA server's namespace. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of **Root\\.Objects\\.TempSensor\\.Name** is “**TH-101**”. |
|||
|
|||
_Device Node expression:_ |
|||
|
|||
**`Root\.Objects\.TempSensor`** |
|||
|
|||
_Expression:_ |
|||
|
|||
**`.Version`** |
|||
|
|||
In this example, **the gateway will search for the child node "Name" in the device node (parent node) |
|||
"Root\\.Objects\\.TempSensor"** and will write received data on it. |
|||
@ -0,0 +1,34 @@ |
|||
## Device Node Field |
|||
|
|||
### Identifier: |
|||
|
|||
Device Node field value is used to identify the node for the current device. |
|||
|
|||
An Identifier type is a unique ID assigned to a node within the OPC-UA server. It is used to directly reference specific nodes without navigating through the namespace hierarchy. |
|||
The Identifier type in the OPC-UA connector configuration can be used in various forms to uniquely reference nodes in the OPC-UA server's address space. Identifiers can be of different types, such as numeric (`i`), string (`s`), byte string (`b`), and GUID (`g`). Below is an explanation of each identifier type with examples. |
|||
|
|||
- ##### Numeric Identifier (`i`) |
|||
A numeric identifier uses an integer value to uniquely reference a node in the OPC-UA server. |
|||
###### Example: |
|||
`ns=2;i=1234` |
|||
In this example, `ns=2` specifies the namespace index `2`, and `i=1234` specifies the numeric identifier `1234` for the node. |
|||
|
|||
- ##### String Identifier (`s`) |
|||
A string identifier uses a string value to uniquely reference a node in the OPC-UA server. |
|||
###### Example: |
|||
`ns=3;s=TemperatureSensor` |
|||
Here, `ns=3` specifies the namespace index `3`, and `s=TemperatureSensor` specifies the string identifier for the node. |
|||
|
|||
- ##### Byte String Identifier (`b`) |
|||
An byte string identifier uses a byte string to uniquely reference a node in the OPC-UA server. This is useful for binary data that can be converted to a byte string. |
|||
###### Example: |
|||
`ns=4;b=Q2xpZW50RGF0YQ==` |
|||
In this example, `ns=4` specifies the namespace index `4`, and `b=Q2xpZW50RGF0YQ==` specifies the byte string identifier for the node (base64 encoded). |
|||
|
|||
- ##### GUID Identifier (`g`) |
|||
A GUID identifier uses a globally unique identifier (GUID) to uniquely reference a node in the OPC-UA server. |
|||
###### Example: |
|||
`ns=1;g=550e8400-e29b-41d4-a716-446655440000` |
|||
Here, `ns=1` specifies the namespace index `1`, and `g=550e8400-e29b-41d4-a716-446655440000` specifies the GUID for the node. |
|||
|
|||
By using these different identifier types, you can accurately and uniquely reference nodes in the OPC-UA server's address space, regardless of the format of the node identifiers. |
|||
@ -0,0 +1,20 @@ |
|||
## Device Node Field |
|||
### Path: |
|||
|
|||
Device Node field value is used to identify the node for the current device. The connector will use this node as the parent node of the device. |
|||
|
|||
A Path type refers to the hierarchical address within the OPC-UA server's namespace. It is used to navigate to specific nodes in the server. |
|||
|
|||
The path for Device node can be only absolute. |
|||
|
|||
An absolute path specifies the full hierarchical address from the root of the OPC-UA server's namespace to the target node. |
|||
|
|||
###### Examples: |
|||
|
|||
- `Root\.Objects\.TempSensor` |
|||
|
|||
In this example, the `Value` specifies the full path to the `TempSensor` node located in the `Objects` namespace, starting from the root. |
|||
|
|||
Additionally, you can use the node browser name to ensure that your path cannot be altered by the user or server. |
|||
|
|||
- `Root\.0:Objects\.3:Simulation` |
|||
@ -0,0 +1,67 @@ |
|||
## Device Name Field |
|||
|
|||
Device name field is used for looking the device name in some variable. |
|||
|
|||
An **Identifier** type is a unique ID assigned to a node within the OPC-UA server. It is used to directly reference |
|||
specific nodes without navigating through the namespace hierarchy. |
|||
|
|||
**Identifier** type in the OPC-UA connector configuration can be used in various forms to uniquely reference nodes in |
|||
the OPC-UA server's address space. Identifiers can be of different types, such as numeric (`**i**`), string (`**s**`), |
|||
byte string (`**b**`), and GUID (`**g**`). Below is an explanation of each identifier type with examples. |
|||
|
|||
- ##### **Numeric Identifier (`i`)** |
|||
|
|||
A **numeric identifier** uses an integer value to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### **Example:** |
|||
|
|||
Gateway expects that the node exist and the value of **ns=2;i=1234** node is “**TH-101**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${ns=2;i=1234}`** |
|||
|
|||
In this example, created device on platform will have “**Device TH-101**” name. |
|||
|
|||
- ##### **String Identifier (`s`)** |
|||
|
|||
A **string identifier** uses a string value to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### **Example:** |
|||
|
|||
Gateway expects that the node exist and the value of **ns=3;s=TemperatureSensor** node is “**TH-101**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${ns=3;s=TemperatureSensor}`** |
|||
|
|||
In this example, created device on platform will have “**Device TH-101**” name. |
|||
|
|||
- ##### **Byte String Identifier (`b`)** |
|||
|
|||
A **byte string identifier** uses a byte string to uniquely reference a node in the OPC-UA server. |
|||
This is useful for binary data that can be converted to a byte string. |
|||
|
|||
###### **Example:** |
|||
|
|||
Gateway expects that the node exist and the value of **ns=4;b=Q2xpZW50RGF0YQ==** node is “**TH-101**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${ns=4;b=Q2xpZW50RGF0YQ==}`** |
|||
|
|||
In this example, created device on platform will have “**Device TH-101**” name. |
|||
|
|||
- ##### GUID Identifier (**`g`**) |
|||
|
|||
A **GUID identifier** uses a globally unique identifier (GUID) to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### **Example:** |
|||
|
|||
Gateway expects that the node exist and the value of **ns=1;g=550e8400-e29b-41d4-a716-446655440000** node is “**TH-101**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
Device ${ns=1;g=550e8400-e29b-41d4-a716-446655440000} |
|||
|
|||
In this example, created device on platform will have “**Device TH-101**” name. |
|||
@ -0,0 +1,41 @@ |
|||
## Device Name Field |
|||
|
|||
Device name field is used for looking the device name in some variable. |
|||
|
|||
A **Path** type refers to the hierarchical address within the OPC-UA server's namespace. It is used to navigate to |
|||
specific nodes in the server. |
|||
|
|||
The path for device name can be absolute or relative. |
|||
|
|||
### Absolute Path |
|||
An **absolute path** specifies the full hierarchical address from the root of the OPC-UA server's namespace to the |
|||
target node. |
|||
|
|||
##### **Example:** |
|||
|
|||
Gateway expects that the node exist and the value of **Root\\.Objects\\.TempSensor\\.Name** is “**TH-101**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
`**Device ${Root\.Objects\.TempSensor\.Name}**` |
|||
|
|||
In this example, created device on platform will have “**Device TH-101**” name. |
|||
|
|||
### Relative Path |
|||
A relative path specifies the address relative to a predefined starting point in the OPC-UA server's namespace. |
|||
|
|||
##### **Example:** |
|||
|
|||
Gateway expects that the node exist and the value of **Root\\.Objects\\.TempSensor\\.Name** is “**TH-101**”. |
|||
|
|||
_Device Node expression:_ |
|||
|
|||
`**Root\.Objects\.TempSensor**` |
|||
|
|||
_Expression:_ |
|||
|
|||
`**Device ${Name}**` |
|||
|
|||
In this example, **the gateway will search for the child node "Name" in the device node (parent node) |
|||
"Root\\.Objects\\.TempSensor"** and the created device on the platform will be named "**Device TH-101**". |
|||
|
|||
@ -0,0 +1,60 @@ |
|||
## Profile Name Field |
|||
|
|||
Profile name field is used for looking the device profile name in some variable. |
|||
|
|||
An **Identifier** type is a unique ID assigned to a node within the OPC-UA server. It is used to directly reference |
|||
specific nodes without navigating through the namespace hierarchy. |
|||
|
|||
The **Identifier** type in the OPC-UA connector configuration can be used in various forms to uniquely reference nodes |
|||
in the OPC-UA server's address space. Identifiers can be of different types, such as numeric (**`i`**), string (**`s`**), |
|||
byte string (**`b`**), and GUID (**`g`**). Below is an explanation of each identifier type with examples. |
|||
|
|||
- ##### Numeric Identifier (**`i`**) |
|||
A **numeric identifier** uses an integer value to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of **ns=2;i=1235** node is “**thermostat**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${ns=2;i=1235}`** |
|||
|
|||
In this example, created device on platform will have “**thermostat**” profile name. |
|||
|
|||
- ##### String Identifier (**`s`**) |
|||
A **string identifier** uses a string value to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of **ns=3;s=TemperatureSensorType** node is “**thermostat**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${ns=3;s=TemperatureSensorType}`** |
|||
|
|||
In this example, created device on platform will have “**thermostat**” profile name. |
|||
|
|||
- ##### Byte String Identifier (**`b`**) |
|||
A **byte string identifier** uses a byte string to uniquely reference a node in the OPC-UA server. This is useful for |
|||
binary data that can be converted to a byte string. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of **ns=4;b=Q2xpZW50RGF0YQ==** node is “**thermostat**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${ns=4;b=Q2xpZW50RGF0YQ==}`** |
|||
|
|||
In this example, created device on platform will have “**thermostat**” profile name. |
|||
|
|||
- ##### GUID Identifier (**`g`**) |
|||
A **GUID identifier** uses a globally unique identifier (GUID) to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of **ns=1;g=550e8400-e29b-41d4-a716-446655440000** node is |
|||
“**thermostat**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${ns=1;g=550e8400-e29b-41d4-a716-446655440000}`** |
|||
|
|||
In this example, created device on platform will have “**thermostat**” profile name. |
|||
@ -0,0 +1,38 @@ |
|||
## Profile Name Field |
|||
|
|||
The profile name field is used for looking the device profile name in some variable. |
|||
|
|||
A **Path** type refers to the hierarchical address within the OPC-UA server's namespace. It is used to navigate to |
|||
specific nodes in the server. |
|||
|
|||
The path for device name can be absolute or relative. |
|||
|
|||
### Absolute Path |
|||
An absolute path specifies the full hierarchical address from the root of the OPC-UA server's namespace to the target |
|||
node. |
|||
|
|||
##### Example: |
|||
Gateway expects that the node exist and the value of **Root\\.Objects\\.TempSensor\\.Name** is “**thermostat**”. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${Root\.Objects\.TempSensor\.Type}`** |
|||
|
|||
In this example, created device on platform will have “**thermostat**” profile name. |
|||
|
|||
### Relative Path |
|||
A relative path specifies the address relative to a predefined starting point in the OPC-UA server's namespace. |
|||
|
|||
##### Example: |
|||
Gateway expects that the node exist and the value of Root\\.Objects\\.TempSensor\\.Type is “thermostat”. |
|||
|
|||
_Device Node expression:_ |
|||
|
|||
**`Root\.Objects\.TempSensor`** |
|||
|
|||
_Expression:_ |
|||
|
|||
**`Device ${Type}`** |
|||
|
|||
In this example, **the gateway will search for the child node "Name" in the device node (parent node) |
|||
"Root\\.Objects\\.TempSensor"** and the created device on the platform will have "thermostat" profile name. |
|||
@ -0,0 +1,62 @@ |
|||
An **Identifier** type is a unique ID assigned to a node within the OPC-UA server. It is used to directly reference |
|||
specific nodes without navigating through the namespace hierarchy. |
|||
|
|||
The **Identifier** type in the OPC-UA connector configuration can be used in various forms to uniquely reference nodes in |
|||
the OPC-UA server's address space. Identifiers can be of different types, such as numeric (`i`), string (`s`), |
|||
byte string (`b`), and GUID (`g`). Below is an explanation of each identifier type with examples. |
|||
|
|||
- ##### Numeric Identifier (`i`) |
|||
A **numeric identifier** uses an integer value to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**ns=2;i=1235**” node is **21.34**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${ns=2;i=1235}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`21.34`** |
|||
|
|||
- ##### String Identifier (`s`) |
|||
A **string identifier** uses a string value to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**ns=3;s=TemperatureSensor**” node is **21.34**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${ns=3;s=TemperatureSensor}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`21.34`** |
|||
|
|||
- ##### Byte String Identifier (`b`) |
|||
A **byte string identifier** uses a byte string to uniquely reference a node in the OPC-UA server. This is useful for binary data that can be converted to a byte string. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**ns=4;b=Q2xpZW50RGF0YQ==**” node is **21.34**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${ns=4;b=Q2xpZW50RGF0YQ==}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`21.34`** |
|||
|
|||
- ##### GUID Identifier (`g`) |
|||
A **GUID identifier** uses a globally unique identifier (GUID) to uniquely reference a node in the OPC-UA server. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**ns=1;g=550e8400-e29b-41d4-a716-446655440000**” node is **21.34**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${ns=1;g=550e8400-e29b-41d4-a716-446655440000}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`21.34`** |
|||
@ -0,0 +1,45 @@ |
|||
A **Path** type refers to the hierarchical address within the OPC-UA server's namespace. It is used to navigate to |
|||
specific nodes in the server. |
|||
|
|||
The path for the attribute value can be absolute or relative. |
|||
|
|||
### Absolute Path |
|||
An **absolute path** specifies the full hierarchical address from the root of the OPC-UA server's namespace to |
|||
the target node. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of **Root\\.Objects\\.TempSensor\\.Temperature** is **23.54**. |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${Root\.Objects\.TempSensor\.Temperature}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`23.54`** |
|||
|
|||
### Relative Path |
|||
A **relative path** specifies the address relative to a predefined starting point in the OPC-UA server's namespace. |
|||
|
|||
###### Example: |
|||
Gateway expects that the node exist and the value of “**Root\\.Objects\\.TempSensor\\.Temperature**” is **23.56**. |
|||
|
|||
_Device Node expression:_ |
|||
|
|||
**`Root\.Objects\.TempSensor`** |
|||
|
|||
_Expression:_ |
|||
|
|||
**`${Temperature}`** |
|||
|
|||
_Converted data:_ |
|||
|
|||
**`23.56`** |
|||
|
|||
In this example, **the gateway will search for the child node "Temperature" in the device node (parent node) |
|||
"Root\\.Objects\\.TempSensor"** and will send converted data to the device. |
|||
|
|||
Additionally, you can use the node browser name to ensure that your path cannot be altered by the user or server. |
|||
|
|||
###### Example: |
|||
**`Root\.0:Objects\.3:Simulation`** |
|||
Loading…
Reference in new issue