diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/SnmpDeviceTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/SnmpDeviceTransportConfiguration.java
index a7bc143d81..d377ede985 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/SnmpDeviceTransportConfiguration.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/SnmpDeviceTransportConfiguration.java
@@ -51,6 +51,13 @@ public class SnmpDeviceTransportConfiguration implements DeviceTransportConfigur
private String privacyPassphrase;
private String engineId;
+ public SnmpDeviceTransportConfiguration() {
+ this.host = "localhost";
+ this.port = 161;
+ this.protocolVersion = SnmpProtocolVersion.V2C;
+ this.community = "public";
+ }
+
@Override
public DeviceTransportType getType() {
return DeviceTransportType.SNMP;
@@ -76,7 +83,7 @@ public class SnmpDeviceTransportConfiguration implements DeviceTransportConfigur
isValid = StringUtils.isNotBlank(username) && StringUtils.isNotBlank(securityName)
&& contextName != null && authenticationProtocol != null
&& StringUtils.isNotBlank(authenticationPassphrase)
- && privacyProtocol != null && privacyPassphrase != null && engineId != null;
+ && privacyProtocol != null && StringUtils.isNotBlank(privacyPassphrase) && engineId != null;
break;
}
}
diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts
index 3958830088..d0ad42b62e 100644
--- a/ui-ngx/src/app/modules/home/components/home-components.module.ts
+++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts
@@ -99,7 +99,6 @@ import { DeviceProfileDialogComponent } from '@home/components/profile/device-pr
import { DeviceProfileAutocompleteComponent } from '@home/components/profile/device-profile-autocomplete.component';
import { MqttDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component';
import { CoapDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/coap-device-profile-transport-configuration.component';
-import { SnmpDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/snmp-device-profile-transport-configuration.component';
import { DeviceProfileAlarmsComponent } from '@home/components/profile/alarm/device-profile-alarms.component';
import { DeviceProfileAlarmComponent } from '@home/components/profile/alarm/device-profile-alarm.component';
import { CreateAlarmRulesComponent } from '@home/components/profile/alarm/create-alarm-rules.component';
@@ -143,6 +142,7 @@ import { SecurityConfigLwm2mComponent } from '@home/components/device/security-c
import { SecurityConfigLwm2mServerComponent } from '@home/components/device/security-config-lwm2m-server.component';
import { DashboardImageDialogComponent } from '@home/components/dashboard-page/dashboard-image-dialog.component';
import { WidgetContainerComponent } from '@home/components/widget/widget-container.component';
+import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snpm/snmp-device-profile-transport.module';
@NgModule({
declarations:
@@ -228,7 +228,6 @@ import { WidgetContainerComponent } from '@home/components/widget/widget-contain
DefaultDeviceProfileTransportConfigurationComponent,
MqttDeviceProfileTransportConfigurationComponent,
CoapDeviceProfileTransportConfigurationComponent,
- SnmpDeviceProfileTransportConfigurationComponent,
DeviceProfileTransportConfigurationComponent,
CreateAlarmRulesComponent,
AlarmRuleComponent,
@@ -272,6 +271,7 @@ import { WidgetContainerComponent } from '@home/components/widget/widget-contain
SharedModule,
SharedHomeComponentsModule,
Lwm2mProfileComponentsModule,
+ SnmpDeviceProfileTransportModule,
StatesControllerModule
],
exports: [
@@ -339,7 +339,6 @@ import { WidgetContainerComponent } from '@home/components/widget/widget-contain
DefaultDeviceProfileTransportConfigurationComponent,
MqttDeviceProfileTransportConfigurationComponent,
CoapDeviceProfileTransportConfigurationComponent,
- SnmpDeviceProfileTransportConfigurationComponent,
DeviceProfileTransportConfigurationComponent,
CreateAlarmRulesComponent,
AlarmRuleComponent,
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts
index 305a0a84b6..50b3bc801c 100644
--- a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts
+++ b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts
@@ -89,7 +89,9 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu
if (configuration) {
delete configuration.type;
}
- this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
+ setTimeout(() => {
+ this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
+ });
}
private updateModel() {
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.html
deleted file mode 100644
index f57b1ac716..0000000000
--- a/ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.html b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.html
new file mode 100644
index 0000000000..7d2f8a154c
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+ device-profile.snmp.scope
+
+
+ {{ snmpSpecTypeTranslationMap.get(snmpSpecType) }}
+
+
+
+ {{ 'device-profile.snmp.scope-required' | translate }}
+
+
+
+
+
+
+
+
+ device-profile.snmp.please-add-communication-config
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.scss b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.scss
new file mode 100644
index 0000000000..3b6661b862
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.scss
@@ -0,0 +1,44 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+:host {
+ .communication-config {
+ border: 2px groove rgba(0, 0, 0, 0.25);
+ border-radius: 4px;
+ padding: 8px;
+ min-width: 0;
+ }
+
+ .scope-row {
+ padding-bottom: 8px;
+ }
+
+ .required-text {
+ margin: 16px 0
+ }
+}
+
+:host ::ng-deep {
+ .mat-form-field.spec {
+ .mat-form-field-infix {
+ width: 160px;
+ }
+ }
+ .button-icon{
+ font-size: 20px;
+ width: 20px;
+ height: 20px;
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.ts
new file mode 100644
index 0000000000..7af2140efe
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-communication-config.component.ts
@@ -0,0 +1,218 @@
+///
+/// Copyright © 2016-2021 The Thingsboard Authors
+///
+/// Licensed under the Apache License, Version 2.0 (the "License");
+/// you may not use this file except in compliance with the License.
+/// You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing, software
+/// distributed under the License is distributed on an "AS IS" BASIS,
+/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+/// See the License for the specific language governing permissions and
+/// limitations under the License.
+///
+
+import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
+import {
+ AbstractControl,
+ ControlValueAccessor,
+ FormArray,
+ FormBuilder,
+ FormGroup,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ Validator,
+ Validators
+} from '@angular/forms';
+import { SnmpCommunicationConfig, SnmpSpecType, SnmpSpecTypeTranslationMap } from '@shared/models/device.models';
+import { Subject, Subscription } from 'rxjs';
+import { isUndefinedOrNull } from '@core/utils';
+import { takeUntil } from 'rxjs/operators';
+
+@Component({
+ selector: 'tb-snmp-device-profile-communication-config',
+ templateUrl: './snmp-device-profile-communication-config.component.html',
+ styleUrls: ['./snmp-device-profile-communication-config.component.scss'],
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => SnmpDeviceProfileCommunicationConfigComponent),
+ multi: true
+ },
+ {
+ provide: NG_VALIDATORS,
+ useExisting: forwardRef(() => SnmpDeviceProfileCommunicationConfigComponent),
+ multi: true
+ }]
+})
+export class SnmpDeviceProfileCommunicationConfigComponent implements OnInit, OnDestroy, ControlValueAccessor, Validator {
+
+ snmpSpecTypes = Object.values(SnmpSpecType);
+ snmpSpecTypeTranslationMap = SnmpSpecTypeTranslationMap;
+
+ deviceProfileCommunicationConfig: FormGroup;
+
+ @Input()
+ disabled: boolean;
+
+ private usedSpecType: SnmpSpecType[] = [];
+ private valueChange$: Subscription = null;
+ private destroy$ = new Subject();
+ private propagateChange = (v: any) => { };
+
+ constructor(private fb: FormBuilder) { }
+
+ ngOnInit(): void {
+ this.deviceProfileCommunicationConfig = this.fb.group({
+ communicationConfig: this.fb.array([])
+ });
+ }
+
+ ngOnDestroy() {
+ if (this.valueChange$) {
+ this.valueChange$.unsubscribe();
+ }
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
+ communicationConfigFormArray(): FormArray {
+ return this.deviceProfileCommunicationConfig.get('communicationConfig') as FormArray;
+ }
+
+ registerOnChange(fn: any): void {
+ this.propagateChange = fn;
+ }
+
+ registerOnTouched(fn: any): void {
+ }
+
+ setDisabledState(isDisabled: boolean) {
+ this.disabled = isDisabled;
+ if (this.disabled) {
+ this.deviceProfileCommunicationConfig.disable({emitEvent: false});
+ } else {
+ this.deviceProfileCommunicationConfig.enable({emitEvent: false});
+ }
+ }
+
+ writeValue(communicationConfig: SnmpCommunicationConfig[]) {
+ if (this.valueChange$) {
+ this.valueChange$.unsubscribe();
+ }
+ const communicationConfigControl: Array = [];
+ if (communicationConfig) {
+ communicationConfig.forEach((config) => {
+ communicationConfigControl.push(this.createdFormGroup(config));
+ });
+ }
+ this.deviceProfileCommunicationConfig.setControl('communicationConfig', this.fb.array(communicationConfigControl));
+ if (!communicationConfig || !communicationConfig.length) {
+ this.addCommunicationConfig();
+ }
+ if (this.disabled) {
+ this.deviceProfileCommunicationConfig.disable({emitEvent: false});
+ } else {
+ this.deviceProfileCommunicationConfig.enable({emitEvent: false});
+ }
+ this.valueChange$ = this.deviceProfileCommunicationConfig.valueChanges.subscribe(() => {
+ this.updateModel();
+ });
+ this.updateUsedSpecType();
+ if (!this.disabled && !this.deviceProfileCommunicationConfig.valid) {
+ this.updateModel();
+ }
+ }
+
+ public validate() {
+ return this.deviceProfileCommunicationConfig.valid && this.deviceProfileCommunicationConfig.value.communicationConfig.length ? null : {
+ communicationConfig: false
+ };
+ }
+
+ public removeCommunicationConfig(index: number) {
+ this.communicationConfigFormArray().removeAt(index);
+ }
+
+
+ get isAddEnabled(): boolean {
+ return this.communicationConfigFormArray().length !== Object.keys(SnmpSpecType).length;
+ }
+
+ public addCommunicationConfig() {
+ this.communicationConfigFormArray().push(this.createdFormGroup());
+ this.deviceProfileCommunicationConfig.updateValueAndValidity();
+ if (!this.deviceProfileCommunicationConfig.valid) {
+ this.updateModel();
+ }
+ }
+
+ private getFirstUnusedSeverity(): SnmpSpecType {
+ for (const type of Object.values(SnmpSpecType)) {
+ if (this.usedSpecType.indexOf(type) === -1) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ public isDisabledSeverity(type: SnmpSpecType, index: number): boolean {
+ const usedIndex = this.usedSpecType.indexOf(type);
+ return usedIndex > -1 && usedIndex !== index;
+ }
+
+ public isShowFrequency(type: SnmpSpecType): boolean {
+ return type === SnmpSpecType.TELEMETRY_QUERYING || type === SnmpSpecType.CLIENT_ATTRIBUTES_QUERYING;
+ }
+
+ private updateUsedSpecType() {
+ this.usedSpecType = [];
+ const value: SnmpCommunicationConfig[] = this.deviceProfileCommunicationConfig.get('communicationConfig').value;
+ value.forEach((rule, index) => {
+ this.usedSpecType[index] = rule.spec;
+ });
+ }
+
+ private createdFormGroup(value?: SnmpCommunicationConfig): FormGroup {
+ if (isUndefinedOrNull(value)) {
+ value = {
+ spec: this.getFirstUnusedSeverity(),
+ queryingFrequencyMs: 5000,
+ mappings: null
+ };
+ }
+ const form = this.fb.group({
+ spec: [value.spec, Validators.required],
+ mappings: [value.mappings]
+ });
+ if (this.isShowFrequency(value.spec)) {
+ form.addControl('queryingFrequencyMs',
+ this.fb.control(value.queryingFrequencyMs, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]));
+ }
+ form.get('spec').valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe(spec => {
+ if (this.isShowFrequency(spec)) {
+ form.addControl('queryingFrequencyMs',
+ this.fb.control(5000, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]));
+ } else {
+ form.removeControl('queryingFrequencyMs');
+ }
+ });
+ return form;
+ }
+
+ private updateModel() {
+ const value: SnmpCommunicationConfig[] = this.deviceProfileCommunicationConfig.get('communicationConfig').value;
+ value.forEach(config => {
+ if (!this.isShowFrequency(config.spec)) {
+ delete config.queryingFrequencyMs;
+ }
+ });
+ this.updateUsedSpecType();
+ this.propagateChange(value);
+ }
+
+}
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.html b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.html
new file mode 100644
index 0000000000..a2a0a97d15
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.html
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ device-profile.snmp.please-add-mapping-config
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.scss b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.scss
new file mode 100644
index 0000000000..5972aee722
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.scss
@@ -0,0 +1,49 @@
+/**
+ * Copyright © 2016-2021 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+:host {
+ .mapping-config {
+ min-width: 518px;
+ }
+ .mapping-list {
+ padding-bottom: 8px;
+ height: 46px;
+ }
+
+ .required-text {
+ margin: 14px 0;
+ }
+}
+
+:host ::ng-deep {
+ .mapping-list {
+ mat-form-field {
+ .mat-form-field-wrapper {
+ padding-bottom: 0;
+ .mat-form-field-infix {
+ border-top-width: 0.2em;
+ width: auto;
+ min-width: auto;
+ }
+ .mat-form-field-underline {
+ bottom: 0;
+ }
+ .mat-form-field-subscript-wrapper{
+ margin-top: 1.8em;
+ }
+ }
+ }
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.ts
new file mode 100644
index 0000000000..53dbec422c
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-mapping.component.ts
@@ -0,0 +1,165 @@
+///
+/// Copyright © 2016-2021 The Thingsboard Authors
+///
+/// Licensed under the Apache License, Version 2.0 (the "License");
+/// you may not use this file except in compliance with the License.
+/// You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing, software
+/// distributed under the License is distributed on an "AS IS" BASIS,
+/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+/// See the License for the specific language governing permissions and
+/// limitations under the License.
+///
+
+import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
+import {
+ AbstractControl,
+ ControlValueAccessor,
+ FormArray,
+ FormBuilder,
+ FormGroup,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ ValidationErrors,
+ Validator,
+ Validators
+} from '@angular/forms';
+import { SnmpMapping } from '@shared/models/device.models';
+import { Subscription } from 'rxjs';
+import { DataType, DataTypeTranslationMap } from '@shared/models/constants';
+import { isUndefinedOrNull } from '@core/utils';
+
+@Component({
+ selector: 'tb-snmp-device-profile-mapping',
+ templateUrl: './snmp-device-profile-mapping.component.html',
+ styleUrls: ['./snmp-device-profile-mapping.component.scss'],
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => SnmpDeviceProfileMappingComponent),
+ multi: true
+ },
+ {
+ provide: NG_VALIDATORS,
+ useExisting: forwardRef(() => SnmpDeviceProfileMappingComponent),
+ multi: true
+ }]
+})
+export class SnmpDeviceProfileMappingComponent implements OnInit, OnDestroy, ControlValueAccessor, Validator {
+
+ mappingsConfigForm: FormGroup;
+
+ dataTypes = Object.values(DataType);
+ dataTypesTranslationMap = DataTypeTranslationMap;
+
+ @Input()
+ disabled: boolean;
+
+ private readonly oidPattern: RegExp = /^\.?([0-2])((\.0)|(\.[1-9][0-9]*))*$/;
+
+ private valueChange$: Subscription = null;
+ private propagateChange = (v: any) => { };
+
+ constructor(private fb: FormBuilder) { }
+
+ ngOnInit() {
+ this.mappingsConfigForm = this.fb.group({
+ mappings: this.fb.array([])
+ });
+ }
+
+ ngOnDestroy() {
+ if (this.valueChange$) {
+ this.valueChange$.unsubscribe();
+ }
+ }
+
+ registerOnChange(fn: any) {
+ this.propagateChange = fn;
+ }
+
+ registerOnTouched(fn: any) {
+ }
+
+ setDisabledState(isDisabled: boolean) {
+ this.disabled = isDisabled;
+ if (this.disabled) {
+ this.mappingsConfigForm.disable({emitEvent: false});
+ } else {
+ this.mappingsConfigForm.enable({emitEvent: false});
+ }
+ }
+
+ validate(): ValidationErrors | null {
+ return this.mappingsConfigForm.valid && this.mappingsConfigForm.value.mappings.length ? null : {
+ mapping: false
+ };
+ }
+
+ writeValue(mappings: SnmpMapping[]) {
+ if (this.valueChange$) {
+ this.valueChange$.unsubscribe();
+ }
+ const mappingsControl: Array = [];
+ if (mappings) {
+ mappings.forEach((config) => {
+ mappingsControl.push(this.createdFormGroup(config));
+ });
+ }
+ this.mappingsConfigForm.setControl('mappings', this.fb.array(mappingsControl));
+ if (!mappings || !mappings.length) {
+ this.addMappingConfig();
+ }
+ if (this.disabled) {
+ this.mappingsConfigForm.disable({emitEvent: false});
+ } else {
+ this.mappingsConfigForm.enable({emitEvent: false});
+ }
+ this.valueChange$ = this.mappingsConfigForm.valueChanges.subscribe(() => {
+ this.updateModel();
+ });
+ if (!this.disabled && !this.mappingsConfigForm.valid) {
+ this.updateModel();
+ }
+ }
+
+ mappingsConfigFormArray(): FormArray {
+ return this.mappingsConfigForm.get('mappings') as FormArray;
+ }
+
+ public addMappingConfig() {
+ this.mappingsConfigFormArray().push(this.createdFormGroup());
+ this.mappingsConfigForm.updateValueAndValidity();
+ if (!this.mappingsConfigForm.valid) {
+ this.updateModel();
+ }
+ }
+
+ public removeMappingConfig(index: number) {
+ this.mappingsConfigFormArray().removeAt(index);
+ }
+
+ private createdFormGroup(value?: SnmpMapping): FormGroup {
+ if (isUndefinedOrNull(value)) {
+ value = {
+ dataType: DataType.STRING,
+ key: '',
+ oid: ''
+ };
+ }
+ return this.fb.group({
+ dataType: [value.dataType, Validators.required],
+ key: [value.key, Validators.required],
+ oid: [value.oid, [Validators.required, Validators.pattern(this.oidPattern)]]
+ });
+ }
+
+ private updateModel() {
+ const value: SnmpMapping[] = this.mappingsConfigForm.get('mappings').value;
+ this.propagateChange(value);
+ }
+
+}
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component.html
new file mode 100644
index 0000000000..7dad337d72
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component.html
@@ -0,0 +1,46 @@
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component.ts
similarity index 66%
rename from ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.ts
rename to ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component.ts
index e6749a9219..400199ef9c 100644
--- a/ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.ts
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component.ts
@@ -15,9 +15,16 @@
///
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
-import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
-import { Store } from '@ngrx/store';
-import { AppState } from '@app/core/core.state';
+import {
+ ControlValueAccessor,
+ FormBuilder,
+ FormGroup,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ ValidationErrors,
+ Validator,
+ Validators
+} from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
DeviceProfileTransportConfiguration,
@@ -40,19 +47,24 @@ export interface OidMappingConfiguration {
selector: 'tb-snmp-device-profile-transport-configuration',
templateUrl: './snmp-device-profile-transport-configuration.component.html',
styleUrls: [],
- providers: [{
- provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => SnmpDeviceProfileTransportConfigurationComponent),
- multi: true
- }]
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => SnmpDeviceProfileTransportConfigurationComponent),
+ multi: true
+ },
+ {
+ provide: NG_VALIDATORS,
+ useExisting: forwardRef(() => SnmpDeviceProfileTransportConfigurationComponent),
+ multi: true
+ }]
})
-export class SnmpDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy {
+export class SnmpDeviceProfileTransportConfigurationComponent implements OnInit, OnDestroy, ControlValueAccessor, Validator {
snmpDeviceProfileTransportConfigurationFormGroup: FormGroup;
private destroy$ = new Subject();
private requiredValue: boolean;
- private configuration = [];
get required(): boolean {
return this.requiredValue;
@@ -69,12 +81,14 @@ export class SnmpDeviceProfileTransportConfigurationComponent implements Control
private propagateChange = (v: any) => {
}
- constructor(private store: Store, private fb: FormBuilder) {
+ constructor(private fb: FormBuilder) {
}
ngOnInit(): void {
this.snmpDeviceProfileTransportConfigurationFormGroup = this.fb.group({
- configuration: [null, Validators.required]
+ timeoutMs: [500, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
+ retries: [0, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
+ communicationConfigs: [null, Validators.required],
});
this.snmpDeviceProfileTransportConfigurationFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
@@ -95,18 +109,33 @@ export class SnmpDeviceProfileTransportConfigurationComponent implements Control
registerOnTouched(fn: any): void {
}
+ setDisabledState(isDisabled: boolean) {
+ this.disabled = isDisabled;
+ if (this.disabled) {
+ this.snmpDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false});
+ } else {
+ this.snmpDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false});
+ }
+ }
+
writeValue(value: SnmpDeviceProfileTransportConfiguration | null): void {
if (isDefinedAndNotNull(value)) {
- this.snmpDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
+ this.snmpDeviceProfileTransportConfigurationFormGroup.patchValue(value, {emitEvent: !value.communicationConfigs});
}
}
private updateModel() {
let configuration: DeviceProfileTransportConfiguration = null;
if (this.snmpDeviceProfileTransportConfigurationFormGroup.valid) {
- configuration = this.snmpDeviceProfileTransportConfigurationFormGroup.getRawValue().configuration;
+ configuration = this.snmpDeviceProfileTransportConfigurationFormGroup.getRawValue();
configuration.type = DeviceTransportType.SNMP;
}
this.propagateChange(configuration);
}
+
+ validate(): ValidationErrors | null {
+ return this.snmpDeviceProfileTransportConfigurationFormGroup.valid ? null : {
+ snmpDeviceProfileTransportConfiguration: false
+ };
+ }
}
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts
new file mode 100644
index 0000000000..c0797d9b0e
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/device/snpm/snmp-device-profile-transport.module.ts
@@ -0,0 +1,38 @@
+///
+/// Copyright © 2016-2021 The Thingsboard Authors
+///
+/// Licensed under the Apache License, Version 2.0 (the "License");
+/// you may not use this file except in compliance with the License.
+/// You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing, software
+/// distributed under the License is distributed on an "AS IS" BASIS,
+/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+/// See the License for the specific language governing permissions and
+/// limitations under the License.
+///
+
+import { NgModule } from '@angular/core';
+import { SharedModule } from '@shared/shared.module';
+import { CommonModule } from '@angular/common';
+import { SnmpDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/snpm/snmp-device-profile-transport-configuration.component';
+import { SnmpDeviceProfileCommunicationConfigComponent } from './snmp-device-profile-communication-config.component';
+import { SnmpDeviceProfileMappingComponent } from './snmp-device-profile-mapping.component';
+
+@NgModule({
+ declarations: [
+ SnmpDeviceProfileTransportConfigurationComponent,
+ SnmpDeviceProfileCommunicationConfigComponent,
+ SnmpDeviceProfileMappingComponent
+ ],
+ imports: [
+ CommonModule,
+ SharedModule
+ ],
+ exports: [
+ SnmpDeviceProfileTransportConfigurationComponent
+ ]
+})
+export class SnmpDeviceProfileTransportModule { }
diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts
index 1a510692db..a175764d89 100644
--- a/ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts
@@ -15,7 +15,16 @@
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
-import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
+import {
+ ControlValueAccessor,
+ FormBuilder,
+ FormGroup,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ ValidationErrors,
+ Validator,
+ Validators
+} from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
@@ -29,13 +38,20 @@ import {
selector: 'tb-device-data',
templateUrl: './device-data.component.html',
styleUrls: [],
- providers: [{
- provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => DeviceDataComponent),
- multi: true
- }]
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => DeviceDataComponent),
+ multi: true
+ },
+ {
+ provide: NG_VALIDATORS,
+ useExisting: forwardRef(() => DeviceDataComponent),
+ multi: true
+ },
+ ]
})
-export class DeviceDataComponent implements ControlValueAccessor, OnInit {
+export class DeviceDataComponent implements ControlValueAccessor, OnInit, Validator {
deviceDataFormGroup: FormGroup;
@@ -97,6 +113,12 @@ export class DeviceDataComponent implements ControlValueAccessor, OnInit {
this.deviceDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false});
}
+ validate(): ValidationErrors | null {
+ return this.deviceDataFormGroup.valid ? null : {
+ deviceDataForm: false
+ };
+ }
+
private updateModel() {
let deviceData: DeviceData = null;
if (this.deviceDataFormGroup.valid) {
diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts
index 0e9d7e24a9..82359232a9 100644
--- a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts
@@ -15,27 +15,39 @@
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
-import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
+import {
+ ControlValueAccessor,
+ FormBuilder,
+ FormGroup,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ ValidationErrors,
+ Validator,
+ Validators
+} from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
-import {
- DeviceTransportConfiguration,
- DeviceTransportType
-} from '@shared/models/device.models';
+import { DeviceTransportConfiguration, DeviceTransportType } from '@shared/models/device.models';
import { deepClone } from '@core/utils';
@Component({
selector: 'tb-device-transport-configuration',
templateUrl: './device-transport-configuration.component.html',
styleUrls: [],
- providers: [{
- provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => DeviceTransportConfigurationComponent),
- multi: true
- }]
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => DeviceTransportConfigurationComponent),
+ multi: true
+ },
+ {
+ provide: NG_VALIDATORS,
+ useExisting: forwardRef(() => DeviceTransportConfigurationComponent),
+ multi: true
+ }]
})
-export class DeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit {
+export class DeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit, Validator {
deviceTransportType = DeviceTransportType;
@@ -92,7 +104,15 @@ export class DeviceTransportConfigurationComponent implements ControlValueAccess
if (configuration) {
delete configuration.type;
}
- this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
+ setTimeout(() => {
+ this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
+ }, 0);
+ }
+
+ validate(): ValidationErrors | null {
+ return this.deviceTransportConfigurationFormGroup.valid ? null : {
+ deviceTransportConfiguration: false
+ };
}
private updateModel() {
diff --git a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.html b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.html
index fc9f615db9..dadc98425e 100644
--- a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.html
+++ b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.html
@@ -15,10 +15,119 @@
limitations under the License.
-->
-
diff --git a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts
index 165a2906f4..f35d538bfa 100644
--- a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts
@@ -14,31 +14,57 @@
/// limitations under the License.
///
-import {Component, forwardRef, Input, OnInit} from '@angular/core';
-import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms';
-import {Store} from '@ngrx/store';
-import {AppState} from '@app/core/core.state';
-import {coerceBooleanProperty} from '@angular/cdk/coercion';
+import { Component, forwardRef, Input, OnInit } from '@angular/core';
+import {
+ ControlValueAccessor,
+ FormBuilder,
+ FormGroup,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ ValidationErrors,
+ Validator,
+ Validators
+} from '@angular/forms';
+import { Store } from '@ngrx/store';
+import { AppState } from '@app/core/core.state';
+import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
DeviceTransportConfiguration,
DeviceTransportType,
- SnmpDeviceTransportConfiguration
+ SnmpAuthenticationProtocol,
+ SnmpAuthenticationProtocolTranslationMap,
+ SnmpDeviceProtocolVersion,
+ SnmpDeviceTransportConfiguration,
+ SnmpPrivacyProtocol,
+ SnmpPrivacyProtocolTranslationMap
} from '@shared/models/device.models';
+import { isDefinedAndNotNull } from '@core/utils';
@Component({
selector: 'tb-snmp-device-transport-configuration',
templateUrl: './snmp-device-transport-configuration.component.html',
styleUrls: [],
- providers: [{
- provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => SnmpDeviceTransportConfigurationComponent),
- multi: true
- }]
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => SnmpDeviceTransportConfigurationComponent),
+ multi: true
+ }, {
+ provide: NG_VALIDATORS,
+ useExisting: forwardRef(() => SnmpDeviceTransportConfigurationComponent),
+ multi: true
+ }]
})
-export class SnmpDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit {
+export class SnmpDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit, Validator {
snmpDeviceTransportConfigurationFormGroup: FormGroup;
+ snmpDeviceProtocolVersions = Object.values(SnmpDeviceProtocolVersion);
+ snmpAuthenticationProtocols = Object.values(SnmpAuthenticationProtocol);
+ snmpAuthenticationProtocolTranslation = SnmpAuthenticationProtocolTranslationMap;
+ snmpPrivacyProtocols = Object.values(SnmpPrivacyProtocol);
+ snmpPrivacyProtocolTranslation = SnmpPrivacyProtocolTranslationMap;
+
private requiredValue: boolean;
get required(): boolean {
@@ -53,8 +79,7 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc
@Input()
disabled: boolean;
- private propagateChange = (v: any) => {
- };
+ private propagateChange = (v: any) => { };
constructor(private store: Store,
private fb: FormBuilder) {
@@ -69,13 +94,33 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc
ngOnInit() {
this.snmpDeviceTransportConfigurationFormGroup = this.fb.group({
- configuration: [null, Validators.required]
+ host: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
+ port: [null, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
+ protocolVersion: [SnmpDeviceProtocolVersion.V2C, Validators.required],
+ community: ['public', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
+ username: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
+ securityName: ['public', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
+ contextName: [null],
+ authenticationProtocol: [SnmpAuthenticationProtocol.SHA_512, Validators.required],
+ authenticationPassphrase: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
+ privacyProtocol: [SnmpPrivacyProtocol.DES, Validators.required],
+ privacyPassphrase: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
+ engineId: ['']
+ });
+ this.snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').valueChanges.subscribe((protocol: SnmpDeviceProtocolVersion) => {
+ this.updateDisabledFormValue(protocol);
});
this.snmpDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
+ validate(): ValidationErrors | null {
+ return this.snmpDeviceTransportConfigurationFormGroup.valid ? null : {
+ snmpDeviceTransportConfiguration: false
+ };
+ }
+
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
@@ -86,13 +131,46 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc
}
writeValue(value: SnmpDeviceTransportConfiguration | null): void {
- this.snmpDeviceTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
+ if (isDefinedAndNotNull(value)) {
+ this.snmpDeviceTransportConfigurationFormGroup.patchValue(value, {emitEvent: false});
+ if (this.snmpDeviceTransportConfigurationFormGroup.enabled) {
+ this.updateDisabledFormValue(value.protocolVersion || SnmpDeviceProtocolVersion.V2C);
+ }
+ }
+ }
+
+ isV3protocolVersion(): boolean {
+ return this.snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').value === SnmpDeviceProtocolVersion.V3;
+ }
+
+ private updateDisabledFormValue(protocol: SnmpDeviceProtocolVersion) {
+ if (protocol === SnmpDeviceProtocolVersion.V3) {
+ this.snmpDeviceTransportConfigurationFormGroup.get('community').disable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('username').enable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('securityName').enable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('contextName').enable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('authenticationProtocol').enable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('authenticationPassphrase').enable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('privacyProtocol').enable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('privacyPassphrase').enable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('engineId').enable({emitEvent: false});
+ } else {
+ this.snmpDeviceTransportConfigurationFormGroup.get('community').enable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('username').disable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('securityName').disable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('contextName').disable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('authenticationProtocol').disable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('authenticationPassphrase').disable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('privacyProtocol').disable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('privacyPassphrase').disable({emitEvent: false});
+ this.snmpDeviceTransportConfigurationFormGroup.get('engineId').disable({emitEvent: false});
+ }
}
private updateModel() {
let configuration: DeviceTransportConfiguration = null;
if (this.snmpDeviceTransportConfigurationFormGroup.valid) {
- configuration = this.snmpDeviceTransportConfigurationFormGroup.getRawValue().configuration;
+ configuration = this.snmpDeviceTransportConfigurationFormGroup.value;
configuration.type = DeviceTransportType.SNMP;
}
this.propagateChange(configuration);
diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts
index 56347f1261..cf95a154da 100644
--- a/ui-ngx/src/app/shared/models/constants.ts
+++ b/ui-ngx/src/app/shared/models/constants.ts
@@ -148,6 +148,22 @@ export enum ValueType {
JSON = 'JSON'
}
+export enum DataType {
+ STRING = 'STRING',
+ LONG = 'LONG',
+ BOOLEAN = 'BOOLEAN',
+ DOUBLE = 'DOUBLE',
+ JSON = 'JSON'
+}
+
+export const DataTypeTranslationMap = new Map([
+ [DataType.STRING, 'value.string'],
+ [DataType.LONG, 'value.integer'],
+ [DataType.BOOLEAN, 'value.boolean'],
+ [DataType.DOUBLE, 'value.double'],
+ [DataType.JSON, 'value.json']
+]);
+
export const valueTypesMap = new Map(
[
[
diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts
index 7af8e56472..a766c3a6c3 100644
--- a/ui-ngx/src/app/shared/models/device.models.ts
+++ b/ui-ngx/src/app/shared/models/device.models.ts
@@ -29,6 +29,7 @@ import * as _moment from 'moment';
import { AbstractControl, ValidationErrors } from '@angular/forms';
import { OtaPackageId } from '@shared/models/id/ota-package-id';
import { DashboardId } from '@shared/models/id/dashboard-id';
+import { DataType } from '@shared/models/constants';
export enum DeviceProfileType {
DEFAULT = 'DEFAULT',
@@ -257,7 +258,35 @@ export interface Lwm2mDeviceProfileTransportConfiguration {
}
export interface SnmpDeviceProfileTransportConfiguration {
- [key: string]: any;
+ timeoutMs?: number;
+ retries?: number;
+ communicationConfigs?: SnmpCommunicationConfig[];
+}
+
+export enum SnmpSpecType {
+ TELEMETRY_QUERYING = 'TELEMETRY_QUERYING',
+ CLIENT_ATTRIBUTES_QUERYING = 'CLIENT_ATTRIBUTES_QUERYING',
+ SHARED_ATTRIBUTES_SETTING = 'SHARED_ATTRIBUTES_SETTING',
+ TO_DEVICE_RPC_REQUEST = 'TO_DEVICE_RPC_REQUEST'
+}
+
+export const SnmpSpecTypeTranslationMap = new Map([
+ [SnmpSpecType.TELEMETRY_QUERYING, ' Telemetry'],
+ [SnmpSpecType.CLIENT_ATTRIBUTES_QUERYING, 'Client attributes'],
+ [SnmpSpecType.SHARED_ATTRIBUTES_SETTING, 'Shared attributes'],
+ [SnmpSpecType.TO_DEVICE_RPC_REQUEST, 'RPC request']
+]);
+
+export interface SnmpCommunicationConfig {
+ spec: SnmpSpecType;
+ mappings: SnmpMapping[];
+ queryingFrequencyMs?: number;
+}
+
+export interface SnmpMapping {
+ oid: string;
+ key: string;
+ dataType: DataType;
}
export type DeviceProfileTransportConfigurations = DefaultDeviceProfileTransportConfiguration &
@@ -332,7 +361,11 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT
transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
break;
case DeviceTransportType.SNMP:
- const snmpTransportConfiguration: SnmpDeviceProfileTransportConfiguration = {};
+ const snmpTransportConfiguration: SnmpDeviceProfileTransportConfiguration = {
+ timeoutMs: 500,
+ retries: 0,
+ communicationConfigs: null
+ };
transportConfiguration = {...snmpTransportConfiguration, type: DeviceTransportType.SNMP};
break;
}
@@ -361,7 +394,12 @@ export function createDeviceTransportConfiguration(type: DeviceTransportType): D
transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
break;
case DeviceTransportType.SNMP:
- const snmpTransportConfiguration: SnmpDeviceTransportConfiguration = {};
+ const snmpTransportConfiguration: SnmpDeviceTransportConfiguration = {
+ host: 'localhost',
+ port: 161,
+ protocolVersion: SnmpDeviceProtocolVersion.V2C,
+ community: 'public'
+ };
transportConfiguration = {...snmpTransportConfiguration, type: DeviceTransportType.SNMP};
break;
}
@@ -539,8 +577,57 @@ export interface Lwm2mDeviceTransportConfiguration {
[key: string]: any;
}
+export enum SnmpDeviceProtocolVersion {
+ V1 = 'V1',
+ V2C = 'V2C',
+ V3 = 'V3'
+}
+
+export enum SnmpAuthenticationProtocol {
+ SHA_1 = 'SHA_1',
+ SHA_224 = 'SHA_224',
+ SHA_256 = 'SHA_256',
+ SHA_384 = 'SHA_384',
+ SHA_512 = 'SHA_512',
+ MD5 = 'MD%'
+}
+
+export const SnmpAuthenticationProtocolTranslationMap = new Map([
+ [SnmpAuthenticationProtocol.SHA_1, 'SHA-1'],
+ [SnmpAuthenticationProtocol.SHA_224, 'SHA-224'],
+ [SnmpAuthenticationProtocol.SHA_256, 'SHA-256'],
+ [SnmpAuthenticationProtocol.SHA_384, 'SHA-384'],
+ [SnmpAuthenticationProtocol.SHA_512, 'SHA-512'],
+ [SnmpAuthenticationProtocol.MD5, 'MD5']
+]);
+
+export enum SnmpPrivacyProtocol {
+ DES = 'DES',
+ AES_128 = 'AES_128',
+ AES_192 = 'AES_192',
+ AES_256 = 'AES_256'
+}
+
+export const SnmpPrivacyProtocolTranslationMap = new Map([
+ [SnmpPrivacyProtocol.DES, 'DES'],
+ [SnmpPrivacyProtocol.AES_128, 'AES-128'],
+ [SnmpPrivacyProtocol.AES_192, 'AES-192'],
+ [SnmpPrivacyProtocol.AES_256, 'AES-256'],
+]);
+
export interface SnmpDeviceTransportConfiguration {
- [key: string]: any;
+ host?: string;
+ port?: number;
+ protocolVersion?: SnmpDeviceProtocolVersion;
+ community?: string;
+ username?: string;
+ securityName?: string;
+ contextName?: string;
+ authenticationProtocol?: SnmpAuthenticationProtocol;
+ authenticationPassphrase?: string;
+ privacyProtocol?: SnmpPrivacyProtocol;
+ privacyPassphrase?: string;
+ engineId?: string;
}
export type DeviceTransportConfigurations = DefaultDeviceTransportConfiguration &
diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json
index 172cc2033d..791fd97cc3 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -1297,6 +1297,54 @@
"sw-update-recourse": "Software update CoAP recourse",
"sw-update-recourse-required": "Software update CoAP recourse is required.",
"config-json-tab": "Json Config Profile Device"
+ },
+ "snmp": {
+ "add-communication-config": "Add communication config",
+ "add-mapping": "Add mapping",
+ "authentication-passphrase": "Authentication passphrase",
+ "authentication-passphrase-required": "Authentication passphrase is required.",
+ "authentication-protocol": "Authentication protocol",
+ "authentication-protocol-required": "Authentication protocol is required.",
+ "communication-configs": "Communication configs",
+ "community": "Community string",
+ "community-required": "Community string is required.",
+ "context-name": "Context name",
+ "data-key": "Data key",
+ "data-key-required": "Data key is required.",
+ "data-type": "Data type",
+ "data-type-required": "Data type is required.",
+ "engine-id": "Engine ID",
+ "host": "Host",
+ "host-required": "Host is required.",
+ "oid": "OID",
+ "oid-pattern": "Invalid OID format.",
+ "oid-required": "OID is required.",
+ "please-add-communication-config": "Please add communication config",
+ "please-add-mapping-config": "Please add mapping config",
+ "port": "Port",
+ "port-format": "Invalid port format.",
+ "port-required": "Port is required.",
+ "privacy-passphrase": "Privacy passphrase",
+ "privacy-passphrase-required": "Privacy passphrase is required.",
+ "privacy-protocol": "Privacy protocol",
+ "privacy-protocol-required": "Privacy protocol is required.",
+ "protocol-version": "Protocol version",
+ "protocol-version-required": "Protocol version is required.",
+ "querying-frequency": "Querying frequency, ms",
+ "querying-frequency-invalid-format": "Querying frequency must be a positive integer.",
+ "querying-frequency-required": "Querying frequency is required.",
+ "retries": "Retries",
+ "retries-invalid-format": "Retries must be a positive integer.",
+ "retries-required": "Retries is required.",
+ "scope": "Scope",
+ "scope-required": "Scope is required.",
+ "security-name": "Security name",
+ "security-name-required": "Security name is required.",
+ "timeout-ms": "Timeout, ms",
+ "timeout-ms-invalid-format": "Timeout must be a positive integer.",
+ "timeout-ms-required": "Timeout is required.",
+ "user-name": "User name",
+ "user-name-required": "User name is required."
}
},
"dialog": {