Commit 51814f4017b5971e01e60b9204d57d59583e87dc

Authored by Vladyslav_Prykhodko
1 parent 26bc7841

UI: Refactoring lwm2m device profile: security server config and ota update strategy

@@ -17,7 +17,6 @@ package org.thingsboard.server.controller; @@ -17,7 +17,6 @@ package org.thingsboard.server.controller;
17 17
18 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 -import org.eclipse.leshan.core.SecurityMode;  
21 import org.springframework.security.access.prepost.PreAuthorize; 20 import org.springframework.security.access.prepost.PreAuthorize;
22 import org.springframework.web.bind.annotation.PathVariable; 21 import org.springframework.web.bind.annotation.PathVariable;
23 import org.springframework.web.bind.annotation.RequestBody; 22 import org.springframework.web.bind.annotation.RequestBody;
@@ -45,14 +44,11 @@ import java.util.Map; @@ -45,14 +44,11 @@ import java.util.Map;
45 public class Lwm2mController extends BaseController { 44 public class Lwm2mController extends BaseController {
46 45
47 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 46 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
48 - @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{securityMode}/{bootstrapServerIs}", method = RequestMethod.GET) 47 + @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET)
49 @ResponseBody 48 @ResponseBody
50 - public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("securityMode") String strSecurityMode,  
51 - @PathVariable("bootstrapServerIs") boolean bootstrapServer) throws ThingsboardException {  
52 - checkNotNull(strSecurityMode); 49 + public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("isBootstrapServer") boolean bootstrapServer) throws ThingsboardException {
53 try { 50 try {
54 - SecurityMode securityMode = SecurityMode.valueOf(strSecurityMode);  
55 - return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(securityMode, bootstrapServer); 51 + return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(bootstrapServer);
56 } catch (Exception e) { 52 } catch (Exception e) {
57 throw handleException(e); 53 throw handleException(e);
58 } 54 }
@@ -18,7 +18,6 @@ package org.thingsboard.server.service.lwm2m; @@ -18,7 +18,6 @@ package org.thingsboard.server.service.lwm2m;
18 18
19 import lombok.RequiredArgsConstructor; 19 import lombok.RequiredArgsConstructor;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 -import org.eclipse.leshan.core.SecurityMode;  
22 import org.eclipse.leshan.core.util.Hex; 21 import org.eclipse.leshan.core.util.Hex;
23 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 22 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
24 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
@@ -50,40 +49,20 @@ public class LwM2MServerSecurityInfoRepository { @@ -50,40 +49,20 @@ public class LwM2MServerSecurityInfoRepository {
50 private final LwM2MTransportServerConfig serverConfig; 49 private final LwM2MTransportServerConfig serverConfig;
51 private final LwM2MTransportBootstrapConfig bootstrapConfig; 50 private final LwM2MTransportBootstrapConfig bootstrapConfig;
52 51
53 - /**  
54 - * @param securityMode  
55 - * @param bootstrapServer  
56 - * @return ServerSecurityConfig more value is default: Important - port, host, publicKey  
57 - */  
58 - public ServerSecurityConfig getServerSecurityInfo(SecurityMode securityMode, boolean bootstrapServer) {  
59 - ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig, securityMode); 52 + public ServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer) {
  53 + ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig);
60 result.setBootstrapServerIs(bootstrapServer); 54 result.setBootstrapServerIs(bootstrapServer);
61 return result; 55 return result;
62 } 56 }
63 57
64 - private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig, SecurityMode securityMode) { 58 + private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig) {
65 ServerSecurityConfig bsServ = new ServerSecurityConfig(); 59 ServerSecurityConfig bsServ = new ServerSecurityConfig();
66 bsServ.setServerId(serverConfig.getId()); 60 bsServ.setServerId(serverConfig.getId());
67 - switch (securityMode) {  
68 - case NO_SEC:  
69 - bsServ.setHost(serverConfig.getHost());  
70 - bsServ.setPort(serverConfig.getPort());  
71 - bsServ.setServerPublicKey("");  
72 - break;  
73 - case PSK:  
74 - bsServ.setHost(serverConfig.getSecureHost());  
75 - bsServ.setPort(serverConfig.getSecurePort());  
76 - bsServ.setServerPublicKey("");  
77 - break;  
78 - case RPK:  
79 - case X509:  
80 - bsServ.setHost(serverConfig.getSecureHost());  
81 - bsServ.setPort(serverConfig.getSecurePort());  
82 - bsServ.setServerPublicKey(getPublicKey(serverConfig.getCertificateAlias(), this.serverConfig.getPublicX(), this.serverConfig.getPublicY()));  
83 - break;  
84 - default:  
85 - break;  
86 - } 61 + bsServ.setHost(serverConfig.getHost());
  62 + bsServ.setPort(serverConfig.getPort());
  63 + bsServ.setSecurityHost(serverConfig.getSecureHost());
  64 + bsServ.setSecurityPort(serverConfig.getSecurePort());
  65 + bsServ.setServerPublicKey(getPublicKey(serverConfig.getCertificateAlias(), this.serverConfig.getPublicX(), this.serverConfig.getPublicY()));
87 return bsServ; 66 return bsServ;
88 } 67 }
89 68
@@ -20,7 +20,9 @@ import lombok.Data; @@ -20,7 +20,9 @@ import lombok.Data;
20 @Data 20 @Data
21 public class ServerSecurityConfig { 21 public class ServerSecurityConfig {
22 String host; 22 String host;
  23 + String securityHost;
23 Integer port; 24 Integer port;
  25 + Integer securityPort;
24 String serverPublicKey; 26 String serverPublicKey;
25 boolean bootstrapServerIs = true; 27 boolean bootstrapServerIs = true;
26 Integer clientHoldOffTime = 1; 28 Integer clientHoldOffTime = 1;
@@ -18,20 +18,22 @@ import { Injectable } from '@angular/core'; @@ -18,20 +18,22 @@ import { Injectable } from '@angular/core';
18 import { HttpClient } from '@angular/common/http'; 18 import { HttpClient } from '@angular/common/http';
19 import { PageLink } from '@shared/models/page/page-link'; 19 import { PageLink } from '@shared/models/page/page-link';
20 import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; 20 import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
21 -import { Observable, throwError } from 'rxjs'; 21 +import { Observable, of, throwError } from 'rxjs';
22 import { PageData } from '@shared/models/page/page-data'; 22 import { PageData } from '@shared/models/page/page-data';
23 import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; 23 import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models';
24 import { isDefinedAndNotNull, isEmptyStr } from '@core/utils'; 24 import { isDefinedAndNotNull, isEmptyStr } from '@core/utils';
25 import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; 25 import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
26 import { SortOrder } from '@shared/models/page/sort-order'; 26 import { SortOrder } from '@shared/models/page/sort-order';
27 import { OtaPackageService } from '@core/http/ota-package.service'; 27 import { OtaPackageService } from '@core/http/ota-package.service';
28 -import { mergeMap } from 'rxjs/operators'; 28 +import { mergeMap, tap } from 'rxjs/operators';
29 29
30 @Injectable({ 30 @Injectable({
31 providedIn: 'root' 31 providedIn: 'root'
32 }) 32 })
33 export class DeviceProfileService { 33 export class DeviceProfileService {
34 34
  35 + private lwm2mBootstrapSecurityInfoInMemoryCache = new Map<boolean, ServerSecurityConfig>();
  36 +
35 constructor( 37 constructor(
36 private http: HttpClient, 38 private http: HttpClient,
37 private otaPackageService: OtaPackageService 39 private otaPackageService: OtaPackageService
@@ -58,12 +60,18 @@ export class DeviceProfileService { @@ -58,12 +60,18 @@ export class DeviceProfileService {
58 return this.http.get<Array<ObjectLwM2M>>(url, defaultHttpOptionsFromConfig(config)); 60 return this.http.get<Array<ObjectLwM2M>>(url, defaultHttpOptionsFromConfig(config));
59 } 61 }
60 62
61 - public getLwm2mBootstrapSecurityInfo(securityMode: string, bootstrapServerIs: boolean,  
62 - config?: RequestConfig): Observable<ServerSecurityConfig> {  
63 - return this.http.get<ServerSecurityConfig>(  
64 - `/api/lwm2m/deviceProfile/bootstrap/${securityMode}/${bootstrapServerIs}`,  
65 - defaultHttpOptionsFromConfig(config)  
66 - ); 63 + public getLwm2mBootstrapSecurityInfo(isBootstrapServer: boolean, config?: RequestConfig): Observable<ServerSecurityConfig> {
  64 + const securityConfig = this.lwm2mBootstrapSecurityInfoInMemoryCache.get(isBootstrapServer);
  65 + if (securityConfig) {
  66 + return of(securityConfig);
  67 + } else {
  68 + return this.http.get<ServerSecurityConfig>(
  69 + `/api/lwm2m/deviceProfile/bootstrap/${isBootstrapServer}`,
  70 + defaultHttpOptionsFromConfig(config)
  71 + ).pipe(
  72 + tap(serverConfig => this.lwm2mBootstrapSecurityInfoInMemoryCache.set(isBootstrapServer, serverConfig))
  73 + );
  74 + }
67 } 75 }
68 76
69 public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable<Array<ObjectLwM2M>> { 77 public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable<Array<ObjectLwM2M>> {
@@ -28,60 +28,45 @@ @@ -28,60 +28,45 @@
28 </mat-form-field> 28 </mat-form-field>
29 <mat-form-field fxFlex> 29 <mat-form-field fxFlex>
30 <mat-label>{{ 'device-profile.lwm2m.server-host' | translate }}</mat-label> 30 <mat-label>{{ 'device-profile.lwm2m.server-host' | translate }}</mat-label>
31 - <input matInput type="text" formControlName="host" required  
32 - matTooltip="{{'device-profile.lwm2m.server-host-tip' | translate}}"  
33 - matTooltipPosition="above"> 31 + <input matInput type="text" formControlName="host" required>
34 <mat-error *ngIf="serverFormGroup.get('host').hasError('required')"> 32 <mat-error *ngIf="serverFormGroup.get('host').hasError('required')">
35 - {{ 'device-profile.lwm2m.server-host' | translate }}  
36 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> 33 + {{ 'device-profile.lwm2m.server-host-required' | translate }}
37 </mat-error> 34 </mat-error>
38 </mat-form-field> 35 </mat-form-field>
39 <mat-form-field fxFlex> 36 <mat-form-field fxFlex>
40 <mat-label>{{ 'device-profile.lwm2m.server-port' | translate }}</mat-label> 37 <mat-label>{{ 'device-profile.lwm2m.server-port' | translate }}</mat-label>
41 - <input matInput type="number" formControlName="port" required  
42 - matTooltip="{{'device-profile.lwm2m.server-port-tip' | translate}}"  
43 - matTooltipPosition="above"> 38 + <input matInput type="number" formControlName="port" required min="0">
44 <mat-error *ngIf="serverFormGroup.get('port').hasError('required')"> 39 <mat-error *ngIf="serverFormGroup.get('port').hasError('required')">
45 - {{ 'device-profile.lwm2m.server-port' | translate }}  
46 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> 40 + {{ 'device-profile.lwm2m.server-port-required' | translate }}
47 </mat-error> 41 </mat-error>
48 </mat-form-field> 42 </mat-form-field>
  43 + </div>
  44 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
49 <mat-form-field fxFlex> 45 <mat-form-field fxFlex>
50 <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label> 46 <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
51 - <input matInput type="number" formControlName="serverId" required  
52 - matTooltip="{{'device-profile.lwm2m.short-id-tip' | translate}}"  
53 - matTooltipPosition="above"> 47 + <input matInput type="number" formControlName="serverId" required min="0">
54 <mat-error *ngIf="serverFormGroup.get('serverId').hasError('required')"> 48 <mat-error *ngIf="serverFormGroup.get('serverId').hasError('required')">
55 - {{ 'device-profile.lwm2m.short-id' | translate }}  
56 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> 49 + {{ 'device-profile.lwm2m.short-id-required' | translate }}
57 </mat-error> 50 </mat-error>
58 </mat-form-field> 51 </mat-form-field>
59 - </div>  
60 - <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">  
61 <mat-form-field fxFlex> 52 <mat-form-field fxFlex>
62 <mat-label>{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}</mat-label> 53 <mat-label>{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}</mat-label>
63 - <input matInput type="number" formControlName="clientHoldOffTime" required  
64 - matTooltip="{{'device-profile.lwm2m.client-hold-off-time-tip' | translate}}" 54 + <input matInput type="number" formControlName="clientHoldOffTime" required min="0"
  55 + matTooltip="{{'device-profile.lwm2m.client-hold-off-time-tooltip' | translate}}"
65 matTooltipPosition="above"> 56 matTooltipPosition="above">
66 <mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('required')"> 57 <mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('required')">
67 - {{ 'device-profile.lwm2m.client-hold-off-time' | translate }}  
68 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> 58 + {{ 'device-profile.lwm2m.client-hold-off-time-required' | translate }}
69 </mat-error> 59 </mat-error>
70 </mat-form-field> 60 </mat-form-field>
71 <mat-form-field fxFlex> 61 <mat-form-field fxFlex>
72 - <mat-label>{{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }}</mat-label>  
73 - <input matInput type="number" formControlName="bootstrapServerAccountTimeout" required  
74 - matTooltip="{{'device-profile.lwm2m.bootstrap-server-account-timeout-tip' | translate}}" 62 + <mat-label>{{ 'device-profile.lwm2m.account-after-timeout' | translate }}</mat-label>
  63 + <input matInput type="number" formControlName="bootstrapServerAccountTimeout" required min="0"
  64 + matTooltip="{{'device-profile.lwm2m.account-after-timeout-tooltip' | translate}}"
75 matTooltipPosition="above"> 65 matTooltipPosition="above">
76 <mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('required')"> 66 <mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('required')">
77 - {{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }}  
78 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> 67 + {{ 'device-profile.lwm2m.account-after-timeout-required' | translate }}
79 </mat-error> 68 </mat-error>
80 </mat-form-field> 69 </mat-form-field>
81 - <mat-checkbox fxFlex formControlName="bootstrapServerIs" color="primary">  
82 - {{ 'device-profile.lwm2m.bootstrap-server' | translate }}  
83 - </mat-checkbox>  
84 - <div fxFlex></div>  
85 </div> 70 </div>
86 <div *ngIf="serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK || 71 <div *ngIf="serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
87 serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509"> 72 serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509">
@@ -89,32 +74,22 @@ @@ -89,32 +74,22 @@
89 <mat-label>{{ 'device-profile.lwm2m.server-public-key' | translate }}</mat-label> 74 <mat-label>{{ 'device-profile.lwm2m.server-public-key' | translate }}</mat-label>
90 <textarea matInput 75 <textarea matInput
91 #serverPublicKey 76 #serverPublicKey
92 - maxlength="{{lenMaxServerPublicKey}}" 77 + maxlength="{{maxLengthPublicKey}}"
93 cdkTextareaAutosize 78 cdkTextareaAutosize
94 cdkAutosizeMinRows="1" 79 cdkAutosizeMinRows="1"
95 cols="1" required 80 cols="1" required
96 - style="overflow:hidden"  
97 formControlName="serverPublicKey" 81 formControlName="serverPublicKey"
98 - matTooltip="{{'device-profile.lwm2m.server-public-key-tip' | translate}}"  
99 ></textarea> 82 ></textarea>
100 - <mat-hint align="end">{{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}}</mat-hint> 83 + <mat-hint align="end">{{serverPublicKey.value?.length || 0}}/{{maxLengthPublicKey}}</mat-hint>
101 <mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('required')"> 84 <mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('required')">
102 - {{ 'device-profile.lwm2m.server-public-key' | translate }}  
103 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> 85 + {{ 'device-profile.lwm2m.server-public-key-required' | translate }}
104 </mat-error> 86 </mat-error>
105 - <mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern') &&  
106 - (serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||  
107 - serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509)">  
108 - {{ 'device-profile.lwm2m.server-public-key' | translate }}  
109 - <strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate: {  
110 - count: 0} }}</strong> 87 + <mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern')">
  88 + {{ 'device-profile.lwm2m.server-public-key-pattern' | translate }}
111 </mat-error> 89 </mat-error>
112 - <mat-error *ngIf="(serverFormGroup.get('serverPublicKey').hasError('maxlength') ||  
113 - serverFormGroup.get('serverPublicKey').hasError('minlength')) &&  
114 - serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK">  
115 - {{ 'device-profile.lwm2m.server-public-key' | translate }}  
116 - <strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate: {  
117 - count: lenMaxServerPublicKey } }}</strong> 90 + <mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('maxlength') ||
  91 + serverFormGroup.get('serverPublicKey').hasError('minlength')">
  92 + {{ 'device-profile.lwm2m.server-public-key-length' | translate: {count: maxLengthPublicKey } }}
118 </mat-error> 93 </mat-error>
119 </mat-form-field> 94 </mat-form-field>
120 </div> 95 </div>
@@ -14,26 +14,24 @@ @@ -14,26 +14,24 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import { Component, forwardRef, Inject, Input } from '@angular/core'; 17 +import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
18 import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; 18 import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
19 import { 19 import {
20 - DEFAULT_CLIENT_HOLD_OFF_TIME,  
21 - DEFAULT_ID_SERVER,  
22 DEFAULT_PORT_BOOTSTRAP_NO_SEC, 20 DEFAULT_PORT_BOOTSTRAP_NO_SEC,
23 DEFAULT_PORT_SERVER_NO_SEC, 21 DEFAULT_PORT_SERVER_NO_SEC,
24 KEY_REGEXP_HEX_DEC, 22 KEY_REGEXP_HEX_DEC,
25 LEN_MAX_PUBLIC_KEY_RPK, 23 LEN_MAX_PUBLIC_KEY_RPK,
26 LEN_MAX_PUBLIC_KEY_X509, 24 LEN_MAX_PUBLIC_KEY_X509,
27 - SECURITY_CONFIG_MODE,  
28 - SECURITY_CONFIG_MODE_NAMES, 25 + securityConfigMode,
  26 + securityConfigModeNames,
29 ServerSecurityConfig 27 ServerSecurityConfig
30 } from './lwm2m-profile-config.models'; 28 } from './lwm2m-profile-config.models';
31 -import { coerceBooleanProperty } from '@angular/cdk/coercion';  
32 -import { WINDOW } from '@core/services/window.service';  
33 -import { pairwise, startWith } from 'rxjs/operators';  
34 import { DeviceProfileService } from '@core/http/device-profile.service'; 29 import { DeviceProfileService } from '@core/http/device-profile.service';
  30 +import { of, Subject } from 'rxjs';
  31 +import { map, mergeMap, takeUntil, tap } from 'rxjs/operators';
  32 +import { Observable } from 'rxjs/internal/Observable';
  33 +import { deepClone } from '@core/utils';
35 34
36 -// @dynamic  
37 @Component({ 35 @Component({
38 selector: 'tb-profile-lwm2m-device-config-server', 36 selector: 'tb-profile-lwm2m-device-config-server',
39 templateUrl: './lwm2m-device-config-server.component.html', 37 templateUrl: './lwm2m-device-config-server.component.html',
@@ -46,127 +44,78 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; @@ -46,127 +44,78 @@ import { DeviceProfileService } from '@core/http/device-profile.service';
46 ] 44 ]
47 }) 45 })
48 46
49 -export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor { 47 +export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, OnDestroy {
50 48
51 - private requiredValue: boolean;  
52 private disabled = false; 49 private disabled = false;
  50 + private destroy$ = new Subject();
  51 +
  52 + private securityDefaultConfig: ServerSecurityConfig;
53 53
54 - valuePrev = null;  
55 serverFormGroup: FormGroup; 54 serverFormGroup: FormGroup;
56 - securityConfigLwM2MType = SECURITY_CONFIG_MODE;  
57 - securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE);  
58 - credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES;  
59 - lenMinServerPublicKey = 0;  
60 - lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK; 55 + securityConfigLwM2MType = securityConfigMode;
  56 + securityConfigLwM2MTypes = Object.keys(securityConfigMode);
  57 + credentialTypeLwM2MNamesMap = securityConfigModeNames;
  58 + maxLengthPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
61 currentSecurityMode = null; 59 currentSecurityMode = null;
62 60
63 @Input() 61 @Input()
64 - bootstrapServerIs: boolean; 62 + isBootstrapServer = false;
65 63
66 - get required(): boolean {  
67 - return this.requiredValue;  
68 - } 64 + private propagateChange = (v: any) => { };
69 65
70 - @Input()  
71 - set required(value: boolean) {  
72 - this.requiredValue = coerceBooleanProperty(value); 66 + constructor(public fb: FormBuilder,
  67 + private deviceProfileService: DeviceProfileService) {
73 } 68 }
74 69
75 - constructor(public fb: FormBuilder,  
76 - private deviceProfileService: DeviceProfileService,  
77 - @Inject(WINDOW) private window: Window) {  
78 - this.serverFormGroup = this.initServerGroup(); 70 + ngOnInit(): void {
  71 + this.serverFormGroup = this.fb.group({
  72 + host: ['', Validators.required],
  73 + port: [this.isBootstrapServer ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC, [Validators.required, Validators.min(0)]],
  74 + securityMode: [securityConfigMode.NO_SEC],
  75 + serverPublicKey: ['', Validators.required],
  76 + clientHoldOffTime: ['', [Validators.required, Validators.min(0)]],
  77 + serverId: ['', [Validators.required, Validators.min(0)]],
  78 + bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0)]],
  79 + });
79 this.serverFormGroup.get('securityMode').valueChanges.pipe( 80 this.serverFormGroup.get('securityMode').valueChanges.pipe(
80 - startWith(null),  
81 - pairwise()  
82 - ).subscribe(([previousValue, currentValue]) => {  
83 - if (previousValue === null || previousValue !== currentValue) {  
84 - this.getLwm2mBootstrapSecurityInfo(currentValue);  
85 - this.updateValidate(currentValue);  
86 - this.serverFormGroup.updateValueAndValidity();  
87 - }  
88 - 81 + tap(securityMode => this.updateValidate(securityMode)),
  82 + mergeMap(securityMode => this.getLwm2mBootstrapSecurityInfo(securityMode)),
  83 + takeUntil(this.destroy$)
  84 + ).subscribe(serverSecurityConfig => {
  85 + this.serverFormGroup.patchValue(serverSecurityConfig, {emitEvent: false});
89 }); 86 });
90 - this.serverFormGroup.valueChanges.subscribe(value => {  
91 - if (this.disabled !== undefined && !this.disabled) {  
92 - this.propagateChangeState(value);  
93 - } 87 + this.serverFormGroup.valueChanges.pipe(
  88 + takeUntil(this.destroy$)
  89 + ).subscribe(value => {
  90 + this.propagateChangeState(value);
94 }); 91 });
95 } 92 }
96 93
97 - private updateValueFields = (serverData: ServerSecurityConfig): void => {  
98 - serverData.bootstrapServerIs = this.bootstrapServerIs;  
99 - this.serverFormGroup.patchValue(serverData, {emitEvent: false});  
100 - this.serverFormGroup.get('bootstrapServerIs').disable();  
101 - const securityMode = this.serverFormGroup.get('securityMode').value as SECURITY_CONFIG_MODE;  
102 - this.updateValidate(securityMode); 94 + ngOnDestroy(): void {
  95 + this.destroy$.next();
  96 + this.destroy$.complete();
103 } 97 }
104 98
105 - private updateValidate = (securityMode: SECURITY_CONFIG_MODE): void => {  
106 - switch (securityMode) {  
107 - case SECURITY_CONFIG_MODE.NO_SEC:  
108 - this.setValidatorsNoSecPsk();  
109 - break;  
110 - case SECURITY_CONFIG_MODE.PSK:  
111 - this.setValidatorsNoSecPsk();  
112 - break;  
113 - case SECURITY_CONFIG_MODE.RPK:  
114 - this.lenMinServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK;  
115 - this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK;  
116 - this.setValidatorsRpkX509();  
117 - break;  
118 - case SECURITY_CONFIG_MODE.X509:  
119 - this.lenMinServerPublicKey = 0;  
120 - this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_X509;  
121 - this.setValidatorsRpkX509();  
122 - break; 99 + writeValue(serverData: ServerSecurityConfig): void {
  100 + if (serverData) {
  101 + this.serverFormGroup.patchValue(serverData, {emitEvent: false});
  102 + this.updateValidate(serverData.securityMode);
123 } 103 }
124 - this.serverFormGroup.updateValueAndValidity();  
125 - }  
126 -  
127 - private setValidatorsNoSecPsk = (): void => {  
128 - this.serverFormGroup.get('serverPublicKey').setValidators([]);  
129 - }  
130 -  
131 - private setValidatorsRpkX509 = (): void => {  
132 - this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required,  
133 - Validators.pattern(KEY_REGEXP_HEX_DEC),  
134 - Validators.minLength(this.lenMinServerPublicKey),  
135 - Validators.maxLength(this.lenMaxServerPublicKey)]);  
136 - }  
137 -  
138 - writeValue(value: ServerSecurityConfig): void {  
139 - if (value) {  
140 - this.updateValueFields(value); 104 + if (!this.securityDefaultConfig){
  105 + this.getLwm2mBootstrapSecurityInfo().subscribe(value => {
  106 + if (!serverData) {
  107 + this.serverFormGroup.patchValue(value);
  108 + }
  109 + });
141 } 110 }
142 } 111 }
143 112
144 - private propagateChange = (v: any) => {};  
145 -  
146 registerOnChange(fn: any): void { 113 registerOnChange(fn: any): void {
147 this.propagateChange = fn; 114 this.propagateChange = fn;
148 } 115 }
149 116
150 - private propagateChangeState = (value: any): void => {  
151 - if (value !== undefined) {  
152 - if (this.valuePrev === null) {  
153 - this.valuePrev = 'init';  
154 - } else if (this.valuePrev === 'init') {  
155 - this.valuePrev = value;  
156 - } else if (JSON.stringify(value) !== JSON.stringify(this.valuePrev)) {  
157 - this.valuePrev = value;  
158 - if (this.serverFormGroup.valid) {  
159 - this.propagateChange(value);  
160 - } else {  
161 - this.propagateChange(null);  
162 - }  
163 - }  
164 - }  
165 - }  
166 -  
167 setDisabledState(isDisabled: boolean): void { 117 setDisabledState(isDisabled: boolean): void {
168 this.disabled = isDisabled; 118 this.disabled = isDisabled;
169 - this.valuePrev = null;  
170 if (isDisabled) { 119 if (isDisabled) {
171 this.serverFormGroup.disable({emitEvent: false}); 120 this.serverFormGroup.disable({emitEvent: false});
172 } else { 121 } else {
@@ -177,33 +126,76 @@ export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor { @@ -177,33 +126,76 @@ export class Lwm2mDeviceConfigServerComponent implements ControlValueAccessor {
177 registerOnTouched(fn: any): void { 126 registerOnTouched(fn: any): void {
178 } 127 }
179 128
180 - private initServerGroup = (): FormGroup => {  
181 - const port = this.bootstrapServerIs ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC;  
182 - return this.fb.group({  
183 - host: [this.window.location.hostname, this.required ? Validators.required : ''],  
184 - port: [port, this.required ? Validators.required : ''],  
185 - bootstrapServerIs: [this.bootstrapServerIs, ''],  
186 - securityMode: [this.fb.control(SECURITY_CONFIG_MODE.NO_SEC)],  
187 - serverPublicKey: ['', this.required ? Validators.required : ''],  
188 - clientHoldOffTime: [DEFAULT_CLIENT_HOLD_OFF_TIME, this.required ? Validators.required : ''],  
189 - serverId: [DEFAULT_ID_SERVER, this.required ? Validators.required : ''],  
190 - bootstrapServerAccountTimeout: ['', this.required ? Validators.required : ''],  
191 - }); 129 + private updateValidate(securityMode: securityConfigMode): void {
  130 + switch (securityMode) {
  131 + case securityConfigMode.NO_SEC:
  132 + case securityConfigMode.PSK:
  133 + this.clearValidators();
  134 + break;
  135 + case securityConfigMode.RPK:
  136 + this.maxLengthPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
  137 + this.setValidators(LEN_MAX_PUBLIC_KEY_RPK);
  138 + break;
  139 + case securityConfigMode.X509:
  140 + this.maxLengthPublicKey = LEN_MAX_PUBLIC_KEY_X509;
  141 + this.setValidators(0);
  142 + break;
  143 + }
  144 + this.serverFormGroup.get('serverPublicKey').updateValueAndValidity({emitEvent: false});
  145 + }
  146 +
  147 + private clearValidators(): void {
  148 + this.serverFormGroup.get('serverPublicKey').clearValidators();
  149 + }
  150 +
  151 + private setValidators(minLengthKey: number): void {
  152 + this.serverFormGroup.get('serverPublicKey').setValidators([
  153 + Validators.required,
  154 + Validators.pattern(KEY_REGEXP_HEX_DEC),
  155 + Validators.minLength(minLengthKey),
  156 + Validators.maxLength(this.maxLengthPublicKey)
  157 + ]);
192 } 158 }
193 159
194 - private getLwm2mBootstrapSecurityInfo = (mode: string): void => {  
195 - this.deviceProfileService.getLwm2mBootstrapSecurityInfo(mode, this.serverFormGroup.get('bootstrapServerIs').value).subscribe(  
196 - (serverSecurityConfig) => {  
197 - this.serverFormGroup.patchValue({  
198 - host: serverSecurityConfig.host,  
199 - port: serverSecurityConfig.port,  
200 - serverPublicKey: serverSecurityConfig.serverPublicKey,  
201 - clientHoldOffTime: serverSecurityConfig.clientHoldOffTime,  
202 - serverId: serverSecurityConfig.serverId,  
203 - bootstrapServerAccountTimeout: serverSecurityConfig.bootstrapServerAccountTimeout  
204 - },  
205 - {emitEvent: true}); 160 + private propagateChangeState = (value: ServerSecurityConfig): void => {
  161 + if (value !== undefined) {
  162 + if (this.serverFormGroup.valid) {
  163 + this.propagateChange(value);
  164 + } else {
  165 + this.propagateChange(null);
206 } 166 }
  167 + }
  168 + }
  169 +
  170 + private getLwm2mBootstrapSecurityInfo(securityMode = securityConfigMode.NO_SEC): Observable<ServerSecurityConfig> {
  171 + if (this.securityDefaultConfig) {
  172 + return of(this.processingBootstrapSecurityInfo(this.securityDefaultConfig, securityMode));
  173 + }
  174 + return this.deviceProfileService.getLwm2mBootstrapSecurityInfo(this.isBootstrapServer).pipe(
  175 + map(securityInfo => {
  176 + this.securityDefaultConfig = securityInfo;
  177 + return this.processingBootstrapSecurityInfo(securityInfo, securityMode);
  178 + })
207 ); 179 );
208 } 180 }
  181 +
  182 + private processingBootstrapSecurityInfo(securityConfig: ServerSecurityConfig, securityMode: securityConfigMode): ServerSecurityConfig {
  183 + const config = deepClone(securityConfig);
  184 + switch (securityMode) {
  185 + case securityConfigMode.PSK:
  186 + config.port = config.securityPort;
  187 + config.host = config.securityHost;
  188 + config.serverPublicKey = '';
  189 + break;
  190 + case securityConfigMode.RPK:
  191 + case securityConfigMode.X509:
  192 + config.port = config.securityPort;
  193 + config.host = config.securityHost;
  194 + break;
  195 + case securityConfigMode.NO_SEC:
  196 + config.serverPublicKey = '';
  197 + break;
  198 + }
  199 + return config;
  200 + }
209 } 201 }
@@ -15,231 +15,172 @@ @@ -15,231 +15,172 @@
15 limitations under the License. 15 limitations under the License.
16 16
17 --> 17 -->
18 -<section style="padding-bottom: 16px; margin: 0" mat-dialog-content> 18 +<section style="padding-bottom: 16px; margin: 0">
19 <mat-tab-group dynamicHeight> 19 <mat-tab-group dynamicHeight>
20 <mat-tab label="{{ 'device-profile.lwm2m.model-tab' | translate }}"> 20 <mat-tab label="{{ 'device-profile.lwm2m.model-tab' | translate }}">
21 <ng-template matTabContent> 21 <ng-template matTabContent>
22 <section [formGroup]="lwm2mDeviceProfileFormGroup"> 22 <section [formGroup]="lwm2mDeviceProfileFormGroup">
23 - <div class="mat-padding" style="padding-top: 0">  
24 - <tb-profile-lwm2m-object-list  
25 - (addList)="addObjectsList($event)"  
26 - (removeList)="removeObjectsList($event)"  
27 - [required]="required"  
28 - formControlName="objectIds">  
29 - </tb-profile-lwm2m-object-list>  
30 - </div>  
31 - <div class="mat-padding">  
32 - <tb-profile-lwm2m-observe-attr-telemetry  
33 - [required]="required"  
34 - formControlName="observeAttrTelemetry">  
35 - </tb-profile-lwm2m-observe-attr-telemetry>  
36 - </div>  
37 - </section>  
38 - </ng-template>  
39 - </mat-tab>  
40 - <mat-tab label="{{ 'device-profile.lwm2m.bootstrap-tab' | translate }}">  
41 - <ng-template matTabContent>  
42 - <section [formGroup]="lwm2mDeviceProfileFormGroup">  
43 - <div class="mat-padding">  
44 - <mat-accordion multi="true" class="mat-body-1">  
45 - <mat-expansion-panel>  
46 - <mat-expansion-panel-header>  
47 - <mat-panel-title>  
48 - <div class="tb-panel-title">{{ 'device-profile.lwm2m.servers' | translate | uppercase }}</div>  
49 - </mat-panel-title>  
50 - </mat-expansion-panel-header>  
51 - <ng-template matExpansionPanelContent>  
52 - <div fxLayout="column">  
53 - <div fxLayout="row" fxLayoutGap="8px">  
54 - <mat-form-field fxFlex>  
55 - <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>  
56 - <input matInput type="number" formControlName="shortId" required>  
57 - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('shortId').hasError('required')">  
58 - {{ 'device-profile.lwm2m.short-id' | translate }}  
59 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>  
60 - </mat-error>  
61 - </mat-form-field>  
62 - <mat-form-field fxFlex>  
63 - <mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label>  
64 - <input matInput type="number" formControlName="lifetime" required>  
65 - <mat-error  
66 - *ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')">  
67 - {{ 'device-profile.lwm2m.lifetime' | translate }}  
68 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>  
69 - </mat-error>  
70 - </mat-form-field>  
71 - <mat-form-field fxFlex>  
72 - <mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>  
73 - <input matInput type="number" formControlName="defaultMinPeriod" required>  
74 - <mat-error  
75 - *ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')">  
76 - {{ 'device-profile.lwm2m.default-min-period' | translate }}  
77 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>  
78 - </mat-error>  
79 - </mat-form-field>  
80 - </div>  
81 - <div fxLayout="row" fxLayoutGap="8px">  
82 - <mat-form-field class="mat-block" fxFlex="100">  
83 - <mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>  
84 - <mat-select formControlName="binding">  
85 - <mat-option *ngFor="let bindingMode of bindingModeTypes"  
86 - [value]="bindingMode">  
87 - {{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}  
88 - </mat-option>  
89 - </mat-select>  
90 - </mat-form-field>  
91 - </div>  
92 - <div>  
93 - <mat-checkbox formControlName="notifIfDisabled" color="primary">  
94 - {{ 'device-profile.lwm2m.notif-if-disabled' | translate }}  
95 - </mat-checkbox>  
96 - </div>  
97 - </div>  
98 - </ng-template>  
99 - </mat-expansion-panel>  
100 - </mat-accordion>  
101 - <mat-accordion multi="true" class="mat-body-1">  
102 - <mat-expansion-panel>  
103 - <mat-expansion-panel-header>  
104 - <mat-panel-title>  
105 - <div  
106 - class="tb-panel-title">{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}</div>  
107 - </mat-panel-title>  
108 - </mat-expansion-panel-header>  
109 - <ng-template matExpansionPanelContent>  
110 - <div class="mat-padding">  
111 - <tb-profile-lwm2m-device-config-server  
112 - [required]="required"  
113 - formControlName="bootstrapServer"  
114 - [bootstrapServerIs]=true>  
115 - </tb-profile-lwm2m-device-config-server>  
116 - </div>  
117 - </ng-template>  
118 - </mat-expansion-panel>  
119 - </mat-accordion>  
120 - <mat-accordion multi="true" class="mat-body-1">  
121 - <mat-expansion-panel>  
122 - <mat-expansion-panel-header>  
123 - <mat-panel-title>  
124 - <div class="tb-panel-title">{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}</div>  
125 - </mat-panel-title>  
126 - </mat-expansion-panel-header>  
127 - <ng-template matExpansionPanelContent>  
128 - <div class="mat-padding">  
129 - <tb-profile-lwm2m-device-config-server  
130 - [required]="required"  
131 - formControlName="lwm2mServer"  
132 - [bootstrapServerIs]=false>  
133 - </tb-profile-lwm2m-device-config-server>  
134 - </div>  
135 - </ng-template>  
136 - </mat-expansion-panel>  
137 - </mat-accordion>  
138 - </div> 23 + <tb-profile-lwm2m-object-list
  24 + (addList)="addObjectsList($event)"
  25 + (removeList)="removeObjectsList($event)"
  26 + [required]="required"
  27 + formControlName="objectIds">
  28 + </tb-profile-lwm2m-object-list>
  29 + <tb-profile-lwm2m-observe-attr-telemetry
  30 + [required]="required"
  31 + formControlName="observeAttrTelemetry">
  32 + </tb-profile-lwm2m-observe-attr-telemetry>
139 </section> 33 </section>
140 </ng-template> 34 </ng-template>
141 </mat-tab> 35 </mat-tab>
142 - <mat-tab label="{{ 'device-profile.lwm2m.others-tab' | translate }}"> 36 + <mat-tab label="{{ 'device-profile.lwm2m.servers' | translate }}">
143 <ng-template matTabContent> 37 <ng-template matTabContent>
144 - <section [formGroup]="lwm2mDeviceProfileFormGroup">  
145 - <mat-accordion multi="true" class="mat-body-1">  
146 - <div *ngIf="false">  
147 - <mat-expansion-panel>  
148 - <mat-expansion-panel-header>  
149 - <mat-panel-title>  
150 - <div  
151 - class="tb-panel-title">{{ 'device-profile.lwm2m.client-strategy' | translate | uppercase }}</div>  
152 - </mat-panel-title>  
153 - </mat-expansion-panel-header>  
154 - <ng-template matExpansionPanelContent>  
155 - <div fxLayout="column">  
156 - <mat-form-field class="mat-block">  
157 - <mat-label>{{ 'device-profile.lwm2m.client-strategy-label' | translate }}</mat-label>  
158 - <mat-select formControlName="clientStrategy"  
159 - matTooltip="{{ 'device-profile.lwm2m.client-strategy-tip' | translate:  
160 - { count: +lwm2mDeviceProfileFormGroup.get('clientStrategy').value } }}"  
161 - matTooltipPosition="above">  
162 - <mat-option value=1>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:  
163 - {count: 1} }}</mat-option>  
164 - <mat-option value=2>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:  
165 - {count: 2} }}</mat-option>  
166 - </mat-select>  
167 - </mat-form-field>  
168 - </div>  
169 - </ng-template>  
170 - </mat-expansion-panel>  
171 - </div> 38 + <section [formGroup]="lwm2mDeviceProfileFormGroup" style="padding: 4px 2px">
  39 + <mat-accordion multi="true">
172 <mat-expansion-panel> 40 <mat-expansion-panel>
173 <mat-expansion-panel-header> 41 <mat-expansion-panel-header>
174 - <mat-panel-title>  
175 - <div  
176 - class="tb-panel-title">{{ 'device-profile.lwm2m.ota-update-strategy' | translate | uppercase }}</div>  
177 - </mat-panel-title> 42 + <mat-panel-title>{{ 'device-profile.lwm2m.servers' | translate }}</mat-panel-title>
178 </mat-expansion-panel-header> 43 </mat-expansion-panel-header>
179 <ng-template matExpansionPanelContent> 44 <ng-template matExpansionPanelContent>
180 - <div fxLayout="column">  
181 - <mat-form-field class="mat-block" fxFlex>  
182 - <mat-label>{{ 'device-profile.lwm2m.fw-update-strategy-label' | translate }}</mat-label>  
183 - <mat-select formControlName="fwUpdateStrategy" (selectionChange)="changeFwUpdateStrategy($event)">  
184 - <mat-option value=1>{{ 'device-profile.lwm2m.fw-update-strategy' | translate:  
185 - {count: 1} }}</mat-option>  
186 - <mat-option value=2>{{ 'device-profile.lwm2m.fw-update-strategy' | translate:  
187 - {count: 2} }}</mat-option>  
188 - <mat-option value=3>{{ 'device-profile.lwm2m.fw-update-strategy' | translate:  
189 - {count: 3} }}</mat-option>  
190 - </mat-select> 45 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
  46 + <mat-form-field fxFlex>
  47 + <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
  48 + <input matInput type="number" formControlName="shortId" required>
  49 + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('shortId').hasError('required')">
  50 + {{ 'device-profile.lwm2m.short-id' | translate }}
  51 + <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
  52 + </mat-error>
191 </mat-form-field> 53 </mat-form-field>
192 - <mat-form-field class="mat-block" fxFlex>  
193 - <mat-label>{{ 'device-profile.lwm2m.sw-update-strategy-label' | translate }}</mat-label>  
194 - <mat-select formControlName="swUpdateStrategy" (selectionChange)="changeSwUpdateStrategy($event)">  
195 - <mat-option value=1>{{ 'device-profile.lwm2m.sw-update-strategy' | translate:  
196 - {count: 1} }}</mat-option>  
197 - <mat-option value=2>{{ 'device-profile.lwm2m.sw-update-strategy' | translate:  
198 - {count: 2} }}</mat-option>  
199 - </mat-select> 54 + <mat-form-field fxFlex>
  55 + <mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label>
  56 + <input matInput type="number" formControlName="lifetime" required>
  57 + <mat-error
  58 + *ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')">
  59 + {{ 'device-profile.lwm2m.lifetime' | translate }}
  60 + <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
  61 + </mat-error>
  62 + </mat-form-field>
  63 + <mat-form-field fxFlex>
  64 + <mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
  65 + <input matInput type="number" formControlName="defaultMinPeriod" required>
  66 + <mat-error
  67 + *ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')">
  68 + {{ 'device-profile.lwm2m.default-min-period' | translate }}
  69 + <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
  70 + </mat-error>
200 </mat-form-field> 71 </mat-form-field>
201 </div> 72 </div>
  73 + <mat-form-field class="mat-block">
  74 + <mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
  75 + <mat-select formControlName="binding">
  76 + <mat-option *ngFor="let bindingMode of bindingModeTypes"
  77 + [value]="bindingMode">
  78 + {{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}
  79 + </mat-option>
  80 + </mat-select>
  81 + </mat-form-field>
  82 + <mat-checkbox formControlName="notifIfDisabled" color="primary">
  83 + {{ 'device-profile.lwm2m.notif-if-disabled' | translate }}
  84 + </mat-checkbox>
202 </ng-template> 85 </ng-template>
203 </mat-expansion-panel> 86 </mat-expansion-panel>
204 - <mat-expansion-panel *ngIf="isFwUpdateStrategy || isSwUpdateStrategy"> 87 + <mat-expansion-panel>
205 <mat-expansion-panel-header> 88 <mat-expansion-panel-header>
206 - <mat-panel-title>  
207 - <div  
208 - class="tb-panel-title">{{ 'device-profile.lwm2m.ota-update-recourse' | translate | uppercase }}</div>  
209 - </mat-panel-title> 89 + <mat-panel-title>{{ 'device-profile.lwm2m.bootstrap-server' | translate }}</mat-panel-title>
210 </mat-expansion-panel-header> 90 </mat-expansion-panel-header>
211 <ng-template matExpansionPanelContent> 91 <ng-template matExpansionPanelContent>
212 - <div fxLayout="column">  
213 - <div *ngIf="isFwUpdateStrategy">  
214 - <mat-form-field class="mat-block" fxFlex>  
215 - <mat-label>{{ 'device-profile.lwm2m.fw-update-recourse' | translate }}</mat-label>  
216 - <input matInput formControlName="fwUpdateRecourse" required>  
217 - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').hasError('required')">  
218 - {{ 'device-profile.lwm2m.fw-update-recourse' | translate }}  
219 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>  
220 - </mat-error>  
221 - </mat-form-field>  
222 - </div>  
223 - <div *ngIf="isSwUpdateStrategy">  
224 - <mat-form-field class="mat-block" fxFlex>  
225 - <mat-label>{{ 'device-profile.lwm2m.sw-update-recourse' | translate }}</mat-label>  
226 - <input matInput formControlName="swUpdateRecourse" required>  
227 - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').hasError('required')">  
228 - {{ 'device-profile.lwm2m.sw-update-recourse' | translate }}  
229 - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>  
230 - </mat-error>  
231 - </mat-form-field>  
232 - </div>  
233 - </div> 92 + <tb-profile-lwm2m-device-config-server
  93 + [required]="required"
  94 + formControlName="bootstrapServer"
  95 + [isBootstrapServer]="true">
  96 + </tb-profile-lwm2m-device-config-server>
  97 + </ng-template>
  98 + </mat-expansion-panel>
  99 + <mat-expansion-panel>
  100 + <mat-expansion-panel-header>
  101 + <mat-panel-title>{{ 'device-profile.lwm2m.lwm2m-server' | translate }}</mat-panel-title>
  102 + </mat-expansion-panel-header>
  103 + <ng-template matExpansionPanelContent>
  104 + <tb-profile-lwm2m-device-config-server
  105 + [required]="required"
  106 + formControlName="lwm2mServer"
  107 + [isBootstrapServer]="false">
  108 + </tb-profile-lwm2m-device-config-server>
234 </ng-template> 109 </ng-template>
235 </mat-expansion-panel> 110 </mat-expansion-panel>
236 </mat-accordion> 111 </mat-accordion>
237 </section> 112 </section>
238 </ng-template> 113 </ng-template>
239 </mat-tab> 114 </mat-tab>
  115 + <mat-tab label="{{ 'device-profile.lwm2m.others-tab' | translate }}">
  116 + <ng-template matTabContent>
  117 + <section [formGroup]="lwm2mDeviceProfileFormGroup">
  118 + <fieldset class="fields-group">
  119 + <legend class="group-title" translate>device-profile.lwm2m.fw-update</legend>
  120 + <mat-form-field class="mat-block" fxFlex>
  121 + <mat-label>{{ 'device-profile.lwm2m.fw-update-strategy' | translate }}</mat-label>
  122 + <mat-select formControlName="fwUpdateStrategy">
  123 + <mat-option [value]=1>{{ 'device-profile.lwm2m.fw-update-strategy-package' | translate }}</mat-option>
  124 + <mat-option [value]=2>{{ 'device-profile.lwm2m.fw-update-strategy-package-uri' | translate }}</mat-option>
  125 + <mat-option [value]=3>{{ 'device-profile.lwm2m.fw-update-strategy-data' | translate }}</mat-option>
  126 + </mat-select>
  127 + </mat-form-field>
  128 + <mat-form-field class="mat-block" fxFlex *ngIf="isFwUpdateStrategy">
  129 + <mat-label>{{ 'device-profile.lwm2m.fw-update-recourse' | translate }}</mat-label>
  130 + <input matInput formControlName="fwUpdateRecourse" required>
  131 + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').hasError('required')">
  132 + {{ 'device-profile.lwm2m.fw-update-recourse-required' | translate }}
  133 + </mat-error>
  134 + </mat-form-field>
  135 + </fieldset>
  136 + <fieldset class="fields-group">
  137 + <legend class="group-title" translate>device-profile.lwm2m.sw-update</legend>
  138 + <mat-form-field class="mat-block" fxFlex>
  139 + <mat-label>{{ 'device-profile.lwm2m.sw-update-strategy' | translate }}</mat-label>
  140 + <mat-select formControlName="swUpdateStrategy">
  141 + <mat-option [value]=1>{{ 'device-profile.lwm2m.sw-update-strategy-package' | translate }}</mat-option>
  142 + <mat-option [value]=2>{{ 'device-profile.lwm2m.sw-update-strategy-package-uri' | translate }}</mat-option>
  143 + </mat-select>
  144 + </mat-form-field>
  145 + <mat-form-field class="mat-block" fxFlex *ngIf="isSwUpdateStrategy">
  146 + <mat-label>{{ 'device-profile.lwm2m.sw-update-recourse' | translate }}</mat-label>
  147 + <input matInput formControlName="swUpdateRecourse" required>
  148 + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').hasError('required')">
  149 + {{ 'device-profile.lwm2m.sw-update-recourse-required' | translate }}
  150 + </mat-error>
  151 + </mat-form-field>
  152 + </fieldset>
  153 +<!-- <mat-accordion multi="true">-->
  154 +<!-- <div *ngIf="false">-->
  155 +<!-- <mat-expansion-panel>-->
  156 +<!-- <mat-expansion-panel-header>-->
  157 +<!-- <mat-panel-title>{{ 'device-profile.lwm2m.client-strategy' | translate }}</mat-panel-title>-->
  158 +<!-- </mat-expansion-panel-header>-->
  159 +<!-- <ng-template matExpansionPanelContent>-->
  160 +<!-- <div fxLayout="column">-->
  161 +<!-- <mat-form-field class="mat-block">-->
  162 +<!-- <mat-label>{{ 'device-profile.lwm2m.client-strategy-label' | translate }}</mat-label>-->
  163 +<!-- <mat-select formControlName="clientStrategy"-->
  164 +<!-- matTooltip="{{ 'device-profile.lwm2m.client-strategy-tip' | translate:-->
  165 +<!-- { count: +lwm2mDeviceProfileFormGroup.get('clientStrategy').value } }}"-->
  166 +<!-- matTooltipPosition="above">-->
  167 +<!-- <mat-option value=1>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:-->
  168 +<!-- {count: 1} }}</mat-option>-->
  169 +<!-- <mat-option value=2>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:-->
  170 +<!-- {count: 2} }}</mat-option>-->
  171 +<!-- </mat-select>-->
  172 +<!-- </mat-form-field>-->
  173 +<!-- </div>-->
  174 +<!-- </ng-template>-->
  175 +<!-- </mat-expansion-panel>-->
  176 +<!-- </div>-->
  177 +<!-- </mat-accordion>-->
  178 + </section>
  179 + </ng-template>
  180 + </mat-tab>
240 <mat-tab label="{{ 'device-profile.lwm2m.config-json-tab' | translate }}"> 181 <mat-tab label="{{ 'device-profile.lwm2m.config-json-tab' | translate }}">
241 <ng-template matTabContent> 182 <ng-template matTabContent>
242 - <section [formGroup]="lwm2mDeviceConfigFormGroup" class="mat-padding"> 183 + <section [formGroup]="lwm2mDeviceConfigFormGroup" style="padding: 8px 0">
243 <tb-json-object-edit 184 <tb-json-object-edit
244 [required]="required" 185 [required]="required"
245 [sort]="sortFunction" 186 [sort]="sortFunction"
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +:host{
  17 + .fields-group {
  18 + padding: 8px;
  19 + margin: 10px 0;
  20 + border: 1px groove rgba(0, 0, 0, .25);
  21 + border-radius: 4px;
  22 +
  23 + legend {
  24 + color: rgba(0, 0, 0, .7);
  25 + }
  26 + }
  27 +}
@@ -43,11 +43,11 @@ import { Direction } from '@shared/models/page/sort-order'; @@ -43,11 +43,11 @@ import { Direction } from '@shared/models/page/sort-order';
43 import _ from 'lodash'; 43 import _ from 'lodash';
44 import { Subject } from 'rxjs'; 44 import { Subject } from 'rxjs';
45 import { takeUntil } from 'rxjs/operators'; 45 import { takeUntil } from 'rxjs/operators';
46 -import { MatSelectChange } from '@angular/material/select';  
47 46
48 @Component({ 47 @Component({
49 selector: 'tb-profile-lwm2m-device-transport-configuration', 48 selector: 'tb-profile-lwm2m-device-transport-configuration',
50 templateUrl: './lwm2m-device-profile-transport-configuration.component.html', 49 templateUrl: './lwm2m-device-profile-transport-configuration.component.html',
  50 + styleUrls: ['./lwm2m-device-profile-transport-configuration.component.scss'],
51 providers: [{ 51 providers: [{
52 provide: NG_VALUE_ACCESSOR, 52 provide: NG_VALUE_ACCESSOR,
53 useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent), 53 useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent),
@@ -100,12 +100,38 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -100,12 +100,38 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
100 clientStrategy: [1, []], 100 clientStrategy: [1, []],
101 fwUpdateStrategy: [1, []], 101 fwUpdateStrategy: [1, []],
102 swUpdateStrategy: [1, []], 102 swUpdateStrategy: [1, []],
103 - fwUpdateRecourse: ['', []],  
104 - swUpdateRecourse: ['', []] 103 + fwUpdateRecourse: [{value: '', disabled: true}, []],
  104 + swUpdateRecourse: [{value: '', disabled: true}, []]
105 }); 105 });
106 this.lwm2mDeviceConfigFormGroup = this.fb.group({ 106 this.lwm2mDeviceConfigFormGroup = this.fb.group({
107 configurationJson: [null, Validators.required] 107 configurationJson: [null, Validators.required]
108 }); 108 });
  109 + this.lwm2mDeviceProfileFormGroup.get('fwUpdateStrategy').valueChanges.pipe(
  110 + takeUntil(this.destroy$)
  111 + ).subscribe((fwStrategy) => {
  112 + if (fwStrategy === 2) {
  113 + this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').enable({emitEvent: false});
  114 + this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').patchValue(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false});
  115 + this.isFwUpdateStrategy = true;
  116 + } else {
  117 + this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').disable({emitEvent: false});
  118 + this.isFwUpdateStrategy = false;
  119 + }
  120 + this.otaUpdateFwStrategyValidate(true);
  121 + });
  122 + this.lwm2mDeviceProfileFormGroup.get('swUpdateStrategy').valueChanges.pipe(
  123 + takeUntil(this.destroy$)
  124 + ).subscribe((swStrategy) => {
  125 + if (swStrategy === 2) {
  126 + this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').enable({emitEvent: false});
  127 + this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').patchValue(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false});
  128 + this.isSwUpdateStrategy = true;
  129 + } else {
  130 + this.isSwUpdateStrategy = false;
  131 + this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').disable({emitEvent: false});
  132 + }
  133 + this.otaUpdateSwStrategyValidate(true);
  134 + });
109 this.lwm2mDeviceProfileFormGroup.valueChanges.pipe( 135 this.lwm2mDeviceProfileFormGroup.valueChanges.pipe(
110 takeUntil(this.destroy$) 136 takeUntil(this.destroy$)
111 ).subscribe((value) => { 137 ).subscribe((value) => {
@@ -176,11 +202,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -176,11 +202,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
176 } 202 }
177 203
178 private updateWriteValue = (value: ModelValue): void => { 204 private updateWriteValue = (value: ModelValue): void => {
179 - let fwResource = this.configurationValue.clientLwM2mSettings.fwUpdateStrategy === '2' &&  
180 - isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateRecourse) ? 205 + const fwResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateRecourse) ?
181 this.configurationValue.clientLwM2mSettings.fwUpdateRecourse : ''; 206 this.configurationValue.clientLwM2mSettings.fwUpdateRecourse : '';
182 - let swResource = this.configurationValue.clientLwM2mSettings.swUpdateStrategy === '2' &&  
183 - isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateRecourse) ? 207 + const swResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateRecourse) ?
184 this.configurationValue.clientLwM2mSettings.swUpdateRecourse : ''; 208 this.configurationValue.clientLwM2mSettings.swUpdateRecourse : '';
185 this.lwm2mDeviceProfileFormGroup.patchValue({ 209 this.lwm2mDeviceProfileFormGroup.patchValue({
186 objectIds: value, 210 objectIds: value,
@@ -193,16 +217,16 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -193,16 +217,16 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
193 bootstrapServer: this.configurationValue.bootstrap.bootstrapServer, 217 bootstrapServer: this.configurationValue.bootstrap.bootstrapServer,
194 lwm2mServer: this.configurationValue.bootstrap.lwm2mServer, 218 lwm2mServer: this.configurationValue.bootstrap.lwm2mServer,
195 clientStrategy: this.configurationValue.clientLwM2mSettings.clientStrategy, 219 clientStrategy: this.configurationValue.clientLwM2mSettings.clientStrategy,
196 - fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy,  
197 - swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy, 220 + fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1,
  221 + swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1,
198 fwUpdateRecourse: fwResource, 222 fwUpdateRecourse: fwResource,
199 swUpdateRecourse: swResource 223 swUpdateRecourse: swResource
200 }, 224 },
201 {emitEvent: false}); 225 {emitEvent: false});
202 this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = fwResource; 226 this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = fwResource;
203 this.configurationValue.clientLwM2mSettings.swUpdateRecourse = swResource; 227 this.configurationValue.clientLwM2mSettings.swUpdateRecourse = swResource;
204 - this.isFwUpdateStrategy = this.configurationValue.clientLwM2mSettings.fwUpdateStrategy === '2';  
205 - this.isSwUpdateStrategy = this.configurationValue.clientLwM2mSettings.swUpdateStrategy === '2'; 228 + this.isFwUpdateStrategy = this.configurationValue.clientLwM2mSettings.fwUpdateStrategy === 2;
  229 + this.isSwUpdateStrategy = this.configurationValue.clientLwM2mSettings.swUpdateStrategy === 2;
206 this.otaUpdateSwStrategyValidate(); 230 this.otaUpdateSwStrategyValidate();
207 this.otaUpdateFwStrategyValidate(); 231 this.otaUpdateFwStrategyValidate();
208 } 232 }
@@ -239,8 +263,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -239,8 +263,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
239 this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = config.fwUpdateRecourse; 263 this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = config.fwUpdateRecourse;
240 this.configurationValue.clientLwM2mSettings.swUpdateRecourse = config.swUpdateRecourse; 264 this.configurationValue.clientLwM2mSettings.swUpdateRecourse = config.swUpdateRecourse;
241 this.upDateJsonAllConfig(); 265 this.upDateJsonAllConfig();
242 - this.updateModel();  
243 } 266 }
  267 + this.updateModel();
244 } 268 }
245 269
246 private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): object => { 270 private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): object => {
@@ -513,53 +537,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -513,53 +537,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
513 }); 537 });
514 } 538 }
515 539
516 - changeFwUpdateStrategy($event: MatSelectChange) {  
517 - if ($event.value === '2') {  
518 - this.isFwUpdateStrategy = true;  
519 - if (isEmpty(this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').value)) {  
520 - this.lwm2mDeviceProfileFormGroup.patchValue({  
521 - fwUpdateRecourse: DEFAULT_FW_UPDATE_RESOURCE  
522 - },  
523 - {emitEvent: false});  
524 - }  
525 - } else {  
526 - this.isFwUpdateStrategy = false;  
527 - }  
528 - this.otaUpdateFwStrategyValidate();  
529 - }  
530 -  
531 - changeSwUpdateStrategy($event: MatSelectChange) {  
532 - if ($event.value === '2') {  
533 - this.isSwUpdateStrategy = true;  
534 - if (isEmpty(this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').value)) {  
535 - this.lwm2mDeviceProfileFormGroup.patchValue({  
536 - swUpdateRecourse: DEFAULT_SW_UPDATE_RESOURCE  
537 - },  
538 - {emitEvent: false});  
539 -  
540 - }  
541 - } else {  
542 - this.isSwUpdateStrategy = false;  
543 - }  
544 - this.otaUpdateSwStrategyValidate();  
545 - }  
546 -  
547 - private otaUpdateFwStrategyValidate(): void { 540 + private otaUpdateFwStrategyValidate(updated = false): void {
548 if (this.isFwUpdateStrategy) { 541 if (this.isFwUpdateStrategy) {
549 this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').setValidators([Validators.required]); 542 this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').setValidators([Validators.required]);
550 } else { 543 } else {
551 this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').clearValidators(); 544 this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').clearValidators();
552 } 545 }
553 - this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').updateValueAndValidity(); 546 + this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').updateValueAndValidity({emitEvent: updated});
554 } 547 }
555 548
556 - private otaUpdateSwStrategyValidate(): void { 549 + private otaUpdateSwStrategyValidate(updated = false): void {
557 if (this.isSwUpdateStrategy) { 550 if (this.isSwUpdateStrategy) {
558 this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').setValidators([Validators.required]); 551 this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').setValidators([Validators.required]);
559 } else { 552 } else {
560 this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').clearValidators(); 553 this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').clearValidators();
561 } 554 }
562 - this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').updateValueAndValidity(); 555 + this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').updateValueAndValidity({emitEvent: updated});
563 } 556 }
564 557
565 } 558 }
@@ -20,7 +20,6 @@ export const INSTANCE = 'instance'; @@ -20,7 +20,6 @@ export const INSTANCE = 'instance';
20 export const RESOURCES = 'resources'; 20 export const RESOURCES = 'resources';
21 export const ATTRIBUTE_LWM2M = 'attributeLwm2m'; 21 export const ATTRIBUTE_LWM2M = 'attributeLwm2m';
22 export const CLIENT_LWM2M = 'clientLwM2M'; 22 export const CLIENT_LWM2M = 'clientLwM2M';
23 -export const CLIENT_LWM2M_SETTINGS = 'clientLwM2mSettings';  
24 export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry'; 23 export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry';
25 export const OBSERVE = 'observe'; 24 export const OBSERVE = 'observe';
26 export const ATTRIBUTE = 'attribute'; 25 export const ATTRIBUTE = 'attribute';
@@ -43,9 +42,9 @@ export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; @@ -43,9 +42,9 @@ export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/;
43 export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/; 42 export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/;
44 export const INSTANCES_ID_VALUE_MIN = 0; 43 export const INSTANCES_ID_VALUE_MIN = 0;
45 export const INSTANCES_ID_VALUE_MAX = 65535; 44 export const INSTANCES_ID_VALUE_MAX = 65535;
46 -export const DEFAULT_OTA_UPDATE_PROTOCOL = "coap://";  
47 -export const DEFAULT_FW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ":"+ DEFAULT_PORT_SERVER_NO_SEC;  
48 -export const DEFAULT_SW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ":"+ DEFAULT_PORT_SERVER_NO_SEC; 45 +export const DEFAULT_OTA_UPDATE_PROTOCOL = 'coap://';
  46 +export const DEFAULT_FW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ':' + DEFAULT_PORT_SERVER_NO_SEC;
  47 +export const DEFAULT_SW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ':' + DEFAULT_PORT_SERVER_NO_SEC;
49 48
50 49
51 export enum BINDING_MODE { 50 export enum BINDING_MODE {
@@ -113,19 +112,19 @@ export const ATTRIBUTE_LWM2M_MAP = new Map<ATTRIBUTE_LWM2M_ENUM, string>( @@ -113,19 +112,19 @@ export const ATTRIBUTE_LWM2M_MAP = new Map<ATTRIBUTE_LWM2M_ENUM, string>(
113 112
114 export const ATTRIBUTE_KEYS = Object.keys(ATTRIBUTE_LWM2M_ENUM) as string[]; 113 export const ATTRIBUTE_KEYS = Object.keys(ATTRIBUTE_LWM2M_ENUM) as string[];
115 114
116 -export enum SECURITY_CONFIG_MODE { 115 +export enum securityConfigMode {
117 PSK = 'PSK', 116 PSK = 'PSK',
118 RPK = 'RPK', 117 RPK = 'RPK',
119 X509 = 'X509', 118 X509 = 'X509',
120 NO_SEC = 'NO_SEC' 119 NO_SEC = 'NO_SEC'
121 } 120 }
122 121
123 -export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>( 122 +export const securityConfigModeNames = new Map<securityConfigMode, string>(
124 [ 123 [
125 - [SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'],  
126 - [SECURITY_CONFIG_MODE.RPK, 'Raw Public Key'],  
127 - [SECURITY_CONFIG_MODE.X509, 'X.509 Certificate'],  
128 - [SECURITY_CONFIG_MODE.NO_SEC, 'No Security'] 124 + [securityConfigMode.PSK, 'Pre-Shared Key'],
  125 + [securityConfigMode.RPK, 'Raw Public Key'],
  126 + [securityConfigMode.X509, 'X.509 Certificate'],
  127 + [securityConfigMode.NO_SEC, 'No Security']
129 ] 128 ]
130 ); 129 );
131 130
@@ -144,9 +143,10 @@ export interface BootstrapServersSecurityConfig { @@ -144,9 +143,10 @@ export interface BootstrapServersSecurityConfig {
144 143
145 export interface ServerSecurityConfig { 144 export interface ServerSecurityConfig {
146 host?: string; 145 host?: string;
  146 + securityHost?: string;
147 port?: number; 147 port?: number;
148 - bootstrapServerIs?: boolean;  
149 - securityMode: string; 148 + securityPort?: number;
  149 + securityMode: securityConfigMode;
150 clientPublicKeyOrId?: string; 150 clientPublicKeyOrId?: string;
151 clientSecretKey?: string; 151 clientSecretKey?: string;
152 serverPublicKey?: string; 152 serverPublicKey?: string;
@@ -169,8 +169,8 @@ export interface Lwm2mProfileConfigModels { @@ -169,8 +169,8 @@ export interface Lwm2mProfileConfigModels {
169 169
170 export interface ClientLwM2mSettings { 170 export interface ClientLwM2mSettings {
171 clientStrategy: string; 171 clientStrategy: string;
172 - fwUpdateStrategy: string;  
173 - swUpdateStrategy: string; 172 + fwUpdateStrategy: number;
  173 + swUpdateStrategy: number;
174 fwUpdateRecourse: string; 174 fwUpdateRecourse: string;
175 swUpdateRecourse: string; 175 swUpdateRecourse: string;
176 } 176 }
@@ -193,12 +193,11 @@ export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecu @@ -193,12 +193,11 @@ export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecu
193 }; 193 };
194 } 194 }
195 195
196 -export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSecurityConfig { 196 +export function getDefaultBootstrapServerSecurityConfig(hostname: string): ServerSecurityConfig {
197 return { 197 return {
198 host: hostname, 198 host: hostname,
199 port: DEFAULT_PORT_BOOTSTRAP_NO_SEC, 199 port: DEFAULT_PORT_BOOTSTRAP_NO_SEC,
200 - bootstrapServerIs: true,  
201 - securityMode: SECURITY_CONFIG_MODE.NO_SEC.toString(), 200 + securityMode: securityConfigMode.NO_SEC,
202 serverPublicKey: '', 201 serverPublicKey: '',
203 clientHoldOffTime: DEFAULT_CLIENT_HOLD_OFF_TIME, 202 clientHoldOffTime: DEFAULT_CLIENT_HOLD_OFF_TIME,
204 serverId: DEFAULT_ID_BOOTSTRAP, 203 serverId: DEFAULT_ID_BOOTSTRAP,
@@ -208,7 +207,6 @@ export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSe @@ -208,7 +207,6 @@ export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSe
208 207
209 export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig { 208 export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig {
210 const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname); 209 const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname);
211 - DefaultLwM2MServerSecurityConfig.bootstrapServerIs = false;  
212 DefaultLwM2MServerSecurityConfig.port = DEFAULT_PORT_SERVER_NO_SEC; 210 DefaultLwM2MServerSecurityConfig.port = DEFAULT_PORT_SERVER_NO_SEC;
213 DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER; 211 DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER;
214 return DefaultLwM2MServerSecurityConfig; 212 return DefaultLwM2MServerSecurityConfig;
@@ -242,9 +240,9 @@ export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModel @@ -242,9 +240,9 @@ export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModel
242 240
243 function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings { 241 function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings {
244 return { 242 return {
245 - clientStrategy: "1",  
246 - fwUpdateStrategy: "1",  
247 - swUpdateStrategy: "1", 243 + clientStrategy: '1',
  244 + fwUpdateStrategy: 1,
  245 + swUpdateStrategy: 1,
248 fwUpdateRecourse: DEFAULT_FW_UPDATE_RESOURCE, 246 fwUpdateRecourse: DEFAULT_FW_UPDATE_RESOURCE,
249 swUpdateRecourse: DEFAULT_SW_UPDATE_RESOURCE 247 swUpdateRecourse: DEFAULT_SW_UPDATE_RESOURCE
250 }; 248 };
@@ -1243,7 +1243,7 @@ @@ -1243,7 +1243,7 @@
1243 "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }", 1243 "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }",
1244 "servers": "Servers", 1244 "servers": "Servers",
1245 "short-id": "Short ID", 1245 "short-id": "Short ID",
1246 - "short-id-tip": "Short Server ID", 1246 + "short-id-required": "Short ID is required.",
1247 "lifetime": "Lifetime of the registration for this LwM2M client", 1247 "lifetime": "Lifetime of the registration for this LwM2M client",
1248 "default-min-period": "Minimum Period between two notifications (sec)", 1248 "default-min-period": "Minimum Period between two notifications (sec)",
1249 "notif-if-disabled": "Notification Storing When Disabled or Offline", 1249 "notif-if-disabled": "Notification Storing When Disabled or Offline",
@@ -1252,28 +1252,37 @@ @@ -1252,28 +1252,37 @@
1252 "bootstrap-server": "Bootstrap Server", 1252 "bootstrap-server": "Bootstrap Server",
1253 "lwm2m-server": "LwM2M Server", 1253 "lwm2m-server": "LwM2M Server",
1254 "server-host": "Host", 1254 "server-host": "Host",
1255 - "server-host-tip": "Server Host", 1255 + "server-host-required": "Host is required.",
1256 "server-port": "Port", 1256 "server-port": "Port",
1257 - "server-port-tip": "Server Port", 1257 + "server-port-required": "Port is required.",
1258 "server-public-key": "Server Public Key", 1258 "server-public-key": "Server Public Key",
1259 - "server-public-key-tip": "Server Public Key only for X509, RPK", 1259 + "server-public-key-required": "Server Public Key is required.",
  1260 + "server-public-key-pattern": "Server Public Key must be hex decimal format.",
  1261 + "server-public-key-length": "Server Public Key must be {{ count }} characters.",
1260 "client-hold-off-time": "Hold Off Time", 1262 "client-hold-off-time": "Hold Off Time",
1261 - "client-hold-off-time-tip": "Client Hold Off Time for use with a Bootstrap-Server only",  
1262 - "bootstrap-server-account-timeout": "Account after the timeout",  
1263 - "bootstrap-server-account-timeout-tip": "Bootstrap-Server Account after the timeout value given by this resource.",  
1264 - "others-tab": "Other settings...", 1263 + "client-hold-off-time-required": "Hold Off Time is required.",
  1264 + "client-hold-off-time-tooltip": "Client Hold Off Time for use with a Bootstrap-Server only",
  1265 + "account-after-timeout": "Account after the timeout",
  1266 + "account-after-timeout-required": "Account after the timeout is required.",
  1267 + "account-after-timeout-tooltip": "Bootstrap-Server Account after the timeout value given by this resource.",
  1268 + "others-tab": "Other settings",
1265 "client-strategy": "Client strategy when connecting", 1269 "client-strategy": "Client strategy when connecting",
1266 "client-strategy-label": "Strategy", 1270 "client-strategy-label": "Strategy",
1267 "client-strategy-connect": "{ count, plural, 1 {1: Only Observe Request to the client after the initial connection} other {2: Read All Resources & Observe Request to the client after registration} }", 1271 "client-strategy-connect": "{ count, plural, 1 {1: Only Observe Request to the client after the initial connection} other {2: Read All Resources & Observe Request to the client after registration} }",
1268 "client-strategy-tip": "{ count, plural, 1 {Strategy 1: After the initial connection of the LWM2M Client, the server sends Observe resources Request to the client, those resources that are marked as observation in the Device profile and which exist on the LWM2M client.} other {Strategy 2: After the registration, request the client to read all the resource values for all objects that the LWM2M client has,\n then execute: the server sends Observe resources Request to the client, those resources that are marked as observation in the Device profile and which exist on the LWM2M client.} }", 1272 "client-strategy-tip": "{ count, plural, 1 {Strategy 1: After the initial connection of the LWM2M Client, the server sends Observe resources Request to the client, those resources that are marked as observation in the Device profile and which exist on the LWM2M client.} other {Strategy 2: After the registration, request the client to read all the resource values for all objects that the LWM2M client has,\n then execute: the server sends Observe resources Request to the client, those resources that are marked as observation in the Device profile and which exist on the LWM2M client.} }",
1269 - "ota-update-strategy": "Ota update strategy",  
1270 - "fw-update-strategy-label": "Firmware update strategy",  
1271 - "fw-update-strategy": "{ count, plural, 1 {Push firmware update as binary file using Object 5 and Resource 0 (Package).} 2 {Auto-generate unique CoAP URL to download the package and push firmware update as Object 5 and Resource 1 (Package URI).} other {Push firmware update as binary file using Object 19 and Resource 0 (Data).} }",  
1272 - "sw-update-strategy-label": "Software update strategy",  
1273 - "sw-update-strategy": "{ count, plural, 1 {Push binary file using Object 9 and Resource 2 (Package).} other {Auto-generate unique CoAP URL to download the package and push software update using Object 9 and Resource 3 (Package URI).} }",  
1274 - "ota-update-recourse": "Ota update Coap recourse",  
1275 - "fw-update-recourse": "Firmware update Coap recourse",  
1276 - "sw-update-recourse": "Software update Coap recourse", 1273 + "fw-update": "Firmware update",
  1274 + "fw-update-strategy": "Firmware update strategy",
  1275 + "fw-update-strategy-data": "Push firmware update as binary file using Object 19 and Resource 0 (Data)",
  1276 + "fw-update-strategy-package": "Push firmware update as binary file using Object 5 and Resource 0 (Package)",
  1277 + "fw-update-strategy-package-uri": "Auto-generate unique CoAP URL to download the package and push firmware update as Object 5 and Resource 1 (Package URI)",
  1278 + "sw-update": "Software update",
  1279 + "sw-update-strategy": "Software update strategy",
  1280 + "sw-update-strategy-package": "Push binary file using Object 9 and Resource 2 (Package)",
  1281 + "sw-update-strategy-package-uri": "Auto-generate unique CoAP URL to download the package and push software update using Object 9 and Resource 3 (Package URI)",
  1282 + "fw-update-recourse": "Firmware update CoAP recourse",
  1283 + "fw-update-recourse-required": "Firmware update CoAP recourse is required.",
  1284 + "sw-update-recourse": "Software update CoAP recourse",
  1285 + "sw-update-recourse-required": "Software update CoAP recourse is required.",
1277 "config-json-tab": "Json Config Profile Device" 1286 "config-json-tab": "Json Config Profile Device"
1278 } 1287 }
1279 }, 1288 },