Commit fe3378eab125b6f59ae316890f3ed4384b16f114
1 parent
75801045
UI: Add SNMP device transport configuration
Showing
10 changed files
with
366 additions
and
50 deletions
... | ... | @@ -51,6 +51,13 @@ public class SnmpDeviceTransportConfiguration implements DeviceTransportConfigur |
51 | 51 | private String privacyPassphrase; |
52 | 52 | private String engineId; |
53 | 53 | |
54 | + public SnmpDeviceTransportConfiguration() { | |
55 | + this.host = "localhost"; | |
56 | + this.port = 161; | |
57 | + this.protocolVersion = SnmpProtocolVersion.V2C; | |
58 | + this.community = "public"; | |
59 | + } | |
60 | + | |
54 | 61 | @Override |
55 | 62 | public DeviceTransportType getType() { |
56 | 63 | return DeviceTransportType.SNMP; |
... | ... | @@ -76,7 +83,7 @@ public class SnmpDeviceTransportConfiguration implements DeviceTransportConfigur |
76 | 83 | isValid = StringUtils.isNotBlank(username) && StringUtils.isNotBlank(securityName) |
77 | 84 | && contextName != null && authenticationProtocol != null |
78 | 85 | && StringUtils.isNotBlank(authenticationPassphrase) |
79 | - && privacyProtocol != null && privacyPassphrase != null && engineId != null; | |
86 | + && privacyProtocol != null && StringUtils.isNotBlank(privacyPassphrase) && engineId != null; | |
80 | 87 | break; |
81 | 88 | } |
82 | 89 | } | ... | ... |
... | ... | @@ -179,7 +179,7 @@ export class SnmpDeviceProfileCommunicationConfigComponent implements OnInit, On |
179 | 179 | if (isUndefinedOrNull(value)) { |
180 | 180 | value = { |
181 | 181 | spec: this.getFirstUnusedSeverity(), |
182 | - queryingFrequencyMs: 0, | |
182 | + queryingFrequencyMs: 5000, | |
183 | 183 | mappings: null |
184 | 184 | }; |
185 | 185 | } |
... | ... | @@ -196,7 +196,7 @@ export class SnmpDeviceProfileCommunicationConfigComponent implements OnInit, On |
196 | 196 | ).subscribe(spec => { |
197 | 197 | if (this.isShowFrequency(spec)) { |
198 | 198 | form.addControl('queryingFrequencyMs', |
199 | - this.fb.control(0, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')])); | |
199 | + this.fb.control(5000, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')])); | |
200 | 200 | } else { |
201 | 201 | form.removeControl('queryingFrequencyMs'); |
202 | 202 | } | ... | ... |
... | ... | @@ -86,7 +86,7 @@ export class SnmpDeviceProfileTransportConfigurationComponent implements OnInit, |
86 | 86 | |
87 | 87 | ngOnInit(): void { |
88 | 88 | this.snmpDeviceProfileTransportConfigurationFormGroup = this.fb.group({ |
89 | - timeoutMs: [0, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | |
89 | + timeoutMs: [500, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | |
90 | 90 | retries: [0, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], |
91 | 91 | communicationConfigs: [null, Validators.required], |
92 | 92 | }); | ... | ... |
... | ... | @@ -15,7 +15,16 @@ |
15 | 15 | /// |
16 | 16 | |
17 | 17 | import { Component, forwardRef, Input, OnInit } from '@angular/core'; |
18 | -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | |
18 | +import { | |
19 | + ControlValueAccessor, | |
20 | + FormBuilder, | |
21 | + FormGroup, | |
22 | + NG_VALIDATORS, | |
23 | + NG_VALUE_ACCESSOR, | |
24 | + ValidationErrors, | |
25 | + Validator, | |
26 | + Validators | |
27 | +} from '@angular/forms'; | |
19 | 28 | import { Store } from '@ngrx/store'; |
20 | 29 | import { AppState } from '@app/core/core.state'; |
21 | 30 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
... | ... | @@ -29,13 +38,20 @@ import { |
29 | 38 | selector: 'tb-device-data', |
30 | 39 | templateUrl: './device-data.component.html', |
31 | 40 | styleUrls: [], |
32 | - providers: [{ | |
33 | - provide: NG_VALUE_ACCESSOR, | |
34 | - useExisting: forwardRef(() => DeviceDataComponent), | |
35 | - multi: true | |
36 | - }] | |
41 | + providers: [ | |
42 | + { | |
43 | + provide: NG_VALUE_ACCESSOR, | |
44 | + useExisting: forwardRef(() => DeviceDataComponent), | |
45 | + multi: true | |
46 | + }, | |
47 | + { | |
48 | + provide: NG_VALIDATORS, | |
49 | + useExisting: forwardRef(() => DeviceDataComponent), | |
50 | + multi: true | |
51 | + }, | |
52 | + ] | |
37 | 53 | }) |
38 | -export class DeviceDataComponent implements ControlValueAccessor, OnInit { | |
54 | +export class DeviceDataComponent implements ControlValueAccessor, OnInit, Validator { | |
39 | 55 | |
40 | 56 | deviceDataFormGroup: FormGroup; |
41 | 57 | |
... | ... | @@ -97,6 +113,12 @@ export class DeviceDataComponent implements ControlValueAccessor, OnInit { |
97 | 113 | this.deviceDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false}); |
98 | 114 | } |
99 | 115 | |
116 | + validate(): ValidationErrors | null { | |
117 | + return this.deviceDataFormGroup.valid ? null : { | |
118 | + deviceDataForm: false | |
119 | + }; | |
120 | + } | |
121 | + | |
100 | 122 | private updateModel() { |
101 | 123 | let deviceData: DeviceData = null; |
102 | 124 | if (this.deviceDataFormGroup.valid) { | ... | ... |
... | ... | @@ -15,27 +15,39 @@ |
15 | 15 | /// |
16 | 16 | |
17 | 17 | import { Component, forwardRef, Input, OnInit } from '@angular/core'; |
18 | -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | |
18 | +import { | |
19 | + ControlValueAccessor, | |
20 | + FormBuilder, | |
21 | + FormGroup, | |
22 | + NG_VALIDATORS, | |
23 | + NG_VALUE_ACCESSOR, | |
24 | + ValidationErrors, | |
25 | + Validator, | |
26 | + Validators | |
27 | +} from '@angular/forms'; | |
19 | 28 | import { Store } from '@ngrx/store'; |
20 | 29 | import { AppState } from '@app/core/core.state'; |
21 | 30 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
22 | -import { | |
23 | - DeviceTransportConfiguration, | |
24 | - DeviceTransportType | |
25 | -} from '@shared/models/device.models'; | |
31 | +import { DeviceTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; | |
26 | 32 | import { deepClone } from '@core/utils'; |
27 | 33 | |
28 | 34 | @Component({ |
29 | 35 | selector: 'tb-device-transport-configuration', |
30 | 36 | templateUrl: './device-transport-configuration.component.html', |
31 | 37 | styleUrls: [], |
32 | - providers: [{ | |
33 | - provide: NG_VALUE_ACCESSOR, | |
34 | - useExisting: forwardRef(() => DeviceTransportConfigurationComponent), | |
35 | - multi: true | |
36 | - }] | |
38 | + providers: [ | |
39 | + { | |
40 | + provide: NG_VALUE_ACCESSOR, | |
41 | + useExisting: forwardRef(() => DeviceTransportConfigurationComponent), | |
42 | + multi: true | |
43 | + }, | |
44 | + { | |
45 | + provide: NG_VALIDATORS, | |
46 | + useExisting: forwardRef(() => DeviceTransportConfigurationComponent), | |
47 | + multi: true | |
48 | + }] | |
37 | 49 | }) |
38 | -export class DeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit { | |
50 | +export class DeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit, Validator { | |
39 | 51 | |
40 | 52 | deviceTransportType = DeviceTransportType; |
41 | 53 | |
... | ... | @@ -92,7 +104,15 @@ export class DeviceTransportConfigurationComponent implements ControlValueAccess |
92 | 104 | if (configuration) { |
93 | 105 | delete configuration.type; |
94 | 106 | } |
95 | - this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); | |
107 | + setTimeout(() => { | |
108 | + this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); | |
109 | + }, 0); | |
110 | + } | |
111 | + | |
112 | + validate(): ValidationErrors | null { | |
113 | + return this.deviceTransportConfigurationFormGroup.valid ? null : { | |
114 | + deviceTransportConfiguration: false | |
115 | + }; | |
96 | 116 | } |
97 | 117 | |
98 | 118 | private updateModel() { | ... | ... |
... | ... | @@ -15,10 +15,119 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<form [formGroup]="snmpDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;"> | |
19 | - <tb-json-object-edit | |
20 | - [required]="required" | |
21 | - label="{{ 'device-profile.transport-type-snmp-hint' | translate }}" | |
22 | - formControlName="configuration"> | |
23 | - </tb-json-object-edit> | |
18 | +<form [formGroup]="snmpDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;" fxLayoutGap="8px" fxLayout="column"> | |
19 | + <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"> | |
20 | + <mat-form-field fxFlex> | |
21 | + <mat-label translate>device-profile.snmp.host</mat-label> | |
22 | + <input matInput formControlName="host" required> | |
23 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('host').hasError('required') || | |
24 | + snmpDeviceTransportConfigurationFormGroup.get('host').hasError('pattern')"> | |
25 | + {{ 'device-profile.snmp.host-required' | translate }} | |
26 | + </mat-error> | |
27 | + </mat-form-field> | |
28 | + <mat-form-field fxFlex> | |
29 | + <mat-label translate>device-profile.snmp.port</mat-label> | |
30 | + <input matInput formControlName="port" type="number" min="0" required> | |
31 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('port').hasError('required')"> | |
32 | + {{ 'device-profile.snmp.port-required' | translate }} | |
33 | + </mat-error> | |
34 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('port').hasError('pattern') || | |
35 | + snmpDeviceTransportConfigurationFormGroup.get('port').hasError('min')"> | |
36 | + {{ 'device-profile.snmp.port-format' | translate }} | |
37 | + </mat-error> | |
38 | + </mat-form-field> | |
39 | + </div> | |
40 | + <mat-form-field class="mat-block" floatLabel="always" hideRequiredMarker> | |
41 | + <mat-label translate>device-profile.snmp.protocol-version</mat-label> | |
42 | + <mat-select formControlName="protocolVersion" required> | |
43 | + <mat-option *ngFor="let snmpDeviceProtocolVersion of snmpDeviceProtocolVersions" [value]="snmpDeviceProtocolVersion"> | |
44 | + {{ snmpDeviceProtocolVersion | lowercase }} | |
45 | + </mat-option> | |
46 | + </mat-select> | |
47 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').hasError('required')"> | |
48 | + {{ 'device-profile.snmp.protocol-version-required' | translate }} | |
49 | + </mat-error> | |
50 | + </mat-form-field> | |
51 | + <section *ngIf="!isV3protocolVersion()"> | |
52 | + <mat-form-field class="mat-block"> | |
53 | + <mat-label translate>device-profile.snmp.community</mat-label> | |
54 | + <input matInput formControlName="community" required> | |
55 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('community').hasError('required') || | |
56 | + snmpDeviceTransportConfigurationFormGroup.get('community').hasError('pattern')"> | |
57 | + {{ 'device-profile.snmp.community-required' | translate }} | |
58 | + </mat-error> | |
59 | + </mat-form-field> | |
60 | + </section> | |
61 | + <section *ngIf="isV3protocolVersion()"> | |
62 | + <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"> | |
63 | + <mat-form-field fxFlex> | |
64 | + <mat-label translate>device-profile.snmp.user-name</mat-label> | |
65 | + <input matInput formControlName="username" required> | |
66 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('username').hasError('required') || | |
67 | + snmpDeviceTransportConfigurationFormGroup.get('username').hasError('pattern')"> | |
68 | + {{ 'device-profile.snmp.user-name-required' | translate }} | |
69 | + </mat-error> | |
70 | + </mat-form-field> | |
71 | + <mat-form-field fxFlex> | |
72 | + <mat-label translate>device-profile.snmp.security-name</mat-label> | |
73 | + <input matInput formControlName="securityName" required> | |
74 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('securityName').hasError('required') || | |
75 | + snmpDeviceTransportConfigurationFormGroup.get('securityName').hasError('pattern')"> | |
76 | + {{ 'device-profile.snmp.security-name-required' | translate }} | |
77 | + </mat-error> | |
78 | + </mat-form-field> | |
79 | + </div> | |
80 | + <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"> | |
81 | + <mat-form-field fxFlex floatLabel="always" hideRequiredMarker> | |
82 | + <mat-label translate>device-profile.snmp.authentication-protocol</mat-label> | |
83 | + <mat-select formControlName="authenticationProtocol" required> | |
84 | + <mat-option *ngFor="let snmpAuthenticationProtocol of snmpAuthenticationProtocols" [value]="snmpAuthenticationProtocol"> | |
85 | + {{ snmpAuthenticationProtocolTranslation.get(snmpAuthenticationProtocol) }} | |
86 | + </mat-option> | |
87 | + </mat-select> | |
88 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('authenticationProtocol').hasError('required')"> | |
89 | + {{ 'device-profile.snmp.authentication-protocol-required' | translate }} | |
90 | + </mat-error> | |
91 | + </mat-form-field> | |
92 | + <mat-form-field fxFlex> | |
93 | + <mat-label translate>device-profile.snmp.authentication-passphrase</mat-label> | |
94 | + <input matInput formControlName="authenticationPassphrase" required> | |
95 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('authenticationPassphrase').hasError('required') || | |
96 | + snmpDeviceTransportConfigurationFormGroup.get('authenticationPassphrase').hasError('pattern')"> | |
97 | + {{ 'device-profile.snmp.authentication-passphrase-required' | translate }} | |
98 | + </mat-error> | |
99 | + </mat-form-field> | |
100 | + </div> | |
101 | + <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"> | |
102 | + <mat-form-field fxFlex floatLabel="always" hideRequiredMarker> | |
103 | + <mat-label translate>device-profile.snmp.privacy-protocol</mat-label> | |
104 | + <mat-select formControlName="privacyProtocol" required> | |
105 | + <mat-option *ngFor="let snmpPrivacyProtocol of snmpPrivacyProtocols" [value]="snmpPrivacyProtocol"> | |
106 | + {{ snmpPrivacyProtocolTranslation.get(snmpPrivacyProtocol) }} | |
107 | + </mat-option> | |
108 | + </mat-select> | |
109 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('privacyProtocol').hasError('required')"> | |
110 | + {{ 'device-profile.snmp.privacy-protocol-required' | translate }} | |
111 | + </mat-error> | |
112 | + </mat-form-field> | |
113 | + <mat-form-field fxFlex> | |
114 | + <mat-label translate>device-profile.snmp.privacy-passphrase</mat-label> | |
115 | + <input matInput formControlName="privacyPassphrase" required> | |
116 | + <mat-error *ngIf="snmpDeviceTransportConfigurationFormGroup.get('privacyPassphrase').hasError('required') || | |
117 | + snmpDeviceTransportConfigurationFormGroup.get('privacyPassphrase').hasError('pattern')"> | |
118 | + {{ 'device-profile.snmp.privacy-passphrase-required' | translate }} | |
119 | + </mat-error> | |
120 | + </mat-form-field> | |
121 | + </div> | |
122 | + <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"> | |
123 | + <mat-form-field fxFlex> | |
124 | + <mat-label translate>device-profile.snmp.context-name</mat-label> | |
125 | + <input matInput formControlName="contextName"> | |
126 | + </mat-form-field> | |
127 | + <mat-form-field fxFlex> | |
128 | + <mat-label translate>device-profile.snmp.engine-id</mat-label> | |
129 | + <input matInput formControlName="engineId"> | |
130 | + </mat-form-field> | |
131 | + </div> | |
132 | + </section> | |
24 | 133 | </form> | ... | ... |
... | ... | @@ -14,31 +14,57 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | -import {Component, forwardRef, Input, OnInit} from '@angular/core'; | |
18 | -import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; | |
19 | -import {Store} from '@ngrx/store'; | |
20 | -import {AppState} from '@app/core/core.state'; | |
21 | -import {coerceBooleanProperty} from '@angular/cdk/coercion'; | |
17 | +import { Component, forwardRef, Input, OnInit } from '@angular/core'; | |
18 | +import { | |
19 | + ControlValueAccessor, | |
20 | + FormBuilder, | |
21 | + FormGroup, | |
22 | + NG_VALIDATORS, | |
23 | + NG_VALUE_ACCESSOR, | |
24 | + ValidationErrors, | |
25 | + Validator, | |
26 | + Validators | |
27 | +} from '@angular/forms'; | |
28 | +import { Store } from '@ngrx/store'; | |
29 | +import { AppState } from '@app/core/core.state'; | |
30 | +import { coerceBooleanProperty } from '@angular/cdk/coercion'; | |
22 | 31 | import { |
23 | 32 | DeviceTransportConfiguration, |
24 | 33 | DeviceTransportType, |
25 | - SnmpDeviceTransportConfiguration | |
34 | + SnmpAuthenticationProtocol, | |
35 | + SnmpAuthenticationProtocolTranslationMap, | |
36 | + SnmpDeviceProtocolVersion, | |
37 | + SnmpDeviceTransportConfiguration, | |
38 | + SnmpPrivacyProtocol, | |
39 | + SnmpPrivacyProtocolTranslationMap | |
26 | 40 | } from '@shared/models/device.models'; |
41 | +import { isDefinedAndNotNull } from '@core/utils'; | |
27 | 42 | |
28 | 43 | @Component({ |
29 | 44 | selector: 'tb-snmp-device-transport-configuration', |
30 | 45 | templateUrl: './snmp-device-transport-configuration.component.html', |
31 | 46 | styleUrls: [], |
32 | - providers: [{ | |
33 | - provide: NG_VALUE_ACCESSOR, | |
34 | - useExisting: forwardRef(() => SnmpDeviceTransportConfigurationComponent), | |
35 | - multi: true | |
36 | - }] | |
47 | + providers: [ | |
48 | + { | |
49 | + provide: NG_VALUE_ACCESSOR, | |
50 | + useExisting: forwardRef(() => SnmpDeviceTransportConfigurationComponent), | |
51 | + multi: true | |
52 | + }, { | |
53 | + provide: NG_VALIDATORS, | |
54 | + useExisting: forwardRef(() => SnmpDeviceTransportConfigurationComponent), | |
55 | + multi: true | |
56 | + }] | |
37 | 57 | }) |
38 | -export class SnmpDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit { | |
58 | +export class SnmpDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit, Validator { | |
39 | 59 | |
40 | 60 | snmpDeviceTransportConfigurationFormGroup: FormGroup; |
41 | 61 | |
62 | + snmpDeviceProtocolVersions = Object.values(SnmpDeviceProtocolVersion); | |
63 | + snmpAuthenticationProtocols = Object.values(SnmpAuthenticationProtocol); | |
64 | + snmpAuthenticationProtocolTranslation = SnmpAuthenticationProtocolTranslationMap; | |
65 | + snmpPrivacyProtocols = Object.values(SnmpPrivacyProtocol); | |
66 | + snmpPrivacyProtocolTranslation = SnmpPrivacyProtocolTranslationMap; | |
67 | + | |
42 | 68 | private requiredValue: boolean; |
43 | 69 | |
44 | 70 | get required(): boolean { |
... | ... | @@ -53,8 +79,7 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc |
53 | 79 | @Input() |
54 | 80 | disabled: boolean; |
55 | 81 | |
56 | - private propagateChange = (v: any) => { | |
57 | - }; | |
82 | + private propagateChange = (v: any) => { }; | |
58 | 83 | |
59 | 84 | constructor(private store: Store<AppState>, |
60 | 85 | private fb: FormBuilder) { |
... | ... | @@ -69,13 +94,33 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc |
69 | 94 | |
70 | 95 | ngOnInit() { |
71 | 96 | this.snmpDeviceTransportConfigurationFormGroup = this.fb.group({ |
72 | - configuration: [null, Validators.required] | |
97 | + host: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], | |
98 | + port: [null, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | |
99 | + protocolVersion: [SnmpDeviceProtocolVersion.V2C, Validators.required], | |
100 | + community: ['public', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], | |
101 | + username: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], | |
102 | + securityName: ['public', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], | |
103 | + contextName: [null], | |
104 | + authenticationProtocol: [SnmpAuthenticationProtocol.SHA_512, Validators.required], | |
105 | + authenticationPassphrase: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], | |
106 | + privacyProtocol: [SnmpPrivacyProtocol.DES, Validators.required], | |
107 | + privacyPassphrase: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], | |
108 | + engineId: [''] | |
109 | + }); | |
110 | + this.snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').valueChanges.subscribe((protocol: SnmpDeviceProtocolVersion) => { | |
111 | + this.updateDisabledFormValue(protocol); | |
73 | 112 | }); |
74 | 113 | this.snmpDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => { |
75 | 114 | this.updateModel(); |
76 | 115 | }); |
77 | 116 | } |
78 | 117 | |
118 | + validate(): ValidationErrors | null { | |
119 | + return this.snmpDeviceTransportConfigurationFormGroup.valid ? null : { | |
120 | + snmpDeviceTransportConfiguration: false | |
121 | + }; | |
122 | + } | |
123 | + | |
79 | 124 | setDisabledState(isDisabled: boolean): void { |
80 | 125 | this.disabled = isDisabled; |
81 | 126 | if (this.disabled) { |
... | ... | @@ -86,13 +131,46 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc |
86 | 131 | } |
87 | 132 | |
88 | 133 | writeValue(value: SnmpDeviceTransportConfiguration | null): void { |
89 | - this.snmpDeviceTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false}); | |
134 | + if (isDefinedAndNotNull(value)) { | |
135 | + this.snmpDeviceTransportConfigurationFormGroup.patchValue(value, {emitEvent: false}); | |
136 | + if (this.snmpDeviceTransportConfigurationFormGroup.enabled) { | |
137 | + this.updateDisabledFormValue(value.protocolVersion || SnmpDeviceProtocolVersion.V2C); | |
138 | + } | |
139 | + } | |
140 | + } | |
141 | + | |
142 | + isV3protocolVersion(): boolean { | |
143 | + return this.snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').value === SnmpDeviceProtocolVersion.V3; | |
144 | + } | |
145 | + | |
146 | + private updateDisabledFormValue(protocol: SnmpDeviceProtocolVersion) { | |
147 | + if (protocol === SnmpDeviceProtocolVersion.V3) { | |
148 | + this.snmpDeviceTransportConfigurationFormGroup.get('community').disable({emitEvent: false}); | |
149 | + this.snmpDeviceTransportConfigurationFormGroup.get('username').enable({emitEvent: false}); | |
150 | + this.snmpDeviceTransportConfigurationFormGroup.get('securityName').enable({emitEvent: false}); | |
151 | + this.snmpDeviceTransportConfigurationFormGroup.get('contextName').enable({emitEvent: false}); | |
152 | + this.snmpDeviceTransportConfigurationFormGroup.get('authenticationProtocol').enable({emitEvent: false}); | |
153 | + this.snmpDeviceTransportConfigurationFormGroup.get('authenticationPassphrase').enable({emitEvent: false}); | |
154 | + this.snmpDeviceTransportConfigurationFormGroup.get('privacyProtocol').enable({emitEvent: false}); | |
155 | + this.snmpDeviceTransportConfigurationFormGroup.get('privacyPassphrase').enable({emitEvent: false}); | |
156 | + this.snmpDeviceTransportConfigurationFormGroup.get('engineId').enable({emitEvent: false}); | |
157 | + } else { | |
158 | + this.snmpDeviceTransportConfigurationFormGroup.get('community').enable({emitEvent: false}); | |
159 | + this.snmpDeviceTransportConfigurationFormGroup.get('username').disable({emitEvent: false}); | |
160 | + this.snmpDeviceTransportConfigurationFormGroup.get('securityName').disable({emitEvent: false}); | |
161 | + this.snmpDeviceTransportConfigurationFormGroup.get('contextName').disable({emitEvent: false}); | |
162 | + this.snmpDeviceTransportConfigurationFormGroup.get('authenticationProtocol').disable({emitEvent: false}); | |
163 | + this.snmpDeviceTransportConfigurationFormGroup.get('authenticationPassphrase').disable({emitEvent: false}); | |
164 | + this.snmpDeviceTransportConfigurationFormGroup.get('privacyProtocol').disable({emitEvent: false}); | |
165 | + this.snmpDeviceTransportConfigurationFormGroup.get('privacyPassphrase').disable({emitEvent: false}); | |
166 | + this.snmpDeviceTransportConfigurationFormGroup.get('engineId').disable({emitEvent: false}); | |
167 | + } | |
90 | 168 | } |
91 | 169 | |
92 | 170 | private updateModel() { |
93 | 171 | let configuration: DeviceTransportConfiguration = null; |
94 | 172 | if (this.snmpDeviceTransportConfigurationFormGroup.valid) { |
95 | - configuration = this.snmpDeviceTransportConfigurationFormGroup.getRawValue().configuration; | |
173 | + configuration = this.snmpDeviceTransportConfigurationFormGroup.value; | |
96 | 174 | configuration.type = DeviceTransportType.SNMP; |
97 | 175 | } |
98 | 176 | this.propagateChange(configuration); | ... | ... |
... | ... | @@ -362,7 +362,7 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT |
362 | 362 | break; |
363 | 363 | case DeviceTransportType.SNMP: |
364 | 364 | const snmpTransportConfiguration: SnmpDeviceProfileTransportConfiguration = { |
365 | - timeoutMs: 0, | |
365 | + timeoutMs: 500, | |
366 | 366 | retries: 0, |
367 | 367 | communicationConfigs: null |
368 | 368 | }; |
... | ... | @@ -394,7 +394,12 @@ export function createDeviceTransportConfiguration(type: DeviceTransportType): D |
394 | 394 | transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M}; |
395 | 395 | break; |
396 | 396 | case DeviceTransportType.SNMP: |
397 | - const snmpTransportConfiguration: SnmpDeviceTransportConfiguration = {}; | |
397 | + const snmpTransportConfiguration: SnmpDeviceTransportConfiguration = { | |
398 | + host: 'localhost', | |
399 | + port: 161, | |
400 | + protocolVersion: SnmpDeviceProtocolVersion.V2C, | |
401 | + community: 'public' | |
402 | + }; | |
398 | 403 | transportConfiguration = {...snmpTransportConfiguration, type: DeviceTransportType.SNMP}; |
399 | 404 | break; |
400 | 405 | } |
... | ... | @@ -572,8 +577,57 @@ export interface Lwm2mDeviceTransportConfiguration { |
572 | 577 | [key: string]: any; |
573 | 578 | } |
574 | 579 | |
580 | +export enum SnmpDeviceProtocolVersion { | |
581 | + V1 = 'V1', | |
582 | + V2C = 'V2C', | |
583 | + V3 = 'V3' | |
584 | +} | |
585 | + | |
586 | +export enum SnmpAuthenticationProtocol { | |
587 | + SHA_1 = 'SHA_1', | |
588 | + SHA_224 = 'SHA_224', | |
589 | + SHA_256 = 'SHA_256', | |
590 | + SHA_384 = 'SHA_384', | |
591 | + SHA_512 = 'SHA_512', | |
592 | + MD5 = 'MD%' | |
593 | +} | |
594 | + | |
595 | +export const SnmpAuthenticationProtocolTranslationMap = new Map<SnmpAuthenticationProtocol, string>([ | |
596 | + [SnmpAuthenticationProtocol.SHA_1, 'SHA-1'], | |
597 | + [SnmpAuthenticationProtocol.SHA_224, 'SHA-224'], | |
598 | + [SnmpAuthenticationProtocol.SHA_256, 'SHA-256'], | |
599 | + [SnmpAuthenticationProtocol.SHA_384, 'SHA-384'], | |
600 | + [SnmpAuthenticationProtocol.SHA_512, 'SHA-512'], | |
601 | + [SnmpAuthenticationProtocol.MD5, 'MD5'] | |
602 | +]); | |
603 | + | |
604 | +export enum SnmpPrivacyProtocol { | |
605 | + DES = 'DES', | |
606 | + AES_128 = 'AES_128', | |
607 | + AES_192 = 'AES_192', | |
608 | + AES_256 = 'AES_256' | |
609 | +} | |
610 | + | |
611 | +export const SnmpPrivacyProtocolTranslationMap = new Map<SnmpPrivacyProtocol, string>([ | |
612 | + [SnmpPrivacyProtocol.DES, 'DES'], | |
613 | + [SnmpPrivacyProtocol.AES_128, 'AES-128'], | |
614 | + [SnmpPrivacyProtocol.AES_192, 'AES-192'], | |
615 | + [SnmpPrivacyProtocol.AES_256, 'AES-256'], | |
616 | +]); | |
617 | + | |
575 | 618 | export interface SnmpDeviceTransportConfiguration { |
576 | - [key: string]: any; | |
619 | + host?: string; | |
620 | + port?: number; | |
621 | + protocolVersion?: SnmpDeviceProtocolVersion; | |
622 | + community?: string; | |
623 | + username?: string; | |
624 | + securityName?: string; | |
625 | + contextName?: string; | |
626 | + authenticationProtocol?: SnmpAuthenticationProtocol; | |
627 | + authenticationPassphrase?: string; | |
628 | + privacyProtocol?: SnmpPrivacyProtocol; | |
629 | + privacyPassphrase?: string; | |
630 | + engineId?: string; | |
577 | 631 | } |
578 | 632 | |
579 | 633 | export type DeviceTransportConfigurations = DefaultDeviceTransportConfiguration & | ... | ... |
... | ... | @@ -1301,16 +1301,35 @@ |
1301 | 1301 | "snmp": { |
1302 | 1302 | "add-communication-config": "Add communication config", |
1303 | 1303 | "add-mapping": "Add mapping", |
1304 | + "authentication-passphrase": "Authentication passphrase", | |
1305 | + "authentication-passphrase-required": "Authentication passphrase is required.", | |
1306 | + "authentication-protocol": "Authentication protocol", | |
1307 | + "authentication-protocol-required": "Authentication protocol is required.", | |
1304 | 1308 | "communication-configs": "Communication configs", |
1309 | + "community": "Community string", | |
1310 | + "community-required": "Community string is required.", | |
1311 | + "context-name": "Context name", | |
1305 | 1312 | "data-key": "Data key", |
1306 | 1313 | "data-key-required": "Data key is required.", |
1307 | 1314 | "data-type": "Data type", |
1308 | 1315 | "data-type-required": "Data type is required.", |
1316 | + "engine-id": "Engine ID", | |
1317 | + "host": "Host", | |
1318 | + "host-required": "Host is required.", | |
1309 | 1319 | "oid": "OID", |
1310 | 1320 | "oid-pattern": "Invalid OID format.", |
1311 | 1321 | "oid-required": "OID is required.", |
1312 | 1322 | "please-add-communication-config": "Please add communication config", |
1313 | 1323 | "please-add-mapping-config": "Please add mapping config", |
1324 | + "port": "Port", | |
1325 | + "port-format": "Invalid port format.", | |
1326 | + "port-required": "Port is required.", | |
1327 | + "privacy-passphrase": "Privacy passphrase", | |
1328 | + "privacy-passphrase-required": "Privacy passphrase is required.", | |
1329 | + "privacy-protocol": "Privacy protocol", | |
1330 | + "privacy-protocol-required": "Privacy protocol is required.", | |
1331 | + "protocol-version": "Protocol version", | |
1332 | + "protocol-version-required": "Protocol version is required.", | |
1314 | 1333 | "querying-frequency": "Querying frequency, ms", |
1315 | 1334 | "querying-frequency-invalid-format": "Querying frequency must be a positive integer.", |
1316 | 1335 | "querying-frequency-required": "Querying frequency is required.", |
... | ... | @@ -1319,9 +1338,13 @@ |
1319 | 1338 | "retries-required": "Retries is required.", |
1320 | 1339 | "scope": "Scope", |
1321 | 1340 | "scope-required": "Scope is required.", |
1341 | + "security-name": "Security name", | |
1342 | + "security-name-required": "Security name is required.", | |
1322 | 1343 | "timeout-ms": "Timeout, ms", |
1323 | 1344 | "timeout-ms-invalid-format": "Timeout must be a positive integer.", |
1324 | - "timeout-ms-required": "Timeout is required." | |
1345 | + "timeout-ms-required": "Timeout is required.", | |
1346 | + "user-name": "User name", | |
1347 | + "user-name-required": "User name is required." | |
1325 | 1348 | } |
1326 | 1349 | }, |
1327 | 1350 | "dialog": { | ... | ... |