diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index bb34f6d5b2..36798b5b75 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -73,8 +73,12 @@ import org.thingsboard.server.service.entitiy.device.TbDeviceService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -125,6 +129,8 @@ public class DeviceController extends BaseController { private final TbDeviceService tbDeviceService; + private final SystemSecurityService systemSecurityService; + @ApiOperation(value = "Get Device (getDeviceById)", notes = "Fetch the Device object based on the provided Device Id. " + "If the user has the authority of 'TENANT_ADMIN', the server checks that the device is owned by the same tenant. " + @@ -155,6 +161,27 @@ public class DeviceController extends BaseController { return checkDeviceInfoId(deviceId, Operation.READ); } + @ApiOperation(value = "Get commands to publish device telemetry (getDevicePublishTelemetryCommands)", + notes = "Fetch the list of commands to publish device telemetry based on device profile " + + "If the user has the authority of 'Tenant Administrator', the server checks that the device is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer. " + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/device/info/{deviceId}/commands", method = RequestMethod.GET) + @ResponseBody + public List getDevicePublishTelemetryCommands(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_ID) String strDeviceId, HttpServletRequest request) throws ThingsboardException, URISyntaxException { + checkParameter(DEVICE_ID, strDeviceId); + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); + Device device = checkDeviceId(deviceId, Operation.READ_CREDENTIALS); + URI baseUri = new URI(systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request)); + List commands = deviceService.findDevicePublishTelemetryCommands(device); + return commands.stream() + .map(s -> s.replace("$THINGSBOARD_HOST_NAME", baseUri.getHost()) + .replace("$THINGSBOARD_BASE_URL", baseUri.toString())) + .collect(Collectors.toList()); + } + @ApiOperation(value = "Create Or Update Device (saveDevice)", notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK + "Device credentials are also generated if not provided in the 'accessToken' request parameter. " + diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index a90ea9a572..d8e2a62040 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -43,6 +43,8 @@ public interface DeviceService extends EntityDaoService { DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId); + List findDevicePublishTelemetryCommands(Device device); + Device findDeviceById(TenantId tenantId, DeviceId deviceId); ListenableFuture findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 46830f8f76..3f52ec5afe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -38,6 +39,7 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfiguration; @@ -47,6 +49,10 @@ import org.thingsboard.server.common.data.device.data.DeviceData; import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; +import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; @@ -122,6 +128,67 @@ public class DeviceServiceImpl extends AbstractCachedEntityService findDevicePublishTelemetryCommands(Device device) { + DeviceId deviceId = device.getId(); + log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId); + validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); + + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); + DeviceCredentialsType credentialsType = deviceCredentials.getCredentialsType(); + + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); + + ArrayList commands = new ArrayList<>(); + switch (deviceProfile.getTransportType()) { + case DEFAULT: + switch (credentialsType) { + case ACCESS_TOKEN: + commands.add(getMqttAccessTokenCommand(deviceCredentials) + " -m {temperature:15}"); + commands.add(getHttpAccessTokenCommand(deviceCredentials) + " --data \"{temperature:16}\""); + commands.add("echo -n {temperature:17} | " + getCoapAccessTokenCommand(deviceCredentials) + " -f-"); + break; + case MQTT_BASIC: + commands.add(getMqttBasicPublishCommand(deviceCredentials) + " -m {temperature:18}"); + break; + case X509_CERTIFICATE: + commands.add(getMqttX509Command() + " -m {temperature:19}"); + break; + } + break; + case MQTT: + MqttDeviceProfileTransportConfiguration transportConfiguration = + (MqttDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); + TransportPayloadType payloadType = transportConfiguration.getTransportPayloadTypeConfiguration().getTransportPayloadType(); + String payload = (payloadType == TransportPayloadType.PROTOBUF) ? " -f protobufFileName" : " -m {temperature:25}"; + switch (credentialsType) { + case ACCESS_TOKEN: + commands.add(getMqttAccessTokenCommand(deviceCredentials) + payload); + break; + case MQTT_BASIC: + commands.add(getMqttBasicPublishCommand(deviceCredentials) + payload); + break; + case X509_CERTIFICATE: + commands.add(getMqttX509Command() + payload); + break; + } + break; + case COAP: + CoapDeviceProfileTransportConfiguration coapTransportConfiguration = + (CoapDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); + CoapDeviceTypeConfiguration coapConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration(); + if (coapConfiguration instanceof DefaultCoapDeviceTypeConfiguration) { + DefaultCoapDeviceTypeConfiguration configuration = + (DefaultCoapDeviceTypeConfiguration) coapTransportConfiguration.getCoapDeviceTypeConfiguration(); + TransportPayloadType transportPayloadType = configuration.getTransportPayloadTypeConfiguration().getTransportPayloadType(); + String payloadExample = (transportPayloadType == TransportPayloadType.PROTOBUF) ? " -t binary -f protobufFileName" : " -t json -f jsonFileName"; + commands.add(getCoapAccessTokenCommand(deviceCredentials) + payloadExample); + } + break; + } + return commands; + } + @Override public Device findDeviceById(TenantId tenantId, DeviceId deviceId) { log.trace("Executing findDeviceById [{}]", deviceId); @@ -681,4 +748,36 @@ public class DeviceServiceImpl extends AbstractCachedEntityService