Device Profile controller

This commit is contained in:
Andrii Shvaika 2021-10-15 16:15:01 +03:00
parent 26c54f7a35
commit f47de8cfa6
4 changed files with 140 additions and 23 deletions

View File

@ -165,7 +165,7 @@ public abstract class BaseController {
"See the 'Model' tab of the Response Class for more details. ";
public static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
public static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
public static final String DEVICE_PROFILE_ID_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
public static final String DEVICE_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
public static final String TENANT_ID_PARAM_DESCRIPTION = "A string value representing the tenant id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
public static final String EDGE_ID_PARAM_DESCRIPTION = "A string value representing the edge id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
public static final String CUSTOMER_ID_PARAM_DESCRIPTION = "A string value representing the customer id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
@ -176,6 +176,8 @@ public abstract class BaseController {
public static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'";
public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority.";
protected static final String TENANT_AND_USER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority.";
protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page";
protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0";
@ -186,6 +188,7 @@ public abstract class BaseController {
protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name.";
protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title.";
protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name.";
protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name.";
protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title.";
protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name.";
protected static final String EVENT_TEXT_SEARCH_DESCRIPTION = "The value is not used in searching.";
@ -194,6 +197,7 @@ public abstract class BaseController {
protected static final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title";
protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city";
protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle";
protected static final String DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, transportType, description, isDefault";
protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle";
protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status";
protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id";
@ -201,11 +205,13 @@ public abstract class BaseController {
protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus";
protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)";
protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC";
protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP";
protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. ";
protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. ";
protected static final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that also contains name of the alarm originator.";
protected static final String RELATION_INFO_DESCRIPTION = "Relation Info is an extension of the default Relation object that contains information about the 'from' and 'to' entity names. ";
protected static final String EDGE_INFO_DESCRIPTION = "Edge Info is an extension of the default Edge object that contains information about the assigned customer name. ";
protected static final String DEVICE_PROFILE_INFO_DESCRIPTION = "Device Profile Info is a lightweight object that includes main information about Device Profile excluding the heavyweight configuration object. ";
protected static final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name.";
protected static final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name.";

View File

@ -415,7 +415,7 @@ public class DeviceController extends BaseController {
@RequestParam int page,
@ApiParam(value = DEVICE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_PROFILE_ID_DESCRIPTION)
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String deviceProfileId,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ -509,7 +509,7 @@ public class DeviceController extends BaseController {
@RequestParam int page,
@ApiParam(value = DEVICE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_PROFILE_ID_DESCRIPTION)
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String deviceProfileId,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,

View File

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -58,10 +60,16 @@ public class DeviceProfileController extends BaseController {
@Autowired
private TimeseriesService timeseriesService;
@ApiOperation(value = "Get Device Profile (getDeviceProfileById)",
notes = "Fetch the Device Profile object based on the provided Device Profile Id. " +
"The server checks that the device profile is owned by the same tenant. " + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
public DeviceProfile getDeviceProfileById(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
public DeviceProfile getDeviceProfileById(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
@ -71,10 +79,16 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Get Device Profile Info (getDeviceProfileInfoById)",
notes = "Fetch the Device Profile Info object based on the provided Device Profile Id. "
+ DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
public DeviceProfileInfo getDeviceProfileInfoById(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
public DeviceProfileInfo getDeviceProfileInfoById(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
@ -84,6 +98,10 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Get Default Device Profile (getDefaultDeviceProfileInfo)",
notes = "Fetch the Default Device Profile Info object. " +
DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
@ -95,10 +113,18 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Get time-series keys (getTimeseriesKeys)",
notes = "Get a set of unique time-series keys used by devices that belong to specified profile. " +
"If profile is not set returns a list of unique keys among all profiles. " +
"The call is used for auto-complete in the UI forms. " +
"The implementation limits the number of devices that participate in search to 100 as a trade of between accurate results and time-consuming queries. " +
TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/devices/keys/timeseries", method = RequestMethod.GET)
@ResponseBody
public List<String> getTimeseriesKeys(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException {
DeviceProfileId deviceProfileId;
if (StringUtils.isNotEmpty(deviceProfileIdStr)) {
@ -115,10 +141,18 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Get attribute keys (getAttributesKeys)",
notes = "Get a set of unique attribute keys used by devices that belong to specified profile. " +
"If profile is not set returns a list of unique keys among all profiles. " +
"The call is used for auto-complete in the UI forms. " +
"The implementation limits the number of devices that participate in search to 100 as a trade of between accurate results and time-consuming queries. " +
TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/devices/keys/attributes", method = RequestMethod.GET)
@ResponseBody
public List<String> getAttributesKeys(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException {
DeviceProfileId deviceProfileId;
if (StringUtils.isNotEmpty(deviceProfileIdStr)) {
@ -135,10 +169,20 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Create Or Update Device Profile (saveDevice)",
notes = "Create or update the Device Profile. When creating device profile, platform generates device profile id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
"The newly created device profile id will be present in the response. " +
"Specify existing device profile id to update the device profile. " +
"Referencing non-existing device profile Id will cause 'Not Found' error. " +
"\n\nDevice profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json",
consumes = "application/json")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile", method = RequestMethod.POST)
@ResponseBody
public DeviceProfile saveDeviceProfile(@RequestBody DeviceProfile deviceProfile) throws ThingsboardException {
public DeviceProfile saveDeviceProfile(
@ApiParam(value = "A JSON value representing the device profile.")
@RequestBody DeviceProfile deviceProfile) throws ThingsboardException {
try {
boolean created = deviceProfile.getId() == null;
deviceProfile.setTenantId(getTenantId());
@ -180,10 +224,16 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Delete device profile (deleteDeviceProfile)",
notes = "Deletes the device profile. Referencing non-existing device profile Id will cause an error. " +
"Can't delete the device profile if it is referenced by existing devices." + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteDeviceProfile(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
public void deleteDeviceProfile(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
@ -207,10 +257,15 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Make Device Profile Default (setDefaultDeviceProfile)",
notes = "Marks device profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}/default", method = RequestMethod.POST)
@ResponseBody
public DeviceProfile setDefaultDeviceProfile(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
public DeviceProfile setDefaultDeviceProfile(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
@ -238,14 +293,24 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Get Device Profiles (getDeviceProfiles)",
notes = "Returns a page of devices profile objects owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DeviceProfile> getDeviceProfiles(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
public PageData<DeviceProfile> getDeviceProfiles(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfiles(getTenantId(), pageLink));
@ -254,15 +319,26 @@ public class DeviceProfileController extends BaseController {
}
}
@ApiOperation(value = "Get Device Profiles for transport type (getDeviceProfileInfos)",
notes = "Returns a page of devices profile info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH,
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DeviceProfileInfo> getDeviceProfileInfos(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder,
@RequestParam(required = false) String transportType) throws ThingsboardException {
public PageData<DeviceProfileInfo> getDeviceProfileInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "Type of the transport", allowableValues = TRANSPORT_TYPE_ALLOWABLE_VALUES)
@RequestParam(required = false) String transportType) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfileInfos(getTenantId(), pageLink, transportType));

View File

@ -17,6 +17,8 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@ -34,34 +36,51 @@ import java.io.IOException;
import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo.mapper;
@ApiModel
@Data
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId, HasOtaPackage {
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id that owns the profile.", readOnly = true)
private TenantId tenantId;
@NoXss
@ApiModelProperty(position = 4, value = "Unique Device Profile Name in scope of Tenant.", example = "Moisture Sensor")
private String name;
@NoXss
@ApiModelProperty(position = 11, value = "Device Profile description. ")
private String description;
@ApiModelProperty(position = 12, value = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ")
private String image;
private boolean isDefault;
@ApiModelProperty(position = 16, value = "Type of the profile. Always 'DEFAULT' for now. Reserved for future use.")
private DeviceProfileType type;
@ApiModelProperty(position = 14, value = "Type of the transport used to connect the device. Default transport supports HTTP, CoAP and MQTT.")
private DeviceTransportType transportType;
@ApiModelProperty(position = 15, value = "Provisioning strategy.")
private DeviceProfileProvisionType provisionType;
@ApiModelProperty(position = 7, value = "Reference to the rule chain. " +
"If present, the specified rule chain will be used to process all messages related to device, including telemetry, attribute updates, etc. " +
"Otherwise, the root rule chain will be used to process those messages.")
private RuleChainId defaultRuleChainId;
@ApiModelProperty(position = 6, value = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.")
private DashboardId defaultDashboardId;
@NoXss
@ApiModelProperty(position = 8, value = "Reference to the rule engine queue. " +
"If present, the specified queue will be used to store all unprocessed messages related to device, including telemetry, attribute updates, etc. " +
"Otherwise, the 'Main' queue will be used to store those messages.")
private String defaultQueueName;
@Valid
private transient DeviceProfileData profileData;
@JsonIgnore
private byte[] profileDataBytes;
@NoXss
@ApiModelProperty(position = 13, value = "Unique provisioning key used by 'Device Provisioning' feature.")
private String provisionDeviceKey;
@ApiModelProperty(position = 9, value = "Reference to the firmware OTA package. If present, the specified package will be used as default device firmware. ")
private OtaPackageId firmwareId;
@ApiModelProperty(position = 10, value = "Reference to the software OTA package. If present, the specified package will be used as default device software. ")
private OtaPackageId softwareId;
public DeviceProfile() {
@ -88,16 +107,32 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
this.softwareId = deviceProfile.getSoftwareId();
}
@ApiModelProperty(position = 1, value = "JSON object with the device profile Id. " +
"Specify this field to update the device profile. " +
"Referencing non-existing device profile Id will cause error. " +
"Omit this field to create new device profile.")
@Override
public DeviceProfileId getId() {
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the profile creation, in milliseconds", example = "1609459200000", readOnly = true)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@Override
public String getSearchText() {
return getName();
}
@Override
public String getName() {
return name;
@ApiModelProperty(position = 5, value = "Used to mark the default profile. Default profile is used when the device profile is not specified during device creation.")
public boolean isDefault(){
return isDefault;
}
@ApiModelProperty(position = 16, value = "Complex JSON object that includes addition device profile configuration (transport, alarm rules, etc).")
public DeviceProfileData getProfileData() {
if (profileData != null) {
return profileData;