connectors templates
This commit is contained in:
parent
bccb2e7e8c
commit
6ee6ccaa36
@ -0,0 +1,54 @@
|
||||
<!--
|
||||
|
||||
Copyright © 2016-2023 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.
|
||||
|
||||
-->
|
||||
<mat-toolbar color="primary">
|
||||
<h2 translate>gateway.rpc.save-template</h2>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button
|
||||
(click)="close()"
|
||||
type="button">
|
||||
<mat-icon class="material-icons">close</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
<div mat-dialog-content style="width: 600px" class="mat-content" fxLayout="column">
|
||||
<mat-form-field class="mat-block tb-value-type" style="flex-grow: 0">
|
||||
<mat-label translate>gateway.rpc.template-name</mat-label>
|
||||
<input matInput [formControl]="templateNameCtrl" required/>
|
||||
<mat-error
|
||||
*ngIf="templateNameCtrl.hasError('required')">
|
||||
{{ 'gateway.rpc.template-name-required' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<div class="mat-mdc-form-field-error"
|
||||
style="margin-top: -15px; padding-left: 10px; font-size: 14px;"
|
||||
*ngIf="validateDuplicateName(templateNameCtrl)">
|
||||
{{ 'gateway.rpc.template-name-duplicate' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<div mat-dialog-actions fxLayoutAlign="end center">
|
||||
<button mat-button
|
||||
type="button"
|
||||
(click)="close()">
|
||||
{{ 'action.cancel' | translate }}
|
||||
</button>
|
||||
<button mat-raised-button color="primary"
|
||||
type="button"
|
||||
[disabled]="!templateNameCtrl.valid"
|
||||
(click)="save()">
|
||||
{{ 'action.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
@ -0,0 +1,62 @@
|
||||
///
|
||||
/// Copyright © 2016-2023 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, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { DialogComponent } from '@shared/components/dialog.component';
|
||||
import { Router } from '@angular/router';
|
||||
import { FormBuilder, FormControl, UntypedFormControl, Validators } from '@angular/forms';
|
||||
import { RPCTemplate, SaveRPCTemplateData } from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||
|
||||
@Component({
|
||||
selector: 'gateway-service-rpc-connector-template-dialog',
|
||||
templateUrl: './gateway-service-rpc-connector-template-dialog.html'
|
||||
})
|
||||
|
||||
export class GatewayServiceRPCConnectorTemplateDialogComponent extends DialogComponent<GatewayServiceRPCConnectorTemplateDialogComponent, boolean> {
|
||||
|
||||
config: {
|
||||
[key: string]: any;
|
||||
};
|
||||
templates: Array<RPCTemplate>;
|
||||
templateNameCtrl: FormControl;
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
protected router: Router,
|
||||
@Inject(MAT_DIALOG_DATA) public data: SaveRPCTemplateData,
|
||||
public dialogRef: MatDialogRef<GatewayServiceRPCConnectorTemplateDialogComponent, boolean>,
|
||||
public fb: FormBuilder) {
|
||||
super(store, router, dialogRef);
|
||||
this.config = this.data.config;
|
||||
this.templates = this.data.templates;
|
||||
this.templateNameCtrl = this.fb.control('', [Validators.required])
|
||||
}
|
||||
|
||||
validateDuplicateName(c: UntypedFormControl) {
|
||||
const name = c.value.trim();
|
||||
return !!this.templates.find((template) => template.name === name);
|
||||
};
|
||||
|
||||
close(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
save(): void {
|
||||
this.dialogRef.close(this.templateNameCtrl.value);
|
||||
}
|
||||
}
|
||||
@ -22,13 +22,10 @@
|
||||
{{template.name}}
|
||||
</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
<button mat-icon-button matTooltip="Delete" (click)="deleteTemplate($event)">
|
||||
<button mat-icon-button matTooltip="Delete" (click)="deleteTemplate($event, template)">
|
||||
<mat-icon class="material-icons">delete</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltip="Copy" (click)="copyTemplate($event)">
|
||||
<mat-icon class="material-icons">content_copy</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltip="Use" (click)="useTemplate($event)">
|
||||
<button mat-icon-button matTooltip="Use" (click)="applyTemplate($event, template)">
|
||||
<mat-icon class="material-icons">play_arrow</mat-icon>
|
||||
</button>
|
||||
</mat-panel-description>
|
||||
@ -37,13 +34,15 @@
|
||||
<ng-container
|
||||
*ngFor="let config of template.config | keyvalue : originalOrder"
|
||||
[ngTemplateOutlet]="RPCTemplateRef"
|
||||
[ngTemplateOutletContext]="{ $implicit: config, padding: false }">
|
||||
[ngTemplateOutletContext]="{ $implicit: config, innerValue: false }">
|
||||
</ng-container>
|
||||
<ng-template #RPCTemplateRef let-config let-padding='padding'>
|
||||
<ng-template #RPCTemplateRef let-config let-innerValue='innerValue'>
|
||||
<div [fxLayout]="isObject(config.value) ? 'column': 'row'"
|
||||
[fxLayoutAlign]="!isObject(config.value) ? 'space-between center' : ''"
|
||||
[ngStyle]="{'padding-left': padding ? '16px': '0'}">
|
||||
<div class="template-key">{{config.key}}</div>
|
||||
[ngStyle]="{'padding-left': innerValue ? '16px': '0'}">
|
||||
<div class="template-key">
|
||||
{{!innerValue ? ('gateway.rpc.' + config.key | translate) : config.key}}
|
||||
</div>
|
||||
<div *ngIf="!isObject(config.value) else RPCObjectRow"
|
||||
[ngClass]="{'boolean-true': config.value === true,
|
||||
'boolean-false': config.value === false }">
|
||||
@ -52,7 +51,7 @@
|
||||
<ng-container
|
||||
*ngFor="let subConfig of config.value | keyvalue : originalOrder"
|
||||
[ngTemplateOutlet]="RPCTemplateRef"
|
||||
[ngTemplateOutletContext]="{ $implicit: subConfig, padding: true }">
|
||||
[ngTemplateOutletContext]="{ $implicit: subConfig, innerValue: true }">
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
@ -50,6 +50,11 @@
|
||||
background-color: rgba(25, 128, 56, 0.08);
|
||||
}
|
||||
|
||||
mat-expansion-panel {
|
||||
margin-top: 10px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header-description {
|
||||
flex-direction: row-reverse;
|
||||
align-items: center;
|
||||
|
||||
@ -15,9 +15,16 @@
|
||||
///
|
||||
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { ConnectorType, RPCTemplate } from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
ConnectorType,
|
||||
RPCTemplate
|
||||
} from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||
import { KeyValue } from '@angular/common';
|
||||
import { EntityType } from '@shared/models/entity-type.models';
|
||||
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
|
||||
import { AttributeService } from '@core/http/attribute.service';
|
||||
import { WidgetContext } from '@home/models/widget-component.models';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-gateway-service-rpc-connector-templates',
|
||||
@ -29,52 +36,52 @@ export class GatewayServiceRPCConnectorTemplatesComponent implements OnInit {
|
||||
@Input()
|
||||
connectorType: ConnectorType;
|
||||
|
||||
@Input()
|
||||
ctx: WidgetContext;
|
||||
|
||||
@Output()
|
||||
saveTemplate: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
rpcTemplates: Array<RPCTemplate> = [];
|
||||
@Output()
|
||||
useTemplate: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
constructor(private translate: TranslateService) {
|
||||
this.rpcTemplates.push(
|
||||
{
|
||||
name: 'Test Template',
|
||||
config: {
|
||||
fieldString: 'string',
|
||||
fieldNumber: 666,
|
||||
fieldBool: true,
|
||||
fieldArray: [111, 222, 333, "String", "444"],
|
||||
fieldObj: {
|
||||
subKey1: 'dasd',
|
||||
subKey2: 666,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@Input()
|
||||
rpcTemplates: Array<RPCTemplate>;
|
||||
|
||||
constructor(private attributeService: AttributeService) {
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
public useTemplate($event: Event): void {
|
||||
public applyTemplate($event: Event, template: RPCTemplate): void {
|
||||
$event.stopPropagation();
|
||||
console.log("useTemplate")
|
||||
this.useTemplate.emit(template);
|
||||
}
|
||||
|
||||
public copyTemplate($event: Event): void {
|
||||
public deleteTemplate($event: Event, template: RPCTemplate): void {
|
||||
$event.stopPropagation();
|
||||
console.log("copyTemplate")
|
||||
const index = this.rpcTemplates.findIndex(data => {
|
||||
return data.name == template.name;
|
||||
})
|
||||
this.rpcTemplates.splice(index, 1);
|
||||
const key = `${this.connectorType}_template`;
|
||||
this.attributeService.saveEntityAttributes(
|
||||
{
|
||||
id: this.ctx.defaultSubscription.targetDeviceId,
|
||||
entityType: EntityType.DEVICE
|
||||
}
|
||||
, AttributeScope.SERVER_SCOPE, [{
|
||||
key,
|
||||
value: this.rpcTemplates
|
||||
}]).subscribe(() => {
|
||||
})
|
||||
}
|
||||
|
||||
public deleteTemplate($event: Event): void {
|
||||
$event.stopPropagation();
|
||||
console.log("deleteTemplate")
|
||||
}
|
||||
|
||||
public originalOrder = (a: KeyValue<string, any>, b: KeyValue<string, any>): number => {
|
||||
public originalOrder = (a, b): number => {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public isObject(value: any) {
|
||||
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
@ -16,7 +16,8 @@
|
||||
|
||||
-->
|
||||
<div fxLayout="column" class="command-form" [formGroup]="commandForm">
|
||||
<div class="mat-subtitle-1 title">{{ 'gateway.rpc.title' | translate: {type: gatewayConnectorDefaultTypesTranslates.get(connectorType)} }}</div>
|
||||
<div
|
||||
class="mat-subtitle-1 title">{{ 'gateway.rpc.title' | translate: {type: gatewayConnectorDefaultTypesTranslates.get(connectorType)} }}</div>
|
||||
<ng-template [ngIf]="connectorType">
|
||||
<ng-container [ngSwitch]="connectorType">
|
||||
<ng-template [ngSwitchCase]="ConnectorType.MQTT">
|
||||
@ -26,27 +27,26 @@
|
||||
placeholder="echo"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.request-topic-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.requestTopicExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="requestTopicExpression"
|
||||
placeholder="sensor/${deviceName}/request/${methodName}/${requestId}"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.response-topic-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.responseTopicExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="responseTopicExpression"
|
||||
placeholder="sensor/${deviceName}/response/${methodName}/${requestId}"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.response-timeout' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.responseTimeout' | translate }}</mat-label>
|
||||
<input matInput formControlName="responseTimeout" type="number"
|
||||
placeholder="10000" min="10" step="1"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.value-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.valueExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="valueExpression"
|
||||
placeholder="${params}"/>
|
||||
</mat-form-field>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.MODBUS">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.tag' | translate }}</mat-label>
|
||||
@ -62,7 +62,7 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="50" class="mat-block">
|
||||
<mat-label>{{ 'gateway.rpc.function-code' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.functionCode' | translate }}</mat-label>
|
||||
<mat-select formControlName="functionCode">
|
||||
<mat-option *ngFor="let code of codesArray" [value]="code">
|
||||
{{ code }}
|
||||
@ -77,20 +77,19 @@
|
||||
placeholder="1" step="1"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="50">
|
||||
<mat-label>{{ 'gateway.rpc.objects-count' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.objectsCount' | translate }}</mat-label>
|
||||
<input matInput formControlName="objectsCount" type="number" min="0"
|
||||
placeholder="31" step="1"/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.BACNET">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-rpc' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
|
||||
<input matInput formControlName="method" placeholder="set_state"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block">
|
||||
<mat-label>{{ 'gateway.rpc.request-type' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.requestType' | translate }}</mat-label>
|
||||
<mat-select formControlName="requestType">
|
||||
<mat-option *ngFor="let type of bACnetRequestTypes" [value]="type">
|
||||
{{bACnetRequestTypesTranslates.get(type) | translate}}
|
||||
@ -98,13 +97,13 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.request-timeout' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.requestTimeout' | translate }}</mat-label>
|
||||
<input matInput formControlName="requestTimeout" type="number"
|
||||
min="10" step="1" placeholder="1000"/>
|
||||
</mat-form-field>
|
||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||
<mat-form-field fxFlex="50" class="mat-block">
|
||||
<mat-label>{{ 'gateway.rpc.object-type' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.objectType' | translate }}</mat-label>
|
||||
<mat-select formControlName="objectType">
|
||||
<mat-option *ngFor="let type of bACnetObjectTypes" [value]="type">
|
||||
{{bACnetObjectTypesTranslates.get(type) | translate}}
|
||||
@ -118,22 +117,21 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field class="mat-block">
|
||||
<mat-label>{{ 'gateway.rpc.property-id' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.propertyId' | translate }}</mat-label>
|
||||
<input matInput formControlName="propertyId" placeholder="presentValue"/>
|
||||
</mat-form-field>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.BLE">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-rpc' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
|
||||
<input matInput formControlName="methodRPC" placeholder="rpcMethod1"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.characteristic-uuid' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.characteristicUUID' | translate }}</mat-label>
|
||||
<input matInput formControlName="characteristicUUID" placeholder="00002A00-0000-1000-8000-00805F9B34FB"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block">
|
||||
<mat-label>{{ 'gateway.rpc.method-processing' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodProcessing' | translate }}</mat-label>
|
||||
<mat-select formControlName="methodProcessing">
|
||||
<mat-option *ngFor="let type of bLEMethods" [value]="type">
|
||||
{{bLEMethodsTranslates.get(type) | translate}}
|
||||
@ -141,35 +139,34 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle class="mat-slide" formControlName="withResponse">
|
||||
{{ 'gateway.rpc.with-response' | translate }}
|
||||
{{ 'gateway.rpc.withResponse' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.CAN">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-rpc' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
|
||||
<input matInput formControlName="method" placeholder="sendSameData"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.node-id' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.nodeID' | translate }}</mat-label>
|
||||
<input matInput formControlName="nodeID" type="number" placeholder="4" min="0" step="1"/>
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle class="mat-slide margin" formControlName="isExtendedID">
|
||||
{{ 'gateway.rpc.is-extended-id' | translate }}
|
||||
{{ 'gateway.rpc.isExtendedID' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<mat-slide-toggle class="mat-slide margin" formControlName="isFD">
|
||||
{{ 'gateway.rpc.is-fd' | translate }}
|
||||
{{ 'gateway.rpc.isFD' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<mat-slide-toggle class="mat-slide margin" formControlName="bitrateSwitch">
|
||||
{{ 'gateway.rpc.bitrate-switch' | translate }}
|
||||
{{ 'gateway.rpc.bitrateSwitch' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||
<mat-form-field fxFlex="50">
|
||||
<mat-label>{{ 'gateway.rpc.data-length' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.dataLength' | translate }}</mat-label>
|
||||
<input matInput formControlName="dataLength" type="number" placeholder="2" min="1" step="1"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block" fxFlex="50">
|
||||
<mat-label>{{ 'gateway.rpc.data-byte-order' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.dataByteorder' | translate }}</mat-label>
|
||||
<mat-select formControlName="dataByteorder">
|
||||
<mat-option *ngFor="let order of cANByteOrders" [value]="order">
|
||||
{{ order | translate }}
|
||||
@ -179,59 +176,55 @@
|
||||
</div>
|
||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||
<mat-form-field fxFlex="50">
|
||||
<mat-label>{{ 'gateway.rpc.data-before' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.dataBefore' | translate }}</mat-label>
|
||||
<input matInput formControlName="dataBefore" placeholder="00AA"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="50">
|
||||
<mat-label>{{ 'gateway.rpc.data-after' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.dataAfter' | translate }}</mat-label>
|
||||
<input matInput formControlName="dataAfter" placeholder="0102"/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.data-in-hex' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.dataInHEX' | translate }}</mat-label>
|
||||
<input matInput formControlName="dataInHEX"
|
||||
placeholder="aa bb cc dd ee ff aa bb aa bb cc d ee ff"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.data-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.dataExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="dataExpression"
|
||||
placeholder="userSpeed if maxAllowedSpeed > userSpeed else maxAllowedSpeed"/>
|
||||
</mat-form-field>
|
||||
</ng-template>
|
||||
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.FTP">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-filter' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodFilter' | translate }}</mat-label>
|
||||
<input matInput formControlName="methodFilter" placeholder="read"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.value-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.valueExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="valueExpression" placeholder="${params}"/>
|
||||
</mat-form-field>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.OCPP">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-rpc' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
|
||||
<input matInput formControlName="methodRPC" placeholder="rpc1"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.value-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.valueExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="valueExpression" placeholder="${params}"/>
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle class="mat-slide margin" formControlName="withResponse">
|
||||
{{ 'gateway.rpc.with-response' | translate }}
|
||||
{{ 'gateway.rpc.withResponse' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.SOCKET">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-rpc' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
|
||||
<input matInput formControlName="methodRPC" placeholder="rpcMethod1"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block">
|
||||
<mat-label>{{ 'gateway.rpc.method-processing' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodProcessing' | translate }}</mat-label>
|
||||
<mat-select formControlName="methodProcessing">
|
||||
<mat-option *ngFor="let method of socketMethodProcessings" [value]="method">
|
||||
{{ SocketMethodProcessingsTranslates.get(method) | translate }}
|
||||
@ -247,27 +240,25 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle class="mat-slide margin" formControlName="withResponse">
|
||||
{{ 'gateway.rpc.with-response' | translate }}
|
||||
{{ 'gateway.rpc.withResponse' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.XMPP">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-rpc' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
|
||||
<input matInput formControlName="methodRPC" placeholder="rpc1"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.value-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.valueExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="valueExpression" placeholder="${params}"/>
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle class="mat-slide margin" formControlName="withResponse">
|
||||
{{ 'gateway.rpc.with-response' | translate }}
|
||||
{{ 'gateway.rpc.withResponse' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.SNMP">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.request-filter' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.requestFilter' | translate }}</mat-label>
|
||||
<input matInput formControlName="requestFilter" placeholder="setData"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block">
|
||||
@ -298,15 +289,14 @@
|
||||
</button>
|
||||
</fieldset>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.REST">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-filter' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodFilter' | translate }}</mat-label>
|
||||
<input matInput formControlName="methodFilter" placeholder="post_attributes"/>
|
||||
</mat-form-field>
|
||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||
<mat-form-field class="mat-block" fxFlex="33">
|
||||
<mat-label>{{ 'gateway.rpc.http-method' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.HTTPMethod' | translate }}</mat-label>
|
||||
<mat-select formControlName="HTTPMethod">
|
||||
<mat-option *ngFor="let method of hTTPMethods" [value]="method">
|
||||
{{ method }}
|
||||
@ -314,14 +304,14 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'gateway.rpc.request-url' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.requestUrlExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="requestUrlExpression"
|
||||
placeholder="http://127.0.0.1:5000/my_devices"/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||
<mat-form-field fxFlex="33">
|
||||
<mat-label>{{ 'gateway.rpc.response-timeout' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.responseTimeout' | translate }}</mat-label>
|
||||
<input matInput formControlName="responseTimeout" type="number"
|
||||
step="1" min="10" placeholder="10"/>
|
||||
</mat-form-field>
|
||||
@ -337,11 +327,11 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.value-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.valueExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="valueExpression" placeholder="${params}"/>
|
||||
</mat-form-field>
|
||||
<fieldset class="fields border" fxLayout="column" fxLayoutGap="10px" formArrayName="httpHeaders">
|
||||
<span class="fields-label">{{ 'gateway.rpc.http-headers' | translate }}</span>
|
||||
<span class="fields-label">{{ 'gateway.rpc.httpHeaders' | translate }}</span>
|
||||
<div class="border" fxLayout="column" fxLayoutGap="10px" *ngIf="getFormArrayControls('httpHeaders').length">
|
||||
<div fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="center center">
|
||||
<span fxFlex class="title">{{ 'gateway.rpc.header-name' | translate }}</span>
|
||||
@ -405,15 +395,14 @@
|
||||
</button>
|
||||
</fieldset>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.REQUEST">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.method-filter' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.methodFilter' | translate }}</mat-label>
|
||||
<input matInput formControlName="methodFilter" placeholder="echo"/>
|
||||
</mat-form-field>
|
||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||
<mat-form-field class="mat-block" fxFlex="33">
|
||||
<mat-label>{{ 'gateway.rpc.method' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.httpMethod' | translate }}</mat-label>
|
||||
<mat-select formControlName="httpMethod">
|
||||
<mat-option *ngFor="let method of hTTPMethods" [value]="method">
|
||||
{{ method }}
|
||||
@ -421,13 +410,13 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'gateway.rpc.request-url' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.requestUrlExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="requestUrlExpression" placeholder="http://127.0.0.1:5000/my_devices"/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex fxLayout="row" fxLayoutGap="10px">
|
||||
<mat-form-field fxFlex="33">
|
||||
<mat-label>{{ 'gateway.rpc.response-timeout' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.responseTimeout' | translate }}</mat-label>
|
||||
<input matInput formControlName="responseTimeout" type="number"
|
||||
step="1" min="10" placeholder="10"/>
|
||||
</mat-form-field>
|
||||
@ -443,15 +432,15 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.request-value-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.requestValueExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="requestValueExpression" placeholder="${params}"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.rpc.response-value-expression' | translate }}</mat-label>
|
||||
<mat-label>{{ 'gateway.rpc.responseValueExpression' | translate }}</mat-label>
|
||||
<input matInput formControlName="responseValueExpression" placeholder="${temp}"/>
|
||||
</mat-form-field>
|
||||
<fieldset class="fields border" fxLayout="column" fxLayoutGap="10px" formArrayName="httpHeaders">
|
||||
<span class="fields-label">{{ 'gateway.rpc.http-headers' | translate }}</span>
|
||||
<span class="fields-label">{{ 'gateway.rpc.httpHeaders' | translate }}</span>
|
||||
<div class="border" fxLayout="column" fxLayoutGap="10px" *ngIf="getFormArrayControls('httpHeaders').length">
|
||||
<div fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="center center">
|
||||
<span fxFlex class="title">{{ 'gateway.rpc.header-name' | translate }}</span>
|
||||
@ -483,7 +472,6 @@
|
||||
</button>
|
||||
</fieldset>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngSwitchCase]="ConnectorType.OPCUA_ASYNCIO">
|
||||
<ng-container *ngTemplateOutlet="OPCUAForm"></ng-container>
|
||||
</ng-template>
|
||||
@ -513,11 +501,27 @@
|
||||
</button>
|
||||
</fieldset>
|
||||
</ng-template>
|
||||
<ng-template ngSwitchDefault>
|
||||
{{'dsadas'}}
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'gateway.statistics.command' | translate }}</mat-label>
|
||||
<input matInput formControlName="command"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'widget-config.datasource-parameters' | translate }}</mat-label>
|
||||
<input matInput formControlName="params" type="JSON"/>
|
||||
<mat-icon class="material-icons-outlined" aria-hidden="false" aria-label="help-icon"
|
||||
matIconSuffix style="cursor:pointer;"
|
||||
(click)="openEditJSONDialog($event)"
|
||||
matTooltip="{{ 'gateway.rpc-command-edit-params' | translate }}">edit
|
||||
</mat-icon>
|
||||
</mat-form-field>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
<div class="template-actions" fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="10px">
|
||||
<button mat-raised-button
|
||||
(click)="sendCommand.emit()"
|
||||
(click)="save()"
|
||||
[disabled]="commandForm.invalid">
|
||||
{{ 'gateway.rpc-command-save-template' | translate }}
|
||||
</button>
|
||||
|
||||
@ -14,27 +14,57 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core';
|
||||
import {
|
||||
BACnetObjectTypes, BACnetObjectTypesTranslates,
|
||||
BACnetRequestTypes, BACnetRequestTypesTranslates, BLEMethods, BLEMethodsTranslates,
|
||||
ControlValueAccessor,
|
||||
FormArray,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
NG_VALUE_ACCESSOR,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import {
|
||||
BACnetObjectTypes,
|
||||
BACnetObjectTypesTranslates,
|
||||
BACnetRequestTypes,
|
||||
BACnetRequestTypesTranslates,
|
||||
BLEMethods,
|
||||
BLEMethodsTranslates,
|
||||
CANByteOrders,
|
||||
ConnectorType, GatewayConnectorDefaultTypesTranslates, HTTPMethods,
|
||||
ConnectorType,
|
||||
GatewayConnectorDefaultTypesTranslates,
|
||||
HTTPMethods,
|
||||
ModbusCommandTypes,
|
||||
RPCCommand,
|
||||
SNMPMethods, SNMPMethodsTranslations,
|
||||
RPCTemplateConfig,
|
||||
SNMPMethods,
|
||||
SNMPMethodsTranslations,
|
||||
SocketEncodings,
|
||||
SocketMethodProcessings, SocketMethodProcessingsTranslates
|
||||
SocketMethodProcessings,
|
||||
SocketMethodProcessingsTranslates
|
||||
} from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import {
|
||||
JsonObjectEditDialogComponent,
|
||||
JsonObjectEditDialogData
|
||||
} from '@shared/components/dialog/json-object-edit-dialog.component';
|
||||
import { jsonRequired } from '@shared/components/json-object-edit.component';
|
||||
import { deepClone } from '@core/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-gateway-service-rpc-connector',
|
||||
templateUrl: './gateway-service-rpc-connector.component.html',
|
||||
styleUrls: ['./gateway-service-rpc-connector.component.scss']
|
||||
styleUrls: ['./gateway-service-rpc-connector.component.scss'],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => GatewayServiceRPCConnectorComponent),
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
})
|
||||
export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
export class GatewayServiceRPCConnectorComponent implements OnInit, ControlValueAccessor {
|
||||
|
||||
@Input()
|
||||
connectorType: ConnectorType;
|
||||
@ -42,6 +72,9 @@ export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
@Output()
|
||||
sendCommand: EventEmitter<RPCCommand> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
saveTemplate: EventEmitter<RPCTemplateConfig> = new EventEmitter();
|
||||
|
||||
commandForm: FormGroup;
|
||||
|
||||
codesArray: Array<number> = [1, 2, 3, 4, 5, 6, 15, 16];
|
||||
@ -74,14 +107,41 @@ export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
'(\\#[-a-z\\d_]*)?$', // fragment locator
|
||||
'i'
|
||||
);
|
||||
private propagateChange = (v: any) => {
|
||||
}
|
||||
|
||||
constructor(private fb: FormBuilder,
|
||||
private translate: TranslateService) {
|
||||
private dialog: MatDialog,) {
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.commandForm = this.connectorParamsFormGroupByType(this.connectorType)
|
||||
this.commandForm = this.connectorParamsFormGroupByType(this.connectorType);
|
||||
this.commandForm.valueChanges.subscribe(value => {
|
||||
const httpHeaders = {};
|
||||
const security = {};
|
||||
switch (this.connectorType) {
|
||||
case ConnectorType.REST:
|
||||
value.httpHeaders.forEach(data => {
|
||||
httpHeaders[data.headerName] = data.value;
|
||||
})
|
||||
value.httpHeaders = httpHeaders;
|
||||
value.security.forEach(data => {
|
||||
security[data.securityName] = data.value;
|
||||
})
|
||||
value.security = security;
|
||||
break;
|
||||
case ConnectorType.REQUEST:
|
||||
value.httpHeaders.forEach(data => {
|
||||
httpHeaders[data.headerName] = data.value;
|
||||
})
|
||||
value.httpHeaders = httpHeaders;
|
||||
break;
|
||||
}
|
||||
if (this.commandForm.valid) {
|
||||
this.propagateChange({...this.commandForm.value,...value});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
connectorParamsFormGroupByType(type: ConnectorType): FormGroup {
|
||||
@ -206,6 +266,13 @@ export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
method: [null, [Validators.required]],
|
||||
arguments: this.fb.array([]),
|
||||
})
|
||||
break;
|
||||
default:
|
||||
formGroup = this.fb.group({
|
||||
command: [null, [Validators.required]],
|
||||
params: ['{}', [jsonRequired]],
|
||||
})
|
||||
|
||||
}
|
||||
return formGroup;
|
||||
}
|
||||
@ -213,7 +280,7 @@ export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
addSNMPoid(value: string = null) {
|
||||
const oidsFA = this.commandForm.get('oid') as FormArray;
|
||||
if (oidsFA) {
|
||||
oidsFA.push(this.fb.control(value, [Validators.required]));
|
||||
oidsFA.push(this.fb.control(value, [Validators.required]), {emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +296,7 @@ export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
value: [value.value, [Validators.required]]
|
||||
})
|
||||
if (headerFA) {
|
||||
headerFA.push(formGroup);
|
||||
headerFA.push(formGroup, {emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,7 +312,7 @@ export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
value: [value.value, [Validators.required]]
|
||||
})
|
||||
if (securityFA) {
|
||||
securityFA.push(formGroup);
|
||||
securityFA.push(formGroup, {emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +328,7 @@ export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
addOCPUAArguments(value: string = null) {
|
||||
const oidsFA = this.commandForm.get('arguments') as FormArray;
|
||||
if (oidsFA) {
|
||||
oidsFA.push(this.fb.control(value));
|
||||
oidsFA.push(this.fb.control(value), {emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,4 +336,86 @@ export class GatewayServiceRPCConnectorComponent implements OnInit {
|
||||
const oidsFA = this.commandForm.get('arguments') as FormArray;
|
||||
oidsFA.removeAt(index);
|
||||
}
|
||||
|
||||
openEditJSONDialog($event: Event) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
this.dialog.open<JsonObjectEditDialogComponent, JsonObjectEditDialogData, object>(JsonObjectEditDialogComponent, {
|
||||
disableClose: true,
|
||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||
data: {
|
||||
jsonValue: JSON.parse(this.commandForm.get('params').value),
|
||||
required: true
|
||||
}
|
||||
}).afterClosed().subscribe(
|
||||
(res) => {
|
||||
if (res) {
|
||||
this.commandForm.get('params').setValue(JSON.stringify(res));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.saveTemplate.emit();
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: any): void {
|
||||
}
|
||||
|
||||
clearFromArrayByName(name: string) {
|
||||
const formArray = this.commandForm.get(name) as FormArray;
|
||||
while (formArray.length !== 0) {
|
||||
formArray.removeAt(0)
|
||||
}
|
||||
}
|
||||
|
||||
writeValue(value: RPCTemplateConfig): void {
|
||||
if (typeof value == "object") {
|
||||
value = deepClone(value);
|
||||
switch (this.connectorType) {
|
||||
case ConnectorType.SNMP:
|
||||
this.clearFromArrayByName("oids");
|
||||
value.oids.forEach(value => {
|
||||
this.addSNMPoid(value)
|
||||
})
|
||||
delete value.oids;
|
||||
break;
|
||||
case ConnectorType.REQUEST:
|
||||
this.clearFromArrayByName("httpHeaders");
|
||||
value.httpHeaders && Object.entries(value.httpHeaders).forEach(httpHeader => {
|
||||
this.addHTTPHeader({headerName: httpHeader[0], value: httpHeader[1] as string})
|
||||
})
|
||||
delete value.httpHeaders;
|
||||
break;
|
||||
case ConnectorType.REST:
|
||||
this.clearFromArrayByName("httpHeaders");
|
||||
this.clearFromArrayByName("security");
|
||||
value.security && Object.entries(value.security).forEach(securityHeader => {
|
||||
this.addHTTPSecurity({securityName: securityHeader[0], value: securityHeader[1] as string})
|
||||
})
|
||||
delete value.security;
|
||||
value.httpHeaders && Object.entries(value.httpHeaders).forEach(httpHeader => {
|
||||
this.addHTTPHeader({headerName: httpHeader[0], value: httpHeader[1] as string})
|
||||
})
|
||||
delete value.httpHeaders;
|
||||
break;
|
||||
case ConnectorType.OPCUA:
|
||||
case ConnectorType.OPCUA_ASYNCIO:
|
||||
this.clearFromArrayByName("arguments");
|
||||
value.arguments.forEach(value => {
|
||||
this.addOCPUAArguments(value)
|
||||
})
|
||||
delete value.arguments;
|
||||
break;
|
||||
}
|
||||
this.commandForm.patchValue(value, {onlySelf: false});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -41,7 +41,8 @@
|
||||
</button>
|
||||
</ng-container>
|
||||
<ng-template #connectorForm>
|
||||
<tb-gateway-service-rpc-connector [connectorType]="connectorType" (sendCommand)="sendCommand()"/>
|
||||
<tb-gateway-service-rpc-connector formControlName="params" [connectorType]="connectorType"
|
||||
(sendCommand)="sendCommand()" (saveTemplate)="saveTemplate()"/>
|
||||
</ng-template>
|
||||
</div>
|
||||
<section class="result-block" [formGroup]="commandForm">
|
||||
@ -52,4 +53,6 @@
|
||||
<tb-json-content [contentType]="contentTypes.JSON" readonly="true" formControlName="result"></tb-json-content>
|
||||
</section>
|
||||
</div>
|
||||
<tb-gateway-service-rpc-connector-templates fxFlex="30" *ngIf="isConnector" class="border"></tb-gateway-service-rpc-connector-templates>
|
||||
<tb-gateway-service-rpc-connector-templates fxFlex="30" *ngIf="isConnector" class="border" [rpcTemplates]="templates"
|
||||
[ctx]="ctx" [connectorType]="connectorType" (useTemplate)="useTemplate($event)">
|
||||
</tb-gateway-service-rpc-connector-templates>
|
||||
|
||||
@ -14,17 +14,28 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { OnInit, Component, Input } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { WidgetContext } from '@home/models/widget-component.models';
|
||||
import { ContentType } from '@shared/models/constants';
|
||||
import {
|
||||
JsonObjectEditDialogComponent,
|
||||
JsonObjectEditDialogData
|
||||
} from '@shared/components/dialog/json-object-edit-dialog.component';
|
||||
import { jsonRequired } from '@shared/components/json-object-edit.component';
|
||||
import { ConnectorType, RPCCommand } from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||
import {
|
||||
ConnectorType,
|
||||
RPCCommand,
|
||||
RPCTemplate,
|
||||
RPCTemplateConfig,
|
||||
SaveRPCTemplateData
|
||||
} from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||
import {
|
||||
GatewayServiceRPCConnectorTemplateDialogComponent
|
||||
} from '@home/components/widget/lib/gateway/gateway-service-rpc-connector-template-dialog';
|
||||
import { AttributeService } from '@core/http/attribute.service';
|
||||
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
|
||||
import { EntityType } from '@shared/models/entity-type.models';
|
||||
import { DatasourceType, widgetType } from '@shared/models/widget.models';
|
||||
import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-gateway-service-rpc',
|
||||
@ -58,9 +69,27 @@ export class GatewayServiceRPCComponent implements OnInit {
|
||||
];
|
||||
|
||||
public connectorType: ConnectorType;
|
||||
public templates: Array<RPCTemplate> = [];
|
||||
|
||||
private subscription: IWidgetSubscription;
|
||||
private subscriptionOptions: WidgetSubscriptionOptions = {
|
||||
callbacks: {
|
||||
onDataUpdated: () => this.ctx.ngZone.run(() => {
|
||||
this.updateTemplates()
|
||||
}),
|
||||
onDataUpdateError: (subscription, e) => this.ctx.ngZone.run(() => {
|
||||
this.onDataUpdateError(e);
|
||||
}),
|
||||
dataLoading: () => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
constructor(private fb: FormBuilder,
|
||||
private dialog: MatDialog) {
|
||||
private dialog: MatDialog,
|
||||
private utils: UtilsService,
|
||||
private cd: ChangeDetectorRef,
|
||||
private attributeService: AttributeService) {
|
||||
this.commandForm = this.fb.group({
|
||||
command: [null, [Validators.required]],
|
||||
time: [60, [Validators.required, Validators.min(1)]],
|
||||
@ -75,6 +104,17 @@ export class GatewayServiceRPCComponent implements OnInit {
|
||||
this.commandForm.get('command').setValue(this.RPCCommands[0]);
|
||||
} else {
|
||||
this.connectorType = this.ctx.stateController.getStateParams().connector_rpc.value.type;
|
||||
const subscriptionInfo = [{
|
||||
type: DatasourceType.entity,
|
||||
entityType: EntityType.DEVICE,
|
||||
entityId: this.ctx.defaultSubscription.targetDeviceId,
|
||||
entityName: 'Connector',
|
||||
attributes: [{name: `${this.connectorType}_template`}]
|
||||
}];
|
||||
this.ctx.subscriptionApi.createSubscriptionFromInfo(widgetType.latest, subscriptionInfo,
|
||||
this.subscriptionOptions, false, true).subscribe(subscription => {
|
||||
this.subscription = subscription;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +122,9 @@ export class GatewayServiceRPCComponent implements OnInit {
|
||||
this.resultTime = null;
|
||||
const formValues = value || this.commandForm.value;
|
||||
const commandPrefix = this.isConnector ? `${this.connectorType}_` : 'gateway_';
|
||||
this.ctx.controlApi.sendTwoWayCommand(commandPrefix + formValues.command.toLowerCase(), formValues.params, formValues.time).subscribe({
|
||||
const command = !this.isConnector ? formValues.command.toLowerCase() : this.getCommandFromParamsByType(formValues.params);
|
||||
const params = formValues.params;
|
||||
this.ctx.controlApi.sendTwoWayCommand(commandPrefix + command, params, formValues.time).subscribe({
|
||||
next: resp => {
|
||||
this.resultTime = new Date().getTime();
|
||||
this.commandForm.get('result').setValue(JSON.stringify(resp))
|
||||
@ -95,23 +137,86 @@ export class GatewayServiceRPCComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
openEditJSONDialog($event: Event) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
getCommandFromParamsByType(params: RPCTemplateConfig) {
|
||||
switch (this.connectorType) {
|
||||
case ConnectorType.MQTT:
|
||||
case ConnectorType.FTP:
|
||||
case ConnectorType.SNMP:
|
||||
case ConnectorType.REST:
|
||||
case ConnectorType.REQUEST:
|
||||
return params.methodFilter;
|
||||
case ConnectorType.MODBUS:
|
||||
return params.tag;
|
||||
case ConnectorType.BACNET:
|
||||
case ConnectorType.CAN:
|
||||
case ConnectorType.OPCUA:
|
||||
case ConnectorType.OPCUA_ASYNCIO:
|
||||
return params.method;
|
||||
case ConnectorType.BLE:
|
||||
case ConnectorType.OCPP:
|
||||
case ConnectorType.SOCKET:
|
||||
case ConnectorType.XMPP:
|
||||
return params.methodRPC;
|
||||
default:
|
||||
return params.command;
|
||||
}
|
||||
this.dialog.open<JsonObjectEditDialogComponent, JsonObjectEditDialogData, object>(JsonObjectEditDialogComponent, {
|
||||
}
|
||||
|
||||
saveTemplate() {
|
||||
this.dialog.open<GatewayServiceRPCConnectorTemplateDialogComponent, SaveRPCTemplateData>
|
||||
(GatewayServiceRPCConnectorTemplateDialogComponent, {
|
||||
disableClose: true,
|
||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||
data: {
|
||||
jsonValue: JSON.parse(this.commandForm.get('params').value),
|
||||
required: true
|
||||
}
|
||||
data: {config: this.commandForm.value.params, templates: this.templates}
|
||||
}).afterClosed().subscribe(
|
||||
(res) => {
|
||||
if (res) {
|
||||
this.commandForm.get('params').setValue(JSON.stringify(res));
|
||||
const templateAttribute: RPCTemplate = {
|
||||
name: res,
|
||||
config: this.commandForm.value.params
|
||||
}
|
||||
const templatesArray = this.templates;
|
||||
const existingIndex = templatesArray.findIndex(template=>{
|
||||
return template.name == templateAttribute.name;
|
||||
})
|
||||
if (existingIndex > -1 ){
|
||||
templatesArray.splice(existingIndex, 1)
|
||||
}
|
||||
templatesArray.push(templateAttribute)
|
||||
const key = `${this.connectorType}_template`;
|
||||
this.attributeService.saveEntityAttributes(
|
||||
{
|
||||
id: this.ctx.defaultSubscription.targetDeviceId,
|
||||
entityType: EntityType.DEVICE
|
||||
}
|
||||
, AttributeScope.SERVER_SCOPE, [{
|
||||
key,
|
||||
value: templatesArray
|
||||
}]).subscribe(() => {
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
useTemplate($event) {
|
||||
this.commandForm.get('params').patchValue($event.config);
|
||||
}
|
||||
|
||||
private updateTemplates() {
|
||||
this.templates = this.subscription.data[0].data[0][1].length ?
|
||||
JSON.parse(this.subscription.data[0].data[0][1]) : [];
|
||||
if (this.templates.length && this.commandForm.get('params').value == "{}") {
|
||||
this.commandForm.get('params').patchValue(this.templates[0].config);
|
||||
}
|
||||
this.cd.detectChanges();
|
||||
}
|
||||
|
||||
private onDataUpdateError(e: any) {
|
||||
const exceptionData = this.utils.parseException(e);
|
||||
let errorText = exceptionData.name;
|
||||
if (exceptionData.message) {
|
||||
errorText += ': ' + exceptionData.message;
|
||||
}
|
||||
console.error(errorText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -261,10 +261,17 @@ export enum SocketEncodings {
|
||||
}
|
||||
|
||||
export interface RPCTemplate {
|
||||
name: string;
|
||||
config: {
|
||||
[key: string]: any;
|
||||
};
|
||||
name?: string;
|
||||
config: RPCTemplateConfig;
|
||||
}
|
||||
|
||||
export interface RPCTemplateConfig {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface SaveRPCTemplateData {
|
||||
config: RPCTemplateConfig,
|
||||
templates: Array<RPCTemplate>
|
||||
}
|
||||
|
||||
export interface LogLink {
|
||||
|
||||
@ -74,6 +74,9 @@ import { ValueChartCardWidgetComponent } from '@home/components/widget/lib/cards
|
||||
import { ProgressBarWidgetComponent } from '@home/components/widget/lib/cards/progress-bar-widget.component';
|
||||
import { LiquidLevelWidgetComponent } from '@home/components/widget/lib/indicator/liquid-level-widget.component';
|
||||
import { DoughnutWidgetComponent } from '@home/components/widget/lib/chart/doughnut-widget.component';
|
||||
import {
|
||||
GatewayServiceRPCConnectorTemplateDialogComponent
|
||||
} from '@home/components/widget/lib/gateway/gateway-service-rpc-connector-template-dialog';
|
||||
|
||||
@NgModule({
|
||||
declarations:
|
||||
@ -107,6 +110,7 @@ import { DoughnutWidgetComponent } from '@home/components/widget/lib/chart/dough
|
||||
DeviceGatewayCommandComponent,
|
||||
GatewayConfigurationComponent,
|
||||
GatewayRemoteConfigurationDialogComponent,
|
||||
GatewayServiceRPCConnectorTemplateDialogComponent,
|
||||
ValueCardWidgetComponent,
|
||||
AggregatedValueCardWidgetComponent,
|
||||
CountWidgetComponent,
|
||||
@ -154,6 +158,7 @@ import { DoughnutWidgetComponent } from '@home/components/widget/lib/chart/dough
|
||||
DeviceGatewayCommandComponent,
|
||||
GatewayConfigurationComponent,
|
||||
GatewayRemoteConfigurationDialogComponent,
|
||||
GatewayServiceRPCConnectorTemplateDialogComponent,
|
||||
ValueCardWidgetComponent,
|
||||
AggregatedValueCardWidgetComponent,
|
||||
CountWidgetComponent,
|
||||
|
||||
@ -2776,54 +2776,54 @@
|
||||
"rpc": {
|
||||
"title": "{{type}} Connector RPC parameters",
|
||||
"templates-title": "Connector RPC Templates",
|
||||
"method-filter": "Method filter",
|
||||
"request-topic-expression": "Request topic expression",
|
||||
"response-topic-expression": "Response topic expression",
|
||||
"response-timeout": "Response Time",
|
||||
"value-expression": "Value Expression",
|
||||
"methodFilter": "Method filter",
|
||||
"requestTopicExpression": "Request topic expression",
|
||||
"responseTopicExpression": "Response topic expression",
|
||||
"responseTimeout": "Response Time",
|
||||
"valueExpression": "Value Expression",
|
||||
"tag": "Tag",
|
||||
"type": "Type",
|
||||
"function-code": "Function Code",
|
||||
"objects-count": "Objects Count",
|
||||
"functionCode": "Function Code",
|
||||
"objectsCount": "Objects Count",
|
||||
"address": "Address",
|
||||
"method": "Method",
|
||||
"request-type": "Request Type",
|
||||
"request-timeout": "Request Timeout",
|
||||
"object-type": "Object type",
|
||||
"requestType": "Request Type",
|
||||
"requestTimeout": "Request Timeout",
|
||||
"objectType": "Object type",
|
||||
"identifier": "Identifier",
|
||||
"property-id": "Property ID",
|
||||
"method-rpc": "Method RPC name",
|
||||
"with-response": "With Response",
|
||||
"characteristic-uuid": "Characteristic UUID",
|
||||
"method-processing": "Method Processing",
|
||||
"node-id": "Node ID",
|
||||
"is-extended-id": "Is Extended ID",
|
||||
"is-fd": "Is FD",
|
||||
"bitrate-switch": "Bitrate Switch",
|
||||
"data-in-hex": "Data In HEX",
|
||||
"data-length": "Data Length",
|
||||
"data-byte-order": "Data Byte Order",
|
||||
"data-before": "Data Before",
|
||||
"data-after": "Data After",
|
||||
"data-expression": "Data Expression",
|
||||
"propertyId": "Property ID",
|
||||
"methodRPC": "Method RPC name",
|
||||
"withResponse": "With Response",
|
||||
"characteristicUUID": "Characteristic UUID",
|
||||
"methodProcessing": "Method Processing",
|
||||
"nodeID": "Node ID",
|
||||
"isExtendedID": "Is Extended ID",
|
||||
"isFD": "Is FD",
|
||||
"bitrateSwitch": "Bitrate Switch",
|
||||
"dataInHEX": "Data In HEX",
|
||||
"dataLength": "Data Length",
|
||||
"dataByteorder": "Data Byte Order",
|
||||
"dataBefore": "Data Before",
|
||||
"dataAfter": "Data After",
|
||||
"dataExpression": "Data Expression",
|
||||
"encoding": "Encoding",
|
||||
"oid": "OID",
|
||||
"add-oid": "Add OID",
|
||||
"add-header": "Add header",
|
||||
"add-security": "Add security",
|
||||
"remove": "Remove",
|
||||
"request-filter": "Request Filter",
|
||||
"request-url": "Request URL Expression",
|
||||
"http-method": "HTTP Method",
|
||||
"requestFilter": "Request Filter",
|
||||
"requestUrlExpression": "Request URL Expression",
|
||||
"HTTPMethod": "HTTP Method",
|
||||
"timeout": "Timeout",
|
||||
"tries": "Tries",
|
||||
"http-headers": "HTTP Headers",
|
||||
"httpHeaders": "HTTP Headers",
|
||||
"header-name": "Header name",
|
||||
"security-name": "Security name",
|
||||
"value": "Value",
|
||||
"security": "Security",
|
||||
"response-value-expression": "Response Value Expression",
|
||||
"request-value-expression": "Request Value Expression",
|
||||
"responseValueExpression": "Response Value Expression",
|
||||
"requestValueExpression": "Request Value Expression",
|
||||
"arguments": "Arguments",
|
||||
"add-argument": "Add argument",
|
||||
"write-property": "Write property",
|
||||
@ -2843,7 +2843,12 @@
|
||||
"multi-get": "Multiget",
|
||||
"get-next": "Get next",
|
||||
"bulk-get": "Bulk get",
|
||||
"walk": "Walk"
|
||||
"walk": "Walk",
|
||||
"save-template": "Save template",
|
||||
"template-name": "Template name",
|
||||
"template-name-required": "Template name is required.",
|
||||
"template-name-duplicate": "The name is already used."
|
||||
|
||||
|
||||
},
|
||||
"other": "Other",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user