【功能新增】IoT:设备注册 sub register 逻辑
This commit is contained in:
parent
5f7bb8041f
commit
4254c06c37
|
@ -53,6 +53,15 @@ public interface IotDeviceUpstreamApi {
|
|||
@PostMapping(PREFIX + "/register")
|
||||
CommonResult<Boolean> registerDevice(@Valid @RequestBody IotDeviceRegisterReqDTO registerReqDTO);
|
||||
|
||||
// TODO @芋艿:这个需要 plugins 接入下
|
||||
/**
|
||||
* 注册子设备
|
||||
*
|
||||
* @param registerReqDTO 注册子设备 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/register-sub")
|
||||
CommonResult<Boolean> registerSubDevice(@Valid @RequestBody IotDeviceRegisterSubReqDTO registerReqDTO);
|
||||
|
||||
// ========== 插件相关 ==========
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
|||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 设备【注册】注册 Request DTO
|
||||
* IoT 设备【注册】自己 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IoT 设备【注册】子设备 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceRegisterSubReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 子设备数组
|
||||
*/
|
||||
@NotEmpty(message = "子设备不能为空")
|
||||
private List<Device> params;
|
||||
|
||||
/**
|
||||
* 设备信息
|
||||
*/
|
||||
@Data
|
||||
public static class Device {
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -29,8 +29,8 @@ public enum IotDeviceMessageIdentifierEnum {
|
|||
OTA_REPORT("report"), // 上行
|
||||
|
||||
REGISTER_REGISTER("register"), // 上行
|
||||
REGISTER_SUB_REGISTER("sub_register"), // 上行
|
||||
REGISTER_SUB_UNREGISTER("sub_unregister"),; // 下行
|
||||
REGISTER_REGISTER_SUB("register_sub"), // 上行
|
||||
REGISTER_UNREGISTER_SUB("unregister_sub"),; // 下行
|
||||
|
||||
/**
|
||||
* 标志符
|
||||
|
|
|
@ -46,4 +46,14 @@ public enum IotProductDeviceTypeEnum implements ArrayValuable<Integer> {
|
|||
return GATEWAY.getType().equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是网关子设备
|
||||
*
|
||||
* @param type 类型
|
||||
* @return 是否是网关子设备
|
||||
*/
|
||||
public static boolean isGatewaySub(Integer type) {
|
||||
return GATEWAY_SUB.getType().equals(type);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,12 @@ public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
|
|||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) {
|
||||
deviceUpstreamService.registerSubDevice(registerReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 插件相关 ==========
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
|
@ -18,8 +17,7 @@ public class IotDeviceSaveReqVO {
|
|||
@Size(max = 50, message = "设备编号长度不能超过 50 个字符")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.AUTO, example = "王五")
|
||||
private String deviceName;
|
||||
|
||||
@Schema(description = "备注名称", example = "张三")
|
||||
|
|
|
@ -30,10 +30,12 @@ public interface IotDeviceService {
|
|||
*
|
||||
* @param productKey 产品标识
|
||||
* @param deviceName 设备名称
|
||||
* @param gatewayId 网关设备 ID
|
||||
* @return 设备
|
||||
*/
|
||||
IotDeviceDO createDevice(@NotEmpty(message = "产品标识不能为空") String productKey,
|
||||
@NotEmpty(message = "设备名称不能为空") String deviceName);
|
||||
@NotEmpty(message = "设备名称不能为空") String deviceName,
|
||||
Long gatewayId);
|
||||
|
||||
/**
|
||||
* 更新设备
|
||||
|
@ -42,6 +44,17 @@ public interface IotDeviceService {
|
|||
*/
|
||||
void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO);
|
||||
|
||||
// TODO @芋艿:先这么实现。未来看情况,要不要自己实现
|
||||
/**
|
||||
* 更新设备的所属网关
|
||||
*
|
||||
* @param id 编号
|
||||
* @param gatewayId 网关设备 ID
|
||||
*/
|
||||
default void updateDeviceGateway(Long id, Long gatewayId) {
|
||||
updateDevice(new IotDeviceSaveReqVO().setId(id).setGatewayId(gatewayId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备状态
|
||||
*
|
||||
|
|
|
@ -64,22 +64,10 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
if (product == null) {
|
||||
throw exception(PRODUCT_NOT_EXISTS);
|
||||
}
|
||||
// 1.2 校验设备标识是否唯一
|
||||
TenantUtils.executeIgnore(() -> {
|
||||
if (deviceMapper.selectByDeviceKey(createReqVO.getDeviceKey()) != null) {
|
||||
throw exception(PRODUCT_KEY_EXISTS);
|
||||
}
|
||||
});
|
||||
// 1.3 校验设备名称在同一产品下是否唯一
|
||||
if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), createReqVO.getDeviceName()) != null) {
|
||||
throw exception(DEVICE_NAME_EXISTS);
|
||||
}
|
||||
// 1.4 校验父设备是否为合法网关
|
||||
if (IotProductDeviceTypeEnum.isGateway(product.getDeviceType())
|
||||
&& createReqVO.getGatewayId() != null) {
|
||||
validateGatewayDeviceExists(createReqVO.getGatewayId());
|
||||
}
|
||||
// 1.5 校验分组存在
|
||||
// 1.2 统一校验
|
||||
validateCreateDeviceParam(product.getProductKey(), createReqVO.getDeviceName(), createReqVO.getDeviceKey(),
|
||||
createReqVO.getGatewayId(), product);
|
||||
// 1.3 校验分组存在
|
||||
deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds());
|
||||
|
||||
// 2. 插入到数据库
|
||||
|
@ -90,34 +78,47 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IotDeviceDO createDevice(String productKey, String deviceName) {
|
||||
public IotDeviceDO createDevice(String productKey, String deviceName, Long gatewayId) {
|
||||
String deviceKey = generateDeviceKey();
|
||||
// 1.1 校验产品是否存在
|
||||
IotProductDO product = TenantUtils.executeIgnore(() ->
|
||||
productService.getProductByProductKey(productKey));
|
||||
if (product == null) {
|
||||
throw exception(PRODUCT_NOT_EXISTS);
|
||||
}
|
||||
// 1.2 校验设备标识是否唯一
|
||||
String deviceKey = generateDeviceKey();
|
||||
TenantUtils.executeIgnore(() -> {
|
||||
if (deviceMapper.selectByDeviceKey(deviceKey) != null) {
|
||||
throw exception(PRODUCT_KEY_EXISTS);
|
||||
}
|
||||
});
|
||||
return TenantUtils.execute(product.getTenantId(), () -> {
|
||||
// 1.3 校验设备名称在同一产品下是否唯一
|
||||
if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), deviceName) != null) {
|
||||
throw exception(DEVICE_NAME_EXISTS);
|
||||
}
|
||||
// 1.2 校验设备名称在同一产品下是否唯一
|
||||
validateCreateDeviceParam(productKey, deviceName, deviceKey, gatewayId, product);
|
||||
|
||||
// 2. 插入到数据库
|
||||
IotDeviceDO device = new IotDeviceDO().setDeviceName(deviceName).setDeviceKey(deviceKey);
|
||||
IotDeviceDO device = new IotDeviceDO().setDeviceName(deviceName).setDeviceKey(deviceKey)
|
||||
.setGatewayId(gatewayId);
|
||||
initDevice(device, product);
|
||||
deviceMapper.insert(device);
|
||||
return device;
|
||||
});
|
||||
}
|
||||
|
||||
private void validateCreateDeviceParam(String productKey, String deviceName, String deviceKey,
|
||||
Long gatewayId, IotProductDO product) {
|
||||
TenantUtils.executeIgnore(() -> {
|
||||
// 校验设备名称在同一产品下是否唯一
|
||||
if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) {
|
||||
throw exception(DEVICE_NAME_EXISTS);
|
||||
}
|
||||
// 校验设备标识是否唯一
|
||||
if (deviceMapper.selectByDeviceKey(deviceKey) != null) {
|
||||
throw exception(DEVICE_KEY_EXISTS);
|
||||
}
|
||||
});
|
||||
|
||||
// 校验父设备是否为合法网关
|
||||
if (IotProductDeviceTypeEnum.isGatewaySub(product.getDeviceType())
|
||||
&& gatewayId != null) {
|
||||
validateGatewayDeviceExists(gatewayId);
|
||||
}
|
||||
}
|
||||
|
||||
private void initDevice(IotDeviceDO device, IotProductDO product) {
|
||||
device.setProductId(product.getId()).setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType());
|
||||
// 生成并设置必要的字段
|
||||
|
@ -136,7 +137,7 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
// 1.1 校验存在
|
||||
IotDeviceDO device = validateDeviceExists(updateReqVO.getId());
|
||||
// 1.2 校验父设备是否为合法网关
|
||||
if (IotProductDeviceTypeEnum.isGateway(device.getDeviceType())
|
||||
if (IotProductDeviceTypeEnum.isGatewaySub(device.getDeviceType())
|
||||
&& updateReqVO.getGatewayId() != null) {
|
||||
validateGatewayDeviceExists(updateReqVO.getGatewayId());
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package cn.iocoder.yudao.module.iot.service.device.control;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceRegisterReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
|
@ -51,4 +48,11 @@ public interface IotDeviceUpstreamService {
|
|||
*/
|
||||
void registerDevice(IotDeviceRegisterReqDTO registerReqDTO);
|
||||
|
||||
/**
|
||||
* 注册子设备
|
||||
*
|
||||
* @param registerReqDTO 注册子设备 DTO
|
||||
*/
|
||||
void registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cn.iocoder.yudao.module.iot.service.device.control;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
|
@ -13,6 +14,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
|||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
|
@ -164,20 +166,30 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
|
|||
|
||||
@Override
|
||||
public void registerDevice(IotDeviceRegisterReqDTO registerReqDTO) {
|
||||
// 1.1 注册设备
|
||||
log.info("[registerDevice][注册设备: {}]", registerReqDTO);
|
||||
IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(
|
||||
registerReqDTO.getProductKey(), registerReqDTO.getDeviceName());
|
||||
boolean register = device == null;
|
||||
registerDevice0(registerReqDTO.getProductKey(), registerReqDTO.getDeviceName(), null, registerReqDTO);
|
||||
}
|
||||
|
||||
private void registerDevice0(String productKey, String deviceName, Long gatewayId,
|
||||
IotDeviceUpstreamAbstractReqDTO registerReqDTO) {
|
||||
// 1.1 注册设备
|
||||
IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(productKey, deviceName);
|
||||
boolean registerNew = device == null;
|
||||
if (device == null) {
|
||||
device = deviceService.createDevice(registerReqDTO.getProductKey(), registerReqDTO.getDeviceName());
|
||||
log.info("[registerDevice][请求({}) 成功注册设备({})]", registerReqDTO, device);
|
||||
device = deviceService.createDevice(productKey, deviceName, gatewayId);
|
||||
log.info("[registerDevice0][消息({}) 设备({}/{}) 成功注册]", registerReqDTO, productKey, device);
|
||||
} else if (gatewayId != null && ObjUtil.notEqual(device.getGatewayId(), gatewayId)) {
|
||||
Long deviceId = device.getId();
|
||||
TenantUtils.execute(device.getTenantId(),
|
||||
() -> deviceService.updateDeviceGateway(deviceId, gatewayId));
|
||||
log.info("[registerDevice0][消息({}) 设备({}/{}) 更新网关设备编号({})]",
|
||||
registerReqDTO, productKey, device, gatewayId);
|
||||
}
|
||||
// 1.2 记录设备的最后时间
|
||||
updateDeviceLastTime(device, registerReqDTO);
|
||||
|
||||
// 2. 发送设备消息
|
||||
if (register) {
|
||||
if (registerNew) {
|
||||
IotDeviceMessage message = BeanUtils.toBean(registerReqDTO, IotDeviceMessage.class)
|
||||
.setType(IotDeviceMessageTypeEnum.REGISTER.getType())
|
||||
.setIdentifier(IotDeviceMessageIdentifierEnum.REGISTER_REGISTER.getIdentifier());
|
||||
|
@ -185,6 +197,39 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) {
|
||||
// 1.1 注册子设备
|
||||
log.info("[registerSubDevice][注册子设备: {}]", registerReqDTO);
|
||||
IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(
|
||||
registerReqDTO.getProductKey(), registerReqDTO.getDeviceName());
|
||||
if (device == null) {
|
||||
log.error("[registerSubDevice][设备({}/{}) 不存在]",
|
||||
registerReqDTO.getProductKey(), registerReqDTO.getDeviceName());
|
||||
return;
|
||||
}
|
||||
if (!IotProductDeviceTypeEnum.isGateway(device.getDeviceType())) {
|
||||
log.error("[registerSubDevice][设备({}/{}) 不是网关设备({}),无法进行注册]",
|
||||
registerReqDTO.getProductKey(), registerReqDTO.getDeviceName(), device);
|
||||
return;
|
||||
}
|
||||
// 1.2 记录设备的最后时间
|
||||
updateDeviceLastTime(device, registerReqDTO);
|
||||
|
||||
// 2. 处理子设备
|
||||
if (CollUtil.isNotEmpty(registerReqDTO.getParams())) {
|
||||
registerReqDTO.getParams().forEach(subDevice -> registerDevice0(
|
||||
subDevice.getProductKey(), subDevice.getDeviceName(), device.getId(), registerReqDTO));
|
||||
}
|
||||
|
||||
// 3. 发送设备消息
|
||||
IotDeviceMessage message = BeanUtils.toBean(registerReqDTO, IotDeviceMessage.class)
|
||||
.setType(IotDeviceMessageTypeEnum.REGISTER.getType())
|
||||
.setIdentifier(IotDeviceMessageIdentifierEnum.REGISTER_REGISTER_SUB.getIdentifier())
|
||||
.setData(registerReqDTO.getParams());
|
||||
sendDeviceMessage(message, device);
|
||||
}
|
||||
|
||||
private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) {
|
||||
// 1. 【异步】记录设备与插件实例的映射
|
||||
pluginInstanceService.updateDevicePluginInstanceProcessIdAsync(device.getDeviceKey(), reqDTO.getProcessId());
|
||||
|
|
Loading…
Reference in New Issue