Browse Source

UI: Device profile transport configuration

pull/3477/head
Igor Kulikov 6 years ago
parent
commit
3adbb481a1
  1. 2
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  2. 6
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  3. 5
      ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html
  4. 4
      ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.ts
  5. 11
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.html
  6. 33
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts
  7. 24
      ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-transport-configuration.component.html
  8. 97
      ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-transport-configuration.component.ts
  9. 2
      ui-ngx/src/app/modules/home/components/profile/device/device-profile-configuration.component.ts
  10. 27
      ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html
  11. 103
      ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts
  12. 11
      ui-ngx/src/app/modules/home/pages/device-profile/device-profiles-table-config.resolver.ts
  13. 84
      ui-ngx/src/app/shared/models/device.models.ts
  14. 5
      ui-ngx/src/assets/locale/locale.constant-en_US.json

2
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -181,8 +181,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
switch (deviceProfile.getTransportType()){
case DEFAULT:
deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration());
break;
case MQTT:
deviceData.setTransportConfiguration(new MqttDeviceTransportConfiguration());
break;
case LWM2M:
deviceData.setTransportConfiguration(new Lwm2mDeviceTransportConfiguration());
break;

6
ui-ngx/src/app/modules/home/components/home-components.module.ts

@ -92,6 +92,8 @@ import { DefaultDeviceProfileConfigurationComponent } from './profile/device/def
import { DeviceProfileConfigurationComponent } from './profile/device/device-profile-configuration.component';
import { DeviceProfileDataComponent } from './profile/device-profile-data.component';
import { DeviceProfileComponent } from './profile/device-profile.component';
import { DefaultDeviceProfileTransportConfigurationComponent } from './profile/device/default-device-profile-transport-configuration.component';
import { DeviceProfileTransportConfigurationComponent } from './profile/device/device-profile-transport-configuration.component';
@NgModule({
declarations:
@ -165,6 +167,8 @@ import { DeviceProfileComponent } from './profile/device-profile.component';
TenantProfileDialogComponent,
DefaultDeviceProfileConfigurationComponent,
DeviceProfileConfigurationComponent,
DefaultDeviceProfileTransportConfigurationComponent,
DeviceProfileTransportConfigurationComponent,
DeviceProfileDataComponent,
DeviceProfileComponent
],
@ -229,6 +233,8 @@ import { DeviceProfileComponent } from './profile/device-profile.component';
TenantProfileDialogComponent,
DefaultDeviceProfileConfigurationComponent,
DeviceProfileConfigurationComponent,
DefaultDeviceProfileTransportConfigurationComponent,
DeviceProfileTransportConfigurationComponent,
DeviceProfileDataComponent,
DeviceProfileComponent
],

5
ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html

@ -34,7 +34,10 @@
<div translate>device-profile.transport-configuration</div>
</mat-panel-title>
</mat-expansion-panel-header>
TODO
<tb-device-profile-transport-configuration
formControlName="transportConfiguration"
required>
</tb-device-profile-transport-configuration>
</mat-expansion-panel>
</mat-accordion>
</div>

4
ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.ts

@ -62,7 +62,8 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit
ngOnInit() {
this.deviceProfileDataFormGroup = this.fb.group({
configuration: [null, Validators.required]
configuration: [null, Validators.required],
transportConfiguration: [null, Validators.required]
});
this.deviceProfileDataFormGroup.valueChanges.subscribe(() => {
this.updateModel();
@ -80,6 +81,7 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit
writeValue(value: DeviceProfileData | null): void {
this.deviceProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false});
this.deviceProfileDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false});
}
private updateModel() {

11
ui-ngx/src/app/modules/home/components/profile/device-profile.component.html

@ -65,6 +65,17 @@
{{ 'device-profile.type-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>device-profile.transport-type</mat-label>
<mat-select formControlName="transportType" required>
<mat-option *ngFor="let type of deviceTransportTypes" [value]="type">
{{deviceTransportTypeTranslations.get(type) | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="entityForm.get('transportType').hasError('required')">
{{ 'device-profile.transport-type-required' | translate }}
</mat-error>
</mat-form-field>
<tb-device-profile-data
formControlName="profileData"
required>

33
ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts

@ -27,7 +27,10 @@ import {
DeviceProfile,
DeviceProfileData,
DeviceProfileType,
deviceProfileTypeTranslationMap
deviceProfileTypeTranslationMap,
DeviceTransportType,
deviceTransportTypeTranslationMap,
createDeviceProfileTransportConfiguration
} from '@shared/models/device.models';
import { EntityType } from '@shared/models/entity-type.models';
import { RuleChainId } from '@shared/models/id/rule-chain-id';
@ -48,6 +51,10 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
deviceProfileTypeTranslations = deviceProfileTypeTranslationMap;
deviceTransportTypes = Object.keys(DeviceTransportType);
deviceTransportTypeTranslations = deviceTransportTypeTranslationMap;
constructor(protected store: Store<AppState>,
protected translate: TranslateService,
@Optional() @Inject('entity') protected entityValue: DeviceProfile,
@ -68,7 +75,8 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
const form = this.fb.group(
{
name: [entity ? entity.name : '', [Validators.required]],
type: [entity ? entity.type : '', [Validators.required]],
type: [entity ? entity.type : null, [Validators.required]],
transportType: [entity ? entity.transportType : null, [Validators.required]],
profileData: [entity && !this.isAdd ? entity.profileData : {}, []],
defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []],
description: [entity ? entity.description : '', []],
@ -77,6 +85,9 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
form.get('type').valueChanges.subscribe(() => {
this.deviceProfileTypeChanged(form);
});
form.get('transportType').valueChanges.subscribe(() => {
this.deviceProfileTransportTypeChanged(form);
});
this.checkIsNewDeviceProfile(entity, form);
return form;
}
@ -84,6 +95,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
private checkIsNewDeviceProfile(entity: DeviceProfile, form: FormGroup) {
if (entity && !entity.id) {
form.get('type').patchValue(DeviceProfileType.DEFAULT, {emitEvent: true});
form.get('transportType').patchValue(DeviceTransportType.DEFAULT, {emitEvent: true});
}
}
@ -92,16 +104,31 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
let profileData: DeviceProfileData = form.getRawValue().profileData;
if (!profileData) {
profileData = {
configuration: null
configuration: null,
transportConfiguration: null
};
}
profileData.configuration = createDeviceProfileConfiguration(deviceProfileType);
form.patchValue({profileData});
}
private deviceProfileTransportTypeChanged(form: FormGroup) {
const deviceTransportType: DeviceTransportType = form.get('transportType').value;
let profileData: DeviceProfileData = form.getRawValue().profileData;
if (!profileData) {
profileData = {
configuration: null,
transportConfiguration: null
};
}
profileData.transportConfiguration = createDeviceProfileTransportConfiguration(deviceTransportType);
form.patchValue({profileData});
}
updateForm(entity: DeviceProfile) {
this.entityForm.patchValue({name: entity.name});
this.entityForm.patchValue({type: entity.type});
this.entityForm.patchValue({transportType: entity.transportType});
this.entityForm.patchValue({profileData: entity.profileData});
this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null});
this.entityForm.patchValue({description: entity.description});

24
ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-transport-configuration.component.html

@ -0,0 +1,24 @@
<!--
Copyright © 2016-2020 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.
-->
<form [formGroup]="defaultDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;">
<tb-json-object-edit
[required]="required"
label="{{ 'device-profile.transport-type-default' | translate }}"
formControlName="configuration">
</tb-json-object-edit>
</form>

97
ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-transport-configuration.component.ts

@ -0,0 +1,97 @@
///
/// Copyright © 2016-2020 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, 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 {
DefaultDeviceProfileTransportConfiguration,
DeviceProfileTransportConfiguration,
DeviceTransportType
} from '@shared/models/device.models';
@Component({
selector: 'tb-default-device-profile-transport-configuration',
templateUrl: './default-device-profile-transport-configuration.component.html',
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DefaultDeviceProfileTransportConfigurationComponent),
multi: true
}]
})
export class DefaultDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
defaultDeviceProfileTransportConfigurationFormGroup: FormGroup;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
}
@Input()
disabled: boolean;
private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>,
private fb: FormBuilder) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
this.defaultDeviceProfileTransportConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.defaultDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.defaultDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false});
} else {
this.defaultDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false});
}
}
writeValue(value: DefaultDeviceProfileTransportConfiguration | null): void {
this.defaultDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
}
private updateModel() {
let configuration: DeviceProfileTransportConfiguration = null;
if (this.defaultDeviceProfileTransportConfigurationFormGroup.valid) {
configuration = this.defaultDeviceProfileTransportConfigurationFormGroup.getRawValue().configuration;
configuration.type = DeviceTransportType.DEFAULT;
}
this.propagateChange(configuration);
}
}

2
ui-ngx/src/app/modules/home/components/profile/device/device-profile-configuration.component.ts

@ -20,7 +20,7 @@ import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { DeviceProfileConfiguration, DeviceProfileType } from '@shared/models/device.models';
import { deepClone } from '../../../../../core/utils';
import { deepClone } from '@core/utils';
@Component({
selector: 'tb-device-profile-configuration',

27
ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html

@ -0,0 +1,27 @@
<!--
Copyright © 2016-2020 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.
-->
<div [formGroup]="deviceProfileTransportConfigurationFormGroup">
<div [ngSwitch]="transportType">
<ng-template [ngSwitchCase]="deviceTransportType.DEFAULT">
<tb-default-device-profile-configuration
[required]="required"
formControlName="configuration">
</tb-default-device-profile-configuration>
</ng-template>
</div>
</div>

103
ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts

@ -0,0 +1,103 @@
///
/// Copyright © 2016-2020 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, 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 { DeviceProfileTransportConfiguration, DeviceTransportType } from '@shared/models/device.models';
import { deepClone } from '@core/utils';
@Component({
selector: 'tb-device-profile-transport-configuration',
templateUrl: './device-profile-transport-configuration.component.html',
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DeviceProfileTransportConfigurationComponent),
multi: true
}]
})
export class DeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
deviceTransportType = DeviceTransportType;
deviceProfileTransportConfigurationFormGroup: FormGroup;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
}
@Input()
disabled: boolean;
transportType: DeviceTransportType;
private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>,
private fb: FormBuilder) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
this.deviceProfileTransportConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.deviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.deviceProfileTransportConfigurationFormGroup.disable({emitEvent: false});
} else {
this.deviceProfileTransportConfigurationFormGroup.enable({emitEvent: false});
}
}
writeValue(value: DeviceProfileTransportConfiguration | null): void {
this.transportType = value?.type;
const configuration = deepClone(value);
if (configuration) {
delete configuration.type;
}
this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
}
private updateModel() {
let configuration: DeviceProfileTransportConfiguration = null;
if (this.deviceProfileTransportConfigurationFormGroup.valid) {
configuration = this.deviceProfileTransportConfigurationFormGroup.getRawValue().configuration;
configuration.type = this.transportType;
}
this.propagateChange(configuration);
}
}

11
ui-ngx/src/app/modules/home/pages/device-profile/device-profiles-table-config.resolver.ts

@ -27,7 +27,11 @@ import { DatePipe } from '@angular/common';
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
import { EntityAction } from '@home/models/entity/entity-component.models';
import { DialogService } from '@core/services/dialog.service';
import { DeviceProfile, deviceProfileTypeTranslationMap } from '@shared/models/device.models';
import {
DeviceProfile,
deviceProfileTypeTranslationMap,
deviceTransportTypeTranslationMap
} from '@shared/models/device.models';
import { DeviceProfileService } from '@core/http/device-profile.service';
import { DeviceProfileComponent } from '../../components/profile/device-profile.component';
import { DeviceProfileTabsComponent } from './device-profile-tabs.component';
@ -56,7 +60,10 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
new EntityTableColumn<DeviceProfile>('type', 'device-profile.type', '20%', (deviceProfile) => {
return this.translate.instant(deviceProfileTypeTranslationMap.get(deviceProfile.type));
}),
new EntityTableColumn<DeviceProfile>('description', 'device-profile.description', '60%'),
new EntityTableColumn<DeviceProfile>('transportType', 'device-profile.transport-type', '20%', (deviceProfile) => {
return this.translate.instant(deviceTransportTypeTranslationMap.get(deviceProfile.transportType));
}),
new EntityTableColumn<DeviceProfile>('description', 'device-profile.description', '40%'),
new EntityTableColumn<DeviceProfile>('isDefault', 'device-profile.default', '60px',
entity => {
return checkBoxCell(entity.default);

84
ui-ngx/src/app/shared/models/device.models.ts

@ -28,12 +28,26 @@ export enum DeviceProfileType {
DEFAULT = 'DEFAULT'
}
export enum DeviceTransportType {
DEFAULT = 'DEFAULT',
MQTT = 'MQTT',
LWM2M = 'LWM2M'
}
export const deviceProfileTypeTranslationMap = new Map<DeviceProfileType, string>(
[
[DeviceProfileType.DEFAULT, 'device-profile.type-default']
]
);
export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, string>(
[
[DeviceTransportType.DEFAULT, 'device-profile.transport-type-default'],
[DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt'],
[DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m']
]
);
export interface DefaultDeviceProfileConfiguration {
[key: string]: any;
}
@ -44,6 +58,26 @@ export interface DeviceProfileConfiguration extends DeviceProfileConfigurations
type: DeviceProfileType;
}
export interface DefaultDeviceProfileTransportConfiguration {
[key: string]: any;
}
export interface MqttDeviceProfileTransportConfiguration {
[key: string]: any;
}
export interface Lwm2mDeviceProfileTransportConfiguration {
[key: string]: any;
}
export type DeviceProfileTransportConfigurations = DefaultDeviceProfileTransportConfiguration &
MqttDeviceProfileTransportConfiguration &
Lwm2mDeviceProfileTransportConfiguration;
export interface DeviceProfileTransportConfiguration extends DeviceProfileTransportConfigurations {
type: DeviceTransportType;
}
export function createDeviceProfileConfiguration(type: DeviceProfileType): DeviceProfileConfiguration {
let configuration: DeviceProfileConfiguration = null;
if (type) {
@ -57,8 +91,30 @@ export function createDeviceProfileConfiguration(type: DeviceProfileType): Devic
return configuration;
}
export function createDeviceProfileTransportConfiguration(type: DeviceTransportType): DeviceProfileTransportConfiguration {
let transportConfiguration: DeviceProfileTransportConfiguration = null;
if (type) {
switch (type) {
case DeviceTransportType.DEFAULT:
const defaultTransportConfiguration: DefaultDeviceProfileTransportConfiguration = {};
transportConfiguration = {...defaultTransportConfiguration, type: DeviceTransportType.DEFAULT};
break;
case DeviceTransportType.MQTT:
const mqttTransportConfiguration: MqttDeviceProfileTransportConfiguration = {};
transportConfiguration = {...mqttTransportConfiguration, type: DeviceTransportType.MQTT};
break;
case DeviceTransportType.LWM2M:
const lwm2mTransportConfiguration: Lwm2mDeviceProfileTransportConfiguration = {};
transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
break;
}
}
return transportConfiguration;
}
export interface DeviceProfileData {
configuration: DeviceProfileConfiguration;
transportConfiguration: DeviceProfileTransportConfiguration;
}
export interface DeviceProfile extends BaseData<DeviceProfileId> {
@ -67,29 +123,49 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> {
description?: string;
default: boolean;
type: DeviceProfileType;
transportType: DeviceTransportType;
defaultRuleChainId?: RuleChainId;
profileData: DeviceProfileData;
}
export interface DeviceProfileInfo extends EntityInfoData {
type: DeviceProfileType;
transportType: DeviceTransportType;
}
export interface DefaultDeviceConfiguration {
[key: string]: any;
}
export interface Lwm2mDeviceConfiguration {
[key: string]: any;
}
export type DeviceConfigurations = DefaultDeviceConfiguration & Lwm2mDeviceConfiguration;
export type DeviceConfigurations = DefaultDeviceConfiguration;
export interface DeviceConfiguration extends DeviceConfigurations {
type: DeviceProfileType;
}
export interface DefaultDeviceTransportConfiguration {
[key: string]: any;
}
export interface MqttDeviceTransportConfiguration {
[key: string]: any;
}
export interface Lwm2mDeviceTransportConfiguration {
[key: string]: any;
}
export type DeviceTransportConfigurations = DefaultDeviceTransportConfiguration &
MqttDeviceTransportConfiguration &
Lwm2mDeviceTransportConfiguration;
export interface DeviceTransportConfiguration extends DeviceTransportConfigurations {
type: DeviceTransportType;
}
export interface DeviceData {
configuration: DeviceConfiguration;
transportConfiguration: DeviceTransportConfiguration;
}
export interface Device extends BaseData<DeviceId> {

5
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -770,6 +770,11 @@
"type": "Profile type",
"type-required": "Profile type is required.",
"type-default": "Default",
"transport-type": "Transport type",
"transport-type-required": "Transport type is required.",
"transport-type-default": "Default",
"transport-type-mqtt": "MQTT",
"transport-type-lwm2m": "LWM2M",
"description": "Description",
"default": "Default",
"profile-configuration": "Profile configuration",

Loading…
Cancel
Save