Merge branch 'master' of https://github.com/thingsboard/thingsboard into feature/power-mode
This commit is contained in:
commit
e1373fa83e
@ -21,18 +21,23 @@ import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import { PageData } from '@shared/models/page/page-data';
|
||||
import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models';
|
||||
import { isDefinedAndNotNull, isEmptyStr } from '@core/utils';
|
||||
import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
|
||||
import { deepClone, isDefinedAndNotNull, isEmptyStr } from '@core/utils';
|
||||
import {
|
||||
ObjectLwM2M,
|
||||
securityConfigMode,
|
||||
ServerSecurityConfig,
|
||||
ServerSecurityConfigInfo
|
||||
} from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
|
||||
import { SortOrder } from '@shared/models/page/sort-order';
|
||||
import { OtaPackageService } from '@core/http/ota-package.service';
|
||||
import { mergeMap, tap } from 'rxjs/operators';
|
||||
import { map, mergeMap, tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DeviceProfileService {
|
||||
|
||||
private lwm2mBootstrapSecurityInfoInMemoryCache = new Map<boolean, ServerSecurityConfig>();
|
||||
private lwm2mBootstrapSecurityInfoInMemoryCache = new Map<boolean, ServerSecurityConfigInfo>();
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
@ -60,12 +65,12 @@ export class DeviceProfileService {
|
||||
return this.http.get<Array<ObjectLwM2M>>(url, defaultHttpOptionsFromConfig(config));
|
||||
}
|
||||
|
||||
public getLwm2mBootstrapSecurityInfo(isBootstrapServer: boolean, config?: RequestConfig): Observable<ServerSecurityConfig> {
|
||||
public getLwm2mBootstrapSecurityInfo(isBootstrapServer: boolean, config?: RequestConfig): Observable<ServerSecurityConfigInfo> {
|
||||
const securityConfig = this.lwm2mBootstrapSecurityInfoInMemoryCache.get(isBootstrapServer);
|
||||
if (securityConfig) {
|
||||
return of(securityConfig);
|
||||
} else {
|
||||
return this.http.get<ServerSecurityConfig>(
|
||||
return this.http.get<ServerSecurityConfigInfo>(
|
||||
`/api/lwm2m/deviceProfile/bootstrap/${isBootstrapServer}`,
|
||||
defaultHttpOptionsFromConfig(config)
|
||||
).pipe(
|
||||
@ -74,6 +79,31 @@ export class DeviceProfileService {
|
||||
}
|
||||
}
|
||||
|
||||
public getLwm2mBootstrapSecurityInfoBySecurityType(isBootstrapServer: boolean, securityMode = securityConfigMode.NO_SEC,
|
||||
config?: RequestConfig): Observable<ServerSecurityConfig> {
|
||||
return this.getLwm2mBootstrapSecurityInfo(isBootstrapServer, config).pipe(
|
||||
map(securityConfig => {
|
||||
const serverSecurityConfigInfo = deepClone(securityConfig);
|
||||
switch (securityMode) {
|
||||
case securityConfigMode.PSK:
|
||||
serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort;
|
||||
serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost;
|
||||
serverSecurityConfigInfo.serverPublicKey = '';
|
||||
break;
|
||||
case securityConfigMode.RPK:
|
||||
case securityConfigMode.X509:
|
||||
serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort;
|
||||
serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost;
|
||||
break;
|
||||
case securityConfigMode.NO_SEC:
|
||||
serverSecurityConfigInfo.serverPublicKey = '';
|
||||
break;
|
||||
}
|
||||
return serverSecurityConfigInfo;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable<Array<ObjectLwM2M>> {
|
||||
return this.http.get<Array<ObjectLwM2M>>(
|
||||
`/api/resource/lwm2m/page${pageLink.toQuery()}`,
|
||||
|
||||
@ -89,9 +89,10 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu
|
||||
if (configuration) {
|
||||
delete configuration.type;
|
||||
}
|
||||
this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
|
||||
setTimeout(() => {
|
||||
this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
|
||||
});
|
||||
this.deviceProfileTransportConfigurationFormGroup.updateValueAndValidity();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private updateModel() {
|
||||
|
||||
@ -15,12 +15,11 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<form [formGroup]="attributeLwm2mDialogFormGroup" (ngSubmit)="save()" style="width: 500px;">
|
||||
<form [formGroup]="attributeFormGroup" (ngSubmit)="save()" style="min-width: 500px;">
|
||||
<mat-toolbar color="primary">
|
||||
<div fxFlex fxLayout="column" fxLayoutAlign="start">
|
||||
<h2>{{ (readonly ? 'device-profile.lwm2m.attribute-lwm2m-toolbar-view' :
|
||||
'device-profile.lwm2m.attribute-lwm2m-toolbar-edit') | translate }}</h2>
|
||||
</div>
|
||||
<h2>
|
||||
{{ (readonly ? 'device-profile.lwm2m.view-attributes' : 'device-profile.lwm2m.edit-attributes') | translate : {name: name} }}
|
||||
</h2>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button
|
||||
(click)="cancel()"
|
||||
@ -32,8 +31,8 @@
|
||||
</mat-progress-bar>
|
||||
<div mat-dialog-content>
|
||||
<tb-lwm2m-attributes-key-list
|
||||
formControlName="keyFilters"
|
||||
titleText="{{data.destName}}">
|
||||
[isResource]="isResource"
|
||||
formControlName="attributes">
|
||||
</tb-lwm2m-attributes-key-list>
|
||||
</div>
|
||||
<div mat-dialog-actions fxLayoutAlign="end center">
|
||||
@ -46,7 +45,7 @@
|
||||
<button mat-raised-button color="primary"
|
||||
*ngIf="!readonly"
|
||||
type="submit"
|
||||
[disabled]="(isLoading$ | async) || attributeLwm2mDialogFormGroup.invalid || !attributeLwm2mDialogFormGroup.dirty">
|
||||
[disabled]="(isLoading$ | async) || attributeFormGroup.invalid || !attributeFormGroup.dirty">
|
||||
{{ 'action.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
|
||||
import { Component, Inject, SkipSelf } from '@angular/core';
|
||||
import { ErrorStateMatcher } from '@angular/material/core';
|
||||
import { DialogComponent } from '@shared/components/dialog.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
@ -22,12 +22,13 @@ import { AppState } from '@core/core.state';
|
||||
import { Router } from '@angular/router';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm } from '@angular/forms';
|
||||
import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point';
|
||||
import { AttributesNameValueMap } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
|
||||
|
||||
export interface Lwm2mAttributesDialogData {
|
||||
readonly: boolean;
|
||||
attributeLwm2m: JsonObject;
|
||||
destName: string;
|
||||
attributes: AttributesNameValueMap;
|
||||
modelName: string;
|
||||
isResource: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -36,42 +37,37 @@ export interface Lwm2mAttributesDialogData {
|
||||
styleUrls: ['./lwm2m-attributes.component.scss'],
|
||||
providers: [{provide: ErrorStateMatcher, useExisting: Lwm2mAttributesDialogComponent}],
|
||||
})
|
||||
export class Lwm2mAttributesDialogComponent extends DialogComponent<Lwm2mAttributesDialogComponent, object>
|
||||
implements OnInit, ErrorStateMatcher {
|
||||
export class Lwm2mAttributesDialogComponent
|
||||
extends DialogComponent<Lwm2mAttributesDialogComponent, AttributesNameValueMap> implements ErrorStateMatcher {
|
||||
|
||||
readonly = this.data.readonly;
|
||||
readonly: boolean;
|
||||
name: string;
|
||||
isResource: boolean;
|
||||
|
||||
attributeLwm2m = this.data.attributeLwm2m;
|
||||
private submitted = false;
|
||||
|
||||
submitted = false;
|
||||
|
||||
dirtyValue = false;
|
||||
|
||||
attributeLwm2mDialogFormGroup: FormGroup;
|
||||
attributeFormGroup: FormGroup;
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
protected router: Router,
|
||||
@Inject(MAT_DIALOG_DATA) public data: Lwm2mAttributesDialogData,
|
||||
@Inject(MAT_DIALOG_DATA) private data: Lwm2mAttributesDialogData,
|
||||
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
|
||||
public dialogRef: MatDialogRef<Lwm2mAttributesDialogComponent, object>,
|
||||
public dialogRef: MatDialogRef<Lwm2mAttributesDialogComponent, AttributesNameValueMap>,
|
||||
private fb: FormBuilder) {
|
||||
super(store, router, dialogRef);
|
||||
|
||||
this.attributeLwm2mDialogFormGroup = this.fb.group({
|
||||
keyFilters: [{}, []]
|
||||
});
|
||||
this.attributeLwm2mDialogFormGroup.patchValue({keyFilters: this.attributeLwm2m});
|
||||
this.attributeLwm2mDialogFormGroup.get('keyFilters').valueChanges.subscribe((attributes) => {
|
||||
this.attributeLwm2m = attributes;
|
||||
this.readonly = data.readonly;
|
||||
this.name = data.modelName;
|
||||
this.isResource = data.isResource;
|
||||
|
||||
this.attributeFormGroup = this.fb.group({
|
||||
attributes: [data.attributes]
|
||||
});
|
||||
if (this.readonly) {
|
||||
this.attributeLwm2mDialogFormGroup.disable({emitEvent: false});
|
||||
this.attributeFormGroup.disable({emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
|
||||
const customErrorState = !!(control && control.invalid && this.submitted);
|
||||
@ -80,7 +76,7 @@ export class Lwm2mAttributesDialogComponent extends DialogComponent<Lwm2mAttribu
|
||||
|
||||
save(): void {
|
||||
this.submitted = true;
|
||||
this.dialogRef.close(this.attributeLwm2m);
|
||||
this.dialogRef.close(this.attributeFormGroup.get('attributes').value);
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
|
||||
@ -15,69 +15,60 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<section fxLayout="column" class="tb-kv-map" [formGroup]="kvListFormGroup">
|
||||
<div>
|
||||
<mat-label translate class="tb-title no-padding">device-profile.lwm2m.attribute-lwm2m-destination</mat-label>
|
||||
<mat-label class="tb-editor-area-title-panel">{{ titleText }}</mat-label>
|
||||
</div>
|
||||
<section fxLayout="column" class="name-value-map" [formGroup]="attributesValueFormGroup">
|
||||
<div fxLayout="row" fxLayoutGap="8px" style="max-height: 40px; margin-top: 8px;">
|
||||
<mat-label fxFlex class="tb-title no-padding" translate>device-profile.lwm2m.attribute-lwm2m-name</mat-label>
|
||||
<mat-label fxFlex class="tb-title no-padding" translate>device-profile.lwm2m.attribute-lwm2m-value</mat-label>
|
||||
<div [fxShow]="!disabled" style="width: 40px;"></div>
|
||||
<label fxFlex="40" class="tb-title no-padding" style="min-width: 230px;" translate>device-profile.lwm2m.attribute-name</label>
|
||||
<label fxFlex="60" class="tb-title no-padding" translate>device-profile.lwm2m.attribute-value</label>
|
||||
<span [fxShow]="!disabled" style="width: 40px;"></span>
|
||||
</div>
|
||||
<div fxLayout="column" formArrayName="keyVals"
|
||||
*ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">
|
||||
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
|
||||
<mat-form-field class="mat-block" style="max-heights: 400px">
|
||||
<div fxLayout="column" class="map-list"
|
||||
*ngFor="let nameValueControl of attributesValueFormArray().controls; let $index = index"
|
||||
[formGroup]="nameValueControl">
|
||||
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
|
||||
<mat-form-field fxFlex="40" floatLabel="always" hideRequiredMarker>
|
||||
<mat-label></mat-label>
|
||||
<mat-select [formControl]="keyValControl.get('key')">
|
||||
<mat-option *ngFor="let attributeLwm2m of attrKeys"
|
||||
[value]="attributeLwm2m">
|
||||
{{ attributeLwm2mMap.get(attrKey[attributeLwm2m]) }}
|
||||
<mat-select formControlName="name" required>
|
||||
<mat-option *ngFor="let attributeName of attributeNames" [value]="attributeName"
|
||||
[disabled]="isDisabledAttributeName(attributeName, $index)">
|
||||
{{ attributeNameTranslationMap.get(attributeName) | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="nameValueControl.get('name').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.attribute-name-required' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex floatLabel="always" hideRequiredMarker class="mat-block"
|
||||
style="max-height: 40px;">
|
||||
<mat-form-field fxFlex="60" floatLabel="always" hideRequiredMarker>
|
||||
<mat-label></mat-label>
|
||||
<input [formControl]="keyValControl.get('value')" matInput
|
||||
placeholder="{{ ('key-val.value') | translate }}"/>
|
||||
<input formControlName="value" matInput required type="number"
|
||||
placeholder="{{ 'key-val.value' | translate }}">
|
||||
<mat-error fxLayout="row" *ngIf="nameValueControl.get('value').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.attribute-value-required' | translate }}
|
||||
</mat-error>
|
||||
<mat-error fxLayout="row" *ngIf="nameValueControl.get('value').hasError('min') ||
|
||||
nameValueControl.get('value').hasError('pattern')">
|
||||
{{ 'device-profile.lwm2m.attribute-value-pattern' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<button mat-button mat-icon-button color="primary"
|
||||
[fxShow]="!disabled"
|
||||
<button *ngIf="!disabled"
|
||||
mat-icon-button color="primary" style="min-width: 40px;"
|
||||
type="button"
|
||||
(click)="removeKeyVal($index)"
|
||||
[disabled]="isLoading$ | async"
|
||||
matTooltip="{{ 'device-profile.lwm2m.attribute-lwm2m-remove-tip' | translate }}"
|
||||
matTooltip="{{ 'device-profile.lwm2m.remove-attribute' | translate }}"
|
||||
matTooltipPosition="above">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<mat-error *ngIf="keyValControl.get('key').hasError('required')" style="font-size: smaller">
|
||||
{{ 'device-profile.lwm2m.key-name' | translate }}
|
||||
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
<mat-error fxLayout="row" *ngIf="keyValControl.get('key').hasError('validAttributeKey')"
|
||||
style="font-size: smaller">
|
||||
{{ 'device-profile.lwm2m.valid-attribute-lwm2m-key' | translate: {attrEnums: attrKeys} }}
|
||||
</mat-error>
|
||||
<mat-error fxLayout="row" *ngIf="keyValControl.get('value').hasError('validAttributeValue')"
|
||||
style="font-size: smaller">
|
||||
{{ 'device-profile.lwm2m.valid-attribute-lwm2m-value' | translate: {attrEnums: attrKeys} }}
|
||||
</mat-error>
|
||||
</div>
|
||||
<span [fxShow]="!keyValsFormArray().length"
|
||||
fxLayoutAlign="center center" [ngClass]="{'disabled': disabled}"
|
||||
class="no-data-found" translate>{{noDataText ? noDataText : 'device-profile.lwm2m.no-data'}}</span>
|
||||
<div style="margin-top: 8px;">
|
||||
<button mat-button mat-raised-button color="primary"
|
||||
[fxShow]="!disabled"
|
||||
<div [fxShow]="!attributesValueFormArray().length"
|
||||
fxLayoutAlign="center center"
|
||||
class="map-list" translate>device-profile.lwm2m.no-attributes-set</div>
|
||||
<div style="margin-top: 9px;" *ngIf="!disabled && isAddEnabled">
|
||||
<button mat-stroked-button color="primary"
|
||||
[disabled]="isLoading$ | async"
|
||||
(click)="addKeyVal()"
|
||||
type="button"
|
||||
matTooltip="{{ 'device-profile.lwm2m.attribute-lwm2m-add-tip' | translate }}"
|
||||
matTooltipPosition="above">
|
||||
{{ 'action.add' | translate }}
|
||||
(click)="addKeyVal()">
|
||||
<mat-icon class="button-icon">add_circle_outline</mat-icon>
|
||||
{{ 'device-profile.lwm2m.add-attribute' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright © 2016-2021 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 {
|
||||
.name-value-map {
|
||||
span.no-data-found {
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 40px;
|
||||
|
||||
&.disabled {
|
||||
color: rgba(0, 0, 0, .38);
|
||||
}
|
||||
}
|
||||
|
||||
.map-list{
|
||||
height: 45px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:host ::ng-deep {
|
||||
.mat-form-field-wrapper {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.mat-form-field-infix {
|
||||
border-top: 0;
|
||||
}
|
||||
.mat-form-field-underline {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.button-icon{
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.map-list {
|
||||
mat-form-field {
|
||||
.mat-form-field-wrapper {
|
||||
padding-bottom: 0;
|
||||
.mat-form-field-infix {
|
||||
border-top-width: 0.2em;
|
||||
width: auto;
|
||||
min-width: auto;
|
||||
}
|
||||
.mat-form-field-underline {
|
||||
bottom: 0;
|
||||
}
|
||||
.mat-form-field-subscript-wrapper{
|
||||
margin-top: 1.8em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,35 +14,36 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, forwardRef, Input, OnInit } from '@angular/core';
|
||||
import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
|
||||
import {
|
||||
AbstractControl,
|
||||
ControlValueAccessor,
|
||||
FormArray,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
NG_VALIDATORS,
|
||||
NG_VALUE_ACCESSOR,
|
||||
Validator,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import {
|
||||
ATTRIBUTE_KEYS,
|
||||
ATTRIBUTE_LWM2M_ENUM,
|
||||
ATTRIBUTE_LWM2M_MAP
|
||||
AttributeName,
|
||||
AttributeNameTranslationMap,
|
||||
AttributesNameValue,
|
||||
AttributesNameValueMap,
|
||||
valueValidatorByAttributeName
|
||||
} from './lwm2m-profile-config.models';
|
||||
import { isDefinedAndNotNull, isEmpty, isEmptyStr, isUndefinedOrNull } from '@core/utils';
|
||||
import { isUndefinedOrNull } from '@core/utils';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { PageComponent } from '@shared/components/page.component';
|
||||
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-lwm2m-attributes-key-list',
|
||||
templateUrl: './lwm2m-attributes-key-list.component.html',
|
||||
styleUrls: ['./lwm2m-attributes.component.scss'],
|
||||
styleUrls: ['./lwm2m-attributes-key-list.component.scss'],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
@ -56,39 +57,46 @@ import { PageComponent } from '@shared/components/page.component';
|
||||
}
|
||||
]
|
||||
})
|
||||
export class Lwm2mAttributesKeyListComponent extends PageComponent implements ControlValueAccessor, OnInit, Validator {
|
||||
export class Lwm2mAttributesKeyListComponent extends PageComponent implements ControlValueAccessor, OnDestroy, OnDestroy, Validator {
|
||||
|
||||
attrKeys = ATTRIBUTE_KEYS;
|
||||
|
||||
attrKey = ATTRIBUTE_LWM2M_ENUM;
|
||||
|
||||
attributeLwm2mMap = ATTRIBUTE_LWM2M_MAP;
|
||||
attributeNames;
|
||||
attributeNameTranslationMap = AttributeNameTranslationMap;
|
||||
|
||||
@Input() disabled: boolean;
|
||||
|
||||
@Input() titleText: string;
|
||||
@Input()
|
||||
isResource = false;
|
||||
|
||||
@Input() noDataText: string;
|
||||
|
||||
kvListFormGroup: FormGroup;
|
||||
attributesValueFormGroup: FormGroup;
|
||||
|
||||
private propagateChange = null;
|
||||
|
||||
private valueChangeSubscription: Subscription = null;
|
||||
private valueChange$: Subscription = null;
|
||||
private destroy$ = new Subject();
|
||||
private usedAttributesName: AttributeName[] = [];
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
private fb: FormBuilder) {
|
||||
super(store);
|
||||
this.attributesValueFormGroup = this.fb.group({
|
||||
attributesValue: this.fb.array([])
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.kvListFormGroup = this.fb.group({});
|
||||
this.kvListFormGroup.addControl('keyVals',
|
||||
this.fb.array([]));
|
||||
ngOnInit() {
|
||||
if (this.isResource) {
|
||||
this.attributeNames = Object.values(AttributeName);
|
||||
} else {
|
||||
this.attributeNames = Object.values(AttributeName)
|
||||
.filter(item => ![AttributeName.lt, AttributeName.gt, AttributeName.st].includes(item));
|
||||
}
|
||||
}
|
||||
|
||||
keyValsFormArray(): FormArray {
|
||||
return this.kvListFormGroup.get('keyVals') as FormArray;
|
||||
ngOnDestroy() {
|
||||
if (this.valueChange$) {
|
||||
this.valueChange$.unsubscribe();
|
||||
}
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
@ -101,127 +109,111 @@ export class Lwm2mAttributesKeyListComponent extends PageComponent implements Co
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled;
|
||||
if (this.disabled) {
|
||||
this.kvListFormGroup.disable({emitEvent: false});
|
||||
this.attributesValueFormGroup.disable({emitEvent: false});
|
||||
} else {
|
||||
this.kvListFormGroup.enable({emitEvent: false});
|
||||
this.attributesValueFormGroup.enable({emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
writeValue(keyValMap: { [key: string]: string }): void {
|
||||
if (this.valueChangeSubscription) {
|
||||
this.valueChangeSubscription.unsubscribe();
|
||||
writeValue(keyValMap: AttributesNameValueMap): void {
|
||||
if (this.valueChange$) {
|
||||
this.valueChange$.unsubscribe();
|
||||
}
|
||||
const keyValsControls: Array<AbstractControl> = [];
|
||||
const attributesValueControls: Array<AbstractControl> = [];
|
||||
if (keyValMap) {
|
||||
for (const property of Object.keys(keyValMap)) {
|
||||
if (Object.prototype.hasOwnProperty.call(keyValMap, property)) {
|
||||
keyValsControls.push(this.fb.group({
|
||||
key: [property, [Validators.required, this.attributeLwm2mKeyValidator]],
|
||||
value: [keyValMap[property], this.attributeLwm2mValueValidator(property)]
|
||||
}));
|
||||
}
|
||||
}
|
||||
(Object.keys(keyValMap) as AttributeName[]).forEach(name => {
|
||||
attributesValueControls.push(this.createdFormGroup({name, value: keyValMap[name]}));
|
||||
});
|
||||
}
|
||||
this.kvListFormGroup.setControl('keyVals', this.fb.array(keyValsControls));
|
||||
this.valueChangeSubscription = this.kvListFormGroup.valueChanges.subscribe(() => {
|
||||
// this.updateValidate();
|
||||
this.attributesValueFormGroup.setControl('attributesValue', this.fb.array(attributesValueControls));
|
||||
if (this.disabled) {
|
||||
this.attributesValueFormGroup.disable({emitEvent: false});
|
||||
} else {
|
||||
this.attributesValueFormGroup.enable({emitEvent: false});
|
||||
}
|
||||
this.valueChange$ = this.attributesValueFormGroup.valueChanges.subscribe(() => {
|
||||
this.updateModel();
|
||||
});
|
||||
if (this.disabled) {
|
||||
this.kvListFormGroup.disable({emitEvent: false});
|
||||
} else {
|
||||
this.kvListFormGroup.enable({emitEvent: false});
|
||||
}
|
||||
this.updateUsedAttributesName();
|
||||
}
|
||||
|
||||
attributesValueFormArray(): FormArray {
|
||||
return this.attributesValueFormGroup.get('attributesValue') as FormArray;
|
||||
}
|
||||
|
||||
public removeKeyVal(index: number) {
|
||||
(this.kvListFormGroup.get('keyVals') as FormArray).removeAt(index);
|
||||
this.attributesValueFormArray().removeAt(index);
|
||||
}
|
||||
|
||||
public addKeyVal() {
|
||||
const keyValsFormArray = this.kvListFormGroup.get('keyVals') as FormArray;
|
||||
keyValsFormArray.push(this.fb.group({
|
||||
key: ['', [Validators.required, this.attributeLwm2mKeyValidator]],
|
||||
value: ['', []]
|
||||
}));
|
||||
this.attributesValueFormArray().push(this.createdFormGroup());
|
||||
this.attributesValueFormGroup.updateValueAndValidity({emitEvent: false});
|
||||
if (this.attributesValueFormGroup.invalid) {
|
||||
this.updateModel();
|
||||
}
|
||||
}
|
||||
|
||||
public validate(c?: FormControl) {
|
||||
const kvList: { key: string; value: string }[] = this.kvListFormGroup.get('keyVals').value;
|
||||
let valid = true;
|
||||
for (const entry of kvList) {
|
||||
if (isUndefinedOrNull(entry.key) || isEmptyStr(entry.key) || !ATTRIBUTE_KEYS.includes(entry.key)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (entry.key !== 'ver' && isNaN(Number(entry.value))) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
private createdFormGroup(value?: AttributesNameValue): FormGroup {
|
||||
if (isUndefinedOrNull(value)) {
|
||||
value = {
|
||||
name: this.getFirstUnusedAttributesName(),
|
||||
value: null
|
||||
};
|
||||
}
|
||||
return (valid) ? null : {
|
||||
keyVals: {
|
||||
valid: false,
|
||||
},
|
||||
const form = this.fb.group({
|
||||
name: [value.name, Validators.required],
|
||||
value: [value.value, valueValidatorByAttributeName(value.name)]
|
||||
});
|
||||
form.get('name').valueChanges.pipe(
|
||||
takeUntil(this.destroy$)
|
||||
).subscribe(name => {
|
||||
form.get('value').setValidators(valueValidatorByAttributeName(name));
|
||||
form.get('value').updateValueAndValidity();
|
||||
});
|
||||
return form;
|
||||
}
|
||||
|
||||
public validate() {
|
||||
return this.attributesValueFormGroup.valid ? null : {
|
||||
attributesValue: {
|
||||
valid: false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private updateValidate() {
|
||||
const kvList = this.kvListFormGroup.get('keyVals') as FormArray;
|
||||
kvList.controls.forEach(fg => {
|
||||
if (fg.get('key').value === 'ver') {
|
||||
fg.get('value').setValidators(null);
|
||||
fg.get('value').setErrors(null);
|
||||
}
|
||||
else {
|
||||
fg.get('value').setValidators(this.attributeLwm2mValueNumberValidator);
|
||||
fg.get('value').setErrors(this.attributeLwm2mValueNumberValidator(fg.get('value')));
|
||||
private updateModel() {
|
||||
const value: AttributesNameValue[] = this.attributesValueFormGroup.get('attributesValue').value;
|
||||
const attributesNameValueMap: AttributesNameValueMap = {};
|
||||
value.forEach(attribute => {
|
||||
attributesNameValueMap[attribute.name] = attribute.value;
|
||||
});
|
||||
this.updateUsedAttributesName();
|
||||
this.propagateChange(attributesNameValueMap);
|
||||
}
|
||||
|
||||
public isDisabledAttributeName(type: AttributeName, index: number): boolean {
|
||||
const usedIndex = this.usedAttributesName.indexOf(type);
|
||||
return usedIndex > -1 && usedIndex !== index;
|
||||
}
|
||||
|
||||
private getFirstUnusedAttributesName(): AttributeName {
|
||||
for (const attributeName of this.attributeNames) {
|
||||
if (this.usedAttributesName.indexOf(attributeName) === -1) {
|
||||
return attributeName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private updateUsedAttributesName() {
|
||||
this.usedAttributesName = [];
|
||||
const value: AttributesNameValue[] = this.attributesValueFormGroup.get('attributesValue').value;
|
||||
value.forEach((attributesValue, index) => {
|
||||
this.usedAttributesName[index] = attributesValue.name;
|
||||
});
|
||||
}
|
||||
|
||||
private updateModel() {
|
||||
this.updateValidate();
|
||||
if (this.validate() === null) {
|
||||
const kvList: { key: string; value: string }[] = this.kvListFormGroup.get('keyVals').value;
|
||||
const keyValMap: { [key: string]: string | number } = {};
|
||||
kvList.forEach((entry) => {
|
||||
if (isUndefinedOrNull(entry.value) || entry.key === 'ver' || isEmptyStr(entry.value.toString())) {
|
||||
keyValMap[entry.key] = entry.value.toString();
|
||||
} else {
|
||||
keyValMap[entry.key] = Number(entry.value);
|
||||
}
|
||||
});
|
||||
this.propagateChange(keyValMap);
|
||||
}
|
||||
else {
|
||||
this.propagateChange(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private attributeLwm2mKeyValidator = (control: AbstractControl) => {
|
||||
const key = control.value as string;
|
||||
if (isDefinedAndNotNull(key) && !isEmpty(key)) {
|
||||
if (!ATTRIBUTE_KEYS.includes(key)) {
|
||||
return {
|
||||
validAttributeKey: true
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private attributeLwm2mValueNumberValidator = (control: AbstractControl) => {
|
||||
if (isNaN(Number(control.value)) || Number(control.value) < 0) {
|
||||
return {
|
||||
validAttributeValue: true
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private attributeLwm2mValueValidator = (property: string): object[] => {
|
||||
return property === 'ver' ? [] : [this.attributeLwm2mValueNumberValidator];
|
||||
get isAddEnabled(): boolean {
|
||||
return this.attributesValueFormArray().length !== this.attributeNames.length;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,18 +15,14 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<div fxLayout="row" [formGroup]="attributeLwm2mFormGroup">
|
||||
<div fxFlex fxLayout="column" class="resource-name-lw-end" fxLayoutAlign="center"
|
||||
[matTooltip]="isToolTipLabel()" matTooltipPosition="above">
|
||||
{{attributeLwm2mToString()}}
|
||||
</div>
|
||||
<div fxLayout="row" [fxHide]="disabled && isEmpty()" fxLayoutAlign="end center" matTooltip="{{ tooltipSetAttributesTelemetry | translate }}" matTooltipPosition="above">
|
||||
<button type="button"
|
||||
[disabled]="isDisableBtn()"
|
||||
mat-button mat-icon-button
|
||||
(click)="editAttributesLwm2m($event)"
|
||||
[matTooltip]="(isIconView() ? 'action.view' : isIconEditAdd() ? 'action.edit' : 'action.add' ) | translate"
|
||||
matTooltip="{{ tooltipButton | translate }}"
|
||||
matTooltipPosition="above">
|
||||
<mat-icon
|
||||
class="material-icons">{{isIconView() ? 'visibility' : isIconEditAdd() ? 'edit' : 'add' }}</mat-icon>
|
||||
class="material-icons">{{ iconButton }}</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -14,48 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
:host {
|
||||
.tb-kv-map {
|
||||
span.no-data-found {
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 40px;
|
||||
.resource-name-lw-end{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align:end;
|
||||
//width: 80px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: rgba(0, 0, 0, .38);
|
||||
}
|
||||
}
|
||||
.resource-name-lw{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
:host ::ng-deep {
|
||||
.mat-form-field-wrapper {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.mat-form-field-infix {
|
||||
border-top: 0;
|
||||
}
|
||||
.mat-form-field-underline {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-padding {
|
||||
padding: 0 0 10px 20px;
|
||||
}
|
||||
|
||||
.resource-name-lw-end{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align:end;
|
||||
//width: 80px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.resource-name-lw{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@ -17,11 +17,10 @@
|
||||
import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';
|
||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
import { deepClone, isDefinedAndNotNull, isEmpty } from '@core/utils';
|
||||
import { isEmpty, isUndefinedOrNull } from '@core/utils';
|
||||
import { Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData } from './lwm2m-attributes-dialog.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ATTRIBUTE_LWM2M_LABEL } from './lwm2m-profile-config.models';
|
||||
import { AttributesNameValueMap } from './lwm2m-profile-config.models';
|
||||
|
||||
|
||||
@Component({
|
||||
@ -36,22 +35,21 @@ import { ATTRIBUTE_LWM2M_LABEL } from './lwm2m-profile-config.models';
|
||||
})
|
||||
export class Lwm2mAttributesComponent implements ControlValueAccessor {
|
||||
attributeLwm2mFormGroup: FormGroup;
|
||||
attributeLwm2mLabel = ATTRIBUTE_LWM2M_LABEL;
|
||||
|
||||
private requiredValue: boolean;
|
||||
|
||||
@Input()
|
||||
attributeLwm2m: {};
|
||||
|
||||
@Input()
|
||||
isAttributeTelemetry: boolean;
|
||||
|
||||
@Input()
|
||||
destName: string;
|
||||
modelName: string;
|
||||
|
||||
@Input()
|
||||
disabled: boolean;
|
||||
|
||||
@Input()
|
||||
isResource = false;
|
||||
|
||||
@Output()
|
||||
updateAttributeLwm2m = new EventEmitter<any>();
|
||||
|
||||
@ -64,8 +62,7 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor {
|
||||
}
|
||||
|
||||
constructor(private dialog: MatDialog,
|
||||
private fb: FormBuilder,
|
||||
private translate: TranslateService) {}
|
||||
private fb: FormBuilder) {}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
@ -85,63 +82,66 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor {
|
||||
|
||||
ngOnInit() {
|
||||
this.attributeLwm2mFormGroup = this.fb.group({
|
||||
attributeLwm2m: [this.attributeLwm2m]
|
||||
attributes: [{}]
|
||||
});
|
||||
}
|
||||
|
||||
writeValue(value: {} | null): void {}
|
||||
|
||||
attributeLwm2mToString = (): string => {
|
||||
return this.isIconEditAdd () ? this.attributeLwm2mLabelToString() : this.translate.instant('device-profile.lwm2m.no-data');
|
||||
writeValue(value: AttributesNameValueMap | null) {
|
||||
this.attributeLwm2mFormGroup.patchValue({attributes: value}, {emitEvent: false});
|
||||
}
|
||||
|
||||
private attributeLwm2mLabelToString = (): string => {
|
||||
let label = JSON.stringify(this.attributeLwm2m);
|
||||
label = deepClone(label.replace('{', ''));
|
||||
label = deepClone(label.replace('}', ''));
|
||||
this.attributeLwm2mLabel.forEach((value: string, key: string) => {
|
||||
const dest = '\"' + key + '\"\:';
|
||||
label = deepClone(label.replace(dest, value));
|
||||
});
|
||||
return label;
|
||||
get attributesValueMap(): AttributesNameValueMap {
|
||||
return this.attributeLwm2mFormGroup.get('attributes').value;
|
||||
}
|
||||
|
||||
isDisableBtn(): boolean {
|
||||
return this.disabled || this.isAttributeTelemetry ? !(isDefinedAndNotNull(this.attributeLwm2m) &&
|
||||
!isEmpty(this.attributeLwm2m) && this.disabled) : this.disabled;
|
||||
return !this.disabled && this.isAttributeTelemetry;
|
||||
}
|
||||
|
||||
isIconView(): boolean {
|
||||
return this.isAttributeTelemetry || this.disabled;
|
||||
isEmpty(): boolean {
|
||||
const value = this.attributesValueMap;
|
||||
return isUndefinedOrNull(value) || isEmpty(value);
|
||||
}
|
||||
|
||||
isIconEditAdd(): boolean {
|
||||
return isDefinedAndNotNull(this.attributeLwm2m) && !isEmpty(this.attributeLwm2m);
|
||||
get tooltipSetAttributesTelemetry(): string {
|
||||
return this.isDisableBtn() ? 'device-profile.lwm2m.edit-attributes-select' : '';
|
||||
}
|
||||
|
||||
isToolTipLabel(): string {
|
||||
return this.disabled ? this.translate.instant('device-profile.lwm2m.attribute-lwm2m-tip') :
|
||||
this.isAttributeTelemetry ? this.translate.instant('device-profile.lwm2m.attribute-lwm2m-disable-tip') :
|
||||
this.translate.instant('device-profile.lwm2m.attribute-lwm2m-tip');
|
||||
get tooltipButton(): string {
|
||||
if (this.disabled) {
|
||||
return 'device-profile.lwm2m.view-attribute';
|
||||
} else if (this.isEmpty()) {
|
||||
return 'device-profile.lwm2m.add-attribute';
|
||||
}
|
||||
return 'device-profile.lwm2m.edit-attribute';
|
||||
}
|
||||
|
||||
get iconButton(): string {
|
||||
if (this.disabled) {
|
||||
return 'visibility';
|
||||
} else if (this.isEmpty()) {
|
||||
return 'add';
|
||||
}
|
||||
return 'edit';
|
||||
}
|
||||
|
||||
public editAttributesLwm2m = ($event: Event): void => {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
this.dialog.open<Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData, object>(Lwm2mAttributesDialogComponent, {
|
||||
this.dialog.open<Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData, AttributesNameValueMap>(Lwm2mAttributesDialogComponent, {
|
||||
disableClose: true,
|
||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||
data: {
|
||||
readonly: this.disabled,
|
||||
attributeLwm2m: this.disabled ? this.attributeLwm2m : deepClone(this.attributeLwm2m),
|
||||
destName: this.destName
|
||||
attributes: this.attributesValueMap,
|
||||
modelName: this.modelName,
|
||||
isResource: this.isResource
|
||||
}
|
||||
}).afterClosed().subscribe((result) => {
|
||||
if (result) {
|
||||
this.attributeLwm2m = result;
|
||||
this.attributeLwm2mFormGroup.patchValue({attributeLwm2m: this.attributeLwm2m});
|
||||
this.updateAttributeLwm2m.next(this.attributeLwm2m);
|
||||
this.attributeLwm2mFormGroup.patchValue({attributeLwm2m: result});
|
||||
this.updateAttributeLwm2m.next(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -35,19 +35,33 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'device-profile.lwm2m.server-port' | translate }}</mat-label>
|
||||
<input matInput type="number" formControlName="port" required min="0">
|
||||
<input matInput type="number" formControlName="port" required min="0" max="65535">
|
||||
<mat-error *ngIf="serverFormGroup.get('port').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.server-port-required' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="serverFormGroup.get('port').hasError('pattern')">
|
||||
{{ 'device-profile.lwm2m.server-port-pattern' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="serverFormGroup.get('port').hasError('min') ||
|
||||
serverFormGroup.get('port').hasError('max')">
|
||||
{{ 'device-profile.lwm2m.server-port-range' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
|
||||
<input matInput type="number" formControlName="serverId" required min="0">
|
||||
<input matInput type="number" min="1" max="65534" formControlName="serverId" required>
|
||||
<mat-error *ngIf="serverFormGroup.get('serverId').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.short-id-required' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="serverFormGroup.get('serverId').hasError('pattern')">
|
||||
{{ 'device-profile.lwm2m.short-id-pattern' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="serverFormGroup.get('serverId').hasError('min') ||
|
||||
serverFormGroup.get('serverId').hasError('max')">
|
||||
{{ 'device-profile.lwm2m.short-id-range' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}</mat-label>
|
||||
@ -57,6 +71,10 @@
|
||||
<mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.client-hold-off-time-required' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('min') ||
|
||||
serverFormGroup.get('clientHoldOffTime').hasError('pattern')">
|
||||
{{ 'device-profile.lwm2m.client-hold-off-time-pattern' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'device-profile.lwm2m.account-after-timeout' | translate }}</mat-label>
|
||||
@ -66,6 +84,10 @@
|
||||
<mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.account-after-timeout-required' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('min') ||
|
||||
serverFormGroup.get('bootstrapServerAccountTimeout').hasError('pattern')">
|
||||
{{ 'device-profile.lwm2m.account-after-timeout-pattern' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div *ngIf="serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
|
||||
|
||||
@ -15,7 +15,16 @@
|
||||
///
|
||||
|
||||
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
NG_VALIDATORS,
|
||||
NG_VALUE_ACCESSOR,
|
||||
ValidationErrors,
|
||||
Validator,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import {
|
||||
DEFAULT_PORT_BOOTSTRAP_NO_SEC,
|
||||
DEFAULT_PORT_SERVER_NO_SEC,
|
||||
@ -27,10 +36,9 @@ import {
|
||||
ServerSecurityConfig
|
||||
} from './lwm2m-profile-config.models';
|
||||
import { DeviceProfileService } from '@core/http/device-profile.service';
|
||||
import { of, Subject } from 'rxjs';
|
||||
import { map, mergeMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { mergeMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { deepClone } from '@core/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-profile-lwm2m-device-config-server',
|
||||
@ -40,16 +48,21 @@ import { deepClone } from '@core/utils';
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => Lwm2mDeviceConfigServerComponent),
|
||||
multi: true
|
||||
}
|
||||
},
|
||||
{
|
||||
provide: NG_VALIDATORS,
|
||||
useExisting: forwardRef(() => Lwm2mDeviceConfigServerComponent),
|
||||
multi: true
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, OnDestroy {
|
||||
export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validator, OnDestroy {
|
||||
|
||||
private disabled = false;
|
||||
private destroy$ = new Subject();
|
||||
|
||||
private securityDefaultConfig: ServerSecurityConfig;
|
||||
private isDataLoadedIntoCache = false;
|
||||
|
||||
serverFormGroup: FormGroup;
|
||||
securityConfigLwM2MType = securityConfigMode;
|
||||
@ -70,12 +83,13 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
|
||||
ngOnInit(): void {
|
||||
this.serverFormGroup = this.fb.group({
|
||||
host: ['', Validators.required],
|
||||
port: [this.isBootstrapServer ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC, [Validators.required, Validators.min(0)]],
|
||||
port: [this.isBootstrapServer ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC,
|
||||
[Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]],
|
||||
securityMode: [securityConfigMode.NO_SEC],
|
||||
serverPublicKey: ['', Validators.required],
|
||||
clientHoldOffTime: ['', [Validators.required, Validators.min(0)]],
|
||||
serverId: ['', [Validators.required, Validators.min(0)]],
|
||||
bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0)]],
|
||||
serverPublicKey: [''],
|
||||
clientHoldOffTime: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
|
||||
serverId: ['', [Validators.required, Validators.min(1), Validators.max(65534), Validators.pattern('[0-9]*')]],
|
||||
bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
|
||||
});
|
||||
this.serverFormGroup.get('securityMode').valueChanges.pipe(
|
||||
tap(securityMode => this.updateValidate(securityMode)),
|
||||
@ -101,7 +115,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
|
||||
this.serverFormGroup.patchValue(serverData, {emitEvent: false});
|
||||
this.updateValidate(serverData.securityMode);
|
||||
}
|
||||
if (!this.securityDefaultConfig){
|
||||
if (!this.isDataLoadedIntoCache){
|
||||
this.getLwm2mBootstrapSecurityInfo().subscribe(value => {
|
||||
if (!serverData) {
|
||||
this.serverFormGroup.patchValue(value);
|
||||
@ -159,43 +173,19 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
|
||||
|
||||
private propagateChangeState = (value: ServerSecurityConfig): void => {
|
||||
if (value !== undefined) {
|
||||
if (this.serverFormGroup.valid) {
|
||||
this.propagateChange(value);
|
||||
} else {
|
||||
this.propagateChange(null);
|
||||
}
|
||||
this.propagateChange(value);
|
||||
}
|
||||
}
|
||||
|
||||
private getLwm2mBootstrapSecurityInfo(securityMode = securityConfigMode.NO_SEC): Observable<ServerSecurityConfig> {
|
||||
if (this.securityDefaultConfig) {
|
||||
return of(this.processingBootstrapSecurityInfo(this.securityDefaultConfig, securityMode));
|
||||
}
|
||||
return this.deviceProfileService.getLwm2mBootstrapSecurityInfo(this.isBootstrapServer).pipe(
|
||||
map(securityInfo => {
|
||||
this.securityDefaultConfig = securityInfo;
|
||||
return this.processingBootstrapSecurityInfo(securityInfo, securityMode);
|
||||
})
|
||||
return this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(this.isBootstrapServer, securityMode).pipe(
|
||||
tap(() => this.isDataLoadedIntoCache = true)
|
||||
);
|
||||
}
|
||||
|
||||
private processingBootstrapSecurityInfo(securityConfig: ServerSecurityConfig, securityMode: securityConfigMode): ServerSecurityConfig {
|
||||
const config = deepClone(securityConfig);
|
||||
switch (securityMode) {
|
||||
case securityConfigMode.PSK:
|
||||
config.port = config.securityPort;
|
||||
config.host = config.securityHost;
|
||||
config.serverPublicKey = '';
|
||||
break;
|
||||
case securityConfigMode.RPK:
|
||||
case securityConfigMode.X509:
|
||||
config.port = config.securityPort;
|
||||
config.host = config.securityHost;
|
||||
break;
|
||||
case securityConfigMode.NO_SEC:
|
||||
config.serverPublicKey = '';
|
||||
break;
|
||||
}
|
||||
return config;
|
||||
validate(): ValidationErrors | null {
|
||||
return this.serverFormGroup.valid ? null : {
|
||||
serverFormGroup: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,53 +34,62 @@
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
<mat-tab label="{{ 'device-profile.lwm2m.servers' | translate }}">
|
||||
<ng-template matTabContent>
|
||||
<section [formGroup]="lwm2mDeviceProfileFormGroup" style="padding: 4px 2px">
|
||||
<section [formGroup]="lwm2mDeviceProfileFormGroup">
|
||||
<section formGroupName="bootstrap" style="padding: 4px 2px">
|
||||
<mat-accordion multi="true">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{ 'device-profile.lwm2m.servers' | translate }}</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<ng-template matExpansionPanelContent formGroupName="servers">
|
||||
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
|
||||
<input matInput type="number" formControlName="shortId" required>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('shortId').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.short-id' | translate }}
|
||||
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
|
||||
<input matInput type="number" min="1" max="65534" formControlName="shortId" required>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.shortId').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.short-id-required' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.shortId').hasError('min') ||
|
||||
lwm2mDeviceProfileFormGroup.get('bootstrap.servers.shortId').hasError('max')">
|
||||
{{ 'device-profile.lwm2m.short-id-range' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.shortId').hasError('pattern')">
|
||||
{{ 'device-profile.lwm2m.short-id-pattern' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label>
|
||||
<input matInput type="number" formControlName="lifetime" required>
|
||||
<mat-error
|
||||
*ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.lifetime' | translate }}
|
||||
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
|
||||
<input matInput type="number" min="0" formControlName="lifetime" required>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.lifetime').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.lifetime-required' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.lifetime').hasError('pattern') ||
|
||||
lwm2mDeviceProfileFormGroup.get('bootstrap.servers.lifetime').hasError('min')">
|
||||
{{ 'device-profile.lwm2m.lifetime-pattern' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
|
||||
<input matInput type="number" formControlName="defaultMinPeriod" required>
|
||||
<mat-error
|
||||
*ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.default-min-period' | translate }}
|
||||
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
|
||||
<input matInput type="number" min="0" formControlName="defaultMinPeriod" required>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.defaultMinPeriod').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.default-min-period-required' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.defaultMinPeriod').hasError('pattern') ||
|
||||
lwm2mDeviceProfileFormGroup.get('bootstrap.servers.defaultMinPeriod').hasError('min')">
|
||||
{{ 'device-profile.lwm2m.default-min-period-pattern' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field class="mat-block">
|
||||
<mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
|
||||
<mat-select formControlName="binding">
|
||||
<mat-option *ngFor="let bindingMode of bindingModeTypes"
|
||||
[value]="bindingMode">
|
||||
{{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}
|
||||
<mat-option *ngFor="let bindingMode of bindingModeTypes" [value]="bindingMode">
|
||||
{{ bindingModeTypeNamesMap.get(bindingMode) | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-checkbox formControlName="notifIfDisabled" color="primary">
|
||||
{{ 'device-profile.lwm2m.notif-if-disabled' | translate }}
|
||||
{{ 'device-profile.lwm2m.notification-storing' | translate }}
|
||||
</mat-checkbox>
|
||||
</ng-template>
|
||||
</mat-expansion-panel>
|
||||
@ -90,7 +99,6 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-profile-lwm2m-device-config-server
|
||||
[required]="required"
|
||||
formControlName="bootstrapServer"
|
||||
[isBootstrapServer]="true">
|
||||
</tb-profile-lwm2m-device-config-server>
|
||||
@ -102,7 +110,6 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-profile-lwm2m-device-config-server
|
||||
[required]="required"
|
||||
formControlName="lwm2mServer"
|
||||
[isBootstrapServer]="false">
|
||||
</tb-profile-lwm2m-device-config-server>
|
||||
@ -110,11 +117,11 @@
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</section>
|
||||
</ng-template>
|
||||
</section>
|
||||
</mat-tab>
|
||||
<mat-tab label="{{ 'device-profile.lwm2m.others-tab' | translate }}">
|
||||
<ng-template matTabContent>
|
||||
<section [formGroup]="lwm2mDeviceProfileFormGroup">
|
||||
<ng-template matTabContent [formGroup]="lwm2mDeviceProfileFormGroup">
|
||||
<section formGroupName="clientLwM2mSettings">
|
||||
<fieldset class="fields-group">
|
||||
<legend class="group-title" translate>device-profile.lwm2m.fw-update</legend>
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
@ -128,7 +135,7 @@
|
||||
<mat-form-field class="mat-block" fxFlex *ngIf="isFwUpdateStrategy">
|
||||
<mat-label>{{ 'device-profile.lwm2m.fw-update-resource' | translate }}</mat-label>
|
||||
<input matInput formControlName="fwUpdateResource" required>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('fwUpdateResource').hasError('required')">
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.fw-update-resource-required' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
@ -145,7 +152,7 @@
|
||||
<mat-form-field class="mat-block" fxFlex *ngIf="isSwUpdateStrategy">
|
||||
<mat-label>{{ 'device-profile.lwm2m.sw-update-resource' | translate }}</mat-label>
|
||||
<input matInput formControlName="swUpdateResource" required>
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('swUpdateResource').hasError('required')">
|
||||
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.sw-update-resource-required' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
@ -193,6 +200,7 @@
|
||||
<ng-template matTabContent>
|
||||
<section [formGroup]="lwm2mDeviceConfigFormGroup" style="padding: 8px 0">
|
||||
<tb-json-object-edit
|
||||
readonly
|
||||
[required]="required"
|
||||
[sort]="sortFunction"
|
||||
label="{{ 'device-profile.transport-type-lwm2m' | translate }}"
|
||||
|
||||
@ -20,11 +20,20 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida
|
||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
import {
|
||||
ATTRIBUTE,
|
||||
BINDING_MODE,
|
||||
BINDING_MODE_NAMES,
|
||||
BingingMode,
|
||||
BingingModeTranslationsMap,
|
||||
DEFAULT_BINDING,
|
||||
DEFAULT_FW_UPDATE_RESOURCE,
|
||||
DEFAULT_ID_SERVER,
|
||||
DEFAULT_LIFE_TIME,
|
||||
DEFAULT_MIN_PERIOD,
|
||||
DEFAULT_NOTIF_IF_DESIBLED,
|
||||
DEFAULT_SW_UPDATE_RESOURCE,
|
||||
getDefaultProfileConfig,
|
||||
getDefaultBootstrapServerSecurityConfig,
|
||||
getDefaultBootstrapServersSecurityConfig,
|
||||
getDefaultLwM2MServerSecurityConfig,
|
||||
getDefaultProfileClientLwM2mSettingsConfig,
|
||||
getDefaultProfileObserveAttrConfig,
|
||||
Instance,
|
||||
INSTANCES,
|
||||
KEY_NAME,
|
||||
@ -32,8 +41,11 @@ import {
|
||||
ModelValue,
|
||||
ObjectLwM2M,
|
||||
OBSERVE,
|
||||
OBSERVE_ATTR_TELEMETRY, PowerMode, PowerModeTranslationMap,
|
||||
OBSERVE_ATTR_TELEMETRY,
|
||||
PowerMode,
|
||||
PowerModeTranslationMap,
|
||||
RESOURCES,
|
||||
ServerSecurityConfig,
|
||||
TELEMETRY
|
||||
} from './lwm2m-profile-config.models';
|
||||
import { DeviceProfileService } from '@core/http/device-profile.service';
|
||||
@ -61,14 +73,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
|
||||
private disabled = false;
|
||||
private destroy$ = new Subject();
|
||||
|
||||
bindingModeType = BINDING_MODE;
|
||||
bindingModeTypes = Object.keys(BINDING_MODE);
|
||||
bindingModeTypeNamesMap = BINDING_MODE_NAMES;
|
||||
bindingModeTypes = Object.values(BingingMode);
|
||||
bindingModeTypeNamesMap = BingingModeTranslationsMap;
|
||||
lwm2mDeviceProfileFormGroup: FormGroup;
|
||||
lwm2mDeviceConfigFormGroup: FormGroup;
|
||||
bootstrapServers: string;
|
||||
bootstrapServer: string;
|
||||
lwm2mServer: string;
|
||||
sortFunction: (key: string, value: object) => object;
|
||||
isFwUpdateStrategy: boolean;
|
||||
isSwUpdateStrategy: boolean;
|
||||
@ -92,46 +100,54 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
|
||||
this.lwm2mDeviceProfileFormGroup = this.fb.group({
|
||||
objectIds: [null, Validators.required],
|
||||
observeAttrTelemetry: [null, Validators.required],
|
||||
shortId: [null, Validators.required],
|
||||
lifetime: [null, Validators.required],
|
||||
defaultMinPeriod: [null, Validators.required],
|
||||
notifIfDisabled: [true, []],
|
||||
binding: [],
|
||||
bootstrapServer: [null, Validators.required],
|
||||
lwm2mServer: [null, Validators.required],
|
||||
clientOnlyObserveAfterConnect: [1, []],
|
||||
fwUpdateStrategy: [1, []],
|
||||
swUpdateStrategy: [1, []],
|
||||
fwUpdateResource: [{value: '', disabled: true}, []],
|
||||
swUpdateResource: [{value: '', disabled: true}, []],
|
||||
powerMode: [null, Validators.required]
|
||||
bootstrap: this.fb.group({
|
||||
servers: this.fb.group({
|
||||
binding: [DEFAULT_BINDING],
|
||||
shortId: [DEFAULT_ID_SERVER, [Validators.required, Validators.min(1), Validators.max(65534), Validators.pattern('[0-9]*')]],
|
||||
lifetime: [DEFAULT_LIFE_TIME, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
|
||||
notifIfDisabled: [DEFAULT_NOTIF_IF_DESIBLED, []],
|
||||
defaultMinPeriod: [DEFAULT_MIN_PERIOD, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
|
||||
}),
|
||||
bootstrapServer: [null, Validators.required],
|
||||
lwm2mServer: [null, Validators.required]
|
||||
}),
|
||||
clientLwM2mSettings: this.fb.group({
|
||||
clientOnlyObserveAfterConnect: [1, []],
|
||||
fwUpdateStrategy: [1, []],
|
||||
swUpdateStrategy: [1, []],
|
||||
fwUpdateResource: [{value: '', disabled: true}, []],
|
||||
swUpdateResource: [{value: '', disabled: true}, []],
|
||||
powerMode: [null, Validators.required]
|
||||
})
|
||||
});
|
||||
this.lwm2mDeviceConfigFormGroup = this.fb.group({
|
||||
configurationJson: [null, Validators.required]
|
||||
});
|
||||
this.lwm2mDeviceProfileFormGroup.get('fwUpdateStrategy').valueChanges.pipe(
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').valueChanges.pipe(
|
||||
takeUntil(this.destroy$)
|
||||
).subscribe((fwStrategy) => {
|
||||
if (fwStrategy === 2) {
|
||||
this.lwm2mDeviceProfileFormGroup.get('fwUpdateResource').enable({emitEvent: false});
|
||||
this.lwm2mDeviceProfileFormGroup.get('fwUpdateResource').patchValue(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false});
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').enable({emitEvent: false});
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource')
|
||||
.patchValue(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false});
|
||||
this.isFwUpdateStrategy = true;
|
||||
} else {
|
||||
this.lwm2mDeviceProfileFormGroup.get('fwUpdateResource').disable({emitEvent: false});
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').disable({emitEvent: false});
|
||||
this.isFwUpdateStrategy = false;
|
||||
}
|
||||
this.otaUpdateFwStrategyValidate(true);
|
||||
});
|
||||
this.lwm2mDeviceProfileFormGroup.get('swUpdateStrategy').valueChanges.pipe(
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').valueChanges.pipe(
|
||||
takeUntil(this.destroy$)
|
||||
).subscribe((swStrategy) => {
|
||||
if (swStrategy === 2) {
|
||||
this.lwm2mDeviceProfileFormGroup.get('swUpdateResource').enable({emitEvent: false});
|
||||
this.lwm2mDeviceProfileFormGroup.get('swUpdateResource').patchValue(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false});
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').enable({emitEvent: false});
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource')
|
||||
.patchValue(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false});
|
||||
this.isSwUpdateStrategy = true;
|
||||
} else {
|
||||
this.isSwUpdateStrategy = false;
|
||||
this.lwm2mDeviceProfileFormGroup.get('swUpdateResource').disable({emitEvent: false});
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').disable({emitEvent: false});
|
||||
}
|
||||
this.otaUpdateSwStrategyValidate(true);
|
||||
});
|
||||
@ -171,12 +187,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
|
||||
}
|
||||
}
|
||||
|
||||
writeValue(value: Lwm2mProfileConfigModels | null): void {
|
||||
async writeValue(value: Lwm2mProfileConfigModels | null) {
|
||||
if (isDefinedAndNotNull(value)) {
|
||||
if (Object.keys(value).length !== 0 && (value?.clientLwM2mSettings || value?.observeAttr || value?.bootstrap)) {
|
||||
if (value?.clientLwM2mSettings || value?.observeAttr || value?.bootstrap) {
|
||||
this.configurationValue = value;
|
||||
} else {
|
||||
this.configurationValue = getDefaultProfileConfig();
|
||||
this.configurationValue = await this.defaultProfileConfig();
|
||||
}
|
||||
this.lwm2mDeviceConfigFormGroup.patchValue({
|
||||
configurationJson: this.configurationValue
|
||||
@ -185,6 +201,29 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
|
||||
}
|
||||
}
|
||||
|
||||
private async defaultProfileConfig(): Promise<Lwm2mProfileConfigModels> {
|
||||
let bootstrap: ServerSecurityConfig;
|
||||
let lwm2m: ServerSecurityConfig;
|
||||
try {
|
||||
[bootstrap, lwm2m] = await Promise.all([
|
||||
this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(true).toPromise(),
|
||||
this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(false).toPromise()
|
||||
]);
|
||||
} catch (e) {
|
||||
bootstrap = getDefaultBootstrapServerSecurityConfig();
|
||||
lwm2m = getDefaultLwM2MServerSecurityConfig();
|
||||
}
|
||||
return {
|
||||
observeAttr: getDefaultProfileObserveAttrConfig(),
|
||||
bootstrap: {
|
||||
servers: getDefaultBootstrapServersSecurityConfig(),
|
||||
bootstrapServer: bootstrap,
|
||||
lwm2mServer: lwm2m
|
||||
},
|
||||
clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig()
|
||||
};
|
||||
}
|
||||
|
||||
private initWriteValue = (): void => {
|
||||
const modelValue = {objectIds: [], objectsList: []} as ModelValue;
|
||||
modelValue.objectIds = this.getObjectsFromJsonAllConfig();
|
||||
@ -212,19 +251,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
|
||||
this.lwm2mDeviceProfileFormGroup.patchValue({
|
||||
objectIds: value,
|
||||
observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value.objectsList),
|
||||
shortId: this.configurationValue.bootstrap.servers.shortId,
|
||||
lifetime: this.configurationValue.bootstrap.servers.lifetime,
|
||||
defaultMinPeriod: this.configurationValue.bootstrap.servers.defaultMinPeriod,
|
||||
notifIfDisabled: this.configurationValue.bootstrap.servers.notifIfDisabled,
|
||||
binding: this.configurationValue.bootstrap.servers.binding,
|
||||
bootstrapServer: this.configurationValue.bootstrap.bootstrapServer,
|
||||
lwm2mServer: this.configurationValue.bootstrap.lwm2mServer,
|
||||
clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect,
|
||||
fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1,
|
||||
swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1,
|
||||
fwUpdateResource: fwResource,
|
||||
swUpdateResource: swResource,
|
||||
powerMode: this.configurationValue.clientLwM2mSettings.powerMode
|
||||
bootstrap: this.configurationValue.bootstrap,
|
||||
clientLwM2mSettings: {
|
||||
clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect,
|
||||
fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1,
|
||||
swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1,
|
||||
fwUpdateResource: fwResource,
|
||||
swUpdateResource: swResource,
|
||||
powerMode: this.configurationValue.clientLwM2mSettings.powerMode
|
||||
}
|
||||
},
|
||||
{emitEvent: false});
|
||||
this.configurationValue.clientLwM2mSettings.fwUpdateResource = fwResource;
|
||||
@ -253,22 +288,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
|
||||
private updateDeviceProfileValue(config): void {
|
||||
if (this.lwm2mDeviceProfileFormGroup.valid) {
|
||||
this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M);
|
||||
this.configurationValue.bootstrap.bootstrapServer = config.bootstrapServer;
|
||||
this.configurationValue.bootstrap.lwm2mServer = config.lwm2mServer;
|
||||
const bootstrapServers = this.configurationValue.bootstrap.servers;
|
||||
bootstrapServers.shortId = config.shortId;
|
||||
bootstrapServers.lifetime = config.lifetime;
|
||||
bootstrapServers.defaultMinPeriod = config.defaultMinPeriod;
|
||||
bootstrapServers.notifIfDisabled = config.notifIfDisabled;
|
||||
bootstrapServers.binding = config.binding;
|
||||
this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect = config.clientOnlyObserveAfterConnect;
|
||||
this.configurationValue.clientLwM2mSettings.fwUpdateStrategy = config.fwUpdateStrategy;
|
||||
this.configurationValue.clientLwM2mSettings.swUpdateStrategy = config.swUpdateStrategy;
|
||||
this.configurationValue.clientLwM2mSettings.fwUpdateResource = config.fwUpdateResource;
|
||||
this.configurationValue.clientLwM2mSettings.swUpdateResource = config.swUpdateResource;
|
||||
this.configurationValue.clientLwM2mSettings.powerMode = config.powerMode;
|
||||
this.upDateJsonAllConfig();
|
||||
}
|
||||
this.configurationValue.bootstrap.bootstrapServer = config.bootstrap.bootstrapServer;
|
||||
this.configurationValue.bootstrap.lwm2mServer = config.bootstrap.lwm2mServer;
|
||||
this.configurationValue.bootstrap.servers = config.bootstrap.servers;
|
||||
this.configurationValue.clientLwM2mSettings = config.clientLwM2mSettings;
|
||||
this.upDateJsonAllConfig();
|
||||
this.updateModel();
|
||||
}
|
||||
|
||||
@ -544,20 +569,20 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
|
||||
|
||||
private otaUpdateFwStrategyValidate(updated = false): void {
|
||||
if (this.isFwUpdateStrategy) {
|
||||
this.lwm2mDeviceProfileFormGroup.get('fwUpdateResource').setValidators([Validators.required]);
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').setValidators([Validators.required]);
|
||||
} else {
|
||||
this.lwm2mDeviceProfileFormGroup.get('fwUpdateResource').clearValidators();
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').clearValidators();
|
||||
}
|
||||
this.lwm2mDeviceProfileFormGroup.get('fwUpdateResource').updateValueAndValidity({emitEvent: updated});
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').updateValueAndValidity({emitEvent: updated});
|
||||
}
|
||||
|
||||
private otaUpdateSwStrategyValidate(updated = false): void {
|
||||
if (this.isSwUpdateStrategy) {
|
||||
this.lwm2mDeviceProfileFormGroup.get('swUpdateResource').setValidators([Validators.required]);
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').setValidators([Validators.required]);
|
||||
} else {
|
||||
this.lwm2mDeviceProfileFormGroup.get('swUpdateResource').clearValidators();
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').clearValidators();
|
||||
}
|
||||
this.lwm2mDeviceProfileFormGroup.get('swUpdateResource').updateValueAndValidity({emitEvent: updated});
|
||||
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').updateValueAndValidity({emitEvent: updated});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -20,27 +20,24 @@
|
||||
*ngFor="let resourceLwM2M of resourceFormArray.controls; let i = index; trackBy: trackByParams">
|
||||
<div class="vertical-padding" fxLayout="column" fxFill [formGroupName]="i">
|
||||
<div fxLayout="row" fxFill fxLayoutAlign="start center" [fxShow]="!i">
|
||||
<div fxFlex="20">
|
||||
<div fxFlex="30">
|
||||
<mat-label translate>device-profile.lwm2m.resource-label</mat-label>
|
||||
</div>
|
||||
<div fxFlex="10">
|
||||
<div fxFlex="10" style="text-align: center">
|
||||
<mat-label translate>device-profile.lwm2m.attribute-label</mat-label>
|
||||
</div>
|
||||
<div fxFlex="10">
|
||||
<div fxFlex="10" style="text-align: center">
|
||||
<mat-label translate>device-profile.lwm2m.telemetry-label</mat-label>
|
||||
</div>
|
||||
<div fxFlex="10">
|
||||
<div fxFlex="10" style="text-align: center">
|
||||
<mat-label translate>device-profile.lwm2m.observe-label</mat-label>
|
||||
</div>
|
||||
<div fxFlex>
|
||||
<mat-label translate>device-profile.lwm2m.key-name-label</mat-label>
|
||||
</div>
|
||||
<div fxFlex="17" fxFlexOffset="0">
|
||||
<mat-label translate>device-profile.lwm2m.attribute-lwm2m-label</mat-label>
|
||||
</div>
|
||||
</div>
|
||||
<div fxLayout="row" fxFill fxLayoutAlign="start center">
|
||||
<div class="resource-name-lw" fxFlex="25"
|
||||
<div class="resource-name-lw" fxFlex="30"
|
||||
matTooltip="{{'device-profile.lwm2m.resource-tip' | translate}}" matTooltipPosition="above">
|
||||
<<b>{{resourceLwM2M.get('id').value}}</b>> <b><i>{{resourceLwM2M.get('name').value}}</i></b>
|
||||
</div>
|
||||
@ -65,7 +62,7 @@
|
||||
matTooltipPosition="above">
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<mat-form-field fxFlex="25">
|
||||
<mat-form-field fxFlex="33">
|
||||
<mat-label *ngIf="resourceLwM2M.get('keyName').hasError('required')">
|
||||
{{ 'device-profile.lwm2m.key-name-label' | translate }}</mat-label>
|
||||
<input class="resource-name-lw" matInput type="text" formControlName="keyName" required
|
||||
@ -77,12 +74,13 @@
|
||||
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<div fxFlex="20" class="resource-name-lw-end" fxFlexOffset="5">
|
||||
<span fxFlex></span>
|
||||
<div class="resource-name-lw-end">
|
||||
<tb-profile-lwm2m-attributes
|
||||
formControlName="attributeLwm2m"
|
||||
[attributeLwm2m]="resourceLwM2M.get('attributeLwm2m').value"
|
||||
[isAttributeTelemetry]="disableObserve(i)"
|
||||
[destName]="getNameResourceLwm2m(resourceLwM2M.value)"
|
||||
isResource="true"
|
||||
[modelName]="getNameResourceLwm2m(resourceLwM2M.value)"
|
||||
[disabled]="this.disabled"
|
||||
(updateAttributeLwm2m)="updateAttributeLwm2m($event, i)">
|
||||
</tb-profile-lwm2m-attributes>
|
||||
|
||||
@ -26,17 +26,15 @@
|
||||
<div fxFlex class="resource-name-lw-end">
|
||||
<tb-profile-lwm2m-attributes
|
||||
formControlName="attributeLwm2m"
|
||||
[attributeLwm2m]="objectLwM2M.get('attributeLwm2m').value"
|
||||
[isAttributeTelemetry]="disableObserveObject(i)"
|
||||
[destName]="getNameObjectLwm2m( objectLwM2M.get('name').value, objectLwM2M.get('keyId').value)"
|
||||
[modelName]="getNameObjectLwm2m( objectLwM2M.get('name').value, objectLwM2M.get('keyId').value)"
|
||||
[disabled]="this.disabled"
|
||||
(updateAttributeLwm2m)="updateAttributeLwm2mObject($event, objectLwM2M.get('keyId').value)">
|
||||
</tb-profile-lwm2m-attributes>
|
||||
</div>
|
||||
</mat-panel-title>
|
||||
<mat-panel-description fxFlex="5" fxLayoutAlign="end center" *ngIf="!disabled">
|
||||
<mat-panel-description fxFlex="5" fxLayoutAlign="end center" *ngIf="!disabled && objectLwM2M.get('multiple').value">
|
||||
<button type="button"
|
||||
[fxShow]="objectLwM2M.get('multiple').value"
|
||||
mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)"
|
||||
matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}"
|
||||
matTooltipPosition="above">
|
||||
@ -56,7 +54,7 @@
|
||||
<mat-panel-title>
|
||||
<div class="tb-panel-title-height" fxFlex="100">
|
||||
<div fxLayout="row" fxFill>
|
||||
<div fxFlex="22">
|
||||
<div fxFlex="30">
|
||||
{{'device-profile.lwm2m.instance-label' | translate}} <<b>{{instances.get('id').value}}</b>>
|
||||
</div>
|
||||
<div class="checkbox-padding" fxFlex="10">
|
||||
@ -95,14 +93,13 @@
|
||||
matTooltipPosition="above">
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div fxFlex="10">
|
||||
<div fxFlex="7">
|
||||
</div>
|
||||
<div fxFlex="37" class="resource-name-lw-end" fxFlexOffset="5">
|
||||
<tb-profile-lwm2m-attributes
|
||||
formControlName="attributeLwm2m"
|
||||
[attributeLwm2m]="instances.get('attributeLwm2m').value"
|
||||
[isAttributeTelemetry]="disableObserveInstance(instances)"
|
||||
[destName]="getNameInstanceLwm2m(instances.value, objectLwM2M.get('keyId').value)"
|
||||
[modelName]="getNameInstanceLwm2m(instances.value, objectLwM2M.get('keyId').value)"
|
||||
[disabled]="this.disabled"
|
||||
(updateAttributeLwm2m)="updateAttributeLwm2mInstance($event, y, objectLwM2M.get('keyId').value)">
|
||||
</tb-profile-lwm2m-attributes>
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { ValidatorFn, Validators } from '@angular/forms';
|
||||
|
||||
export const PAGE_SIZE_LIMIT = 50;
|
||||
export const INSTANCES = 'instances';
|
||||
export const INSTANCE = 'instance';
|
||||
@ -39,7 +41,7 @@ export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0;
|
||||
export const LEN_MAX_PUBLIC_KEY_RPK = 182;
|
||||
export const LEN_MAX_PUBLIC_KEY_X509 = 3000;
|
||||
export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/;
|
||||
export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/;
|
||||
export const KEY_REGEXP_NUMBER = /^(-?|\+?)\d*$/;
|
||||
export const INSTANCES_ID_VALUE_MIN = 0;
|
||||
export const INSTANCES_ID_VALUE_MAX = 65535;
|
||||
export const DEFAULT_OTA_UPDATE_PROTOCOL = 'coap://';
|
||||
@ -47,7 +49,7 @@ export const DEFAULT_FW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_
|
||||
export const DEFAULT_SW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ':' + DEFAULT_PORT_SERVER_NO_SEC;
|
||||
|
||||
|
||||
export enum BINDING_MODE {
|
||||
export enum BingingMode {
|
||||
U = 'U',
|
||||
UQ = 'UQ',
|
||||
T = 'T',
|
||||
@ -60,58 +62,43 @@ export enum BINDING_MODE {
|
||||
TQS = 'TQS'
|
||||
}
|
||||
|
||||
export const BINDING_MODE_NAMES = new Map<BINDING_MODE, string>(
|
||||
export const BingingModeTranslationsMap = new Map<BingingMode, string>(
|
||||
[
|
||||
[BINDING_MODE.U, 'U: UDP connection in standard mode'],
|
||||
[BINDING_MODE.UQ, 'UQ: UDP connection in queue mode'],
|
||||
[BINDING_MODE.US, 'US: both UDP and SMS connections active, both in standard mode'],
|
||||
[BINDING_MODE.UQS, 'UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode'],
|
||||
[BINDING_MODE.T, 'T: TCP connection in standard mode'],
|
||||
[BINDING_MODE.TQ, 'TQ: TCP connection in queue mode'],
|
||||
[BINDING_MODE.TS, 'TS: both TCP and SMS connections active, both in standard mode'],
|
||||
[BINDING_MODE.TQS, 'TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode'],
|
||||
[BINDING_MODE.S, 'S: SMS connection in standard mode'],
|
||||
[BINDING_MODE.SQ, 'SQ: SMS connection in queue mode']
|
||||
[BingingMode.U, 'device-profile.lwm2m.binding-type.u'],
|
||||
[BingingMode.UQ, 'device-profile.lwm2m.binding-type.uq'],
|
||||
[BingingMode.US, 'device-profile.lwm2m.binding-type.us'],
|
||||
[BingingMode.UQS, 'device-profile.lwm2m.binding-type.uqs'],
|
||||
[BingingMode.T, 'device-profile.lwm2m.binding-type.t'],
|
||||
[BingingMode.TQ, 'device-profile.lwm2m.binding-type.tq'],
|
||||
[BingingMode.TS, 'device-profile.lwm2m.binding-type.ts'],
|
||||
[BingingMode.TQS, 'device-profile.lwm2m.binding-type.tqs'],
|
||||
[BingingMode.S, 'device-profile.lwm2m.binding-type.s'],
|
||||
[BingingMode.SQ, 'device-profile.lwm2m.binding-type.sq']
|
||||
]
|
||||
);
|
||||
|
||||
export enum ATTRIBUTE_LWM2M_ENUM {
|
||||
dim = 'dim',
|
||||
ver = 'ver',
|
||||
// TODO: wait release Leshan for issues: https://github.com/eclipse/leshan/issues/1026
|
||||
export enum AttributeName {
|
||||
pmin = 'pmin',
|
||||
pmax = 'pmax',
|
||||
gt = 'gt',
|
||||
lt = 'lt',
|
||||
st = 'st'
|
||||
// epmin = 'epmin',
|
||||
// epmax = 'epmax'
|
||||
}
|
||||
|
||||
export const ATTRIBUTE_LWM2M_LABEL = new Map<ATTRIBUTE_LWM2M_ENUM, string>(
|
||||
export const AttributeNameTranslationMap = new Map<AttributeName, string>(
|
||||
[
|
||||
[ATTRIBUTE_LWM2M_ENUM.dim, 'dim='],
|
||||
[ATTRIBUTE_LWM2M_ENUM.ver, 'ver='],
|
||||
[ATTRIBUTE_LWM2M_ENUM.pmin, 'pmin='],
|
||||
[ATTRIBUTE_LWM2M_ENUM.pmax, 'pmax='],
|
||||
[ATTRIBUTE_LWM2M_ENUM.gt, '>'],
|
||||
[ATTRIBUTE_LWM2M_ENUM.lt, '<'],
|
||||
[ATTRIBUTE_LWM2M_ENUM.st, 'st=']
|
||||
[AttributeName.pmin, 'device-profile.lwm2m.attributes-name.min-period'],
|
||||
[AttributeName.pmax, 'device-profile.lwm2m.attributes-name.max-period'],
|
||||
[AttributeName.gt, 'device-profile.lwm2m.attributes-name.greater-than'],
|
||||
[AttributeName.lt, 'device-profile.lwm2m.attributes-name.less-than'],
|
||||
[AttributeName.st, 'device-profile.lwm2m.attributes-name.step'],
|
||||
// [AttributeName.epmin, 'device-profile.lwm2m.attributes-name.min-evaluation-period'],
|
||||
// [AttributeName.epmax, 'device-profile.lwm2m.attributes-name.max-evaluation-period']
|
||||
]
|
||||
);
|
||||
|
||||
export const ATTRIBUTE_LWM2M_MAP = new Map<ATTRIBUTE_LWM2M_ENUM, string>(
|
||||
[
|
||||
[ATTRIBUTE_LWM2M_ENUM.dim, 'Dimension'],
|
||||
[ATTRIBUTE_LWM2M_ENUM.ver, 'Object version'],
|
||||
[ATTRIBUTE_LWM2M_ENUM.pmin, 'Minimum period'],
|
||||
[ATTRIBUTE_LWM2M_ENUM.pmax, 'Maximum period'],
|
||||
[ATTRIBUTE_LWM2M_ENUM.gt, 'Greater than'],
|
||||
[ATTRIBUTE_LWM2M_ENUM.lt, 'Lesser than'],
|
||||
[ATTRIBUTE_LWM2M_ENUM.st, 'Step'],
|
||||
|
||||
]
|
||||
);
|
||||
|
||||
export const ATTRIBUTE_KEYS = Object.keys(ATTRIBUTE_LWM2M_ENUM) as string[];
|
||||
|
||||
export enum securityConfigMode {
|
||||
PSK = 'PSK',
|
||||
RPK = 'RPK',
|
||||
@ -157,18 +144,20 @@ export interface BootstrapServersSecurityConfig {
|
||||
|
||||
export interface ServerSecurityConfig {
|
||||
host?: string;
|
||||
securityHost?: string;
|
||||
port?: number;
|
||||
securityPort?: number;
|
||||
securityMode: securityConfigMode;
|
||||
clientPublicKeyOrId?: string;
|
||||
clientSecretKey?: string;
|
||||
serverPublicKey?: string;
|
||||
clientHoldOffTime?: number;
|
||||
serverId?: number;
|
||||
bootstrapServerAccountTimeout: number;
|
||||
}
|
||||
|
||||
export interface ServerSecurityConfigInfo extends ServerSecurityConfig {
|
||||
securityHost?: string;
|
||||
securityPort?: number;
|
||||
bootstrapServerIs: boolean;
|
||||
}
|
||||
|
||||
interface BootstrapSecurityConfig {
|
||||
servers: BootstrapServersSecurityConfig;
|
||||
bootstrapServer: ServerSecurityConfig;
|
||||
@ -195,7 +184,7 @@ export interface ObservableAttributes {
|
||||
attribute: string[];
|
||||
telemetry: string[];
|
||||
keyName: {};
|
||||
attributeLwm2m: {};
|
||||
attributeLwm2m?: AttributesNameValueMap;
|
||||
}
|
||||
|
||||
export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig {
|
||||
@ -208,9 +197,9 @@ export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecu
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefaultBootstrapServerSecurityConfig(hostname: string): ServerSecurityConfig {
|
||||
export function getDefaultBootstrapServerSecurityConfig(): ServerSecurityConfig {
|
||||
return {
|
||||
host: hostname,
|
||||
host: DEFAULT_LOCAL_HOST_NAME,
|
||||
port: DEFAULT_PORT_BOOTSTRAP_NO_SEC,
|
||||
securityMode: securityConfigMode.NO_SEC,
|
||||
serverPublicKey: '',
|
||||
@ -220,22 +209,14 @@ export function getDefaultBootstrapServerSecurityConfig(hostname: string): Serve
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig {
|
||||
const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname);
|
||||
export function getDefaultLwM2MServerSecurityConfig(): ServerSecurityConfig {
|
||||
const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig();
|
||||
DefaultLwM2MServerSecurityConfig.port = DEFAULT_PORT_SERVER_NO_SEC;
|
||||
DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER;
|
||||
return DefaultLwM2MServerSecurityConfig;
|
||||
}
|
||||
|
||||
function getDefaultProfileBootstrapSecurityConfig(hostname: any): BootstrapSecurityConfig {
|
||||
return {
|
||||
servers: getDefaultBootstrapServersSecurityConfig(),
|
||||
bootstrapServer: getDefaultBootstrapServerSecurityConfig(hostname),
|
||||
lwm2mServer: getDefaultLwM2MServerSecurityConfig(hostname)
|
||||
};
|
||||
}
|
||||
|
||||
function getDefaultProfileObserveAttrConfig(): ObservableAttributes {
|
||||
export function getDefaultProfileObserveAttrConfig(): ObservableAttributes {
|
||||
return {
|
||||
observe: [],
|
||||
attribute: [],
|
||||
@ -245,15 +226,7 @@ function getDefaultProfileObserveAttrConfig(): ObservableAttributes {
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModels {
|
||||
return {
|
||||
clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig(),
|
||||
observeAttr: getDefaultProfileObserveAttrConfig(),
|
||||
bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_LOCAL_HOST_NAME)
|
||||
};
|
||||
}
|
||||
|
||||
function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings {
|
||||
export function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings {
|
||||
return {
|
||||
clientOnlyObserveAfterConnect: 1,
|
||||
fwUpdateStrategy: 1,
|
||||
@ -271,12 +244,12 @@ export interface ResourceLwM2M {
|
||||
attribute: boolean;
|
||||
telemetry: boolean;
|
||||
keyName: string;
|
||||
attributeLwm2m?: {};
|
||||
attributeLwm2m?: AttributesNameValueMap;
|
||||
}
|
||||
|
||||
export interface Instance {
|
||||
id: number;
|
||||
attributeLwm2m?: {};
|
||||
attributeLwm2m?: AttributesNameValueMap;
|
||||
resources: ResourceLwM2M[];
|
||||
}
|
||||
|
||||
@ -287,12 +260,33 @@ export interface Instance {
|
||||
* mandatory == false => Optional
|
||||
*/
|
||||
export interface ObjectLwM2M {
|
||||
|
||||
id: number;
|
||||
keyId: string;
|
||||
name: string;
|
||||
multiple?: boolean;
|
||||
mandatory?: boolean;
|
||||
attributeLwm2m?: {};
|
||||
attributeLwm2m?: AttributesNameValueMap;
|
||||
instances?: Instance [];
|
||||
}
|
||||
|
||||
export type AttributesNameValueMap = {
|
||||
[key in AttributeName]?: number;
|
||||
};
|
||||
|
||||
export interface AttributesNameValue {
|
||||
name: AttributeName;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export function valueValidatorByAttributeName(attributeName: AttributeName): ValidatorFn[] {
|
||||
const validators = [Validators.required];
|
||||
switch (attributeName) {
|
||||
case AttributeName.pmin:
|
||||
case AttributeName.pmax:
|
||||
// case AttributeName.epmin:
|
||||
// case AttributeName.epmax:
|
||||
validators.push(Validators.min(0), Validators.pattern('[0-9]*'));
|
||||
break;
|
||||
}
|
||||
return validators;
|
||||
}
|
||||
|
||||
@ -1238,36 +1238,53 @@
|
||||
"attribute-label": "Attribute",
|
||||
"telemetry-label": "Telemetry",
|
||||
"key-name-label": "Key Name",
|
||||
"attribute-lwm2m-label": "AttrLwm2m",
|
||||
"resource-tip": "ID & Original Name of the Resource (only Operations isReadable)",
|
||||
"is-observe-tip": "Is Observe",
|
||||
"not-observe-tip": "To observe select telemetry or attributes first",
|
||||
"is-attr-tip": "Is Attribute",
|
||||
"is-telemetry-tip": "Is Telemetry",
|
||||
"key-name-tip": "Key Name in Camel format",
|
||||
"attribute-lwm2m-tip": "Attributes Lwm2m",
|
||||
"attribute-lwm2m-disable-tip": "To edit Attributes Lwm2m select telemetry or attributes first",
|
||||
"valid-attribute-lwm2m-key": "Name have be only '{{attrEnums}}'",
|
||||
"valid-attribute-lwm2m-value": "Value have be Long, Double and greater than zero or null/empty",
|
||||
"no-data": "No attributes",
|
||||
"edit-attributes-select": "To edit attributes select telemetry or attributes",
|
||||
"no-attributes-set": "No attributes set",
|
||||
"key-name": "Key Name",
|
||||
"attribute-lwm2m-name": "Name attribute",
|
||||
"attribute-lwm2m-value": "Value",
|
||||
"attribute-lwm2m-toolbar-edit": "Edit attributes Lwm2m",
|
||||
"attribute-lwm2m-toolbar-view": "View Attributes Lwm2m",
|
||||
"attribute-lwm2m-destination": "Destination:",
|
||||
"attribute-lwm2m-add-tip": "Add attribute lwm2m",
|
||||
"attribute-lwm2m-remove-tip": "Remove attribute lwm2m",
|
||||
"required": " value is required.",
|
||||
"attribute-name": "Name attribute",
|
||||
"attribute-name-required": "Name attribute is required.",
|
||||
"attribute-value": "Attribute value",
|
||||
"attribute-value-required": "Attribute value is required.",
|
||||
"attribute-value-pattern": "Attribute value must be a positive integer.",
|
||||
"edit-attributes": "Edit attributes: {{ name }}",
|
||||
"view-attributes": "View attributes: {{ name }}",
|
||||
"add-attribute": "Add attribute",
|
||||
"edit-attribute": "Edit attribute",
|
||||
"view-attribute": "View attribute",
|
||||
"remove-attribute": "Remove attribute",
|
||||
"mode": "Security config mode",
|
||||
"pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }",
|
||||
"servers": "Servers",
|
||||
"short-id": "Short ID",
|
||||
"short-id-required": "Short ID is required.",
|
||||
"lifetime": "Lifetime of the registration for this LwM2M client",
|
||||
"default-min-period": "Minimum Period between two notifications (sec)",
|
||||
"notif-if-disabled": "Notification Storing When Disabled or Offline",
|
||||
"short-id-range": "Short ID should be in a range from 1 to 65534.",
|
||||
"short-id-pattern": "Short ID must be a positive integer.",
|
||||
"lifetime": "Client registration lifetime",
|
||||
"lifetime-required": "Client registration lifetime is required.",
|
||||
"lifetime-pattern": "Client registration lifetime must be a positive integer.",
|
||||
"default-min-period": "Minimum period between two notifications (s)",
|
||||
"default-min-period-required": "Minimum period is required.",
|
||||
"default-min-period-pattern": "Minimum period must be a positive integer.",
|
||||
"notification-storing": "Notification storing when disabled or offline",
|
||||
"binding": "Binding",
|
||||
"binding-type": {
|
||||
"u": "U: UDP connection in standard mode",
|
||||
"uq": "UQ: UDP connection in queue mode",
|
||||
"us": "US: both UDP and SMS connections active, both in standard mode",
|
||||
"uqs": "UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode",
|
||||
"t": "T: TCP connection in standard mode",
|
||||
"tq": "TQ: TCP connection in queue mode",
|
||||
"ts": "TS: both TCP and SMS connections active, both in standard mode",
|
||||
"tqs": "TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode",
|
||||
"s": "S: SMS connection in standard mode",
|
||||
"sq": "SQ: SMS connection in queue mode"
|
||||
},
|
||||
"bootstrap-tab": "Bootstrap",
|
||||
"bootstrap-server": "Bootstrap Server",
|
||||
"lwm2m-server": "LwM2M Server",
|
||||
@ -1275,15 +1292,19 @@
|
||||
"server-host-required": "Host is required.",
|
||||
"server-port": "Port",
|
||||
"server-port-required": "Port is required.",
|
||||
"server-port-pattern": "Port must be a positive integer.",
|
||||
"server-port-range": "Port should be in a range from 1 to 65535.",
|
||||
"server-public-key": "Server Public Key",
|
||||
"server-public-key-required": "Server Public Key is required.",
|
||||
"server-public-key-pattern": "Server Public Key must be hex decimal format.",
|
||||
"server-public-key-length": "Server Public Key must be {{ count }} characters.",
|
||||
"client-hold-off-time": "Hold Off Time",
|
||||
"client-hold-off-time-required": "Hold Off Time is required.",
|
||||
"client-hold-off-time-pattern": "Hold Off Time must be a positive integer.",
|
||||
"client-hold-off-time-tooltip": "Client Hold Off Time for use with a Bootstrap-Server only",
|
||||
"account-after-timeout": "Account after the timeout",
|
||||
"account-after-timeout-required": "Account after the timeout is required.",
|
||||
"account-after-timeout-pattern": "Account after the timeout must be a positive integer.",
|
||||
"account-after-timeout-tooltip": "Bootstrap-Server Account after the timeout value given by this resource.",
|
||||
"others-tab": "Other settings",
|
||||
"client-strategy": "Client strategy when connecting",
|
||||
@ -1303,7 +1324,16 @@
|
||||
"fw-update-resource-required": "Firmware update CoAP resource is required.",
|
||||
"sw-update-resource": "Software update CoAP resource",
|
||||
"sw-update-resource-required": "Software update CoAP resource is required.",
|
||||
"config-json-tab": "Json Config Profile Device"
|
||||
"config-json-tab": "Json Config Profile Device",
|
||||
"attributes-name": {
|
||||
"min-period": "Minimum period",
|
||||
"max-period": "Maximum period",
|
||||
"greater-than": "Greater than",
|
||||
"less-than": "Less than",
|
||||
"step": "Step",
|
||||
"min-evaluation-period": "Minimum evaluation period",
|
||||
"max-evaluation-period": "Maximum evaluation period"
|
||||
}
|
||||
},
|
||||
"snmp": {
|
||||
"add-communication-config": "Add communication config",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user