Commit 6c631a9f146516fd7dbbc839928eb8ea8a74bce7

Authored by Vladyslav_Prykhodko
Committed by Andrew Shvayka
1 parent 3a7a97dd

UI: Add power mode settings in LwM2M device profile and refactoring lwm2m device…

… profile transport form
@@ -141,7 +141,7 @@ import { DashboardImageDialogComponent } from '@home/components/dashboard-page/d @@ -141,7 +141,7 @@ import { DashboardImageDialogComponent } from '@home/components/dashboard-page/d
141 import { WidgetContainerComponent } from '@home/components/widget/widget-container.component'; 141 import { WidgetContainerComponent } from '@home/components/widget/widget-container.component';
142 import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snpm/snmp-device-profile-transport.module'; 142 import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snpm/snmp-device-profile-transport.module';
143 import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module'; 143 import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module';
144 -import { PowerModeSettingComponent } from '@home/components/profile/device/common/power-mode-setting.component'; 144 +import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module';
145 145
146 @NgModule({ 146 @NgModule({
147 declarations: 147 declarations:
@@ -260,8 +260,7 @@ import { PowerModeSettingComponent } from '@home/components/profile/device/commo @@ -260,8 +260,7 @@ import { PowerModeSettingComponent } from '@home/components/profile/device/commo
260 DashboardStateDialogComponent, 260 DashboardStateDialogComponent,
261 DashboardImageDialogComponent, 261 DashboardImageDialogComponent,
262 EmbedDashboardDialogComponent, 262 EmbedDashboardDialogComponent,
263 - DisplayWidgetTypesPanelComponent,  
264 - PowerModeSettingComponent 263 + DisplayWidgetTypesPanelComponent
265 ], 264 ],
266 imports: [ 265 imports: [
267 CommonModule, 266 CommonModule,
@@ -270,7 +269,8 @@ import { PowerModeSettingComponent } from '@home/components/profile/device/commo @@ -270,7 +269,8 @@ import { PowerModeSettingComponent } from '@home/components/profile/device/commo
270 Lwm2mProfileComponentsModule, 269 Lwm2mProfileComponentsModule,
271 SnmpDeviceProfileTransportModule, 270 SnmpDeviceProfileTransportModule,
272 StatesControllerModule, 271 StatesControllerModule,
273 - DeviceCredentialsModule 272 + DeviceCredentialsModule,
  273 + DeviceProfileCommonModule
274 ], 274 ],
275 exports: [ 275 exports: [
276 EntitiesTableComponent, 276 EntitiesTableComponent,
@@ -371,8 +371,7 @@ import { PowerModeSettingComponent } from '@home/components/profile/device/commo @@ -371,8 +371,7 @@ import { PowerModeSettingComponent } from '@home/components/profile/device/commo
371 DashboardStateDialogComponent, 371 DashboardStateDialogComponent,
372 DashboardImageDialogComponent, 372 DashboardImageDialogComponent,
373 EmbedDashboardDialogComponent, 373 EmbedDashboardDialogComponent,
374 - DisplayWidgetTypesPanelComponent,  
375 - PowerModeSettingComponent 374 + DisplayWidgetTypesPanelComponent
376 ], 375 ],
377 providers: [ 376 providers: [
378 WidgetComponentService, 377 WidgetComponentService,
  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 +
  17 +import { NgModule } from '@angular/core';
  18 +import { PowerModeSettingComponent } from '@home/components/profile/device/common/power-mode-setting.component';
  19 +import { SharedModule } from '@shared/shared.module';
  20 +import { CommonModule } from '@angular/common';
  21 +
  22 +@NgModule({
  23 + declarations: [
  24 + PowerModeSettingComponent
  25 + ],
  26 + imports: [
  27 + CommonModule,
  28 + SharedModule
  29 + ],
  30 + exports: [
  31 + PowerModeSettingComponent
  32 + ]
  33 +})
  34 +export class DeviceProfileCommonModule { }
@@ -132,7 +132,7 @@ @@ -132,7 +132,7 @@
132 <mat-option [value]=3>{{ 'device-profile.lwm2m.fw-update-strategy-data' | translate }}</mat-option> 132 <mat-option [value]=3>{{ 'device-profile.lwm2m.fw-update-strategy-data' | translate }}</mat-option>
133 </mat-select> 133 </mat-select>
134 </mat-form-field> 134 </mat-form-field>
135 - <mat-form-field class="mat-block" fxFlex *ngIf="isFwUpdateStrategy"> 135 + <mat-form-field class="mat-block" fxFlex *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').value === 2">
136 <mat-label>{{ 'device-profile.lwm2m.fw-update-resource' | translate }}</mat-label> 136 <mat-label>{{ 'device-profile.lwm2m.fw-update-resource' | translate }}</mat-label>
137 <input matInput formControlName="fwUpdateResource" required> 137 <input matInput formControlName="fwUpdateResource" required>
138 <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').hasError('required')"> 138 <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').hasError('required')">
@@ -149,7 +149,7 @@ @@ -149,7 +149,7 @@
149 <mat-option [value]=2>{{ 'device-profile.lwm2m.sw-update-strategy-package-uri' | translate }}</mat-option> 149 <mat-option [value]=2>{{ 'device-profile.lwm2m.sw-update-strategy-package-uri' | translate }}</mat-option>
150 </mat-select> 150 </mat-select>
151 </mat-form-field> 151 </mat-form-field>
152 - <mat-form-field class="mat-block" fxFlex *ngIf="isSwUpdateStrategy"> 152 + <mat-form-field class="mat-block" fxFlex *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').value === 2">
153 <mat-label>{{ 'device-profile.lwm2m.sw-update-resource' | translate }}</mat-label> 153 <mat-label>{{ 'device-profile.lwm2m.sw-update-resource' | translate }}</mat-label>
154 <input matInput formControlName="swUpdateResource" required> 154 <input matInput formControlName="swUpdateResource" required>
155 <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').hasError('required')"> 155 <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').hasError('required')">
@@ -159,25 +159,8 @@ @@ -159,25 +159,8 @@
159 </fieldset> 159 </fieldset>
160 <fieldset class="fields-group"> 160 <fieldset class="fields-group">
161 <legend class="group-title" translate>device-profile.power-saving-mode</legend> 161 <legend class="group-title" translate>device-profile.power-saving-mode</legend>
162 - <mat-form-field class="mat-block" fxFlex>  
163 - <mat-label> </mat-label>  
164 - <mat-select formControlName="powerMode">  
165 - <mat-option *ngFor="let powerMod of powerMods" [value]="powerMod">  
166 - {{ powerModeTranslationMap.get(powerMod) | translate}}  
167 - </mat-option>  
168 - </mat-select>  
169 - </mat-form-field>  
170 - <mat-form-field class="mat-block" fxFlex *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.powerMode').value === 'E_DRX'">  
171 - <mat-label>{{ 'device-profile.edrx-cycle' | translate }}</mat-label>  
172 - <input matInput type="number" min="0" formControlName="edrxCycle" required>  
173 - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle').hasError('required')">  
174 - {{ 'device-profile.edrx-cycle-required' | translate }}  
175 - </mat-error>  
176 - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle').hasError('pattern') ||  
177 - lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle').hasError('min')">  
178 - {{ 'device-profile.edrx-cycle-pattern' | translate }}  
179 - </mat-error>  
180 - </mat-form-field> 162 + <tb-power-mode-settings [parentForm]="clientSettingsFormGroup">
  163 + </tb-power-mode-settings>
181 </fieldset> 164 </fieldset>
182 <mat-slide-toggle class="mat-slider" 165 <mat-slide-toggle class="mat-slider"
183 formControlName="compositeOperationsSupport">{{ 'device-profile.lwm2m.composite-operations-support' | translate }}</mat-slide-toggle> 166 formControlName="compositeOperationsSupport">{{ 'device-profile.lwm2m.composite-operations-support' | translate }}</mat-slide-toggle>
@@ -16,7 +16,15 @@ @@ -16,7 +16,15 @@
16 16
17 import { DeviceProfileTransportConfiguration } from '@shared/models/device.models'; 17 import { DeviceProfileTransportConfiguration } from '@shared/models/device.models';
18 import { Component, forwardRef, Input, OnDestroy } from '@angular/core'; 18 import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
19 -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; 19 +import {
  20 + ControlValueAccessor,
  21 + FormBuilder,
  22 + FormGroup, NG_VALIDATORS,
  23 + NG_VALUE_ACCESSOR,
  24 + ValidationErrors,
  25 + Validator,
  26 + Validators
  27 +} from '@angular/forms';
20 import { coerceBooleanProperty } from '@angular/cdk/coercion'; 28 import { coerceBooleanProperty } from '@angular/cdk/coercion';
21 import { 29 import {
22 ATTRIBUTE, 30 ATTRIBUTE,
@@ -30,10 +38,7 @@ import { @@ -30,10 +38,7 @@ import {
30 DEFAULT_NOTIF_IF_DESIBLED, 38 DEFAULT_NOTIF_IF_DESIBLED,
31 DEFAULT_SW_UPDATE_RESOURCE, 39 DEFAULT_SW_UPDATE_RESOURCE,
32 getDefaultBootstrapServerSecurityConfig, 40 getDefaultBootstrapServerSecurityConfig,
33 - getDefaultBootstrapServersSecurityConfig,  
34 getDefaultLwM2MServerSecurityConfig, 41 getDefaultLwM2MServerSecurityConfig,
35 - getDefaultProfileClientLwM2mSettingsConfig,  
36 - getDefaultProfileObserveAttrConfig,  
37 Instance, 42 Instance,
38 INSTANCES, 43 INSTANCES,
39 KEY_NAME, 44 KEY_NAME,
@@ -41,7 +46,6 @@ import { @@ -41,7 +46,6 @@ import {
41 ObjectLwM2M, 46 ObjectLwM2M,
42 OBSERVE, 47 OBSERVE,
43 PowerMode, 48 PowerMode,
44 - PowerModeTranslationMap,  
45 RESOURCES, 49 RESOURCES,
46 ServerSecurityConfig, 50 ServerSecurityConfig,
47 TELEMETRY 51 TELEMETRY
@@ -58,13 +62,19 @@ import { takeUntil } from 'rxjs/operators'; @@ -58,13 +62,19 @@ import { takeUntil } from 'rxjs/operators';
58 selector: 'tb-profile-lwm2m-device-transport-configuration', 62 selector: 'tb-profile-lwm2m-device-transport-configuration',
59 templateUrl: './lwm2m-device-profile-transport-configuration.component.html', 63 templateUrl: './lwm2m-device-profile-transport-configuration.component.html',
60 styleUrls: ['./lwm2m-device-profile-transport-configuration.component.scss'], 64 styleUrls: ['./lwm2m-device-profile-transport-configuration.component.scss'],
61 - providers: [{  
62 - provide: NG_VALUE_ACCESSOR,  
63 - useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent),  
64 - multi: true  
65 - }] 65 + providers: [
  66 + {
  67 + provide: NG_VALUE_ACCESSOR,
  68 + useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent),
  69 + multi: true
  70 + },
  71 + {
  72 + provide: NG_VALIDATORS,
  73 + useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent),
  74 + multi: true
  75 + }]
66 }) 76 })
67 -export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validators, OnDestroy { 77 +export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validator, OnDestroy {
68 78
69 private configurationValue: Lwm2mProfileConfigModels; 79 private configurationValue: Lwm2mProfileConfigModels;
70 private requiredValue: boolean; 80 private requiredValue: boolean;
@@ -76,10 +86,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -76,10 +86,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
76 lwm2mDeviceProfileFormGroup: FormGroup; 86 lwm2mDeviceProfileFormGroup: FormGroup;
77 lwm2mDeviceConfigFormGroup: FormGroup; 87 lwm2mDeviceConfigFormGroup: FormGroup;
78 sortFunction: (key: string, value: object) => object; 88 sortFunction: (key: string, value: object) => object;
79 - isFwUpdateStrategy: boolean;  
80 - isSwUpdateStrategy: boolean;  
81 - powerMods = Object.values(PowerMode);  
82 - powerModeTranslationMap = PowerModeTranslationMap;  
83 89
84 get required(): boolean { 90 get required(): boolean {
85 return this.requiredValue; 91 return this.requiredValue;
@@ -116,7 +122,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -116,7 +122,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
116 fwUpdateResource: [{value: '', disabled: true}, []], 122 fwUpdateResource: [{value: '', disabled: true}, []],
117 swUpdateResource: [{value: '', disabled: true}, []], 123 swUpdateResource: [{value: '', disabled: true}, []],
118 powerMode: [PowerMode.DRX, Validators.required], 124 powerMode: [PowerMode.DRX, Validators.required],
119 - edrxCycle: [0], 125 + edrxCycle: [{disabled: true, value: 0}, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
  126 + psmActivityTimer: [{disabled: true, value: 0}, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
  127 + pagingTransmissionWindow: [{disabled: true, value: 0}, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
120 compositeOperationsSupport: [false] 128 compositeOperationsSupport: [false]
121 }) 129 })
122 }); 130 });
@@ -128,42 +136,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -128,42 +136,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
128 ).subscribe((fwStrategy) => { 136 ).subscribe((fwStrategy) => {
129 if (fwStrategy === 2) { 137 if (fwStrategy === 2) {
130 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').enable({emitEvent: false}); 138 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').enable({emitEvent: false});
131 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource')  
132 - .patchValue(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false});  
133 - this.isFwUpdateStrategy = true;  
134 } else { 139 } else {
135 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').disable({emitEvent: false}); 140 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').disable({emitEvent: false});
136 - this.isFwUpdateStrategy = false; 141 + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource')
  142 + .reset(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false});
137 } 143 }
138 - this.otaUpdateFwStrategyValidate(true);  
139 }); 144 });
140 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').valueChanges.pipe( 145 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').valueChanges.pipe(
141 takeUntil(this.destroy$) 146 takeUntil(this.destroy$)
142 ).subscribe((swStrategy) => { 147 ).subscribe((swStrategy) => {
143 if (swStrategy === 2) { 148 if (swStrategy === 2) {
144 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').enable({emitEvent: false}); 149 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').enable({emitEvent: false});
145 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource')  
146 - .patchValue(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false});  
147 - this.isSwUpdateStrategy = true;  
148 } else { 150 } else {
149 - this.isSwUpdateStrategy = false;  
150 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').disable({emitEvent: false}); 151 this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').disable({emitEvent: false});
  152 + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource')
  153 + .reset(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false});
151 } 154 }
152 - this.otaUpdateSwStrategyValidate(true);  
153 - });  
154 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.powerMode').valueChanges.pipe(  
155 - takeUntil(this.destroy$)  
156 - ).subscribe((powerMode: PowerMode) => {  
157 - if (powerMode === PowerMode.E_DRX) {  
158 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle').enable({emitEvent: false});  
159 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle').patchValue(0, {emitEvent: false});  
160 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle')  
161 - .setValidators([Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]);  
162 - } else {  
163 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle').disable({emitEvent: false});  
164 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle').clearValidators();  
165 - }  
166 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.edrxCycle').updateValueAndValidity({emitEvent: false});  
167 }); 155 });
168 this.lwm2mDeviceProfileFormGroup.valueChanges.pipe( 156 this.lwm2mDeviceProfileFormGroup.valueChanges.pipe(
169 takeUntil(this.destroy$) 157 takeUntil(this.destroy$)
@@ -198,24 +186,33 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -198,24 +186,33 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
198 } else { 186 } else {
199 this.lwm2mDeviceProfileFormGroup.enable({emitEvent: false}); 187 this.lwm2mDeviceProfileFormGroup.enable({emitEvent: false});
200 this.lwm2mDeviceConfigFormGroup.enable({emitEvent: false}); 188 this.lwm2mDeviceConfigFormGroup.enable({emitEvent: false});
  189 + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.powerMode').updateValueAndValidity({onlySelf: true});
  190 + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').updateValueAndValidity({onlySelf: true});
  191 + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').updateValueAndValidity({onlySelf: true});
201 } 192 }
202 } 193 }
203 194
204 async writeValue(value: Lwm2mProfileConfigModels | null) { 195 async writeValue(value: Lwm2mProfileConfigModels | null) {
205 - if (isDefinedAndNotNull(value)) {  
206 - if (value?.clientLwM2mSettings || value?.observeAttr || value?.bootstrap) {  
207 - this.configurationValue = value;  
208 - } else {  
209 - this.configurationValue = await this.defaultProfileConfig();  
210 - } 196 + if (isDefinedAndNotNull(value) && (value?.clientLwM2mSettings || value?.observeAttr || value?.bootstrap)) {
  197 + this.configurationValue = value;
  198 + const defaultFormSettings = !(value.observeAttr.attribute.length && value.observeAttr.telemetry.length);
211 this.lwm2mDeviceConfigFormGroup.patchValue({ 199 this.lwm2mDeviceConfigFormGroup.patchValue({
212 configurationJson: this.configurationValue 200 configurationJson: this.configurationValue
213 - }, {emitEvent: false}); 201 + }, {emitEvent: defaultFormSettings});
  202 + if (defaultFormSettings) {
  203 + await this.defaultProfileConfig();
  204 + }
214 this.initWriteValue(); 205 this.initWriteValue();
215 } 206 }
216 } 207 }
217 208
218 - private async defaultProfileConfig(): Promise<Lwm2mProfileConfigModels> { 209 + validate(): ValidationErrors | null {
  210 + return this.lwm2mDeviceProfileFormGroup.valid ? null : {
  211 + lwm2mDeviceProfile: false
  212 + };
  213 + }
  214 +
  215 + private async defaultProfileConfig(): Promise<void> {
219 let bootstrap: ServerSecurityConfig; 216 let bootstrap: ServerSecurityConfig;
220 let lwm2m: ServerSecurityConfig; 217 let lwm2m: ServerSecurityConfig;
221 try { 218 try {
@@ -227,15 +224,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -227,15 +224,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
227 bootstrap = getDefaultBootstrapServerSecurityConfig(); 224 bootstrap = getDefaultBootstrapServerSecurityConfig();
228 lwm2m = getDefaultLwM2MServerSecurityConfig(); 225 lwm2m = getDefaultLwM2MServerSecurityConfig();
229 } 226 }
230 - return {  
231 - observeAttr: getDefaultProfileObserveAttrConfig(),  
232 - bootstrap: {  
233 - servers: getDefaultBootstrapServersSecurityConfig(),  
234 - bootstrapServer: bootstrap,  
235 - lwm2mServer: lwm2m  
236 - },  
237 - clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig()  
238 - }; 227 +
  228 + this.configurationValue.bootstrap.bootstrapServer = bootstrap;
  229 + this.configurationValue.bootstrap.lwm2mServer = lwm2m;
  230 + this.lwm2mDeviceConfigFormGroup.patchValue({
  231 + configurationJson: this.configurationValue
  232 + }, {emitEvent: false});
  233 + this.lwm2mDeviceProfileFormGroup.patchValue({
  234 + bootstrap: this.configurationValue.bootstrap
  235 + }, {emitEvent: false});
239 } 236 }
240 237
241 private initWriteValue = (): void => { 238 private initWriteValue = (): void => {
@@ -256,10 +253,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -256,10 +253,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
256 } 253 }
257 254
258 private updateWriteValue = (value: ObjectLwM2M[]): void => { 255 private updateWriteValue = (value: ObjectLwM2M[]): void => {
259 - const fwResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateResource) ?  
260 - this.configurationValue.clientLwM2mSettings.fwUpdateResource : '';  
261 - const swResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.swUpdateResource) ?  
262 - this.configurationValue.clientLwM2mSettings.swUpdateResource : '';  
263 this.lwm2mDeviceProfileFormGroup.patchValue({ 256 this.lwm2mDeviceProfileFormGroup.patchValue({
264 objectIds: value, 257 objectIds: value,
265 observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value), 258 observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value),
@@ -268,22 +261,19 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -268,22 +261,19 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
268 clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect, 261 clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect,
269 fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1, 262 fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1,
270 swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1, 263 swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1,
271 - fwUpdateResource: fwResource,  
272 - swUpdateResource: swResource, 264 + fwUpdateResource: this.configurationValue.clientLwM2mSettings.fwUpdateResource || '',
  265 + swUpdateResource: this.configurationValue.clientLwM2mSettings.swUpdateResource || '',
273 powerMode: this.configurationValue.clientLwM2mSettings.powerMode || PowerMode.DRX, 266 powerMode: this.configurationValue.clientLwM2mSettings.powerMode || PowerMode.DRX,
274 edrxCycle: this.configurationValue.clientLwM2mSettings.edrxCycle || 0, 267 edrxCycle: this.configurationValue.clientLwM2mSettings.edrxCycle || 0,
275 compositeOperationsSupport: this.configurationValue.clientLwM2mSettings.compositeOperationsSupport || false 268 compositeOperationsSupport: this.configurationValue.clientLwM2mSettings.compositeOperationsSupport || false
276 } 269 }
277 }, 270 },
278 {emitEvent: false}); 271 {emitEvent: false});
279 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.powerMode')  
280 - .patchValue(this.configurationValue.clientLwM2mSettings.powerMode || PowerMode.DRX, {emitEvent: false, onlySelf: true});  
281 - this.configurationValue.clientLwM2mSettings.fwUpdateResource = fwResource;  
282 - this.configurationValue.clientLwM2mSettings.swUpdateResource = swResource;  
283 - this.isFwUpdateStrategy = this.configurationValue.clientLwM2mSettings.fwUpdateStrategy === 2;  
284 - this.isSwUpdateStrategy = this.configurationValue.clientLwM2mSettings.swUpdateStrategy === 2;  
285 - this.otaUpdateSwStrategyValidate();  
286 - this.otaUpdateFwStrategyValidate(); 272 + if (!this.disabled) {
  273 + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.powerMode').updateValueAndValidity({onlySelf: true});
  274 + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').updateValueAndValidity({onlySelf: true});
  275 + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').updateValueAndValidity({onlySelf: true});
  276 + }
287 } 277 }
288 278
289 private updateModel = (): void => { 279 private updateModel = (): void => {
@@ -576,22 +566,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -576,22 +566,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
576 }); 566 });
577 } 567 }
578 568
579 - private otaUpdateFwStrategyValidate(updated = false): void {  
580 - if (this.isFwUpdateStrategy) {  
581 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').setValidators([Validators.required]);  
582 - } else {  
583 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').clearValidators();  
584 - }  
585 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').updateValueAndValidity({emitEvent: updated});  
586 - }  
587 -  
588 - private otaUpdateSwStrategyValidate(updated = false): void {  
589 - if (this.isSwUpdateStrategy) {  
590 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').setValidators([Validators.required]);  
591 - } else {  
592 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').clearValidators();  
593 - }  
594 - this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').updateValueAndValidity({emitEvent: updated}); 569 + get clientSettingsFormGroup(): FormGroup {
  570 + return this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings') as FormGroup;
595 } 571 }
596 572
597 } 573 }
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 --> 17 -->
18 <form [formGroup]="instancesFormGroup" (ngSubmit)="add()" style="min-width: 400px;"> 18 <form [formGroup]="instancesFormGroup" (ngSubmit)="add()" style="min-width: 400px;">
19 <mat-toolbar fxLayout="row" color="primary"> 19 <mat-toolbar fxLayout="row" color="primary">
20 - <b><i>{{data.objectName}}</i></b> (object <<b>{{data.objectId}}</b>>) 20 + <span style="font-weight: 500">{{data.objectName}}</span>&nbsp;#{{data.objectId}}
21 <span fxFlex></span> 21 <span fxFlex></span>
22 <button mat-button mat-icon-button 22 <button mat-button mat-icon-button
23 (click)="cancel()" 23 (click)="cancel()"
@@ -31,6 +31,7 @@ @@ -31,6 +31,7 @@
31 <div mat-dialog-content> 31 <div mat-dialog-content>
32 <fieldset [disabled]="isLoading$ | async"> 32 <fieldset [disabled]="isLoading$ | async">
33 <tb-profile-lwm2m-object-add-instances-list 33 <tb-profile-lwm2m-object-add-instances-list
  34 + required
34 formControlName="instancesIds"> 35 formControlName="instancesIds">
35 </tb-profile-lwm2m-object-add-instances-list> 36 </tb-profile-lwm2m-object-add-instances-list>
36 </fieldset> 37 </fieldset>
@@ -18,40 +18,32 @@ @@ -18,40 +18,32 @@
18 <section [formGroup]="instancesListFormGroup" class="lwm2m-instances-list"> 18 <section [formGroup]="instancesListFormGroup" class="lwm2m-instances-list">
19 <mat-form-field class="mat-block"> 19 <mat-form-field class="mat-block">
20 <mat-label>{{ 'device-profile.lwm2m.instances-list' | translate }}</mat-label> 20 <mat-label>{{ 'device-profile.lwm2m.instances-list' | translate }}</mat-label>
21 - <mat-chip-list> 21 + <mat-chip-list #chipList formControlName="instanceList" [required]="required" (focus)="onFocus()">
22 <mat-chip 22 <mat-chip
23 *ngFor="let instanceId of instancesId" 23 *ngFor="let instanceId of instancesId"
24 - [selectable]="true"  
25 - [removable]="true" 24 + [selectable]="!disabled"
  25 + [removable]="!disabled"
26 (removed)="remove(instanceId)"> 26 (removed)="remove(instanceId)">
27 {{instanceId}} 27 {{instanceId}}
28 - <mat-icon matChipRemove>close</mat-icon> 28 + <mat-icon matChipRemove *ngIf="!disabled">close</mat-icon>
29 </mat-chip> 29 </mat-chip>
  30 + <input matInput type="text"
  31 + #instanceId
  32 + style="max-width: 70px;"
  33 + formControlName="instanceId"
  34 + [matChipInputFor]="chipList"
  35 + [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
  36 + matChipInputAddOnBlur
  37 + (matChipInputTokenEnd)="add($event)">
30 </mat-chip-list> 38 </mat-chip-list>
31 - </mat-form-field>  
32 - <mat-form-field class="mat-block">  
33 - <mat-label>{{ 'device-profile.lwm2m.instances-input' | translate }}</mat-label>  
34 - <input fxFlexFill matInput type='text'  
35 - placeholder="{{'device-profile.lwm2m.instances-input-holder' | translate}}"  
36 - formControlName="instanceIdInput">  
37 - <button mat-icon-button matSuffix  
38 - (click)="add()" type="button">  
39 - <mat-icon>add</mat-icon>  
40 - </button>  
41 - <mat-error *ngIf="instancesListFormGroup.get('instanceIdInput').hasError('min')">  
42 - {{ 'device-profile.lwm2m.valid-id-instance' | translate: {  
43 - count: 2, instance: instanceId, min: instanceIdValueMin  
44 - } }} 39 + <mat-error *ngIf="instancesListFormGroup.get('instanceList').hasError('required')">
  40 + {{ 'device-profile.lwm2m.instances-list-required' | translate }}
45 </mat-error> 41 </mat-error>
46 - <mat-error *ngIf="instancesListFormGroup.get('instanceIdInput').hasError('max')">  
47 - {{ 'device-profile.lwm2m.valid-id-instance' | translate: {  
48 - count: 1, instance: instanceId, max: instanceIdValueMax  
49 - } }} 42 + <mat-error *ngIf="instancesListFormGroup.get('instanceId').hasError('pattern')">
  43 + {{ 'device-profile.lwm2m.instance-id-pattern' | translate }}
50 </mat-error> 44 </mat-error>
51 - <mat-error *ngIf="instancesListFormGroup.get('instanceIdInput').hasError('pattern')">  
52 - {{ 'device-profile.lwm2m.valid-id-instance' | translate: {  
53 - count: 0, instance: instanceId, max: instanceIdValueMax  
54 - } }} 45 + <mat-error *ngIf="instancesListFormGroup.get('instanceId').hasError('max')">
  46 + {{ 'device-profile.lwm2m.instance-id-max' | translate: {max: instanceIdValueMax} }}
55 </mat-error> 47 </mat-error>
56 </mat-form-field> 48 </mat-form-field>
57 </section> 49 </section>
@@ -14,37 +14,76 @@ @@ -14,37 +14,76 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import { Component, forwardRef } from '@angular/core';  
18 -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';  
19 -import { INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN, KEY_REGEXP_NUMBER } from './lwm2m-profile-config.models'; 17 +import { Component, ElementRef, forwardRef, Input, ViewChild } from '@angular/core';
  18 +import {
  19 + ControlValueAccessor,
  20 + FormBuilder,
  21 + FormGroup,
  22 + NG_VALIDATORS,
  23 + NG_VALUE_ACCESSOR, ValidationErrors, Validator,
  24 + Validators
  25 +} from '@angular/forms';
  26 +import { INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN } from './lwm2m-profile-config.models';
  27 +import { coerceBooleanProperty } from '@angular/cdk/coercion';
  28 +import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
  29 +import { MatChipInputEvent } from '@angular/material/chips';
20 30
21 @Component({ 31 @Component({
22 selector: 'tb-profile-lwm2m-object-add-instances-list', 32 selector: 'tb-profile-lwm2m-object-add-instances-list',
23 templateUrl: './lwm2m-object-add-instances-list.component.html', 33 templateUrl: './lwm2m-object-add-instances-list.component.html',
24 - providers: [{  
25 - provide: NG_VALUE_ACCESSOR,  
26 - useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent),  
27 - multi: true  
28 - }] 34 + providers: [
  35 + {
  36 + provide: NG_VALUE_ACCESSOR,
  37 + useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent),
  38 + multi: true
  39 + },
  40 + {
  41 + provide: NG_VALIDATORS,
  42 + useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent),
  43 + multi: true
  44 + }]
29 }) 45 })
30 -export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccessor { 46 +export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccessor, Validator {
31 47
32 - private disabled = false;  
33 - private dirty = false; 48 + private requiredValue: boolean;
  49 +
  50 + @Input()
  51 + disabled: boolean;
  52 +
  53 + get required(): boolean {
  54 + return this.requiredValue;
  55 + }
  56 +
  57 + @Input()
  58 + set required(value: boolean) {
  59 + this.requiredValue = coerceBooleanProperty(value);
  60 + this.updateValidators();
  61 + }
  62 +
  63 + @ViewChild('instanceId') instanceId: ElementRef<HTMLInputElement>;
34 64
35 instancesListFormGroup: FormGroup; 65 instancesListFormGroup: FormGroup;
36 instancesId = new Set<number>(); 66 instancesId = new Set<number>();
37 - instanceIdValueMin = INSTANCES_ID_VALUE_MIN; 67 + separatorKeysCodes = [ENTER, COMMA, SEMICOLON];
38 instanceIdValueMax = INSTANCES_ID_VALUE_MAX; 68 instanceIdValueMax = INSTANCES_ID_VALUE_MAX;
39 69
40 private propagateChange = (v: any) => { }; 70 private propagateChange = (v: any) => { };
41 71
42 constructor(private fb: FormBuilder) { 72 constructor(private fb: FormBuilder) {
43 this.instancesListFormGroup = this.fb.group({ 73 this.instancesListFormGroup = this.fb.group({
44 - instanceIdInput: [null, [  
45 - Validators.min(this.instanceIdValueMin),  
46 - Validators.max(this.instanceIdValueMax),  
47 - Validators.pattern(KEY_REGEXP_NUMBER)]] 74 + instanceList: [null],
  75 + instanceId: [null, [
  76 + Validators.min(INSTANCES_ID_VALUE_MIN),
  77 + Validators.max(INSTANCES_ID_VALUE_MAX),
  78 + Validators.pattern('[0-9]*')]]
  79 + });
  80 + this.instancesListFormGroup.get('instanceId').statusChanges.subscribe((value) => {
  81 + if (value === 'INVALID') {
  82 + const errors = this.instancesListFormGroup.get('instanceId').errors;
  83 + this.instancesListFormGroup.get('instanceList').setErrors(errors);
  84 + } else {
  85 + this.instancesListFormGroup.get('instanceList').updateValueAndValidity({onlySelf: true});
  86 + }
48 }); 87 });
49 } 88 }
50 89
@@ -67,26 +106,41 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso @@ -67,26 +106,41 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso
67 writeValue(value: Set<number>): void { 106 writeValue(value: Set<number>): void {
68 if (value && value.size) { 107 if (value && value.size) {
69 this.instancesId = value; 108 this.instancesId = value;
  109 + this.instancesListFormGroup.patchValue({instanceList: Array.from(this.instancesId)}, {emitEvent: false});
70 } 110 }
71 - this.dirty = false;  
72 } 111 }
73 112
74 - add = (): void => {  
75 - if (this.instancesListFormGroup.get('instanceIdInput').valid && Number.isFinite(Number(this.instanceId))) {  
76 - this.instancesId.add(Number(this.instanceId));  
77 - this.instancesListFormGroup.get('instanceIdInput').setValue(null); 113 + validate(): ValidationErrors | null {
  114 + return this.instancesListFormGroup.valid ? null : {
  115 + instancesListForm: false
  116 + };
  117 + }
  118 +
  119 + add = (event: MatChipInputEvent): void => {
  120 + const value = event.value;
  121 + if (this.instancesListFormGroup.get('instanceId').valid && value !== '' && Number.isFinite(Number(value))) {
  122 + this.instancesId.add(Number(value));
  123 + this.instancesListFormGroup.patchValue({instanceList: Array.from(this.instancesId)}, {emitEvent: false});
  124 + this.instancesListFormGroup.get('instanceId').setValue(null, {emitEvent: false});
78 this.propagateChange(this.instancesId); 125 this.propagateChange(this.instancesId);
79 - this.dirty = true;  
80 } 126 }
81 } 127 }
82 128
83 remove = (object: number): void => { 129 remove = (object: number): void => {
84 this.instancesId.delete(object); 130 this.instancesId.delete(object);
  131 + this.instancesListFormGroup.patchValue({instanceList: Array.from(this.instancesId)}, {emitEvent: false});
85 this.propagateChange(this.instancesId); 132 this.propagateChange(this.instancesId);
86 - this.dirty = true;  
87 } 133 }
88 134
89 - get instanceId(): number {  
90 - return this.instancesListFormGroup.get('instanceIdInput').value; 135 + onFocus() {
  136 + setTimeout(() => {
  137 + this.instanceId.nativeElement.blur();
  138 + this.instanceId.nativeElement.focus();
  139 + }, 0);
  140 + }
  141 +
  142 + private updateValidators() {
  143 + this.instancesListFormGroup.get('instanceList').setValidators(this.required ? [Validators.required] : []);
  144 + this.instancesListFormGroup.get('instanceList').updateValueAndValidity({emitEvent: false});
91 } 145 }
92 } 146 }
@@ -16,7 +16,8 @@ @@ -16,7 +16,8 @@
16 16
17 --> 17 -->
18 <mat-form-field appearance="standard" [formGroup]="lwm2mListFormGroup" class="mat-block"> 18 <mat-form-field appearance="standard" [formGroup]="lwm2mListFormGroup" class="mat-block">
19 - <mat-chip-list #chipList formControlName="objectsList"> 19 + <mat-label translate>device-profile.lwm2m.object-list</mat-label>
  20 + <mat-chip-list #chipList formControlName="objectsList" [required]="required">
20 <mat-chip 21 <mat-chip
21 *ngFor="let objectLwm2m of objectsList" 22 *ngFor="let objectLwm2m of objectsList"
22 [selectable]="!disabled" 23 [selectable]="!disabled"
@@ -25,7 +26,7 @@ @@ -25,7 +26,7 @@
25 {{objectLwm2m.name}} #{{objectLwm2m.keyId}} 26 {{objectLwm2m.name}} #{{objectLwm2m.keyId}}
26 <mat-icon matChipRemove *ngIf="!disabled">close</mat-icon> 27 <mat-icon matChipRemove *ngIf="!disabled">close</mat-icon>
27 </mat-chip> 28 </mat-chip>
28 - <input matInput type="text" placeholder="{{ !disabled ? ('device-profile.lwm2m.object-list' | translate) : '' }}" 29 + <input matInput type="text"
29 style="max-width: 200px;" 30 style="max-width: 200px;"
30 #objectInput 31 #objectInput
31 (focusin)="onFocus()" 32 (focusin)="onFocus()"
@@ -131,7 +131,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V @@ -131,7 +131,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
131 if (isDisabled) { 131 if (isDisabled) {
132 this.lwm2mListFormGroup.disable({emitEvent: false}); 132 this.lwm2mListFormGroup.disable({emitEvent: false});
133 if (isDefined(this.objectInput)) { 133 if (isDefined(this.objectInput)) {
134 - this.clear(); 134 + this.clear('', false);
135 } 135 }
136 } else { 136 } else {
137 this.lwm2mListFormGroup.enable({emitEvent: false}); 137 this.lwm2mListFormGroup.enable({emitEvent: false});
@@ -196,12 +196,14 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V @@ -196,12 +196,14 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
196 } 196 }
197 } 197 }
198 198
199 - private clear(value: string = '') { 199 + private clear(value = '', emitEvent = true) {
200 this.objectInput.nativeElement.value = value; 200 this.objectInput.nativeElement.value = value;
201 - this.lwm2mListFormGroup.get('objectLwm2m').patchValue(value);  
202 - setTimeout(() => {  
203 - this.objectInput.nativeElement.blur();  
204 - this.objectInput.nativeElement.focus();  
205 - }, 0); 201 + this.lwm2mListFormGroup.get('objectLwm2m').patchValue(value, {emitEvent});
  202 + if (emitEvent) {
  203 + setTimeout(() => {
  204 + this.objectInput.nativeElement.blur();
  205 + this.objectInput.nativeElement.focus();
  206 + }, 0);
  207 + }
206 } 208 }
207 } 209 }
@@ -28,6 +28,7 @@ import { Lwm2mObjectAddInstancesListComponent } from './lwm2m-object-add-instanc @@ -28,6 +28,7 @@ import { Lwm2mObjectAddInstancesListComponent } from './lwm2m-object-add-instanc
28 import { CommonModule } from '@angular/common'; 28 import { CommonModule } from '@angular/common';
29 import { SharedModule } from '@app/shared/shared.module'; 29 import { SharedModule } from '@app/shared/shared.module';
30 import { Lwm2mObserveAttrTelemetryInstancesComponent } from './lwm2m-observe-attr-telemetry-instances.component'; 30 import { Lwm2mObserveAttrTelemetryInstancesComponent } from './lwm2m-observe-attr-telemetry-instances.component';
  31 +import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module';
31 32
32 @NgModule({ 33 @NgModule({
33 declarations: 34 declarations:
@@ -46,7 +47,8 @@ import { Lwm2mObserveAttrTelemetryInstancesComponent } from './lwm2m-observe-att @@ -46,7 +47,8 @@ import { Lwm2mObserveAttrTelemetryInstancesComponent } from './lwm2m-observe-att
46 ], 47 ],
47 imports: [ 48 imports: [
48 CommonModule, 49 CommonModule,
49 - SharedModule 50 + SharedModule,
  51 + DeviceProfileCommonModule
50 ], 52 ],
51 exports: [ 53 exports: [
52 Lwm2mDeviceProfileTransportConfigurationComponent, 54 Lwm2mDeviceProfileTransportConfigurationComponent,
@@ -18,7 +18,6 @@ import { ValidatorFn, Validators } from '@angular/forms'; @@ -18,7 +18,6 @@ import { ValidatorFn, Validators } from '@angular/forms';
18 18
19 export const PAGE_SIZE_LIMIT = 50; 19 export const PAGE_SIZE_LIMIT = 50;
20 export const INSTANCES = 'instances'; 20 export const INSTANCES = 'instances';
21 -export const INSTANCE = 'instance';  
22 export const RESOURCES = 'resources'; 21 export const RESOURCES = 'resources';
23 export const OBSERVE = 'observe'; 22 export const OBSERVE = 'observe';
24 export const ATTRIBUTE = 'attribute'; 23 export const ATTRIBUTE = 'attribute';
@@ -38,7 +37,6 @@ export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; @@ -38,7 +37,6 @@ export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0;
38 export const LEN_MAX_PUBLIC_KEY_RPK = 182; 37 export const LEN_MAX_PUBLIC_KEY_RPK = 182;
39 export const LEN_MAX_PUBLIC_KEY_X509 = 3000; 38 export const LEN_MAX_PUBLIC_KEY_X509 = 3000;
40 export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; 39 export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/;
41 -export const KEY_REGEXP_NUMBER = /^(-?|\+?)\d*$/;  
42 export const INSTANCES_ID_VALUE_MIN = 0; 40 export const INSTANCES_ID_VALUE_MIN = 0;
43 export const INSTANCES_ID_VALUE_MAX = 65535; 41 export const INSTANCES_ID_VALUE_MAX = 65535;
44 export const DEFAULT_OTA_UPDATE_PROTOCOL = 'coap://'; 42 export const DEFAULT_OTA_UPDATE_PROTOCOL = 'coap://';
@@ -170,6 +168,8 @@ export interface ClientLwM2mSettings { @@ -170,6 +168,8 @@ export interface ClientLwM2mSettings {
170 swUpdateResource: string; 168 swUpdateResource: string;
171 powerMode: PowerMode; 169 powerMode: PowerMode;
172 edrxCycle?: number; 170 edrxCycle?: number;
  171 + pagingTransmissionWindow?: number;
  172 + psmActivityTimer?: number;
173 compositeOperationsSupport: boolean; 173 compositeOperationsSupport: boolean;
174 } 174 }
175 175
@@ -16,24 +16,6 @@ @@ -16,24 +16,6 @@
16 16
17 --> 17 -->
18 <form [formGroup]="lwm2mDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;"> 18 <form [formGroup]="lwm2mDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;">
19 - <mat-form-field class="mat-block" fxFlex>  
20 - <mat-label translate>device-profile.power-saving-mode</mat-label>  
21 - <mat-select formControlName="powerMode">  
22 - <mat-option [value]="null">{{ "device-profile.power-saving-mode-type.default" | translate }}</mat-option>  
23 - <mat-option *ngFor="let powerMod of powerMods" [value]="powerMod">  
24 - {{ powerModeTranslationMap.get(powerMod) | translate }}  
25 - </mat-option>  
26 - </mat-select>  
27 - </mat-form-field>  
28 - <mat-form-field class="mat-block" fxFlex *ngIf="lwm2mDeviceTransportConfigurationFormGroup.get('powerMode').value === 'E_DRX'">  
29 - <mat-label>{{ 'device-profile.edrx-cycle' | translate }}</mat-label>  
30 - <input matInput type="number" min="0" formControlName="edrxCycle" required>  
31 - <mat-error *ngIf="lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').hasError('required')">  
32 - {{ 'device-profile.edrx-cycle-required' | translate }}  
33 - </mat-error>  
34 - <mat-error *ngIf="lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').hasError('pattern') ||  
35 - lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').hasError('min')">  
36 - {{ 'device-profile.edrx-cycle-pattern' | translate }}  
37 - </mat-error>  
38 - </mat-form-field> 19 + <tb-power-mode-settings [parentForm]="lwm2mDeviceTransportConfigurationFormGroup" [isDeviceSetting]="true">
  20 + </tb-power-mode-settings>
39 </form> 21 </form>
@@ -19,8 +19,11 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida @@ -19,8 +19,11 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida
19 import { Store } from '@ngrx/store'; 19 import { Store } from '@ngrx/store';
20 import { AppState } from '@app/core/core.state'; 20 import { AppState } from '@app/core/core.state';
21 import { coerceBooleanProperty } from '@angular/cdk/coercion'; 21 import { coerceBooleanProperty } from '@angular/cdk/coercion';
22 -import { DeviceTransportConfiguration, Lwm2mDeviceTransportConfiguration } from '@shared/models/device.models';  
23 -import { PowerMode, PowerModeTranslationMap } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; 22 +import {
  23 + DeviceTransportConfiguration,
  24 + DeviceTransportType,
  25 + Lwm2mDeviceTransportConfiguration
  26 +} from '@shared/models/device.models';
24 import { takeUntil } from 'rxjs/operators'; 27 import { takeUntil } from 'rxjs/operators';
25 import { Subject } from 'rxjs'; 28 import { Subject } from 'rxjs';
26 import { isDefinedAndNotNull } from '@core/utils'; 29 import { isDefinedAndNotNull } from '@core/utils';
@@ -38,8 +41,6 @@ import { isDefinedAndNotNull } from '@core/utils'; @@ -38,8 +41,6 @@ import { isDefinedAndNotNull } from '@core/utils';
38 export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy { 41 export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy {
39 42
40 lwm2mDeviceTransportConfigurationFormGroup: FormGroup; 43 lwm2mDeviceTransportConfigurationFormGroup: FormGroup;
41 - powerMods = Object.values(PowerMode);  
42 - powerModeTranslationMap = PowerModeTranslationMap;  
43 44
44 private requiredValue: boolean; 45 private requiredValue: boolean;
45 get required(): boolean { 46 get required(): boolean {
@@ -70,21 +71,9 @@ export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueA @@ -70,21 +71,9 @@ export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueA
70 ngOnInit() { 71 ngOnInit() {
71 this.lwm2mDeviceTransportConfigurationFormGroup = this.fb.group({ 72 this.lwm2mDeviceTransportConfigurationFormGroup = this.fb.group({
72 powerMode: [null], 73 powerMode: [null],
73 - edrxCycle: [0]  
74 - });  
75 - this.lwm2mDeviceTransportConfigurationFormGroup.get('powerMode').valueChanges.pipe(  
76 - takeUntil(this.destroy$)  
77 - ).subscribe((powerMode: PowerMode) => {  
78 - if (powerMode === PowerMode.E_DRX) {  
79 - this.lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').enable({emitEvent: false});  
80 - this.lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').patchValue(0, {emitEvent: false});  
81 - this.lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle')  
82 - .setValidators([Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]);  
83 - } else {  
84 - this.lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').disable({emitEvent: false});  
85 - this.lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').clearValidators();  
86 - }  
87 - this.lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').updateValueAndValidity({emitEvent: false}); 74 + edrxCycle: [{disabled: true, value: 0}, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
  75 + psmActivityTimer: [{disabled: true, value: 0}, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
  76 + pagingTransmissionWindow: [{disabled: true, value: 0}, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]]
88 }); 77 });
89 this.lwm2mDeviceTransportConfigurationFormGroup.valueChanges.pipe( 78 this.lwm2mDeviceTransportConfigurationFormGroup.valueChanges.pipe(
90 takeUntil(this.destroy$) 79 takeUntil(this.destroy$)
@@ -104,15 +93,18 @@ export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueA @@ -104,15 +93,18 @@ export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueA
104 this.lwm2mDeviceTransportConfigurationFormGroup.disable({emitEvent: false}); 93 this.lwm2mDeviceTransportConfigurationFormGroup.disable({emitEvent: false});
105 } else { 94 } else {
106 this.lwm2mDeviceTransportConfigurationFormGroup.enable({emitEvent: false}); 95 this.lwm2mDeviceTransportConfigurationFormGroup.enable({emitEvent: false});
  96 + this.lwm2mDeviceTransportConfigurationFormGroup.get('powerMode').updateValueAndValidity({onlySelf: true});
107 } 97 }
108 } 98 }
109 99
110 writeValue(value: Lwm2mDeviceTransportConfiguration | null): void { 100 writeValue(value: Lwm2mDeviceTransportConfiguration | null): void {
111 if (isDefinedAndNotNull(value)) { 101 if (isDefinedAndNotNull(value)) {
112 - this.lwm2mDeviceTransportConfigurationFormGroup.get('powerMode').patchValue(value.powerMode, {emitEvent: false, onlySelf: true});  
113 - this.lwm2mDeviceTransportConfigurationFormGroup.get('edrxCycle').patchValue(value.edrxCycle || 0, {emitEvent: false}); 102 + this.lwm2mDeviceTransportConfigurationFormGroup.patchValue(value, {emitEvent: false});
114 } else { 103 } else {
115 - this.lwm2mDeviceTransportConfigurationFormGroup.patchValue({powerMode: null, edrxCycle: 0}, {emitEvent: false}); 104 + this.lwm2mDeviceTransportConfigurationFormGroup.get('powerMode').patchValue(null, {emitEvent: false});
  105 + }
  106 + if (!this.disabled) {
  107 + this.lwm2mDeviceTransportConfigurationFormGroup.get('powerMode').updateValueAndValidity({onlySelf: true});
116 } 108 }
117 } 109 }
118 110
@@ -120,7 +112,7 @@ export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueA @@ -120,7 +112,7 @@ export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueA
120 let configuration: DeviceTransportConfiguration = null; 112 let configuration: DeviceTransportConfiguration = null;
121 if (this.lwm2mDeviceTransportConfigurationFormGroup.valid) { 113 if (this.lwm2mDeviceTransportConfigurationFormGroup.valid) {
122 configuration = this.lwm2mDeviceTransportConfigurationFormGroup.value; 114 configuration = this.lwm2mDeviceTransportConfigurationFormGroup.value;
123 - // configuration.type = DeviceTransportType.LWM2M; 115 + configuration.type = DeviceTransportType.LWM2M;
124 } 116 }
125 this.propagateChange(configuration); 117 this.propagateChange(configuration);
126 } 118 }
@@ -34,6 +34,7 @@ import { CoapDeviceTransportConfigurationComponent } from './data/coap-device-tr @@ -34,6 +34,7 @@ import { CoapDeviceTransportConfigurationComponent } from './data/coap-device-tr
34 import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device-transport-configuration.component'; 34 import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device-transport-configuration.component';
35 import { SnmpDeviceTransportConfigurationComponent } from './data/snmp-device-transport-configuration.component'; 35 import { SnmpDeviceTransportConfigurationComponent } from './data/snmp-device-transport-configuration.component';
36 import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module'; 36 import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module';
  37 +import { DeviceProfileCommonModule } from '@home/components/profile/device/common/device-profile-common.module';
37 38
38 @NgModule({ 39 @NgModule({
39 declarations: [ 40 declarations: [
@@ -57,6 +58,7 @@ import { DeviceCredentialsModule } from '@home/components/device/device-credenti @@ -57,6 +58,7 @@ import { DeviceCredentialsModule } from '@home/components/device/device-credenti
57 HomeComponentsModule, 58 HomeComponentsModule,
58 HomeDialogsModule, 59 HomeDialogsModule,
59 DeviceCredentialsModule, 60 DeviceCredentialsModule,
  61 + DeviceProfileCommonModule,
60 DeviceRoutingModule 62 DeviceRoutingModule
61 ] 63 ]
62 }) 64 })
@@ -30,7 +30,14 @@ import { AbstractControl, ValidationErrors } from '@angular/forms'; @@ -30,7 +30,14 @@ import { AbstractControl, ValidationErrors } from '@angular/forms';
30 import { OtaPackageId } from '@shared/models/id/ota-package-id'; 30 import { OtaPackageId } from '@shared/models/id/ota-package-id';
31 import { DashboardId } from '@shared/models/id/dashboard-id'; 31 import { DashboardId } from '@shared/models/id/dashboard-id';
32 import { DataType } from '@shared/models/constants'; 32 import { DataType } from '@shared/models/constants';
33 -import { PowerMode } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; 33 +import {
  34 + getDefaultBootstrapServerSecurityConfig,
  35 + getDefaultBootstrapServersSecurityConfig,
  36 + getDefaultLwM2MServerSecurityConfig,
  37 + getDefaultProfileClientLwM2mSettingsConfig,
  38 + getDefaultProfileObserveAttrConfig,
  39 + PowerMode
  40 +} from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
34 41
35 export enum DeviceProfileType { 42 export enum DeviceProfileType {
36 DEFAULT = 'DEFAULT', 43 DEFAULT = 'DEFAULT',
@@ -369,7 +376,15 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT @@ -369,7 +376,15 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT
369 transportConfiguration = {...coapTransportConfiguration, type: DeviceTransportType.COAP}; 376 transportConfiguration = {...coapTransportConfiguration, type: DeviceTransportType.COAP};
370 break; 377 break;
371 case DeviceTransportType.LWM2M: 378 case DeviceTransportType.LWM2M:
372 - const lwm2mTransportConfiguration: Lwm2mDeviceProfileTransportConfiguration = {}; 379 + const lwm2mTransportConfiguration: Lwm2mDeviceProfileTransportConfiguration = {
  380 + observeAttr: getDefaultProfileObserveAttrConfig(),
  381 + bootstrap: {
  382 + servers: getDefaultBootstrapServersSecurityConfig(),
  383 + bootstrapServer: getDefaultBootstrapServerSecurityConfig(),
  384 + lwm2mServer: getDefaultLwM2MServerSecurityConfig()
  385 + },
  386 + clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig()
  387 + };
373 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M}; 388 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
374 break; 389 break;
375 case DeviceTransportType.SNMP: 390 case DeviceTransportType.SNMP:
@@ -404,7 +419,9 @@ export function createDeviceTransportConfiguration(type: DeviceTransportType): D @@ -404,7 +419,9 @@ export function createDeviceTransportConfiguration(type: DeviceTransportType): D
404 transportConfiguration = {...coapTransportConfiguration, type: DeviceTransportType.COAP}; 419 transportConfiguration = {...coapTransportConfiguration, type: DeviceTransportType.COAP};
405 break; 420 break;
406 case DeviceTransportType.LWM2M: 421 case DeviceTransportType.LWM2M:
407 - const lwm2mTransportConfiguration: Lwm2mDeviceTransportConfiguration = {}; 422 + const lwm2mTransportConfiguration: Lwm2mDeviceTransportConfiguration = {
  423 + powerMode: null
  424 + };
408 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M}; 425 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
409 break; 426 break;
410 case DeviceTransportType.SNMP: 427 case DeviceTransportType.SNMP:
@@ -592,7 +609,8 @@ export interface CoapDeviceTransportConfiguration { @@ -592,7 +609,8 @@ export interface CoapDeviceTransportConfiguration {
592 export interface Lwm2mDeviceTransportConfiguration { 609 export interface Lwm2mDeviceTransportConfiguration {
593 powerMode?: PowerMode | null; 610 powerMode?: PowerMode | null;
594 edrxCycle?: number; 611 edrxCycle?: number;
595 - [key: string]: any; 612 + pagingTransmissionWindow?: number;
  613 + psmActivityTimer?: number;
596 } 614 }
597 615
598 export enum SnmpDeviceProtocolVersion { 616 export enum SnmpDeviceProtocolVersion {
@@ -1242,14 +1242,12 @@ @@ -1242,14 +1242,12 @@
1242 "object-list": "Object list", 1242 "object-list": "Object list",
1243 "object-list-empty": "No objects selected.", 1243 "object-list-empty": "No objects selected.",
1244 "no-objects-matching": "No objects matching '{{object}}' were found.", 1244 "no-objects-matching": "No objects matching '{{object}}' were found.",
1245 - "valid-id-instance-no-min": "Instance number '{{instance}}' no validated. Min value='{{min}}'",  
1246 - "valid-id-instance-no-max": "Instance number '{{instance}}' no validated. Max value='{{max}}'",  
1247 - "valid-id-instance": "Instance number '{{instance}}' no validated. { count, plural, 1 {Max value='{{max}}'} 2 {Min value='{{min}}'} other {Must be only number} }",  
1248 "model-tab": "LWM2M Model", 1245 "model-tab": "LWM2M Model",
1249 "add-new-instances": "Add new instances", 1246 "add-new-instances": "Add new instances",
1250 "instances-list": "Instances list", 1247 "instances-list": "Instances list",
1251 - "instances-input": "Input Instance Id value",  
1252 - "instances-input-holder": "Input Instance number...", 1248 + "instances-list-required": "Instances list is required.",
  1249 + "instance-id-pattern": "Instance id must be a positive integer.",
  1250 + "instance-id-max": "Maximum instance id value {{max}}.",
1253 "instance": "Instance", 1251 "instance": "Instance",
1254 "resource-label": "#ID Resource name", 1252 "resource-label": "#ID Resource name",
1255 "observe-label": "Observe", 1253 "observe-label": "Observe",