Commit 75801045cfcdda85b90973d7e3079b22b747de52
1 parent
eec4f5a4
UI: Add SNMP device profile configuration
Showing
15 changed files
with
834 additions
and
43 deletions
... | ... | @@ -99,7 +99,6 @@ import { DeviceProfileDialogComponent } from '@home/components/profile/device-pr |
99 | 99 | import { DeviceProfileAutocompleteComponent } from '@home/components/profile/device-profile-autocomplete.component'; |
100 | 100 | import { MqttDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component'; |
101 | 101 | import { CoapDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/coap-device-profile-transport-configuration.component'; |
102 | -import { SnmpDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/snmp-device-profile-transport-configuration.component'; | |
103 | 102 | import { DeviceProfileAlarmsComponent } from '@home/components/profile/alarm/device-profile-alarms.component'; |
104 | 103 | import { DeviceProfileAlarmComponent } from '@home/components/profile/alarm/device-profile-alarm.component'; |
105 | 104 | import { CreateAlarmRulesComponent } from '@home/components/profile/alarm/create-alarm-rules.component'; |
... | ... | @@ -143,6 +142,7 @@ import { SecurityConfigLwm2mComponent } from '@home/components/device/security-c |
143 | 142 | import { SecurityConfigLwm2mServerComponent } from '@home/components/device/security-config-lwm2m-server.component'; |
144 | 143 | import { DashboardImageDialogComponent } from '@home/components/dashboard-page/dashboard-image-dialog.component'; |
145 | 144 | import { WidgetContainerComponent } from '@home/components/widget/widget-container.component'; |
145 | +import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snpm/snmp-device-profile-transport.module'; | |
146 | 146 | |
147 | 147 | @NgModule({ |
148 | 148 | declarations: |
... | ... | @@ -228,7 +228,6 @@ import { WidgetContainerComponent } from '@home/components/widget/widget-contain |
228 | 228 | DefaultDeviceProfileTransportConfigurationComponent, |
229 | 229 | MqttDeviceProfileTransportConfigurationComponent, |
230 | 230 | CoapDeviceProfileTransportConfigurationComponent, |
231 | - SnmpDeviceProfileTransportConfigurationComponent, | |
232 | 231 | DeviceProfileTransportConfigurationComponent, |
233 | 232 | CreateAlarmRulesComponent, |
234 | 233 | AlarmRuleComponent, |
... | ... | @@ -272,6 +271,7 @@ import { WidgetContainerComponent } from '@home/components/widget/widget-contain |
272 | 271 | SharedModule, |
273 | 272 | SharedHomeComponentsModule, |
274 | 273 | Lwm2mProfileComponentsModule, |
274 | + SnmpDeviceProfileTransportModule, | |
275 | 275 | StatesControllerModule |
276 | 276 | ], |
277 | 277 | exports: [ |
... | ... | @@ -339,7 +339,6 @@ import { WidgetContainerComponent } from '@home/components/widget/widget-contain |
339 | 339 | DefaultDeviceProfileTransportConfigurationComponent, |
340 | 340 | MqttDeviceProfileTransportConfigurationComponent, |
341 | 341 | CoapDeviceProfileTransportConfigurationComponent, |
342 | - SnmpDeviceProfileTransportConfigurationComponent, | |
343 | 342 | DeviceProfileTransportConfigurationComponent, |
344 | 343 | CreateAlarmRulesComponent, |
345 | 344 | AlarmRuleComponent, | ... | ... |
... | ... | @@ -89,7 +89,9 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu |
89 | 89 | if (configuration) { |
90 | 90 | delete configuration.type; |
91 | 91 | } |
92 | - this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); | |
92 | + setTimeout(() => { | |
93 | + this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); | |
94 | + }); | |
93 | 95 | } |
94 | 96 | |
95 | 97 | private updateModel() { | ... | ... |
ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.html
deleted
100644 → 0
1 | -<!-- | |
2 | - | |
3 | - Copyright © 2016-2021 The Thingsboard Authors | |
4 | - | |
5 | - Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | - you may not use this file except in compliance with the License. | |
7 | - You may obtain a copy of the License at | |
8 | - | |
9 | - http://www.apache.org/licenses/LICENSE-2.0 | |
10 | - | |
11 | - Unless required by applicable law or agreed to in writing, software | |
12 | - distributed under the License is distributed on an "AS IS" BASIS, | |
13 | - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | - See the License for the specific language governing permissions and | |
15 | - limitations under the License. | |
16 | - | |
17 | ---> | |
18 | -<form [formGroup]="snmpDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;"> | |
19 | - <tb-json-object-edit | |
20 | - required | |
21 | - formControlName="configuration"> | |
22 | - </tb-json-object-edit> | |
23 | -</form> |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2021 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<div fxLayout="column"> | |
19 | + <div *ngFor="let deviceProfileCommunication of communicationConfigFormArray().controls; let $index = index; | |
20 | + last as isLast;" fxLayout="row" fxLayoutAlign="start center" | |
21 | + fxLayoutGap="8px" class="scope-row" [formGroup]="deviceProfileCommunication"> | |
22 | + <div class="communication-config" fxFlex fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start"> | |
23 | + <mat-form-field class="spec mat-block" floatLabel="always" hideRequiredMarker> | |
24 | + <mat-label translate>device-profile.snmp.scope</mat-label> | |
25 | + <mat-select formControlName="spec" required> | |
26 | + <mat-option *ngFor="let snmpSpecType of snmpSpecTypes" [value]="snmpSpecType" | |
27 | + [disabled]="isDisabledSeverity(snmpSpecType, $index)"> | |
28 | + {{ snmpSpecTypeTranslationMap.get(snmpSpecType) }} | |
29 | + </mat-option> | |
30 | + </mat-select> | |
31 | + <mat-error *ngIf="deviceProfileCommunication.get('spec').hasError('required')"> | |
32 | + {{ 'device-profile.snmp.scope-required' | translate }} | |
33 | + </mat-error> | |
34 | + </mat-form-field> | |
35 | + <mat-divider vertical></mat-divider> | |
36 | + <section fxFlex fxLayout="column"> | |
37 | + <mat-form-field *ngIf="isShowFrequency(deviceProfileCommunication.get('spec').value)"> | |
38 | + <mat-label translate>device-profile.snmp.querying-frequency</mat-label> | |
39 | + <input matInput formControlName="queryingFrequencyMs" type="number" min="0" required/> | |
40 | + <mat-error *ngIf="deviceProfileCommunication.get('queryingFrequencyMs').hasError('required')"> | |
41 | + {{ 'device-profile.snmp.querying-frequency-required' | translate }} | |
42 | + </mat-error> | |
43 | + <mat-error *ngIf="deviceProfileCommunication.get('queryingFrequencyMs').hasError('pattern') || | |
44 | + deviceProfileCommunication.get('queryingFrequencyMs').hasError('min')"> | |
45 | + {{ 'device-profile.snmp.querying-frequency-invalid-format' | translate }} | |
46 | + </mat-error> | |
47 | + </mat-form-field> | |
48 | + <tb-snmp-device-profile-mapping formControlName="mappings"> | |
49 | + </tb-snmp-device-profile-mapping> | |
50 | + </section> | |
51 | + </div> | |
52 | + <button *ngIf="!disabled" | |
53 | + mat-icon-button color="primary" style="min-width: 40px;" | |
54 | + type="button" | |
55 | + (click)="removeCommunicationConfig($index)" | |
56 | + matTooltip="{{ 'action.remove' | translate }}" | |
57 | + matTooltipPosition="above"> | |
58 | + <mat-icon>remove_circle_outline</mat-icon> | |
59 | + </button> | |
60 | + </div> | |
61 | + <div *ngIf="!communicationConfigFormArray().controls.length && !disabled"> | |
62 | + <span fxLayoutAlign="center center" class="tb-prompt required required-text" translate>device-profile.snmp.please-add-communication-config</span> | |
63 | + </div> | |
64 | + <div *ngIf="!disabled && isAddEnabled"> | |
65 | + <button mat-stroked-button color="primary" | |
66 | + type="button" | |
67 | + (click)="addCommunicationConfig()"> | |
68 | + <mat-icon class="button-icon">add_circle_outline</mat-icon> | |
69 | + {{ 'device-profile.snmp.add-communication-config' | translate }} | |
70 | + </button> | |
71 | + </div> | |
72 | +</div> | ... | ... |
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 | + .communication-config { | |
18 | + border: 2px groove rgba(0, 0, 0, 0.25); | |
19 | + border-radius: 4px; | |
20 | + padding: 8px; | |
21 | + min-width: 0; | |
22 | + } | |
23 | + | |
24 | + .scope-row { | |
25 | + padding-bottom: 8px; | |
26 | + } | |
27 | + | |
28 | + .required-text { | |
29 | + margin: 16px 0 | |
30 | + } | |
31 | +} | |
32 | + | |
33 | +:host ::ng-deep { | |
34 | + .mat-form-field.spec { | |
35 | + .mat-form-field-infix { | |
36 | + width: 160px; | |
37 | + } | |
38 | + } | |
39 | + .button-icon{ | |
40 | + font-size: 20px; | |
41 | + width: 20px; | |
42 | + height: 20px; | |
43 | + } | |
44 | +} | ... | ... |
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 { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; | |
18 | +import { | |
19 | + AbstractControl, | |
20 | + ControlValueAccessor, | |
21 | + FormArray, | |
22 | + FormBuilder, | |
23 | + FormGroup, | |
24 | + NG_VALIDATORS, | |
25 | + NG_VALUE_ACCESSOR, | |
26 | + Validator, | |
27 | + Validators | |
28 | +} from '@angular/forms'; | |
29 | +import { SnmpCommunicationConfig, SnmpSpecType, SnmpSpecTypeTranslationMap } from '@shared/models/device.models'; | |
30 | +import { Subject, Subscription } from 'rxjs'; | |
31 | +import { isUndefinedOrNull } from '@core/utils'; | |
32 | +import { takeUntil } from 'rxjs/operators'; | |
33 | + | |
34 | +@Component({ | |
35 | + selector: 'tb-snmp-device-profile-communication-config', | |
36 | + templateUrl: './snmp-device-profile-communication-config.component.html', | |
37 | + styleUrls: ['./snmp-device-profile-communication-config.component.scss'], | |
38 | + providers: [ | |
39 | + { | |
40 | + provide: NG_VALUE_ACCESSOR, | |
41 | + useExisting: forwardRef(() => SnmpDeviceProfileCommunicationConfigComponent), | |
42 | + multi: true | |
43 | + }, | |
44 | + { | |
45 | + provide: NG_VALIDATORS, | |
46 | + useExisting: forwardRef(() => SnmpDeviceProfileCommunicationConfigComponent), | |
47 | + multi: true | |
48 | + }] | |
49 | +}) | |
50 | +export class SnmpDeviceProfileCommunicationConfigComponent implements OnInit, OnDestroy, ControlValueAccessor, Validator { | |
51 | + | |
52 | + snmpSpecTypes = Object.values(SnmpSpecType); | |
53 | + snmpSpecTypeTranslationMap = SnmpSpecTypeTranslationMap; | |
54 | + | |
55 | + deviceProfileCommunicationConfig: FormGroup; | |
56 | + | |
57 | + @Input() | |
58 | + disabled: boolean; | |
59 | + | |
60 | + private usedSpecType: SnmpSpecType[] = []; | |
61 | + private valueChange$: Subscription = null; | |
62 | + private destroy$ = new Subject(); | |
63 | + private propagateChange = (v: any) => { }; | |
64 | + | |
65 | + constructor(private fb: FormBuilder) { } | |
66 | + | |
67 | + ngOnInit(): void { | |
68 | + this.deviceProfileCommunicationConfig = this.fb.group({ | |
69 | + communicationConfig: this.fb.array([]) | |
70 | + }); | |
71 | + } | |
72 | + | |
73 | + ngOnDestroy() { | |
74 | + if (this.valueChange$) { | |
75 | + this.valueChange$.unsubscribe(); | |
76 | + } | |
77 | + this.destroy$.next(); | |
78 | + this.destroy$.complete(); | |
79 | + } | |
80 | + | |
81 | + communicationConfigFormArray(): FormArray { | |
82 | + return this.deviceProfileCommunicationConfig.get('communicationConfig') as FormArray; | |
83 | + } | |
84 | + | |
85 | + registerOnChange(fn: any): void { | |
86 | + this.propagateChange = fn; | |
87 | + } | |
88 | + | |
89 | + registerOnTouched(fn: any): void { | |
90 | + } | |
91 | + | |
92 | + setDisabledState(isDisabled: boolean) { | |
93 | + this.disabled = isDisabled; | |
94 | + if (this.disabled) { | |
95 | + this.deviceProfileCommunicationConfig.disable({emitEvent: false}); | |
96 | + } else { | |
97 | + this.deviceProfileCommunicationConfig.enable({emitEvent: false}); | |
98 | + } | |
99 | + } | |
100 | + | |
101 | + writeValue(communicationConfig: SnmpCommunicationConfig[]) { | |
102 | + if (this.valueChange$) { | |
103 | + this.valueChange$.unsubscribe(); | |
104 | + } | |
105 | + const communicationConfigControl: Array<AbstractControl> = []; | |
106 | + if (communicationConfig) { | |
107 | + communicationConfig.forEach((config) => { | |
108 | + communicationConfigControl.push(this.createdFormGroup(config)); | |
109 | + }); | |
110 | + } | |
111 | + this.deviceProfileCommunicationConfig.setControl('communicationConfig', this.fb.array(communicationConfigControl)); | |
112 | + if (!communicationConfig || !communicationConfig.length) { | |
113 | + this.addCommunicationConfig(); | |
114 | + } | |
115 | + if (this.disabled) { | |
116 | + this.deviceProfileCommunicationConfig.disable({emitEvent: false}); | |
117 | + } else { | |
118 | + this.deviceProfileCommunicationConfig.enable({emitEvent: false}); | |
119 | + } | |
120 | + this.valueChange$ = this.deviceProfileCommunicationConfig.valueChanges.subscribe(() => { | |
121 | + this.updateModel(); | |
122 | + }); | |
123 | + this.updateUsedSpecType(); | |
124 | + if (!this.disabled && !this.deviceProfileCommunicationConfig.valid) { | |
125 | + this.updateModel(); | |
126 | + } | |
127 | + } | |
128 | + | |
129 | + public validate() { | |
130 | + return this.deviceProfileCommunicationConfig.valid && this.deviceProfileCommunicationConfig.value.communicationConfig.length ? null : { | |
131 | + communicationConfig: false | |
132 | + }; | |
133 | + } | |
134 | + | |
135 | + public removeCommunicationConfig(index: number) { | |
136 | + this.communicationConfigFormArray().removeAt(index); | |
137 | + } | |
138 | + | |
139 | + | |
140 | + get isAddEnabled(): boolean { | |
141 | + return this.communicationConfigFormArray().length !== Object.keys(SnmpSpecType).length; | |
142 | + } | |
143 | + | |
144 | + public addCommunicationConfig() { | |
145 | + this.communicationConfigFormArray().push(this.createdFormGroup()); | |
146 | + this.deviceProfileCommunicationConfig.updateValueAndValidity(); | |
147 | + if (!this.deviceProfileCommunicationConfig.valid) { | |
148 | + this.updateModel(); | |
149 | + } | |
150 | + } | |
151 | + | |
152 | + private getFirstUnusedSeverity(): SnmpSpecType { | |
153 | + for (const type of Object.values(SnmpSpecType)) { | |
154 | + if (this.usedSpecType.indexOf(type) === -1) { | |
155 | + return type; | |
156 | + } | |
157 | + } | |
158 | + return null; | |
159 | + } | |
160 | + | |
161 | + public isDisabledSeverity(type: SnmpSpecType, index: number): boolean { | |
162 | + const usedIndex = this.usedSpecType.indexOf(type); | |
163 | + return usedIndex > -1 && usedIndex !== index; | |
164 | + } | |
165 | + | |
166 | + public isShowFrequency(type: SnmpSpecType): boolean { | |
167 | + return type === SnmpSpecType.TELEMETRY_QUERYING || type === SnmpSpecType.CLIENT_ATTRIBUTES_QUERYING; | |
168 | + } | |
169 | + | |
170 | + private updateUsedSpecType() { | |
171 | + this.usedSpecType = []; | |
172 | + const value: SnmpCommunicationConfig[] = this.deviceProfileCommunicationConfig.get('communicationConfig').value; | |
173 | + value.forEach((rule, index) => { | |
174 | + this.usedSpecType[index] = rule.spec; | |
175 | + }); | |
176 | + } | |
177 | + | |
178 | + private createdFormGroup(value?: SnmpCommunicationConfig): FormGroup { | |
179 | + if (isUndefinedOrNull(value)) { | |
180 | + value = { | |
181 | + spec: this.getFirstUnusedSeverity(), | |
182 | + queryingFrequencyMs: 0, | |
183 | + mappings: null | |
184 | + }; | |
185 | + } | |
186 | + const form = this.fb.group({ | |
187 | + spec: [value.spec, Validators.required], | |
188 | + mappings: [value.mappings] | |
189 | + }); | |
190 | + if (this.isShowFrequency(value.spec)) { | |
191 | + form.addControl('queryingFrequencyMs', | |
192 | + this.fb.control(value.queryingFrequencyMs, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')])); | |
193 | + } | |
194 | + form.get('spec').valueChanges.pipe( | |
195 | + takeUntil(this.destroy$) | |
196 | + ).subscribe(spec => { | |
197 | + if (this.isShowFrequency(spec)) { | |
198 | + form.addControl('queryingFrequencyMs', | |
199 | + this.fb.control(0, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')])); | |
200 | + } else { | |
201 | + form.removeControl('queryingFrequencyMs'); | |
202 | + } | |
203 | + }); | |
204 | + return form; | |
205 | + } | |
206 | + | |
207 | + private updateModel() { | |
208 | + const value: SnmpCommunicationConfig[] = this.deviceProfileCommunicationConfig.get('communicationConfig').value; | |
209 | + value.forEach(config => { | |
210 | + if (!this.isShowFrequency(config.spec)) { | |
211 | + delete config.queryingFrequencyMs; | |
212 | + } | |
213 | + }); | |
214 | + this.updateUsedSpecType(); | |
215 | + this.propagateChange(value); | |
216 | + } | |
217 | + | |
218 | +} | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2021 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<div fxFlex fxLayout="column" class="mapping-config"> | |
19 | + <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" fxFlex="100"> | |
20 | + <div fxFlex fxLayout="row" fxLayoutGap="8px"> | |
21 | + <label fxFlex="26" class="tb-title no-padding" translate>device-profile.snmp.data-type</label> | |
22 | + <label fxFlex="37" class="tb-title no-padding" translate>device-profile.snmp.data-key</label> | |
23 | + <label fxFlex="37" class="tb-title no-padding" translate>device-profile.snmp.oid</label> | |
24 | + <span style="min-width: 40px" [fxShow]="!disabled"></span> | |
25 | + </div> | |
26 | + </div> | |
27 | + <mat-divider></mat-divider> | |
28 | + <div *ngFor="let mappingConfig of mappingsConfigFormArray().controls; let $index = index; | |
29 | + last as isLast;" fxLayout="row" fxLayoutAlign="start center" | |
30 | + fxLayoutGap="8px" [formGroup]="mappingConfig" class="mapping-list"> | |
31 | + <div fxFlex fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start"> | |
32 | + <mat-form-field fxFlex="26" floatLabel="always" hideRequiredMarker> | |
33 | + <mat-label></mat-label> | |
34 | + <mat-select formControlName="dataType" required> | |
35 | + <mat-option *ngFor="let dataType of dataTypes" [value]="dataType"> | |
36 | + {{ dataTypesTranslationMap.get(dataType) | translate }} | |
37 | + </mat-option> | |
38 | + </mat-select> | |
39 | + <mat-error *ngIf="mappingConfig.get('dataType').hasError('required')"> | |
40 | + {{ 'device-profile.snmp.data-type-required' | translate }} | |
41 | + </mat-error> | |
42 | + </mat-form-field> | |
43 | + <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="37"> | |
44 | + <mat-label></mat-label> | |
45 | + <input matInput formControlName="key" required/> | |
46 | + <mat-error *ngIf="mappingConfig.get('key').hasError('required')"> | |
47 | + {{ 'device-profile.snmp.data-key-required' | translate }} | |
48 | + </mat-error> | |
49 | + </mat-form-field> | |
50 | + <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="37"> | |
51 | + <mat-label></mat-label> | |
52 | + <input matInput formControlName="oid" required/> | |
53 | + <mat-error *ngIf="mappingConfig.get('oid').hasError('required')"> | |
54 | + {{ 'device-profile.snmp.oid-required' | translate }} | |
55 | + </mat-error> | |
56 | + <mat-error *ngIf="mappingConfig.get('oid').hasError('pattern')"> | |
57 | + {{ 'device-profile.snmp.oid-pattern' | translate }} | |
58 | + </mat-error> | |
59 | + </mat-form-field> | |
60 | + <button *ngIf="!disabled" | |
61 | + mat-icon-button color="primary" | |
62 | + type="button" | |
63 | + (click)="removeMappingConfig($index)" | |
64 | + matTooltip="{{ 'action.remove' | translate }}" | |
65 | + matTooltipPosition="above"> | |
66 | + <mat-icon>close</mat-icon> | |
67 | + </button> | |
68 | + </div> | |
69 | + </div> | |
70 | + <div *ngIf="!mappingsConfigFormArray().controls.length && !disabled"> | |
71 | + <span fxLayoutAlign="center center" class="tb-prompt required required-text" translate>device-profile.snmp.please-add-mapping-config</span> | |
72 | + </div> | |
73 | + <div *ngIf="!disabled"> | |
74 | + <button mat-stroked-button color="primary" | |
75 | + type="button" | |
76 | + (click)="addMappingConfig()"> | |
77 | + <mat-icon class="button-icon">add_circle_outline</mat-icon> | |
78 | + {{ 'device-profile.snmp.add-mapping' | translate }} | |
79 | + </button> | |
80 | + </div> | |
81 | +</div> | ... | ... |
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 | + .mapping-config { | |
18 | + min-width: 518px; | |
19 | + } | |
20 | + .mapping-list { | |
21 | + padding-bottom: 8px; | |
22 | + height: 46px; | |
23 | + } | |
24 | + | |
25 | + .required-text { | |
26 | + margin: 14px 0; | |
27 | + } | |
28 | +} | |
29 | + | |
30 | +:host ::ng-deep { | |
31 | + .mapping-list { | |
32 | + mat-form-field { | |
33 | + .mat-form-field-wrapper { | |
34 | + padding-bottom: 0; | |
35 | + .mat-form-field-infix { | |
36 | + border-top-width: 0.2em; | |
37 | + width: auto; | |
38 | + min-width: auto; | |
39 | + } | |
40 | + .mat-form-field-underline { | |
41 | + bottom: 0; | |
42 | + } | |
43 | + } | |
44 | + } | |
45 | + } | |
46 | +} | ... | ... |
ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.ts
0 → 100644
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 { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; | |
18 | +import { | |
19 | + AbstractControl, | |
20 | + ControlValueAccessor, | |
21 | + FormArray, | |
22 | + FormBuilder, | |
23 | + FormGroup, | |
24 | + NG_VALIDATORS, | |
25 | + NG_VALUE_ACCESSOR, | |
26 | + ValidationErrors, | |
27 | + Validator, | |
28 | + Validators | |
29 | +} from '@angular/forms'; | |
30 | +import { SnmpMapping } from '@shared/models/device.models'; | |
31 | +import { Subscription } from 'rxjs'; | |
32 | +import { DataType, DataTypeTranslationMap } from '@shared/models/constants'; | |
33 | +import { isUndefinedOrNull } from '@core/utils'; | |
34 | + | |
35 | +@Component({ | |
36 | + selector: 'tb-snmp-device-profile-mapping', | |
37 | + templateUrl: './snmp-device-profile-mapping.component.html', | |
38 | + styleUrls: ['./snmp-device-profile-mapping.component.scss'], | |
39 | + providers: [ | |
40 | + { | |
41 | + provide: NG_VALUE_ACCESSOR, | |
42 | + useExisting: forwardRef(() => SnmpDeviceProfileMappingComponent), | |
43 | + multi: true | |
44 | + }, | |
45 | + { | |
46 | + provide: NG_VALIDATORS, | |
47 | + useExisting: forwardRef(() => SnmpDeviceProfileMappingComponent), | |
48 | + multi: true | |
49 | + }] | |
50 | +}) | |
51 | +export class SnmpDeviceProfileMappingComponent implements OnInit, OnDestroy, ControlValueAccessor, Validator { | |
52 | + | |
53 | + mappingsConfigForm: FormGroup; | |
54 | + | |
55 | + dataTypes = Object.values(DataType); | |
56 | + dataTypesTranslationMap = DataTypeTranslationMap; | |
57 | + | |
58 | + @Input() | |
59 | + disabled: boolean; | |
60 | + | |
61 | + private readonly oidPattern: RegExp = /^\.?([0-2])((\.0)|(\.[1-9][0-9]*))*$/; | |
62 | + | |
63 | + private valueChange$: Subscription = null; | |
64 | + private propagateChange = (v: any) => { }; | |
65 | + | |
66 | + constructor(private fb: FormBuilder) { } | |
67 | + | |
68 | + ngOnInit() { | |
69 | + this.mappingsConfigForm = this.fb.group({ | |
70 | + mappings: this.fb.array([]) | |
71 | + }); | |
72 | + } | |
73 | + | |
74 | + ngOnDestroy() { | |
75 | + if (this.valueChange$) { | |
76 | + this.valueChange$.unsubscribe(); | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + registerOnChange(fn: any) { | |
81 | + this.propagateChange = fn; | |
82 | + } | |
83 | + | |
84 | + registerOnTouched(fn: any) { | |
85 | + } | |
86 | + | |
87 | + setDisabledState(isDisabled: boolean) { | |
88 | + this.disabled = isDisabled; | |
89 | + if (this.disabled) { | |
90 | + this.mappingsConfigForm.disable({emitEvent: false}); | |
91 | + } else { | |
92 | + this.mappingsConfigForm.enable({emitEvent: false}); | |
93 | + } | |
94 | + } | |
95 | + | |
96 | + validate(): ValidationErrors | null { | |
97 | + return this.mappingsConfigForm.valid && this.mappingsConfigForm.value.mappings.length ? null : { | |
98 | + mapping: false | |
99 | + }; | |
100 | + } | |
101 | + | |
102 | + writeValue(mappings: SnmpMapping[]) { | |
103 | + if (this.valueChange$) { | |
104 | + this.valueChange$.unsubscribe(); | |
105 | + } | |
106 | + const mappingsControl: Array<AbstractControl> = []; | |
107 | + if (mappings) { | |
108 | + mappings.forEach((config) => { | |
109 | + mappingsControl.push(this.createdFormGroup(config)); | |
110 | + }); | |
111 | + } | |
112 | + this.mappingsConfigForm.setControl('mappings', this.fb.array(mappingsControl)); | |
113 | + if (!mappings || !mappings.length) { | |
114 | + this.addMappingConfig(); | |
115 | + } | |
116 | + if (this.disabled) { | |
117 | + this.mappingsConfigForm.disable({emitEvent: false}); | |
118 | + } else { | |
119 | + this.mappingsConfigForm.enable({emitEvent: false}); | |
120 | + } | |
121 | + this.valueChange$ = this.mappingsConfigForm.valueChanges.subscribe(() => { | |
122 | + this.updateModel(); | |
123 | + }); | |
124 | + if (!this.disabled && !this.mappingsConfigForm.valid) { | |
125 | + this.updateModel(); | |
126 | + } | |
127 | + } | |
128 | + | |
129 | + mappingsConfigFormArray(): FormArray { | |
130 | + return this.mappingsConfigForm.get('mappings') as FormArray; | |
131 | + } | |
132 | + | |
133 | + public addMappingConfig() { | |
134 | + this.mappingsConfigFormArray().push(this.createdFormGroup()); | |
135 | + this.mappingsConfigForm.updateValueAndValidity(); | |
136 | + if (!this.mappingsConfigForm.valid) { | |
137 | + this.updateModel(); | |
138 | + } | |
139 | + } | |
140 | + | |
141 | + public removeMappingConfig(index: number) { | |
142 | + this.mappingsConfigFormArray().removeAt(index); | |
143 | + } | |
144 | + | |
145 | + private createdFormGroup(value?: SnmpMapping): FormGroup { | |
146 | + if (isUndefinedOrNull(value)) { | |
147 | + value = { | |
148 | + dataType: DataType.STRING, | |
149 | + key: '', | |
150 | + oid: '' | |
151 | + }; | |
152 | + } | |
153 | + return this.fb.group({ | |
154 | + dataType: [value.dataType, Validators.required], | |
155 | + key: [value.key, Validators.required], | |
156 | + oid: [value.oid, [Validators.required, Validators.pattern(this.oidPattern)]] | |
157 | + }); | |
158 | + } | |
159 | + | |
160 | + private updateModel() { | |
161 | + const value: SnmpMapping[] = this.mappingsConfigForm.get('mappings').value; | |
162 | + this.propagateChange(value); | |
163 | + } | |
164 | + | |
165 | +} | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2021 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<form [formGroup]="snmpDeviceProfileTransportConfigurationFormGroup" style="padding: 8px 0 16px;"> | |
19 | + <section fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"> | |
20 | + <mat-form-field fxFlex> | |
21 | + <mat-label translate>device-profile.snmp.timeout-ms</mat-label> | |
22 | + <input matInput formControlName="timeoutMs" type="number" min="0" required/> | |
23 | + <mat-error *ngIf="snmpDeviceProfileTransportConfigurationFormGroup.get('timeoutMs').hasError('required')"> | |
24 | + {{ 'device-profile.snmp.timeout-ms-required' | translate }} | |
25 | + </mat-error> | |
26 | + <mat-error *ngIf="snmpDeviceProfileTransportConfigurationFormGroup.get('timeoutMs').hasError('pattern') || | |
27 | + snmpDeviceProfileTransportConfigurationFormGroup.get('timeoutMs').hasError('min')"> | |
28 | + {{ 'device-profile.snmp.timeout-ms-invalid-format' | translate }} | |
29 | + </mat-error> | |
30 | + </mat-form-field> | |
31 | + <mat-form-field fxFlex> | |
32 | + <mat-label translate>device-profile.snmp.retries</mat-label> | |
33 | + <input matInput formControlName="retries" type="number" min="0" required/> | |
34 | + <mat-error *ngIf="snmpDeviceProfileTransportConfigurationFormGroup.get('retries').hasError('required')"> | |
35 | + {{ 'device-profile.snmp.retries-required' | translate }} | |
36 | + </mat-error> | |
37 | + <mat-error *ngIf="snmpDeviceProfileTransportConfigurationFormGroup.get('retries').hasError('pattern') || | |
38 | + snmpDeviceProfileTransportConfigurationFormGroup.get('retries').hasError('min')"> | |
39 | + {{ 'device-profile.snmp.retries-invalid-format' | translate }} | |
40 | + </mat-error> | |
41 | + </mat-form-field> | |
42 | + </section> | |
43 | + <div class="tb-small" style="padding-bottom: 8px" translate>device-profile.snmp.communication-configs</div> | |
44 | + <tb-snmp-device-profile-communication-config formControlName="communicationConfigs"> | |
45 | + </tb-snmp-device-profile-communication-config> | |
46 | +</form> | ... | ... |
ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component.ts
renamed from
ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.ts
... | ... | @@ -15,9 +15,16 @@ |
15 | 15 | /// |
16 | 16 | |
17 | 17 | import { Component, forwardRef, Input, OnDestroy, 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'; | |
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'; | |
21 | 28 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
22 | 29 | import { |
23 | 30 | DeviceProfileTransportConfiguration, |
... | ... | @@ -40,19 +47,24 @@ export interface OidMappingConfiguration { |
40 | 47 | selector: 'tb-snmp-device-profile-transport-configuration', |
41 | 48 | templateUrl: './snmp-device-profile-transport-configuration.component.html', |
42 | 49 | styleUrls: [], |
43 | - providers: [{ | |
44 | - provide: NG_VALUE_ACCESSOR, | |
45 | - useExisting: forwardRef(() => SnmpDeviceProfileTransportConfigurationComponent), | |
46 | - multi: true | |
47 | - }] | |
50 | + providers: [ | |
51 | + { | |
52 | + provide: NG_VALUE_ACCESSOR, | |
53 | + useExisting: forwardRef(() => SnmpDeviceProfileTransportConfigurationComponent), | |
54 | + multi: true | |
55 | + }, | |
56 | + { | |
57 | + provide: NG_VALIDATORS, | |
58 | + useExisting: forwardRef(() => SnmpDeviceProfileTransportConfigurationComponent), | |
59 | + multi: true | |
60 | + }] | |
48 | 61 | }) |
49 | -export class SnmpDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy { | |
62 | +export class SnmpDeviceProfileTransportConfigurationComponent implements OnInit, OnDestroy, ControlValueAccessor, Validator { | |
50 | 63 | |
51 | 64 | snmpDeviceProfileTransportConfigurationFormGroup: FormGroup; |
52 | 65 | |
53 | 66 | private destroy$ = new Subject(); |
54 | 67 | private requiredValue: boolean; |
55 | - private configuration = []; | |
56 | 68 | |
57 | 69 | get required(): boolean { |
58 | 70 | return this.requiredValue; |
... | ... | @@ -69,12 +81,14 @@ export class SnmpDeviceProfileTransportConfigurationComponent implements Control |
69 | 81 | private propagateChange = (v: any) => { |
70 | 82 | } |
71 | 83 | |
72 | - constructor(private store: Store<AppState>, private fb: FormBuilder) { | |
84 | + constructor(private fb: FormBuilder) { | |
73 | 85 | } |
74 | 86 | |
75 | 87 | ngOnInit(): void { |
76 | 88 | this.snmpDeviceProfileTransportConfigurationFormGroup = this.fb.group({ |
77 | - configuration: [null, Validators.required] | |
89 | + timeoutMs: [0, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | |
90 | + retries: [0, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | |
91 | + communicationConfigs: [null, Validators.required], | |
78 | 92 | }); |
79 | 93 | this.snmpDeviceProfileTransportConfigurationFormGroup.valueChanges.pipe( |
80 | 94 | takeUntil(this.destroy$) |
... | ... | @@ -95,18 +109,33 @@ export class SnmpDeviceProfileTransportConfigurationComponent implements Control |
95 | 109 | registerOnTouched(fn: any): void { |
96 | 110 | } |
97 | 111 | |
112 | + setDisabledState(isDisabled: boolean) { | |
113 | + this.disabled = isDisabled; | |
114 | + if (this.disabled) { | |
115 | + this.snmpDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false}); | |
116 | + } else { | |
117 | + this.snmpDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false}); | |
118 | + } | |
119 | + } | |
120 | + | |
98 | 121 | writeValue(value: SnmpDeviceProfileTransportConfiguration | null): void { |
99 | 122 | if (isDefinedAndNotNull(value)) { |
100 | - this.snmpDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false}); | |
123 | + this.snmpDeviceProfileTransportConfigurationFormGroup.patchValue(value, {emitEvent: !value.communicationConfigs}); | |
101 | 124 | } |
102 | 125 | } |
103 | 126 | |
104 | 127 | private updateModel() { |
105 | 128 | let configuration: DeviceProfileTransportConfiguration = null; |
106 | 129 | if (this.snmpDeviceProfileTransportConfigurationFormGroup.valid) { |
107 | - configuration = this.snmpDeviceProfileTransportConfigurationFormGroup.getRawValue().configuration; | |
130 | + configuration = this.snmpDeviceProfileTransportConfigurationFormGroup.getRawValue(); | |
108 | 131 | configuration.type = DeviceTransportType.SNMP; |
109 | 132 | } |
110 | 133 | this.propagateChange(configuration); |
111 | 134 | } |
135 | + | |
136 | + validate(): ValidationErrors | null { | |
137 | + return this.snmpDeviceProfileTransportConfigurationFormGroup.valid ? null : { | |
138 | + snmpDeviceProfileTransportConfiguration: false | |
139 | + }; | |
140 | + } | |
112 | 141 | } | ... | ... |
ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts
0 → 100644
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 { SharedModule } from '@shared/shared.module'; | |
19 | +import { CommonModule } from '@angular/common'; | |
20 | +import { SnmpDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component'; | |
21 | +import { SnmpDeviceProfileCommunicationConfigComponent } from './snmp-device-profile-communication-config.component'; | |
22 | +import { SnmpDeviceProfileMappingComponent } from './snmp-device-profile-mapping.component'; | |
23 | + | |
24 | +@NgModule({ | |
25 | + declarations: [ | |
26 | + SnmpDeviceProfileTransportConfigurationComponent, | |
27 | + SnmpDeviceProfileCommunicationConfigComponent, | |
28 | + SnmpDeviceProfileMappingComponent | |
29 | + ], | |
30 | + imports: [ | |
31 | + CommonModule, | |
32 | + SharedModule | |
33 | + ], | |
34 | + exports: [ | |
35 | + SnmpDeviceProfileTransportConfigurationComponent | |
36 | + ] | |
37 | +}) | |
38 | +export class SnmpDeviceProfileTransportModule { } | ... | ... |
... | ... | @@ -147,6 +147,22 @@ export enum ValueType { |
147 | 147 | JSON = 'JSON' |
148 | 148 | } |
149 | 149 | |
150 | +export enum DataType { | |
151 | + STRING = 'STRING', | |
152 | + LONG = 'LONG', | |
153 | + BOOLEAN = 'BOOLEAN', | |
154 | + DOUBLE = 'DOUBLE', | |
155 | + JSON = 'JSON' | |
156 | +} | |
157 | + | |
158 | +export const DataTypeTranslationMap = new Map([ | |
159 | + [DataType.STRING, 'value.string'], | |
160 | + [DataType.LONG, 'value.integer'], | |
161 | + [DataType.BOOLEAN, 'value.boolean'], | |
162 | + [DataType.DOUBLE, 'value.double'], | |
163 | + [DataType.JSON, 'value.json'] | |
164 | +]); | |
165 | + | |
150 | 166 | export const valueTypesMap = new Map<ValueType, ValueTypeData>( |
151 | 167 | [ |
152 | 168 | [ | ... | ... |
... | ... | @@ -29,6 +29,7 @@ import * as _moment from 'moment'; |
29 | 29 | import { AbstractControl, ValidationErrors } from '@angular/forms'; |
30 | 30 | import { OtaPackageId } from '@shared/models/id/ota-package-id'; |
31 | 31 | import { DashboardId } from '@shared/models/id/dashboard-id'; |
32 | +import { DataType } from '@shared/models/constants'; | |
32 | 33 | |
33 | 34 | export enum DeviceProfileType { |
34 | 35 | DEFAULT = 'DEFAULT', |
... | ... | @@ -257,7 +258,35 @@ export interface Lwm2mDeviceProfileTransportConfiguration { |
257 | 258 | } |
258 | 259 | |
259 | 260 | export interface SnmpDeviceProfileTransportConfiguration { |
260 | - [key: string]: any; | |
261 | + timeoutMs?: number; | |
262 | + retries?: number; | |
263 | + communicationConfigs?: SnmpCommunicationConfig[]; | |
264 | +} | |
265 | + | |
266 | +export enum SnmpSpecType { | |
267 | + TELEMETRY_QUERYING = 'TELEMETRY_QUERYING', | |
268 | + CLIENT_ATTRIBUTES_QUERYING = 'CLIENT_ATTRIBUTES_QUERYING', | |
269 | + SHARED_ATTRIBUTES_SETTING = 'SHARED_ATTRIBUTES_SETTING', | |
270 | + TO_DEVICE_RPC_REQUEST = 'TO_DEVICE_RPC_REQUEST' | |
271 | +} | |
272 | + | |
273 | +export const SnmpSpecTypeTranslationMap = new Map<SnmpSpecType, string>([ | |
274 | + [SnmpSpecType.TELEMETRY_QUERYING, ' Telemetry'], | |
275 | + [SnmpSpecType.CLIENT_ATTRIBUTES_QUERYING, 'Client attributes'], | |
276 | + [SnmpSpecType.SHARED_ATTRIBUTES_SETTING, 'Shared attributes'], | |
277 | + [SnmpSpecType.TO_DEVICE_RPC_REQUEST, 'RPC request'] | |
278 | +]); | |
279 | + | |
280 | +export interface SnmpCommunicationConfig { | |
281 | + spec: SnmpSpecType; | |
282 | + mappings: SnmpMapping[]; | |
283 | + queryingFrequencyMs?: number; | |
284 | +} | |
285 | + | |
286 | +export interface SnmpMapping { | |
287 | + oid: string; | |
288 | + key: string; | |
289 | + dataType: DataType; | |
261 | 290 | } |
262 | 291 | |
263 | 292 | export type DeviceProfileTransportConfigurations = DefaultDeviceProfileTransportConfiguration & |
... | ... | @@ -332,7 +361,11 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT |
332 | 361 | transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M}; |
333 | 362 | break; |
334 | 363 | case DeviceTransportType.SNMP: |
335 | - const snmpTransportConfiguration: SnmpDeviceProfileTransportConfiguration = {}; | |
364 | + const snmpTransportConfiguration: SnmpDeviceProfileTransportConfiguration = { | |
365 | + timeoutMs: 0, | |
366 | + retries: 0, | |
367 | + communicationConfigs: null | |
368 | + }; | |
336 | 369 | transportConfiguration = {...snmpTransportConfiguration, type: DeviceTransportType.SNMP}; |
337 | 370 | break; |
338 | 371 | } | ... | ... |
... | ... | @@ -1297,6 +1297,31 @@ |
1297 | 1297 | "sw-update-recourse": "Software update CoAP recourse", |
1298 | 1298 | "sw-update-recourse-required": "Software update CoAP recourse is required.", |
1299 | 1299 | "config-json-tab": "Json Config Profile Device" |
1300 | + }, | |
1301 | + "snmp": { | |
1302 | + "add-communication-config": "Add communication config", | |
1303 | + "add-mapping": "Add mapping", | |
1304 | + "communication-configs": "Communication configs", | |
1305 | + "data-key": "Data key", | |
1306 | + "data-key-required": "Data key is required.", | |
1307 | + "data-type": "Data type", | |
1308 | + "data-type-required": "Data type is required.", | |
1309 | + "oid": "OID", | |
1310 | + "oid-pattern": "Invalid OID format.", | |
1311 | + "oid-required": "OID is required.", | |
1312 | + "please-add-communication-config": "Please add communication config", | |
1313 | + "please-add-mapping-config": "Please add mapping config", | |
1314 | + "querying-frequency": "Querying frequency, ms", | |
1315 | + "querying-frequency-invalid-format": "Querying frequency must be a positive integer.", | |
1316 | + "querying-frequency-required": "Querying frequency is required.", | |
1317 | + "retries": "Retries", | |
1318 | + "retries-invalid-format": "Retries must be a positive integer.", | |
1319 | + "retries-required": "Retries is required.", | |
1320 | + "scope": "Scope", | |
1321 | + "scope-required": "Scope is required.", | |
1322 | + "timeout-ms": "Timeout, ms", | |
1323 | + "timeout-ms-invalid-format": "Timeout must be a positive integer.", | |
1324 | + "timeout-ms-required": "Timeout is required." | |
1300 | 1325 | } |
1301 | 1326 | }, |
1302 | 1327 | "dialog": { | ... | ... |