Commit 66b42367cb7c0178e756398144ec4254ed86fbc1
1 parent
4ea6e08f
reactor:【IoT 物联网】重新梳理下行消息的逻辑(未测试,用于相互 review 作用)
Showing
46 changed files
with
622 additions
and
1424 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/ObjectUtils.java
| @@ -60,4 +60,8 @@ public class ObjectUtils { | @@ -60,4 +60,8 @@ public class ObjectUtils { | ||
| 60 | return Arrays.asList(array).contains(obj); | 60 | return Arrays.asList(array).contains(obj); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | + public static boolean isNotAllEmpty(Object... objs) { | ||
| 64 | + return !ObjectUtil.isAllEmpty(objs); | ||
| 65 | + } | ||
| 66 | + | ||
| 63 | } | 67 | } |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java deleted
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; | ||
| 2 | - | ||
| 3 | -import jakarta.validation.constraints.NotEmpty; | ||
| 4 | -import lombok.Data; | ||
| 5 | - | ||
| 6 | -import java.util.List; | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * IoT 设备【注册】子设备 Request DTO | ||
| 10 | - * | ||
| 11 | - * @author 芋道源码 | ||
| 12 | - */ | ||
| 13 | -@Data | ||
| 14 | -public class IotDeviceRegisterSubReqDTO extends IotDeviceUpstreamAbstractReqDTO { | ||
| 15 | - | ||
| 16 | - // TODO @芋艿:看看要不要优化命名 | ||
| 17 | - /** | ||
| 18 | - * 子设备数组 | ||
| 19 | - */ | ||
| 20 | - @NotEmpty(message = "子设备不能为空") | ||
| 21 | - private List<Device> params; | ||
| 22 | - | ||
| 23 | - /** | ||
| 24 | - * 设备信息 | ||
| 25 | - */ | ||
| 26 | - @Data | ||
| 27 | - public static class Device { | ||
| 28 | - | ||
| 29 | - /** | ||
| 30 | - * 产品标识 | ||
| 31 | - */ | ||
| 32 | - @NotEmpty(message = "产品标识不能为空") | ||
| 33 | - private String productKey; | ||
| 34 | - | ||
| 35 | - /** | ||
| 36 | - * 设备名称 | ||
| 37 | - */ | ||
| 38 | - @NotEmpty(message = "设备名称不能为空") | ||
| 39 | - private String deviceName; | ||
| 40 | - | ||
| 41 | - } | ||
| 42 | - | ||
| 43 | -} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; | ||
| 2 | - | ||
| 3 | -import jakarta.validation.constraints.NotEmpty; | ||
| 4 | -import lombok.Data; | ||
| 5 | - | ||
| 6 | -import java.util.List; | ||
| 7 | - | ||
| 8 | -// TODO @芋艿:要写清楚,是来自设备网关,还是设备。 | ||
| 9 | -/** | ||
| 10 | - * IoT 设备【拓扑】添加 Request DTO | ||
| 11 | - */ | ||
| 12 | -@Data | ||
| 13 | -public class IotDeviceTopologyAddReqDTO extends IotDeviceUpstreamAbstractReqDTO { | ||
| 14 | - | ||
| 15 | - // TODO @芋艿:看看要不要优化命名 | ||
| 16 | - /** | ||
| 17 | - * 子设备数组 | ||
| 18 | - */ | ||
| 19 | - @NotEmpty(message = "子设备不能为空") | ||
| 20 | - private List<IotDeviceRegisterSubReqDTO.Device> params; | ||
| 21 | - | ||
| 22 | - /** | ||
| 23 | - * 设备信息 | ||
| 24 | - */ | ||
| 25 | - @Data | ||
| 26 | - public static class Device { | ||
| 27 | - | ||
| 28 | - /** | ||
| 29 | - * 产品标识 | ||
| 30 | - */ | ||
| 31 | - @NotEmpty(message = "产品标识不能为空") | ||
| 32 | - private String productKey; | ||
| 33 | - | ||
| 34 | - /** | ||
| 35 | - * 设备名称 | ||
| 36 | - */ | ||
| 37 | - @NotEmpty(message = "设备名称不能为空") | ||
| 38 | - private String deviceName; | ||
| 39 | - | ||
| 40 | - // TODO @芋艿:阿里云还有 sign 签名 | ||
| 41 | - | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
| @@ -6,13 +6,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; | @@ -6,13 +6,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 8 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 8 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 9 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; | ||
| 10 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; | ||
| 11 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; | 9 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; |
| 10 | +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageSendReqVO; | ||
| 11 | +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 12 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 12 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 13 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 13 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 14 | -import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService; | ||
| 15 | -import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService; | 14 | +import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; |
| 16 | import io.swagger.v3.oas.annotations.Operation; | 15 | import io.swagger.v3.oas.annotations.Operation; |
| 17 | import io.swagger.v3.oas.annotations.Parameter; | 16 | import io.swagger.v3.oas.annotations.Parameter; |
| 18 | import io.swagger.v3.oas.annotations.tags.Tag; | 17 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -42,9 +41,7 @@ public class IotDeviceController { | @@ -42,9 +41,7 @@ public class IotDeviceController { | ||
| 42 | @Resource | 41 | @Resource |
| 43 | private IotDeviceService deviceService; | 42 | private IotDeviceService deviceService; |
| 44 | @Resource | 43 | @Resource |
| 45 | - private IotDeviceUpstreamService deviceUpstreamService; | ||
| 46 | - @Resource | ||
| 47 | - private IotDeviceDownstreamService deviceDownstreamService; | 44 | + private IotDeviceMessageService deviceMessageService; |
| 48 | 45 | ||
| 49 | @PostMapping("/create") | 46 | @PostMapping("/create") |
| 50 | @Operation(summary = "创建设备") | 47 | @Operation(summary = "创建设备") |
| @@ -161,19 +158,12 @@ public class IotDeviceController { | @@ -161,19 +158,12 @@ public class IotDeviceController { | ||
| 161 | ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list); | 158 | ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list); |
| 162 | } | 159 | } |
| 163 | 160 | ||
| 164 | - @PostMapping("/upstream") | ||
| 165 | - @Operation(summary = "设备上行", description = "可用于设备模拟") | 161 | + // TODO @芋艿:需要重构 |
| 162 | + @PostMapping("/send-message") | ||
| 163 | + @Operation(summary = "发送消息", description = "可用于设备模拟") | ||
| 166 | @PreAuthorize("@ss.hasPermission('iot:device:upstream')") | 164 | @PreAuthorize("@ss.hasPermission('iot:device:upstream')") |
| 167 | - public CommonResult<Boolean> upstreamDevice(@Valid @RequestBody IotDeviceUpstreamReqVO upstreamReqVO) { | ||
| 168 | - deviceUpstreamService.upstreamDevice(upstreamReqVO); | ||
| 169 | - return success(true); | ||
| 170 | - } | ||
| 171 | - | ||
| 172 | - @PostMapping("/downstream") | ||
| 173 | - @Operation(summary = "设备下行", description = "可用于设备模拟") | ||
| 174 | - @PreAuthorize("@ss.hasPermission('iot:device:downstream')") | ||
| 175 | - public CommonResult<Boolean> downstreamDevice(@Valid @RequestBody IotDeviceDownstreamReqVO downstreamReqVO) { | ||
| 176 | - deviceDownstreamService.downstreamDevice(downstreamReqVO); | 165 | + public CommonResult<Boolean> upstreamDevice(@Valid @RequestBody IotDeviceMessageSendReqVO sendReqVO) { |
| 166 | + deviceMessageService.sendDeviceMessage(BeanUtils.toBean(sendReqVO, IotDeviceMessage.class)); | ||
| 177 | return success(true); | 167 | return success(true); |
| 178 | } | 168 | } |
| 179 | 169 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java
| @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 6 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; | 6 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; |
| 7 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogRespVO; | 7 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogRespVO; |
| 8 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | ||
| 9 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; | 8 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; |
| 9 | +import cn.iocoder.yudao.module.iot.service.device.property.IotDeviceLogService; | ||
| 10 | import io.swagger.v3.oas.annotations.Operation; | 10 | import io.swagger.v3.oas.annotations.Operation; |
| 11 | import io.swagger.v3.oas.annotations.tags.Tag; | 11 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 12 | import jakarta.annotation.Resource; | 12 | import jakarta.annotation.Resource; |
| @@ -32,7 +32,7 @@ public class IotDeviceLogController { | @@ -32,7 +32,7 @@ public class IotDeviceLogController { | ||
| 32 | @Operation(summary = "获得设备日志分页") | 32 | @Operation(summary = "获得设备日志分页") |
| 33 | @PreAuthorize("@ss.hasPermission('iot:device:log-query')") | 33 | @PreAuthorize("@ss.hasPermission('iot:device:log-query')") |
| 34 | public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) { | 34 | public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) { |
| 35 | - PageResult<IotDeviceLogDO> pageResult = deviceLogService.getDeviceLogPage(pageReqVO); | 35 | + PageResult<IotDeviceMessageDO> pageResult = deviceLogService.getDeviceLogPage(pageReqVO); |
| 36 | return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class)); | 36 | return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class)); |
| 37 | } | 37 | } |
| 38 | 38 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java
| @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 12 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; | 12 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; |
| 13 | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | 13 | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; |
| 14 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 14 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 15 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | 15 | +import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; |
| 16 | import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; | 16 | import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; |
| 17 | import io.swagger.v3.oas.annotations.Operation; | 17 | import io.swagger.v3.oas.annotations.Operation; |
| 18 | import io.swagger.v3.oas.annotations.Parameter; | 18 | import io.swagger.v3.oas.annotations.Parameter; |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 5 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 6 | -import jakarta.validation.constraints.NotEmpty; | ||
| 7 | -import jakarta.validation.constraints.NotNull; | ||
| 8 | -import lombok.Data; | ||
| 9 | - | ||
| 10 | -@Schema(description = "管理后台 - IoT 设备下行 Request VO") // 服务调用、属性设置、属性获取等 | ||
| 11 | -@Data | ||
| 12 | -public class IotDeviceDownstreamReqVO { | ||
| 13 | - | ||
| 14 | - @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") | ||
| 15 | - @NotNull(message = "设备编号不能为空") | ||
| 16 | - private Long id; | ||
| 17 | - | ||
| 18 | - @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property") | ||
| 19 | - @NotEmpty(message = "消息类型不能为空") | ||
| 20 | - @InEnum(IotDeviceMessageTypeEnum.class) | ||
| 21 | - private String type; | ||
| 22 | - | ||
| 23 | - @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report") | ||
| 24 | - @NotEmpty(message = "标识符不能为空") | ||
| 25 | - private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类 | ||
| 26 | - | ||
| 27 | - @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 28 | - private Object data; // 例如说:服务调用的 params、属性设置的 properties | ||
| 29 | - | ||
| 30 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 5 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 6 | -import jakarta.validation.constraints.NotEmpty; | ||
| 7 | -import jakarta.validation.constraints.NotNull; | ||
| 8 | -import lombok.Data; | ||
| 9 | - | ||
| 10 | -@Schema(description = "管理后台 - IoT 设备上行 Request VO") // 属性上报、事件上报、状态变更等 | ||
| 11 | -@Data | ||
| 12 | -public class IotDeviceUpstreamReqVO { | ||
| 13 | - | ||
| 14 | - @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") | ||
| 15 | - @NotNull(message = "设备编号不能为空") | ||
| 16 | - private Long id; | ||
| 17 | - | ||
| 18 | - @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property") | ||
| 19 | - @NotEmpty(message = "消息类型不能为空") | ||
| 20 | - @InEnum(IotDeviceMessageTypeEnum.class) | ||
| 21 | - private String type; | ||
| 22 | - | ||
| 23 | - @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report") | ||
| 24 | - @NotEmpty(message = "标识符不能为空") | ||
| 25 | - private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类 | ||
| 26 | - | ||
| 27 | - @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 28 | - private Object data; // 例如说:属性上报的 properties、事件上报的 params | ||
| 29 | - | ||
| 30 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageSendReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; | ||
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 6 | +import jakarta.validation.constraints.NotEmpty; | ||
| 7 | +import jakarta.validation.constraints.NotNull; | ||
| 8 | +import lombok.Data; | ||
| 9 | + | ||
| 10 | +@Schema(description = "管理后台 - IoT 设备消息发送 Request VO") // 属性上报、事件上报、状态变更等 | ||
| 11 | +@Data | ||
| 12 | +public class IotDeviceMessageSendReqVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "请求方法", requiredMode = Schema.RequiredMode.REQUIRED, example = "report") | ||
| 15 | + @NotEmpty(message = "请求方法不能为空") | ||
| 16 | + @InEnum(IotDeviceMessageMethodEnum.class) | ||
| 17 | + private String method; | ||
| 18 | + | ||
| 19 | + @Schema(description = "请求参数") | ||
| 20 | + private Object params; // 例如说:属性上报的 properties、事件上报的 params | ||
| 21 | + | ||
| 22 | + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") | ||
| 23 | + @NotNull(message = "设备编号不能为空") | ||
| 24 | + private Long deviceId; | ||
| 25 | + | ||
| 26 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java
| 1 | package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record; | 1 | package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 3 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 4 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; | ||
| 4 | import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; | 5 | import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; |
| 5 | import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; |
| 6 | import com.fhs.core.trans.anno.Trans; | 7 | import com.fhs.core.trans.anno.Trans; |
| @@ -89,7 +90,7 @@ public class IotOtaUpgradeRecordRespVO { | @@ -89,7 +90,7 @@ public class IotOtaUpgradeRecordRespVO { | ||
| 89 | * 升级进度描述 | 90 | * 升级进度描述 |
| 90 | * <p> | 91 | * <p> |
| 91 | * 注意,只记录设备最后一次的升级进度描述 | 92 | * 注意,只记录设备最后一次的升级进度描述 |
| 92 | - * 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志 | 93 | + * 如果想看历史记录,可以查看 {@link IotDeviceMessageDO} 设备日志 |
| 93 | */ | 94 | */ |
| 94 | @Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | 95 | @Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
| 95 | private String description; | 96 | private String description; |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java
| @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsR | @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsR | ||
| 6 | import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsSummaryRespVO; | 6 | import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsSummaryRespVO; |
| 7 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; | 7 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; |
| 8 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 8 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 9 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; | 9 | +import cn.iocoder.yudao.module.iot.service.device.property.IotDeviceLogService; |
| 10 | import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService; | 10 | import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService; |
| 11 | import cn.iocoder.yudao.module.iot.service.product.IotProductService; | 11 | import cn.iocoder.yudao.module.iot.service.product.IotProductService; |
| 12 | import io.swagger.v3.oas.annotations.Operation; | 12 | import io.swagger.v3.oas.annotations.Operation; |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceMessageDO.java
| 1 | package cn.iocoder.yudao.module.iot.dal.dataobject.device; | 1 | package cn.iocoder.yudao.module.iot.dal.dataobject.device; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.util.IdUtil; | 3 | +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; |
| 4 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | 4 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 5 | -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||
| 6 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | ||
| 7 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 8 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 9 | import lombok.Builder; | 6 | import lombok.Builder; |
| 10 | import lombok.Data; | 7 | import lombok.Data; |
| 11 | import lombok.NoArgsConstructor; | 8 | import lombok.NoArgsConstructor; |
| 12 | 9 | ||
| 13 | /** | 10 | /** |
| 14 | - * IoT 设备日志数据 DO | 11 | + * IoT 设备消息数据 DO |
| 15 | * | 12 | * |
| 16 | * 目前使用 TDengine 存储 | 13 | * 目前使用 TDengine 存储 |
| 17 | * | 14 | * |
| @@ -21,80 +18,84 @@ import lombok.NoArgsConstructor; | @@ -21,80 +18,84 @@ import lombok.NoArgsConstructor; | ||
| 21 | @Builder | 18 | @Builder |
| 22 | @NoArgsConstructor | 19 | @NoArgsConstructor |
| 23 | @AllArgsConstructor | 20 | @AllArgsConstructor |
| 24 | -public class IotDeviceLogDO { | ||
| 25 | - | ||
| 26 | - /** | ||
| 27 | - * 日志编号 | ||
| 28 | - * | ||
| 29 | - * 通过 {@link IdUtil#fastSimpleUUID()} 生成 | ||
| 30 | - */ | ||
| 31 | - private String id; | 21 | +public class IotDeviceMessageDO { |
| 32 | 22 | ||
| 33 | /** | 23 | /** |
| 34 | * 消息编号 | 24 | * 消息编号 |
| 35 | - * | ||
| 36 | - * 对应 {@link IotDeviceMessage#getMessageId()} 字段 | ||
| 37 | */ | 25 | */ |
| 38 | - private String messageId; | ||
| 39 | - | 26 | + private String id; |
| 40 | /** | 27 | /** |
| 41 | - * 产品标识 | ||
| 42 | - * <p> | ||
| 43 | - * 关联 {@link IotProductDO#getProductKey()} | 28 | + * 上报时间戳 |
| 44 | */ | 29 | */ |
| 45 | - private String productKey; | 30 | + private Long reportTime; |
| 46 | /** | 31 | /** |
| 47 | - * 设备名称 | ||
| 48 | - * | ||
| 49 | - * 关联 {@link IotDeviceDO#getDeviceName()} | 32 | + * 存储时序时间 |
| 50 | */ | 33 | */ |
| 51 | - private String deviceName; | 34 | + private Long ts; |
| 35 | + | ||
| 52 | /** | 36 | /** |
| 53 | * 设备编号 | 37 | * 设备编号 |
| 54 | * | 38 | * |
| 55 | * 关联 {@link IotDeviceDO#getId()} | 39 | * 关联 {@link IotDeviceDO#getId()} |
| 56 | */ | 40 | */ |
| 57 | private Long deviceId; | 41 | private Long deviceId; |
| 42 | + /** | ||
| 43 | + * 租户编号 | ||
| 44 | + */ | ||
| 45 | + private Long tenantId; | ||
| 58 | 46 | ||
| 59 | /** | 47 | /** |
| 60 | - * 日志类型 | 48 | + * 服务编号,该消息由哪个 server 发送 |
| 49 | + */ | ||
| 50 | + private String serverId; | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * 是否上行消息 | ||
| 61 | * | 54 | * |
| 62 | - * 枚举 {@link IotDeviceMessageTypeEnum} | 55 | + * 由 {@link cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils#isUpstreamMessage(IotDeviceMessage)} 计算。 |
| 56 | + * 计算并存储的目的:方便计算多少条上行、多少条下行 | ||
| 63 | */ | 57 | */ |
| 64 | - private String type; | 58 | + private Boolean upstream; |
| 65 | /** | 59 | /** |
| 66 | - * 标识符 | 60 | + * 是否回复消息 |
| 67 | * | 61 | * |
| 68 | - * 枚举 {@link IotDeviceMessageIdentifierEnum} | 62 | + * 由 {@link cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils#isReplyMessage(IotDeviceMessage)} 计算。 |
| 63 | + * 计算并存储的目的:方便计算多少条请求、多少条回复 | ||
| 69 | */ | 64 | */ |
| 70 | - private String identifier; | 65 | + private Boolean reply; |
| 66 | + | ||
| 67 | + // ========== codec(编解码)字段 ========== | ||
| 71 | 68 | ||
| 72 | /** | 69 | /** |
| 73 | - * 数据内容 | 70 | + * 请求编号 |
| 74 | * | 71 | * |
| 75 | - * 存储具体的消息数据内容,通常是 JSON 格式 | 72 | + * 由设备生成,对应阿里云 IoT 的 Alink 协议中的 id、华为云 IoTDA 协议的 request_id |
| 76 | */ | 73 | */ |
| 77 | - private String content; | 74 | + private String requestId; |
| 78 | /** | 75 | /** |
| 79 | - * 响应码 | 76 | + * 请求方法 |
| 80 | * | 77 | * |
| 81 | - * 目前只有 server 下行消息给 device 设备时,才会有响应码 | 78 | + * 枚举 {@link IotDeviceMessageMethodEnum} |
| 79 | + * 例如说:thing.property.report 属性上报 | ||
| 82 | */ | 80 | */ |
| 83 | - private Integer code; | ||
| 84 | - | 81 | + private String method; |
| 85 | /** | 82 | /** |
| 86 | - * 上报时间戳 | 83 | + * 请求参数 |
| 84 | + * | ||
| 85 | + * 例如说:属性上报的 properties、事件上报的 params | ||
| 87 | */ | 86 | */ |
| 88 | - private Long reportTime; | ||
| 89 | - | 87 | + private Object params; |
| 90 | /** | 88 | /** |
| 91 | - * 租户编号 | 89 | + * 响应结果 |
| 92 | */ | 90 | */ |
| 93 | - private Long tenantId; | ||
| 94 | - | 91 | + private Object data; |
| 95 | /** | 92 | /** |
| 96 | - * 时序时间 | 93 | + * 响应错误码 |
| 97 | */ | 94 | */ |
| 98 | - private Long ts; | 95 | + private Integer code; |
| 96 | + /** | ||
| 97 | + * 响应提示 | ||
| 98 | + */ | ||
| 99 | + private String msg; | ||
| 99 | 100 | ||
| 100 | } | 101 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.ota; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.ota; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 4 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 5 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; | ||
| 5 | import com.baomidou.mybatisplus.annotation.KeySequence; | 6 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 6 | import com.baomidou.mybatisplus.annotation.TableId; | 7 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | import com.baomidou.mybatisplus.annotation.TableName; | 8 | import com.baomidou.mybatisplus.annotation.TableName; |
| @@ -77,7 +78,7 @@ public class IotOtaUpgradeRecordDO extends BaseDO { | @@ -77,7 +78,7 @@ public class IotOtaUpgradeRecordDO extends BaseDO { | ||
| 77 | * 升级进度描述 | 78 | * 升级进度描述 |
| 78 | * | 79 | * |
| 79 | * 注意,只记录设备最后一次的升级进度描述 | 80 | * 注意,只记录设备最后一次的升级进度描述 |
| 80 | - * 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志 | 81 | + * 如果想看历史记录,可以查看 {@link IotDeviceMessageDO} 设备日志 |
| 81 | */ | 82 | */ |
| 82 | private String description; | 83 | private String description; |
| 83 | /** | 84 | /** |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceServerIdRedisDAO.java
| @@ -43,17 +43,6 @@ public class DeviceServerIdRedisDAO { | @@ -43,17 +43,6 @@ public class DeviceServerIdRedisDAO { | ||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | /** | 45 | /** |
| 46 | - * 删除设备关联的网关 serverId | ||
| 47 | - * | ||
| 48 | - * @param productKey 产品标识 | ||
| 49 | - * @param deviceName 设备名称 | ||
| 50 | - */ | ||
| 51 | - public void delete(String productKey, String deviceName) { | ||
| 52 | - String hashKey = buildHashKey(productKey, deviceName); | ||
| 53 | - stringRedisTemplate.opsForHash().delete(RedisKeyConstants.DEVICE_SERVER_ID, hashKey); | ||
| 54 | - } | ||
| 55 | - | ||
| 56 | - /** | ||
| 57 | * 构建 HASH KEY | 46 | * 构建 HASH KEY |
| 58 | * | 47 | * |
| 59 | * @param productKey 产品标识 | 48 | * @param productKey 产品标识 |
| @@ -64,4 +53,4 @@ public class DeviceServerIdRedisDAO { | @@ -64,4 +53,4 @@ public class DeviceServerIdRedisDAO { | ||
| 64 | return productKey + StrUtil.COMMA + deviceName; | 53 | return productKey + StrUtil.COMMA + deviceName; |
| 65 | } | 54 | } |
| 66 | 55 | ||
| 67 | -} | ||
| 68 | \ No newline at end of file | 56 | \ No newline at end of file |
| 57 | +} | ||
| 69 | \ No newline at end of file | 58 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceMessageMapper.java
| 1 | package cn.iocoder.yudao.module.iot.dal.tdengine; | 1 | package cn.iocoder.yudao.module.iot.dal.tdengine; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; | 3 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; |
| 4 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | 4 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; |
| 5 | import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; | 5 | import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; |
| 6 | import com.baomidou.mybatisplus.annotation.InterceptorIgnore; | 6 | import com.baomidou.mybatisplus.annotation.InterceptorIgnore; |
| 7 | import com.baomidou.mybatisplus.core.metadata.IPage; | 7 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| @@ -12,48 +12,48 @@ import java.util.List; | @@ -12,48 +12,48 @@ import java.util.List; | ||
| 12 | import java.util.Map; | 12 | import java.util.Map; |
| 13 | 13 | ||
| 14 | /** | 14 | /** |
| 15 | - * 设备日志 {@link IotDeviceLogDO} Mapper 接口 | 15 | + * 设备消息 {@link IotDeviceMessageDO} Mapper 接口 |
| 16 | */ | 16 | */ |
| 17 | @Mapper | 17 | @Mapper |
| 18 | @TDengineDS | 18 | @TDengineDS |
| 19 | @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 | 19 | @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 |
| 20 | -public interface IotDeviceLogMapper { | 20 | +public interface IotDeviceMessageMapper { |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| 23 | - * 创建设备日志超级表 | 23 | + * 创建设备消息超级表 |
| 24 | */ | 24 | */ |
| 25 | - void createDeviceLogSTable(); | 25 | + void createSTable(); |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | - * 查询设备日志表是否存在 | 28 | + * 查询设备消息表是否存在 |
| 29 | * | 29 | * |
| 30 | * @return 存在则返回表名;不存在则返回 null | 30 | * @return 存在则返回表名;不存在则返回 null |
| 31 | */ | 31 | */ |
| 32 | - String showDeviceLogSTable(); | 32 | + String showSTable(); |
| 33 | 33 | ||
| 34 | /** | 34 | /** |
| 35 | - * 插入设备日志数据 | 35 | + * 插入设备消息数据 |
| 36 | * | 36 | * |
| 37 | * 如果子表不存在,会自动创建子表 | 37 | * 如果子表不存在,会自动创建子表 |
| 38 | * | 38 | * |
| 39 | - * @param log 设备日志数据 | 39 | + * @param message 设备消息数据 |
| 40 | */ | 40 | */ |
| 41 | - void insert(IotDeviceLogDO log); | 41 | + void insert(IotDeviceMessageDO message); |
| 42 | 42 | ||
| 43 | /** | 43 | /** |
| 44 | - * 获得设备日志分页 | 44 | + * 获得设备消息分页 |
| 45 | * | 45 | * |
| 46 | * @param reqVO 分页查询条件 | 46 | * @param reqVO 分页查询条件 |
| 47 | - * @return 设备日志列表 | 47 | + * @return 设备消息列表 |
| 48 | */ | 48 | */ |
| 49 | - IPage<IotDeviceLogDO> selectPage(IPage<IotDeviceLogDO> page, | ||
| 50 | - @Param("reqVO") IotDeviceLogPageReqVO reqVO); | 49 | + IPage<IotDeviceMessageDO> selectPage(IPage<IotDeviceMessageDO> page, |
| 50 | + @Param("reqVO") IotDeviceLogPageReqVO reqVO); | ||
| 51 | 51 | ||
| 52 | /** | 52 | /** |
| 53 | - * 统计设备日志数量 | 53 | + * 统计设备消息数量 |
| 54 | * | 54 | * |
| 55 | - * @param createTime 创建时间,如果为空,则统计所有日志数量 | ||
| 56 | - * @return 日志数量 | 55 | + * @param createTime 创建时间,如果为空,则统计所有消息数量 |
| 56 | + * @return 消息数量 | ||
| 57 | */ | 57 | */ |
| 58 | Long selectCountByCreateTime(@Param("createTime") Long createTime); | 58 | Long selectCountByCreateTime(@Param("createTime") Long createTime); |
| 59 | 59 | ||
| @@ -62,14 +62,14 @@ public interface IotDeviceLogMapper { | @@ -62,14 +62,14 @@ public interface IotDeviceLogMapper { | ||
| 62 | /** | 62 | /** |
| 63 | * 查询每个小时设备上行消息数量 | 63 | * 查询每个小时设备上行消息数量 |
| 64 | */ | 64 | */ |
| 65 | - List<Map<String, Object>> selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey, | 65 | + List<Map<String, Object>> selectDeviceLogUpCountByHour(@Param("deviceId") Long deviceId, |
| 66 | @Param("startTime") Long startTime, | 66 | @Param("startTime") Long startTime, |
| 67 | @Param("endTime") Long endTime); | 67 | @Param("endTime") Long endTime); |
| 68 | 68 | ||
| 69 | /** | 69 | /** |
| 70 | * 查询每个小时设备下行消息数量 | 70 | * 查询每个小时设备下行消息数量 |
| 71 | */ | 71 | */ |
| 72 | - List<Map<String, Object>> selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey, | 72 | + List<Map<String, Object>> selectDeviceLogDownCountByHour(@Param("deviceId") Long deviceId, |
| 73 | @Param("startTime") Long startTime, | 73 | @Param("startTime") Long startTime, |
| 74 | @Param("endTime") Long endTime); | 74 | @Param("endTime") Long endTime); |
| 75 | 75 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitRunner.java
| 1 | package cn.iocoder.yudao.module.iot.framework.tdengine.config; | 1 | package cn.iocoder.yudao.module.iot.framework.tdengine.config; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; | 3 | +import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; |
| 4 | import lombok.RequiredArgsConstructor; | 4 | import lombok.RequiredArgsConstructor; |
| 5 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
| 6 | import org.springframework.boot.ApplicationArguments; | 6 | import org.springframework.boot.ApplicationArguments; |
| @@ -17,16 +17,16 @@ import org.springframework.stereotype.Component; | @@ -17,16 +17,16 @@ import org.springframework.stereotype.Component; | ||
| 17 | @Slf4j | 17 | @Slf4j |
| 18 | public class TDengineTableInitRunner implements ApplicationRunner { | 18 | public class TDengineTableInitRunner implements ApplicationRunner { |
| 19 | 19 | ||
| 20 | - private final IotDeviceLogService deviceLogService; | 20 | + private final IotDeviceMessageService deviceMessageService; |
| 21 | 21 | ||
| 22 | @Override | 22 | @Override |
| 23 | public void run(ApplicationArguments args) { | 23 | public void run(ApplicationArguments args) { |
| 24 | try { | 24 | try { |
| 25 | - // 初始化设备日志表 | ||
| 26 | - deviceLogService.defineDeviceLog(); | 25 | + // 初始化设备消息表 |
| 26 | + deviceMessageService.defineDeviceMessageStable(); | ||
| 27 | } catch (Exception ex) { | 27 | } catch (Exception ex) { |
| 28 | - // 初始化失败时打印错误日志并退出系统 | ||
| 29 | - log.error("[run][TDengine初始化设备日志表结构失败,系统无法正常运行,即将退出]", ex); | 28 | + // 初始化失败时打印错误消息并退出系统 |
| 29 | + log.error("[run][TDengine初始化设备消息表结构失败,系统无法正常运行,即将退出]", ex); | ||
| 30 | System.exit(1); | 30 | System.exit(1); |
| 31 | } | 31 | } |
| 32 | } | 32 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java
| @@ -7,10 +7,10 @@ import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | @@ -7,10 +7,10 @@ import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | ||
| 7 | import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; | 7 | import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; |
| 8 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; | 8 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; |
| 9 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | 9 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 10 | -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | ||
| 11 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 10 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 12 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 11 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 13 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | 12 | +import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; |
| 13 | +import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; | ||
| 14 | import jakarta.annotation.Resource; | 14 | import jakarta.annotation.Resource; |
| 15 | import org.springframework.stereotype.Component; | 15 | import org.springframework.stereotype.Component; |
| 16 | 16 | ||
| @@ -43,10 +43,10 @@ public class IotDeviceOfflineCheckJob implements JobHandler { | @@ -43,10 +43,10 @@ public class IotDeviceOfflineCheckJob implements JobHandler { | ||
| 43 | private IotDeviceService deviceService; | 43 | private IotDeviceService deviceService; |
| 44 | @Resource | 44 | @Resource |
| 45 | private IotDevicePropertyService devicePropertyService; | 45 | private IotDevicePropertyService devicePropertyService; |
| 46 | - | ||
| 47 | @Resource | 46 | @Resource |
| 48 | - private IotDeviceMessageProducer deviceMessageProducer; | 47 | + private IotDeviceMessageService deviceMessageService; |
| 49 | 48 | ||
| 49 | + // TODO @芋艿:需要重构下; | ||
| 50 | @Override | 50 | @Override |
| 51 | @TenantJob | 51 | @TenantJob |
| 52 | public String execute(String param) { | 52 | public String execute(String param) { |
| @@ -69,8 +69,7 @@ public class IotDeviceOfflineCheckJob implements JobHandler { | @@ -69,8 +69,7 @@ public class IotDeviceOfflineCheckJob implements JobHandler { | ||
| 69 | } | 69 | } |
| 70 | offlineDeviceKeys.add(new String[]{device.getProductKey(), device.getDeviceName()}); | 70 | offlineDeviceKeys.add(new String[]{device.getProductKey(), device.getDeviceName()}); |
| 71 | // 为什么不直接更新状态呢?因为通过 IotDeviceMessage 可以经过一系列的处理,例如说记录日志等等 | 71 | // 为什么不直接更新状态呢?因为通过 IotDeviceMessage 可以经过一系列的处理,例如说记录日志等等 |
| 72 | - deviceMessageProducer.sendDeviceMessage(IotDeviceMessage.of(device.getProductKey(), device.getDeviceName()) | ||
| 73 | - .ofStateOffline()); | 72 | + deviceMessageService.sendDeviceMessage(IotDeviceMessage.buildStateOffline().setDeviceId(device.getId())); |
| 74 | } | 73 | } |
| 75 | return JsonUtils.toJsonString(offlineDeviceKeys); | 74 | return JsonUtils.toJsonString(offlineDeviceKeys); |
| 76 | } | 75 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageSubscriber.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.mq.consumer.device; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; | ||
| 4 | -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; | ||
| 5 | -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 6 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; | ||
| 7 | -import jakarta.annotation.PostConstruct; | ||
| 8 | -import jakarta.annotation.Resource; | ||
| 9 | -import lombok.extern.slf4j.Slf4j; | ||
| 10 | -import org.springframework.stereotype.Component; | ||
| 11 | - | ||
| 12 | -/** | ||
| 13 | - * 针对 {@link IotDeviceMessage} 的消费者:记录设备日志 | ||
| 14 | - * | ||
| 15 | - * @author 芋道源码 | ||
| 16 | - */ | ||
| 17 | -@Component | ||
| 18 | -@Slf4j | ||
| 19 | -public class IotDeviceLogMessageSubscriber implements IotMessageSubscriber<IotDeviceMessage> { | ||
| 20 | - | ||
| 21 | - @Resource | ||
| 22 | - private IotMessageBus messageBus; | ||
| 23 | - | ||
| 24 | - @Resource | ||
| 25 | - private IotDeviceLogService deviceLogService; | ||
| 26 | - | ||
| 27 | - @PostConstruct | ||
| 28 | - public void init() { | ||
| 29 | - messageBus.register(this); | ||
| 30 | - } | ||
| 31 | - | ||
| 32 | - @Override | ||
| 33 | - public String getTopic() { | ||
| 34 | - return IotDeviceMessage.MESSAGE_BUS_DEVICE_MESSAGE_TOPIC; | ||
| 35 | - } | ||
| 36 | - | ||
| 37 | - @Override | ||
| 38 | - public String getGroup() { | ||
| 39 | - return "iot_device_log_consumer"; | ||
| 40 | - } | ||
| 41 | - | ||
| 42 | - @Override | ||
| 43 | - public void onMessage(IotDeviceMessage message) { | ||
| 44 | - log.info("[onMessage][消息内容({})]", message); | ||
| 45 | - deviceLogService.createDeviceLog(message); | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceStateMessageSubscriber.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java
| 1 | package cn.iocoder.yudao.module.iot.mq.consumer.device; | 1 | package cn.iocoder.yudao.module.iot.mq.consumer.device; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.ObjectUtil; | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | ||
| 5 | -import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageIdentifierEnum; | ||
| 6 | -import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageTypeEnum; | 4 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 5 | +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; | ||
| 7 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; | 6 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; |
| 8 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; | 7 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; |
| 9 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; | 8 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; |
| 10 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | 9 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 11 | -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | ||
| 12 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; | 10 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; |
| 13 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 11 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 14 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 12 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 15 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | 13 | +import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; |
| 14 | +import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; | ||
| 16 | import jakarta.annotation.PostConstruct; | 15 | import jakarta.annotation.PostConstruct; |
| 17 | import jakarta.annotation.Resource; | 16 | import jakarta.annotation.Resource; |
| 18 | import lombok.extern.slf4j.Slf4j; | 17 | import lombok.extern.slf4j.Slf4j; |
| 19 | import org.springframework.stereotype.Component; | 18 | import org.springframework.stereotype.Component; |
| 20 | 19 | ||
| 21 | import java.time.LocalDateTime; | 20 | import java.time.LocalDateTime; |
| 22 | -import java.util.Objects; | ||
| 23 | 21 | ||
| 24 | /** | 22 | /** |
| 25 | - * 针对 {@link IotDeviceMessage} 的消费者:记录设备状态 | 23 | + * 针对 {@link IotDeviceMessage} 的业务处理器:调用 method 对应的逻辑。例如说: |
| 24 | + * 1. {@link IotDeviceMessageMethodEnum#PROPERTY_REPORT} 属性上报时,记录设备属性 | ||
| 26 | * | 25 | * |
| 27 | - * 特殊:如果是离线的设备,将自动上线 | ||
| 28 | - * | ||
| 29 | - * @author 芋道源码 | 26 | + * @author alwayssuper |
| 30 | */ | 27 | */ |
| 31 | @Component | 28 | @Component |
| 32 | @Slf4j | 29 | @Slf4j |
| 33 | -public class IotDeviceStateMessageSubscriber implements IotMessageSubscriber<IotDeviceMessage> { | 30 | +public class IotDeviceMessageSubscriber implements IotMessageSubscriber<IotDeviceMessage> { |
| 34 | 31 | ||
| 35 | @Resource | 32 | @Resource |
| 36 | private IotDeviceService deviceService; | 33 | private IotDeviceService deviceService; |
| 37 | @Resource | 34 | @Resource |
| 38 | private IotDevicePropertyService devicePropertyService; | 35 | private IotDevicePropertyService devicePropertyService; |
| 36 | + @Resource | ||
| 37 | + private IotDeviceMessageService deviceMessageService; | ||
| 39 | 38 | ||
| 40 | @Resource | 39 | @Resource |
| 41 | private IotMessageBus messageBus; | 40 | private IotMessageBus messageBus; |
| 42 | - @Resource | ||
| 43 | - private IotDeviceMessageProducer deviceMessageProducer; | ||
| 44 | 41 | ||
| 45 | @PostConstruct | 42 | @PostConstruct |
| 46 | public void init() { | 43 | public void init() { |
| @@ -54,53 +51,49 @@ public class IotDeviceStateMessageSubscriber implements IotMessageSubscriber<Iot | @@ -54,53 +51,49 @@ public class IotDeviceStateMessageSubscriber implements IotMessageSubscriber<Iot | ||
| 54 | 51 | ||
| 55 | @Override | 52 | @Override |
| 56 | public String getGroup() { | 53 | public String getGroup() { |
| 57 | - return "iot_device_state_consumer"; | 54 | + return "iot_device_message_consumer"; |
| 58 | } | 55 | } |
| 59 | 56 | ||
| 60 | @Override | 57 | @Override |
| 61 | public void onMessage(IotDeviceMessage message) { | 58 | public void onMessage(IotDeviceMessage message) { |
| 62 | - // 1.1 只处理上行消息,或者是 STATE 相关的消息 | ||
| 63 | - if (!IotDeviceMessageUtils.isUpstreamMessage(message) | ||
| 64 | - && ObjectUtil.notEqual(message.getType(), IotDeviceMessageTypeEnum.STATE.getType())) { | 59 | + if (!IotDeviceMessageUtils.isUpstreamMessage(message)) { |
| 60 | + log.error("[onMessage][message({}) 非上行消息,不进行处理]", message); | ||
| 65 | return; | 61 | return; |
| 66 | } | 62 | } |
| 67 | - // 1.2 校验设备是否存在 | ||
| 68 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 69 | - message.getProductKey(), message.getDeviceName()); | ||
| 70 | - if (device == null) { | ||
| 71 | - log.error("[onMessage][消息({}) 对应的设备部存在]", message); | ||
| 72 | - return; | ||
| 73 | - } | ||
| 74 | - | ||
| 75 | - // 2. 处理消息 | ||
| 76 | - TenantUtils.execute(device.getTenantId(), () -> onMessage(message, device)); | ||
| 77 | - } | ||
| 78 | 63 | ||
| 79 | - private void onMessage(IotDeviceMessage message, IotDeviceDO device) { | ||
| 80 | - // 更新设备的最后时间 | 64 | + // 1.1 更新设备的最后时间 |
| 65 | + // TODO 芋艿:后续加缓存; | ||
| 66 | + IotDeviceDO device = deviceService.validateDeviceExists(message.getDeviceId()); | ||
| 81 | devicePropertyService.updateDeviceReportTime(device.getProductKey(), device.getDeviceName(), LocalDateTime.now()); | 67 | devicePropertyService.updateDeviceReportTime(device.getProductKey(), device.getDeviceName(), LocalDateTime.now()); |
| 68 | + // 1.2 更新设备的连接 server | ||
| 69 | + devicePropertyService.updateDeviceServerId(device.getProductKey(), device.getDeviceName(), message.getServerId()); | ||
| 70 | + | ||
| 71 | + // 2. 未上线的设备,强制上线 | ||
| 72 | + forceDeviceOnline(message, device); | ||
| 73 | + | ||
| 74 | + // 3. 核心:处理消息 | ||
| 75 | + deviceMessageService.handleUpstreamDeviceMessage(message, device); | ||
| 76 | + } | ||
| 82 | 77 | ||
| 83 | - // 情况一:STATE 相关的消息 | ||
| 84 | - if (Objects.equals(message.getType(), IotDeviceMessageTypeEnum.STATE.getType())) { | ||
| 85 | - if (Objects.equals(message.getIdentifier(), IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier())) { | ||
| 86 | - deviceService.updateDeviceState(device.getId(), IotDeviceStateEnum.ONLINE.getState()); | ||
| 87 | - devicePropertyService.updateDeviceServerId(device.getProductKey(), device.getDeviceName(), message.getServerId()); | ||
| 88 | - } else { | ||
| 89 | - deviceService.updateDeviceState(device.getId(), IotDeviceStateEnum.OFFLINE.getState()); | ||
| 90 | - devicePropertyService.deleteDeviceServerId(device.getProductKey(), device.getDeviceName()); | ||
| 91 | - } | ||
| 92 | - // TODO 芋艿:子设备的关联 | 78 | + private void forceDeviceOnline(IotDeviceMessage message, IotDeviceDO device) { |
| 79 | + // 已经在线,无需处理 | ||
| 80 | + if (ObjectUtil.equal(device.getState(), IotDeviceStateEnum.ONLINE.getState())) { | ||
| 81 | + return; | ||
| 82 | + } | ||
| 83 | + // 如果是 STATE 相关的消息,无需处理,不然就重复处理状态了 | ||
| 84 | + if (ObjectUtils.equalsAny(message.getMethod(), IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod(), | ||
| 85 | + IotDeviceMessageMethodEnum.STATE_OFFLINE.getMethod())) { | ||
| 93 | return; | 86 | return; |
| 94 | } | 87 | } |
| 95 | 88 | ||
| 96 | - // 情况二:非 STATE 相关的消息 | ||
| 97 | - devicePropertyService.updateDeviceServerId(device.getProductKey(), device.getDeviceName(), message.getServerId()); | ||
| 98 | // 特殊:设备非在线时,主动标记设备为在线 | 89 | // 特殊:设备非在线时,主动标记设备为在线 |
| 99 | - // 为什么不直接更新状态呢?因为通过 IotDeviceMessage 可以经过一系列的处理,例如说记录日志等等 | ||
| 100 | - if (ObjectUtil.notEqual(device.getState(), IotDeviceStateEnum.ONLINE.getState())) { | ||
| 101 | - deviceMessageProducer.sendDeviceMessage(IotDeviceMessage.of(message.getProductKey(), message.getDeviceName()) | ||
| 102 | - .ofStateOnline()); | 90 | + // 为什么不直接更新状态呢?因为通过 IotDeviceMessage 可以经过一系列的处理,例如说记录日志、规则引擎等等 |
| 91 | + try { | ||
| 92 | + deviceMessageService.sendDeviceMessage(IotDeviceMessage.buildStateOnline().setDeviceId(device.getId())); | ||
| 93 | + } catch (Exception e) { | ||
| 94 | + // 注意:即使执行失败,也不影响主流程 | ||
| 95 | + log.error("[forceDeviceOnline][message({}) device({}) 强制设备上线失败]", message, device, e); | ||
| 103 | } | 96 | } |
| 104 | } | 97 | } |
| 105 | 98 | ||
| 106 | -} | ||
| 107 | \ No newline at end of file | 99 | \ No newline at end of file |
| 100 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageSubscriber.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.mq.consumer.device; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; | ||
| 4 | -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; | ||
| 5 | -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 6 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | ||
| 7 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 8 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | ||
| 9 | -import com.google.common.base.Objects; | ||
| 10 | -import jakarta.annotation.PostConstruct; | ||
| 11 | -import jakarta.annotation.Resource; | ||
| 12 | -import lombok.extern.slf4j.Slf4j; | ||
| 13 | -import org.springframework.stereotype.Component; | ||
| 14 | - | ||
| 15 | -/** | ||
| 16 | - * 针对 {@link IotDeviceMessage} 的消费者:记录设备属性 | ||
| 17 | - * | ||
| 18 | - * @author alwayssuper | ||
| 19 | - */ | ||
| 20 | -@Component | ||
| 21 | -@Slf4j | ||
| 22 | -public class IotDevicePropertyMessageSubscriber implements IotMessageSubscriber<IotDeviceMessage> { | ||
| 23 | - | ||
| 24 | - @Resource | ||
| 25 | - private IotDevicePropertyService deviceDataService; | ||
| 26 | - | ||
| 27 | - @Resource | ||
| 28 | - private IotMessageBus messageBus; | ||
| 29 | - | ||
| 30 | - @PostConstruct | ||
| 31 | - public void init() { | ||
| 32 | - messageBus.register(this); | ||
| 33 | - } | ||
| 34 | - | ||
| 35 | - @Override | ||
| 36 | - public String getTopic() { | ||
| 37 | - return IotDeviceMessage.MESSAGE_BUS_DEVICE_MESSAGE_TOPIC; | ||
| 38 | - } | ||
| 39 | - | ||
| 40 | - @Override | ||
| 41 | - public String getGroup() { | ||
| 42 | - return "iot_device_property_consumer"; | ||
| 43 | - } | ||
| 44 | - | ||
| 45 | - @Override | ||
| 46 | - public void onMessage(IotDeviceMessage message) { | ||
| 47 | - if (Objects.equal(message.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType()) | ||
| 48 | - && Objects.equal(message.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())) { | ||
| 49 | - // 保存设备属性 | ||
| 50 | - deviceDataService.saveDeviceProperty(message); | ||
| 51 | - } | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
| @@ -63,6 +63,14 @@ public interface IotDeviceService { | @@ -63,6 +63,14 @@ public interface IotDeviceService { | ||
| 63 | /** | 63 | /** |
| 64 | * 更新设备状态 | 64 | * 更新设备状态 |
| 65 | * | 65 | * |
| 66 | + * @param device 设备信息 | ||
| 67 | + * @param state 状态 | ||
| 68 | + */ | ||
| 69 | + void updateDeviceState(IotDeviceDO device, Integer state); | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 更新设备状态 | ||
| 73 | + * | ||
| 66 | * @param id 编号 | 74 | * @param id 编号 |
| 67 | * @param state 状态 | 75 | * @param state 状态 |
| 68 | */ | 76 | */ |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
| @@ -272,12 +272,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { | @@ -272,12 +272,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { | ||
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | @Override | 274 | @Override |
| 275 | - public void updateDeviceState(Long id, Integer state) { | ||
| 276 | - // 1. 校验存在 | ||
| 277 | - IotDeviceDO device = validateDeviceExists(id); | ||
| 278 | - | ||
| 279 | - // 2. 更新状态和时间 | ||
| 280 | - IotDeviceDO updateObj = new IotDeviceDO().setId(id).setState(state); | 275 | + public void updateDeviceState(IotDeviceDO device, Integer state) { |
| 276 | + // 1. 更新状态和时间 | ||
| 277 | + IotDeviceDO updateObj = new IotDeviceDO().setId(device.getId()).setState(state); | ||
| 281 | if (device.getOnlineTime() == null | 278 | if (device.getOnlineTime() == null |
| 282 | && Objects.equals(state, IotDeviceStateEnum.ONLINE.getState())) { | 279 | && Objects.equals(state, IotDeviceStateEnum.ONLINE.getState())) { |
| 283 | updateObj.setActiveTime(LocalDateTime.now()); | 280 | updateObj.setActiveTime(LocalDateTime.now()); |
| @@ -289,11 +286,19 @@ public class IotDeviceServiceImpl implements IotDeviceService { | @@ -289,11 +286,19 @@ public class IotDeviceServiceImpl implements IotDeviceService { | ||
| 289 | } | 286 | } |
| 290 | deviceMapper.updateById(updateObj); | 287 | deviceMapper.updateById(updateObj); |
| 291 | 288 | ||
| 292 | - // 3. 清空对应缓存 | 289 | + // 2. 清空对应缓存 |
| 293 | deleteDeviceCache(device); | 290 | deleteDeviceCache(device); |
| 294 | } | 291 | } |
| 295 | 292 | ||
| 296 | @Override | 293 | @Override |
| 294 | + public void updateDeviceState(Long id, Integer state) { | ||
| 295 | + // 校验存在 | ||
| 296 | + IotDeviceDO device = validateDeviceExists(id); | ||
| 297 | + // 执行更新 | ||
| 298 | + updateDeviceState(device, state); | ||
| 299 | + } | ||
| 300 | + | ||
| 301 | + @Override | ||
| 297 | public Long getDeviceCountByProductId(Long productId) { | 302 | public Long getDeviceCountByProductId(Long productId) { |
| 298 | return deviceMapper.selectCountByProductId(productId); | 303 | return deviceMapper.selectCountByProductId(productId); |
| 299 | } | 304 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.device.control; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; | ||
| 4 | -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 5 | -import jakarta.validation.Valid; | ||
| 6 | - | ||
| 7 | -/** | ||
| 8 | - * IoT 设备下行 Service 接口 | ||
| 9 | - * | ||
| 10 | - * 目的:服务端 -> 网关 -> 设备 | ||
| 11 | - * | ||
| 12 | - * @author 芋道源码 | ||
| 13 | - */ | ||
| 14 | -public interface IotDeviceDownstreamService { | ||
| 15 | - | ||
| 16 | - /** | ||
| 17 | - * 设备下行,可用于设备模拟 | ||
| 18 | - * | ||
| 19 | - * @param downstreamReqVO 设备下行请求 VO | ||
| 20 | - * @return 下行消息 | ||
| 21 | - */ | ||
| 22 | - IotDeviceMessage downstreamDevice(@Valid IotDeviceDownstreamReqVO downstreamReqVO); | ||
| 23 | - | ||
| 24 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.device.control; | ||
| 2 | - | ||
| 3 | -import cn.hutool.core.util.StrUtil; | ||
| 4 | -import cn.iocoder.yudao.framework.common.exception.ServiceException; | ||
| 5 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; | ||
| 6 | -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 7 | -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | ||
| 8 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 9 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | ||
| 10 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 11 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | ||
| 12 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | ||
| 13 | -import jakarta.annotation.Resource; | ||
| 14 | -import lombok.extern.slf4j.Slf4j; | ||
| 15 | -import org.springframework.stereotype.Service; | ||
| 16 | -import org.springframework.validation.annotation.Validated; | ||
| 17 | - | ||
| 18 | -import java.util.Map; | ||
| 19 | -import java.util.Objects; | ||
| 20 | - | ||
| 21 | -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; | ||
| 22 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 23 | -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL; | ||
| 24 | - | ||
| 25 | -/** | ||
| 26 | - * IoT 设备下行 Service 实现类 | ||
| 27 | - * | ||
| 28 | - * @author 芋道源码 | ||
| 29 | - */ | ||
| 30 | -@Service | ||
| 31 | -@Validated | ||
| 32 | -@Slf4j | ||
| 33 | -public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamService { | ||
| 34 | - | ||
| 35 | - @Resource | ||
| 36 | - private IotDeviceService deviceService; | ||
| 37 | - @Resource | ||
| 38 | - private IotDevicePropertyService devicePropertyService; | ||
| 39 | - | ||
| 40 | - @Resource | ||
| 41 | - private IotDeviceMessageProducer deviceMessageProducer; | ||
| 42 | - | ||
| 43 | - @Override | ||
| 44 | - public IotDeviceMessage downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { | ||
| 45 | - // 1. 校验设备是否存在 | ||
| 46 | - IotDeviceDO device = deviceService.validateDeviceExists(downstreamReqVO.getId()); | ||
| 47 | - // TODO 芋艿:父设备的处理 | ||
| 48 | - IotDeviceDO parentDevice = null; | ||
| 49 | - | ||
| 50 | - // 2. 构建消息 | ||
| 51 | - IotDeviceMessage message = buildDownstreamDeviceMessage(downstreamReqVO, device, parentDevice); | ||
| 52 | - | ||
| 53 | - // 3.1 发送给网关 | ||
| 54 | - String serverId = devicePropertyService.getDeviceServerId(message.getProductKey(), message.getDeviceName()); | ||
| 55 | - if (StrUtil.isEmpty(serverId)) { | ||
| 56 | - throw exception(DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL); | ||
| 57 | - } | ||
| 58 | - deviceMessageProducer.sendDeviceMessageToGateway(serverId, message); | ||
| 59 | - | ||
| 60 | - // 3.2 发送给服务器(用于设备日志等的记录) | ||
| 61 | - deviceMessageProducer.sendDeviceMessage(message); | ||
| 62 | - return message; | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - @SuppressWarnings("unchecked") | ||
| 66 | - private IotDeviceMessage buildDownstreamDeviceMessage(IotDeviceDownstreamReqVO downstreamReqVO, | ||
| 67 | - IotDeviceDO device, IotDeviceDO parentDevice) { | ||
| 68 | - IotDeviceMessage message = IotDeviceMessage.of(getProductKey(device, parentDevice), | ||
| 69 | - getDeviceName(device, parentDevice)); | ||
| 70 | - // 服务调用 | ||
| 71 | - if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.SERVICE.getType())) { | ||
| 72 | - // TODO @芋艿:待实现 | ||
| 73 | -// return invokeDeviceService(downstreamReqVO, device, parentDevice); | ||
| 74 | - } | ||
| 75 | - // 属性相关 | ||
| 76 | - if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { | ||
| 77 | - // 属性设置 | ||
| 78 | - if (Objects.equals(downstreamReqVO.getIdentifier(), | ||
| 79 | - IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())) { | ||
| 80 | - if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) { | ||
| 81 | - throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); | ||
| 82 | - } | ||
| 83 | - return message.ofPropertySet((Map<String, Object>) downstreamReqVO.getData()); | ||
| 84 | - } | ||
| 85 | - // 属性获取 | ||
| 86 | - if (Objects.equals(downstreamReqVO.getIdentifier(), | ||
| 87 | - IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { | ||
| 88 | - // TODO @芋艿:待实现 | ||
| 89 | -// return getDeviceProperty(downstreamReqVO, device, parentDevice); | ||
| 90 | - } | ||
| 91 | - } | ||
| 92 | - // 配置下发 | ||
| 93 | - if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.CONFIG.getType()) | ||
| 94 | - && Objects.equals(downstreamReqVO.getIdentifier(), | ||
| 95 | - IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) { | ||
| 96 | - // TODO @芋艿:待实现 | ||
| 97 | -// return setDeviceConfig(downstreamReqVO, device, parentDevice); | ||
| 98 | - } | ||
| 99 | - // OTA 升级 | ||
| 100 | - if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.OTA.getType())) { | ||
| 101 | - // TODO @芋艿:待实现 | ||
| 102 | -// return otaUpgrade(downstreamReqVO, device, parentDevice); | ||
| 103 | - } | ||
| 104 | - // TODO @芋艿:取消设备的网关的时,要不要下发 REGISTER_UNREGISTER_SUB ? | ||
| 105 | - throw new IllegalArgumentException("不支持的下行消息类型:" + downstreamReqVO); | ||
| 106 | - } | ||
| 107 | - | ||
| 108 | -// /** | ||
| 109 | -// * 调用设备服务 | ||
| 110 | -// * | ||
| 111 | -// * @param downstreamReqVO 下行请求 | ||
| 112 | -// * @param device 设备 | ||
| 113 | -// * @param parentDevice 父设备 | ||
| 114 | -// * @return 下发消息 | ||
| 115 | -// */ | ||
| 116 | -// @SuppressWarnings("unchecked") | ||
| 117 | -// private IotDeviceMessage invokeDeviceService(IotDeviceDownstreamReqVO downstreamReqVO, | ||
| 118 | -// IotDeviceDO device, IotDeviceDO parentDevice) { | ||
| 119 | -// // 1. 参数校验 | ||
| 120 | -// if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) { | ||
| 121 | -// throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); | ||
| 122 | -// } | ||
| 123 | -// // TODO @super:【可优化】过滤掉不合法的服务 | ||
| 124 | -// | ||
| 125 | -// // 2. 发送请求 | ||
| 126 | -// String url = String.format("sys/%s/%s/thing/service/%s", | ||
| 127 | -// getProductKey(device, parentDevice), getDeviceName(device, parentDevice), | ||
| 128 | -// downstreamReqVO.getIdentifier()); | ||
| 129 | -// IotDeviceServiceInvokeReqDTO reqDTO = new IotDeviceServiceInvokeReqDTO() | ||
| 130 | -// .setParams((Map<String, Object>) downstreamReqVO.getData()); | ||
| 131 | -//// CommonResult<Boolean> result = requestPlugin(url, reqDTO, device); | ||
| 132 | -// CommonResult<Boolean> result = null; | ||
| 133 | -// | ||
| 134 | -// // 3. 发送设备消息 | ||
| 135 | -// IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) | ||
| 136 | -// .setType(IotDeviceMessageTypeEnum.SERVICE.getType()).setIdentifier(reqDTO.getIdentifier()) | ||
| 137 | -// .setData(reqDTO.getParams()); | ||
| 138 | -// sendDeviceMessage(message, device, result.getCode()); | ||
| 139 | -// | ||
| 140 | -// // 4. 如果不成功,抛出异常,提示用户 | ||
| 141 | -// if (result.isError()) { | ||
| 142 | -// log.error("[invokeDeviceService][设备({})服务调用失败,请求参数:({}),响应结果:({})]", | ||
| 143 | -// device.getDeviceKey(), reqDTO, result); | ||
| 144 | -// throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); | ||
| 145 | -// } | ||
| 146 | -// return message; | ||
| 147 | -// } | ||
| 148 | - | ||
| 149 | -// /** | ||
| 150 | -// * 获取设备属性 | ||
| 151 | -// * | ||
| 152 | -// * @param downstreamReqVO 下行请求 | ||
| 153 | -// * @param device 设备 | ||
| 154 | -// * @param parentDevice 父设备 | ||
| 155 | -// * @return 下发消息 | ||
| 156 | -// */ | ||
| 157 | -// @SuppressWarnings("unchecked") | ||
| 158 | -// private IotDeviceMessage getDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, | ||
| 159 | -// IotDeviceDO device, IotDeviceDO parentDevice) { | ||
| 160 | -// // 1. 参数校验 | ||
| 161 | -// if (!(downstreamReqVO.getData() instanceof List<?>)) { | ||
| 162 | -// throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 List 类型"); | ||
| 163 | -// } | ||
| 164 | -// // TODO @super:【可优化】过滤掉不合法的属性 | ||
| 165 | -// | ||
| 166 | -// // 2. 发送请求 | ||
| 167 | -// String url = String.format("sys/%s/%s/thing/service/property/get", | ||
| 168 | -// getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); | ||
| 169 | -// IotDevicePropertyGetReqDTO reqDTO = new IotDevicePropertyGetReqDTO() | ||
| 170 | -// .setIdentifiers((List<String>) downstreamReqVO.getData()); | ||
| 171 | -//// CommonResult<Boolean> result = requestPlugin(url, reqDTO, device); | ||
| 172 | -// CommonResult<Boolean> result = null; | ||
| 173 | -// | ||
| 174 | -// // 3. 发送设备消息 | ||
| 175 | -// IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) | ||
| 176 | -// .setType(IotDeviceMessageTypeEnum.PROPERTY.getType()) | ||
| 177 | -// .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()) | ||
| 178 | -// .setData(reqDTO.getIdentifiers()); | ||
| 179 | -// sendDeviceMessage(message, device, result.getCode()); | ||
| 180 | -// | ||
| 181 | -// // 4. 如果不成功,抛出异常,提示用户 | ||
| 182 | -// if (result.isError()) { | ||
| 183 | -// log.error("[getDeviceProperty][设备({})属性获取失败,请求参数:({}),响应结果:({})]", | ||
| 184 | -// device.getDeviceKey(), reqDTO, result); | ||
| 185 | -// throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); | ||
| 186 | -// } | ||
| 187 | -// return message; | ||
| 188 | -// } | ||
| 189 | - | ||
| 190 | -// /** | ||
| 191 | -// * 设置设备配置 | ||
| 192 | -// * | ||
| 193 | -// * @param downstreamReqVO 下行请求 | ||
| 194 | -// * @param device 设备 | ||
| 195 | -// * @param parentDevice 父设备 | ||
| 196 | -// * @return 下发消息 | ||
| 197 | -// */ | ||
| 198 | -// @SuppressWarnings({ "unchecked", "unused" }) | ||
| 199 | -// private IotDeviceMessage setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, | ||
| 200 | -// IotDeviceDO device, IotDeviceDO parentDevice) { | ||
| 201 | -// // 1. 参数转换,无需校验 | ||
| 202 | -// Map<String, Object> config = JsonUtils.parseObject(device.getConfig(), Map.class); | ||
| 203 | -// | ||
| 204 | -// // 2. 发送请求 | ||
| 205 | -// String url = String.format("sys/%s/%s/thing/service/config/set", | ||
| 206 | -// getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); | ||
| 207 | -// IotDeviceConfigSetReqDTO reqDTO = new IotDeviceConfigSetReqDTO() | ||
| 208 | -// .setConfig(config); | ||
| 209 | -//// CommonResult<Boolean> result = requestPlugin(url, reqDTO, device); | ||
| 210 | -// CommonResult<Boolean> result = null; | ||
| 211 | -// | ||
| 212 | -// // 3. 发送设备消息 | ||
| 213 | -// IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) | ||
| 214 | -// .setType(IotDeviceMessageTypeEnum.CONFIG.getType()) | ||
| 215 | -// .setIdentifier(IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier()) | ||
| 216 | -// .setData(reqDTO.getConfig()); | ||
| 217 | -// sendDeviceMessage(message, device, result.getCode()); | ||
| 218 | -// | ||
| 219 | -// // 4. 如果不成功,抛出异常,提示用户 | ||
| 220 | -// if (result.isError()) { | ||
| 221 | -// log.error("[setDeviceConfig][设备({})配置下发失败,请求参数:({}),响应结果:({})]", | ||
| 222 | -// device.getDeviceKey(), reqDTO, result); | ||
| 223 | -// throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); | ||
| 224 | -// } | ||
| 225 | -// return message; | ||
| 226 | -// } | ||
| 227 | - | ||
| 228 | -// /** | ||
| 229 | -// * 设备 OTA 升级 | ||
| 230 | -// * | ||
| 231 | -// * @param downstreamReqVO 下行请求 | ||
| 232 | -// * @param device 设备 | ||
| 233 | -// * @param parentDevice 父设备 | ||
| 234 | -// * @return 下发消息 | ||
| 235 | -// */ | ||
| 236 | -// private IotDeviceMessage otaUpgrade(IotDeviceDownstreamReqVO downstreamReqVO, | ||
| 237 | -// IotDeviceDO device, IotDeviceDO parentDevice) { | ||
| 238 | -// // 1. 参数校验 | ||
| 239 | -// if (!(downstreamReqVO.getData() instanceof Map<?, ?> data)) { | ||
| 240 | -// throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); | ||
| 241 | -// } | ||
| 242 | -// | ||
| 243 | -// // 2. 发送请求 | ||
| 244 | -// String url = String.format("ota/%s/%s/upgrade", | ||
| 245 | -// getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); | ||
| 246 | -// IotDeviceOtaUpgradeReqDTO reqDTO = IotDeviceOtaUpgradeReqDTO.build(data); | ||
| 247 | -//// CommonResult<Boolean> result = requestPlugin(url, reqDTO, device); | ||
| 248 | -// CommonResult<Boolean> result = null; | ||
| 249 | -// | ||
| 250 | -// // 3. 发送设备消息 | ||
| 251 | -// IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) | ||
| 252 | -// .setType(IotDeviceMessageTypeEnum.OTA.getType()) | ||
| 253 | -// .setIdentifier(IotDeviceMessageIdentifierEnum.OTA_UPGRADE.getIdentifier()) | ||
| 254 | -// .setData(downstreamReqVO.getData()); | ||
| 255 | -// sendDeviceMessage(message, device, result.getCode()); | ||
| 256 | -// | ||
| 257 | -// // 4. 如果不成功,抛出异常,提示用户 | ||
| 258 | -// if (result.isError()) { | ||
| 259 | -// log.error("[otaUpgrade][设备({}) OTA 升级失败,请求参数:({}),响应结果:({})]", | ||
| 260 | -// device.getDeviceKey(), reqDTO, result); | ||
| 261 | -// throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); | ||
| 262 | -// } | ||
| 263 | -// return message; | ||
| 264 | -// } | ||
| 265 | - | ||
| 266 | - private String getDeviceName(IotDeviceDO device, IotDeviceDO parentDevice) { | ||
| 267 | - return parentDevice != null ? parentDevice.getDeviceName() : device.getDeviceName(); | ||
| 268 | - } | ||
| 269 | - | ||
| 270 | - private String getProductKey(IotDeviceDO device, IotDeviceDO parentDevice) { | ||
| 271 | - return parentDevice != null ? parentDevice.getProductKey() : device.getProductKey(); | ||
| 272 | - } | ||
| 273 | - | ||
| 274 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.device.control; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; | ||
| 4 | -import jakarta.validation.Valid; | ||
| 5 | - | ||
| 6 | -/** | ||
| 7 | - * IoT 设备上行 Service 接口 | ||
| 8 | - * | ||
| 9 | - * 目的:设备 -> 网关 -> 服务端 | ||
| 10 | - * | ||
| 11 | - * @author 芋道源码 | ||
| 12 | - */ | ||
| 13 | -public interface IotDeviceUpstreamService { | ||
| 14 | - | ||
| 15 | - /** | ||
| 16 | - * 设备上行,可用于设备模拟 | ||
| 17 | - * | ||
| 18 | - * @param simulatorReqVO 设备上行请求 VO | ||
| 19 | - */ | ||
| 20 | - void upstreamDevice(@Valid IotDeviceUpstreamReqVO simulatorReqVO); | ||
| 21 | - | ||
| 22 | -// /** | ||
| 23 | -// * 上报设备事件数据 | ||
| 24 | -// * | ||
| 25 | -// * @param reportReqDTO 设备事件 | ||
| 26 | -// */ | ||
| 27 | -// void reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO); | ||
| 28 | -// | ||
| 29 | -// /** | ||
| 30 | -// * 注册设备 | ||
| 31 | -// * | ||
| 32 | -// * @param registerReqDTO 注册设备 DTO | ||
| 33 | -// */ | ||
| 34 | -// void registerDevice(IotDeviceRegisterReqDTO registerReqDTO); | ||
| 35 | -// | ||
| 36 | -// /** | ||
| 37 | -// * 注册子设备 | ||
| 38 | -// * | ||
| 39 | -// * @param registerReqDTO 注册子设备 DTO | ||
| 40 | -// */ | ||
| 41 | -// void registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO); | ||
| 42 | -// | ||
| 43 | -// /** | ||
| 44 | -// * 添加设备拓扑 | ||
| 45 | -// * | ||
| 46 | -// * @param addReqDTO 添加设备拓扑 DTO | ||
| 47 | -// */ | ||
| 48 | -// void addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO); | ||
| 49 | - | ||
| 50 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.device.control; | ||
| 2 | - | ||
| 3 | -import cn.hutool.core.collection.CollUtil; | ||
| 4 | -import cn.hutool.core.util.IdUtil; | ||
| 5 | -import cn.hutool.core.util.ObjUtil; | ||
| 6 | -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | ||
| 7 | -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*; | ||
| 8 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; | ||
| 9 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 10 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 11 | -import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; | ||
| 12 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | ||
| 13 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | ||
| 14 | -import jakarta.annotation.Resource; | ||
| 15 | -import lombok.extern.slf4j.Slf4j; | ||
| 16 | -import org.springframework.stereotype.Service; | ||
| 17 | -import org.springframework.validation.annotation.Validated; | ||
| 18 | - | ||
| 19 | -import java.time.LocalDateTime; | ||
| 20 | -import java.util.Map; | ||
| 21 | -import java.util.Objects; | ||
| 22 | - | ||
| 23 | -/** | ||
| 24 | - * IoT 设备上行 Service 实现类 | ||
| 25 | - * | ||
| 26 | - * @author 芋道源码 | ||
| 27 | - */ | ||
| 28 | -@Service | ||
| 29 | -@Validated | ||
| 30 | -@Slf4j | ||
| 31 | -public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { | ||
| 32 | - | ||
| 33 | - @Resource | ||
| 34 | - private IotDeviceService deviceService; | ||
| 35 | - @Resource | ||
| 36 | - private IotDevicePropertyService devicePropertyService; | ||
| 37 | - | ||
| 38 | - // TODO @芋艿:需要重新实现下; | ||
| 39 | - @Override | ||
| 40 | - @SuppressWarnings("unchecked") | ||
| 41 | - public void upstreamDevice(IotDeviceUpstreamReqVO simulatorReqVO) { | ||
| 42 | - // 1. 校验存在 | ||
| 43 | - IotDeviceDO device = deviceService.validateDeviceExists(simulatorReqVO.getId()); | ||
| 44 | - | ||
| 45 | - // 2.1 情况一:属性上报 | ||
| 46 | - String requestId = IdUtil.fastSimpleUUID(); | ||
| 47 | - if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { | ||
| 48 | - reportDeviceProperty(((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO() | ||
| 49 | - .setRequestId(requestId).setReportTime(LocalDateTime.now()) | ||
| 50 | - .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) | ||
| 51 | - .setProperties((Map<String, Object>) simulatorReqVO.getData())); | ||
| 52 | - return; | ||
| 53 | - } | ||
| 54 | - // 2.2 情况二:事件上报 | ||
| 55 | - if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.EVENT.getType())) { | ||
| 56 | - reportDeviceEvent(((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId) | ||
| 57 | - .setReportTime(LocalDateTime.now()) | ||
| 58 | - .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) | ||
| 59 | - .setIdentifier(simulatorReqVO.getIdentifier()) | ||
| 60 | - .setParams((Map<String, Object>) simulatorReqVO.getData())); | ||
| 61 | - return; | ||
| 62 | - } | ||
| 63 | - // 2.3 情况三:状态变更 | ||
| 64 | - if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.STATE.getType())) { | ||
| 65 | - // TODO @芋艿:这里未搞完 | ||
| 66 | - return; | ||
| 67 | - } | ||
| 68 | - throw new IllegalArgumentException("未知的类型:" + simulatorReqVO.getType()); | ||
| 69 | - } | ||
| 70 | - | ||
| 71 | -// @Override TODO 芋艿:待重新实现 | ||
| 72 | - public void reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { | ||
| 73 | - // 1.1 获得设备 | ||
| 74 | - log.info("[reportDeviceProperty][上报设备属性: {}]", reportReqDTO); | ||
| 75 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 76 | - reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); | ||
| 77 | - if (device == null) { | ||
| 78 | - log.error("[reportDeviceProperty][设备({}/{})不存在]", | ||
| 79 | - reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); | ||
| 80 | - return; | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - // 2. 发送设备消息 | ||
| 84 | -// IotDeviceMessage message = BeanUtils.toBean(reportReqDTO, IotDeviceMessage.class) | ||
| 85 | -// .setType(IotDeviceMessageTypeEnum.PROPERTY.getType()) | ||
| 86 | -// .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier()) | ||
| 87 | -// .setData(reportReqDTO.getProperties()); | ||
| 88 | -// sendDeviceMessage(message, device); | ||
| 89 | - } | ||
| 90 | - | ||
| 91 | - // @Override TODO 芋艿:待重新实现 | ||
| 92 | - public void reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { | ||
| 93 | - // 1.1 获得设备 | ||
| 94 | - log.info("[reportDeviceEvent][上报设备事件: {}]", reportReqDTO); | ||
| 95 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 96 | - reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); | ||
| 97 | - if (device == null) { | ||
| 98 | - log.error("[reportDeviceEvent][设备({}/{})不存在]", | ||
| 99 | - reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); | ||
| 100 | - return; | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - // 2. 发送设备消息 | ||
| 104 | -// IotDeviceMessage message = BeanUtils.toBean(reportReqDTO, IotDeviceMessage.class) | ||
| 105 | -// .setType(IotDeviceMessageTypeEnum.EVENT.getType()) | ||
| 106 | -// .setIdentifier(reportReqDTO.getIdentifier()) | ||
| 107 | -// .setData(reportReqDTO.getParams()); | ||
| 108 | -// sendDeviceMessage(message, device); | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | - // @Override TODO 芋艿:待重新实现 | ||
| 112 | - public void registerDevice(IotDeviceRegisterReqDTO registerReqDTO) { | ||
| 113 | - log.info("[registerDevice][注册设备: {}]", registerReqDTO); | ||
| 114 | - registerDevice0(registerReqDTO.getProductKey(), registerReqDTO.getDeviceName(), null, registerReqDTO); | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - private void registerDevice0(String productKey, String deviceName, Long gatewayId, | ||
| 118 | - IotDeviceUpstreamAbstractReqDTO registerReqDTO) { | ||
| 119 | - // 1.1 注册设备 | ||
| 120 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(productKey, deviceName); | ||
| 121 | - boolean registerNew = device == null; | ||
| 122 | - if (device == null) { | ||
| 123 | - device = deviceService.createDevice(productKey, deviceName, gatewayId); | ||
| 124 | - log.info("[registerDevice0][消息({}) 设备({}/{}) 成功注册]", registerReqDTO, productKey, device); | ||
| 125 | - } else if (gatewayId != null && ObjUtil.notEqual(device.getGatewayId(), gatewayId)) { | ||
| 126 | - Long deviceId = device.getId(); | ||
| 127 | - TenantUtils.execute(device.getTenantId(), | ||
| 128 | - () -> deviceService.updateDeviceGateway(deviceId, gatewayId)); | ||
| 129 | - log.info("[registerDevice0][消息({}) 设备({}/{}) 更新网关设备编号({})]", | ||
| 130 | - registerReqDTO, productKey, device, gatewayId); | ||
| 131 | - } | ||
| 132 | - // 1.2 记录设备的最后时间 | ||
| 133 | -// updateDeviceLastTime(device, registerReqDTO); | ||
| 134 | - | ||
| 135 | - // 2. 发送设备消息 | ||
| 136 | - if (registerNew) { | ||
| 137 | -// IotDeviceMessage message = BeanUtils.toBean(registerReqDTO, IotDeviceMessage.class) | ||
| 138 | -// .setType(IotDeviceMessageTypeEnum.REGISTER.getType()) | ||
| 139 | -// .setIdentifier(IotDeviceMessageIdentifierEnum.REGISTER_REGISTER.getIdentifier()); | ||
| 140 | -// sendDeviceMessage(message, device); | ||
| 141 | - } | ||
| 142 | - } | ||
| 143 | - | ||
| 144 | - // @Override TODO 芋艿:待重新实现 | ||
| 145 | - public void registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) { | ||
| 146 | - // 1.1 注册子设备 | ||
| 147 | - log.info("[registerSubDevice][注册子设备: {}]", registerReqDTO); | ||
| 148 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 149 | - registerReqDTO.getProductKey(), registerReqDTO.getDeviceName()); | ||
| 150 | - if (device == null) { | ||
| 151 | - log.error("[registerSubDevice][设备({}/{}) 不存在]", | ||
| 152 | - registerReqDTO.getProductKey(), registerReqDTO.getDeviceName()); | ||
| 153 | - return; | ||
| 154 | - } | ||
| 155 | - if (!IotProductDeviceTypeEnum.isGateway(device.getDeviceType())) { | ||
| 156 | - log.error("[registerSubDevice][设备({}/{}) 不是网关设备({}),无法进行注册]", | ||
| 157 | - registerReqDTO.getProductKey(), registerReqDTO.getDeviceName(), device); | ||
| 158 | - return; | ||
| 159 | - } | ||
| 160 | - // 1.2 记录设备的最后时间 | ||
| 161 | -// updateDeviceLastTime(device, registerReqDTO); | ||
| 162 | - | ||
| 163 | - // 2. 处理子设备 | ||
| 164 | - if (CollUtil.isNotEmpty(registerReqDTO.getParams())) { | ||
| 165 | - registerReqDTO.getParams().forEach(subDevice -> registerDevice0( | ||
| 166 | - subDevice.getProductKey(), subDevice.getDeviceName(), device.getId(), registerReqDTO)); | ||
| 167 | - // TODO @芋艿:后续要处理,每个设备是否成功 | ||
| 168 | - } | ||
| 169 | - | ||
| 170 | - // 3. 发送设备消息 | ||
| 171 | -// IotDeviceMessage message = BeanUtils.toBean(registerReqDTO, IotDeviceMessage.class) | ||
| 172 | -// .setType(IotDeviceMessageTypeEnum.REGISTER.getType()) | ||
| 173 | -// .setIdentifier(IotDeviceMessageIdentifierEnum.REGISTER_REGISTER_SUB.getIdentifier()) | ||
| 174 | -// .setData(registerReqDTO.getParams()); | ||
| 175 | -// sendDeviceMessage(message, device); | ||
| 176 | - } | ||
| 177 | - | ||
| 178 | - // @Override TODO 芋艿:待重新实现 | ||
| 179 | - public void addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) { | ||
| 180 | - // 1.1 获得设备 | ||
| 181 | - log.info("[addDeviceTopology][添加设备拓扑: {}]", addReqDTO); | ||
| 182 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 183 | - addReqDTO.getProductKey(), addReqDTO.getDeviceName()); | ||
| 184 | - if (device == null) { | ||
| 185 | - log.error("[addDeviceTopology][设备({}/{}) 不存在]", | ||
| 186 | - addReqDTO.getProductKey(), addReqDTO.getDeviceName()); | ||
| 187 | - return; | ||
| 188 | - } | ||
| 189 | - if (!IotProductDeviceTypeEnum.isGateway(device.getDeviceType())) { | ||
| 190 | - log.error("[addDeviceTopology][设备({}/{}) 不是网关设备({}),无法进行拓扑添加]", | ||
| 191 | - addReqDTO.getProductKey(), addReqDTO.getDeviceName(), device); | ||
| 192 | - return; | ||
| 193 | - } | ||
| 194 | - | ||
| 195 | - // 2. 处理拓扑 | ||
| 196 | - if (CollUtil.isNotEmpty(addReqDTO.getParams())) { | ||
| 197 | - TenantUtils.execute(device.getTenantId(), () -> { | ||
| 198 | - addReqDTO.getParams().forEach(subDevice -> { | ||
| 199 | - IotDeviceDO subDeviceDO = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 200 | - subDevice.getProductKey(), subDevice.getDeviceName()); | ||
| 201 | - // TODO @芋艿:后续要处理,每个设备是否成功 | ||
| 202 | - if (subDeviceDO == null) { | ||
| 203 | - log.error("[addDeviceTopology][子设备({}/{}) 不存在]", | ||
| 204 | - subDevice.getProductKey(), subDevice.getDeviceName()); | ||
| 205 | - return; | ||
| 206 | - } | ||
| 207 | - deviceService.updateDeviceGateway(subDeviceDO.getId(), device.getId()); | ||
| 208 | - log.info("[addDeviceTopology][子设备({}/{}) 添加到网关设备({}) 成功]", | ||
| 209 | - subDevice.getProductKey(), subDevice.getDeviceName(), device); | ||
| 210 | - }); | ||
| 211 | - }); | ||
| 212 | - } | ||
| 213 | - | ||
| 214 | - // 3. 发送设备消息 | ||
| 215 | -// IotDeviceMessage message = BeanUtils.toBean(addReqDTO, IotDeviceMessage.class) | ||
| 216 | -// .setType(IotDeviceMessageTypeEnum.TOPOLOGY.getType()) | ||
| 217 | -// .setIdentifier(IotDeviceMessageIdentifierEnum.TOPOLOGY_ADD.getIdentifier()) | ||
| 218 | -// .setData(addReqDTO.getParams()); | ||
| 219 | -// sendDeviceMessage(message, device); | ||
| 220 | - } | ||
| 221 | - | ||
| 222 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.device.message; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 4 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * IoT 设备消息 Service 接口 | ||
| 8 | + * | ||
| 9 | + * @author 芋道源码 | ||
| 10 | + */ | ||
| 11 | +public interface IotDeviceMessageService { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 初始化设备消息的 TDengine 超级表 | ||
| 15 | + * | ||
| 16 | + * 系统启动时,会自动初始化一次 | ||
| 17 | + */ | ||
| 18 | + void defineDeviceMessageStable(); | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 发送设备消息 | ||
| 22 | + * | ||
| 23 | + * @param message 消息(“codec(编解码)字段” 部分字段) | ||
| 24 | + * @param device 设备 | ||
| 25 | + * @return 设备消息 | ||
| 26 | + */ | ||
| 27 | + IotDeviceMessage sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device); | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 发送设备消息 | ||
| 31 | + * | ||
| 32 | + * @param message 消息(“codec(编解码)字段” 部分字段) | ||
| 33 | + * @return 设备消息 | ||
| 34 | + */ | ||
| 35 | + IotDeviceMessage sendDeviceMessage(IotDeviceMessage message); | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * 处理设备上行的消息,包括如下步骤: | ||
| 39 | + * | ||
| 40 | + * 1. 处理消息 | ||
| 41 | + * 2. 记录消息 | ||
| 42 | + * 3. 回复消息 | ||
| 43 | + * | ||
| 44 | + * @param message 消息 | ||
| 45 | + * @param device 设备 | ||
| 46 | + */ | ||
| 47 | + void handleUpstreamDeviceMessage(IotDeviceMessage message, IotDeviceDO device); | ||
| 48 | + | ||
| 49 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.device.message; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.exception.ServiceException; | ||
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 6 | +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; | ||
| 7 | +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; | ||
| 8 | +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 9 | +import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | ||
| 10 | +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; | ||
| 11 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 12 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; | ||
| 13 | +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceMessageMapper; | ||
| 14 | +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | ||
| 15 | +import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; | ||
| 16 | +import com.google.common.base.Objects; | ||
| 17 | +import jakarta.annotation.Resource; | ||
| 18 | +import lombok.extern.slf4j.Slf4j; | ||
| 19 | +import org.springframework.stereotype.Service; | ||
| 20 | +import org.springframework.validation.annotation.Validated; | ||
| 21 | + | ||
| 22 | +import java.time.LocalDateTime; | ||
| 23 | + | ||
| 24 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 25 | +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * IoT 设备消息 Service 实现类 | ||
| 29 | + * | ||
| 30 | + * @author 芋道源码 | ||
| 31 | + */ | ||
| 32 | +@Service | ||
| 33 | +@Validated | ||
| 34 | +@Slf4j | ||
| 35 | +public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { | ||
| 36 | + | ||
| 37 | + @Resource | ||
| 38 | + private IotDeviceService deviceService; | ||
| 39 | + @Resource | ||
| 40 | + private IotDevicePropertyService devicePropertyService; | ||
| 41 | + | ||
| 42 | + @Resource | ||
| 43 | + private IotDeviceMessageMapper deviceLogMapper; | ||
| 44 | + | ||
| 45 | + @Resource | ||
| 46 | + private IotDeviceMessageProducer deviceMessageProducer; | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public void defineDeviceMessageStable() { | ||
| 50 | + if (StrUtil.isNotEmpty(deviceLogMapper.showSTable())) { | ||
| 51 | + log.info("[defineDeviceMessageStable][设备消息超级表已存在,创建跳过]"); | ||
| 52 | + return; | ||
| 53 | + } | ||
| 54 | + log.info("[defineDeviceMessageStable][设备消息超级表不存在,创建开始...]"); | ||
| 55 | + deviceLogMapper.createSTable(); | ||
| 56 | + log.info("[defineDeviceMessageStable][设备消息超级表不存在,创建成功]"); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + // TODO @芋艿:要不要异步记录; | ||
| 60 | + private void createDeviceLog(IotDeviceMessage message) { | ||
| 61 | + IotDeviceMessageDO messageDO = BeanUtils.toBean(message, IotDeviceMessageDO.class) | ||
| 62 | + .setUpstream(IotDeviceMessageUtils.isUpstreamMessage(message)); | ||
| 63 | + deviceLogMapper.insert(messageDO); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + @Override | ||
| 67 | + public IotDeviceMessage sendDeviceMessage(IotDeviceMessage message) { | ||
| 68 | + IotDeviceDO device = deviceService.validateDeviceExists(message.getDeviceId()); | ||
| 69 | + return sendDeviceMessage(message, device); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + // TODO @芋艿:针对连接网关的设备,是不是 productKey、deviceName 需要调整下; | ||
| 73 | + @Override | ||
| 74 | + public IotDeviceMessage sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { | ||
| 75 | + // 1. 补充信息 | ||
| 76 | + appendDeviceMessage(message, device); | ||
| 77 | + | ||
| 78 | + // 2.1 情况一:发送上行消息 | ||
| 79 | + boolean upstream = IotDeviceMessageUtils.isUpstreamMessage(message); | ||
| 80 | + if (upstream) { | ||
| 81 | + deviceMessageProducer.sendDeviceMessage(message); | ||
| 82 | + return message; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + // 2.2 情况二:发送下行消息 | ||
| 86 | + // 如果是下行消息,需要校验 serverId 存在 | ||
| 87 | + String serverId = devicePropertyService.getDeviceServerId(device.getProductKey(), device.getDeviceName()); | ||
| 88 | + if (StrUtil.isEmpty(serverId)) { | ||
| 89 | + throw exception(DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL); | ||
| 90 | + } | ||
| 91 | + deviceMessageProducer.sendDeviceMessageToGateway(serverId, message); | ||
| 92 | + // 特殊:记录消息日志。原因:上行消息,消费时,已经会记录;下行消息,因为消费在 Gateway 端,所以需要在这里记录 | ||
| 93 | + createDeviceLog(message); | ||
| 94 | + return message; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + /** | ||
| 98 | + * 补充消息的后端字段 | ||
| 99 | + * | ||
| 100 | + * @param message 消息 | ||
| 101 | + * @param device 设备信息 | ||
| 102 | + * @return 消息 | ||
| 103 | + */ | ||
| 104 | + private IotDeviceMessage appendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { | ||
| 105 | + message.setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now()) | ||
| 106 | + .setDeviceId(device.getId()).setTenantId(device.getTenantId()); | ||
| 107 | + // 特殊:如果设备没有指定 requestId,则使用 messageId | ||
| 108 | + if (StrUtil.isEmpty(message.getRequestId())) { | ||
| 109 | + message.setRequestId(message.getId()); | ||
| 110 | + } | ||
| 111 | + return message; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + @Override | ||
| 115 | + public void handleUpstreamDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { | ||
| 116 | + // 1. 理消息 | ||
| 117 | + Object replyData = null; | ||
| 118 | + ServiceException serviceException = null; | ||
| 119 | + try { | ||
| 120 | + replyData = handleUpstreamDeviceMessage0(message, device); | ||
| 121 | + } catch (ServiceException ex) { | ||
| 122 | + serviceException = ex; | ||
| 123 | + log.warn("[onMessage][message({}) 业务异常]", message, serviceException); | ||
| 124 | + } catch (Exception ex) { | ||
| 125 | + log.error("[onMessage][message({}) 发生异常]", message, ex); | ||
| 126 | + throw ex; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + // 2. 记录消息 | ||
| 130 | + createDeviceLog(message); | ||
| 131 | + | ||
| 132 | + // 3. 回复消息。前提:非 _reply 消息,并且非禁用回复的消息 | ||
| 133 | + if (IotDeviceMessageUtils.isReplyMessage(message) | ||
| 134 | + || IotDeviceMessageMethodEnum.isReplyDisabled(message.getMethod())) { | ||
| 135 | + return; | ||
| 136 | + } | ||
| 137 | + sendDeviceMessage(IotDeviceMessage.replyOf(message.getRequestId(), message.getMethod(), replyData, | ||
| 138 | + serviceException != null ? serviceException.getCode() : null, | ||
| 139 | + serviceException != null ? serviceException.getMessage() : null)); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + // TODO @芋艿:可优化:未来逻辑复杂后,可以独立拆除 Processor 处理器 | ||
| 143 | + private Object handleUpstreamDeviceMessage0(IotDeviceMessage message, IotDeviceDO device) { | ||
| 144 | + // 设备上线 | ||
| 145 | + if (Objects.equal(message.getMethod(), IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod())) { | ||
| 146 | + deviceService.updateDeviceState(device, IotDeviceStateEnum.ONLINE.getState()); | ||
| 147 | + // TODO 芋艿:子设备的关联 | ||
| 148 | + return null; | ||
| 149 | + } | ||
| 150 | + // 设备下线 | ||
| 151 | + if (Objects.equal(message.getMethod(), IotDeviceMessageMethodEnum.STATE_OFFLINE.getMethod())) { | ||
| 152 | + deviceService.updateDeviceState(device, IotDeviceStateEnum.OFFLINE.getState()); | ||
| 153 | + // TODO 芋艿:子设备的关联 | ||
| 154 | + return null; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + // 属性上报 | ||
| 158 | + if (Objects.equal(message.getMethod(), IotDeviceMessageMethodEnum.PROPERTY_REPORT.getMethod())) { | ||
| 159 | + devicePropertyService.saveDeviceProperty(device, message); | ||
| 160 | + return null; | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + // TODO @芋艿:这里可以按需,添加别的逻辑; | ||
| 164 | + return null; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDeviceLogService.java
| 1 | -package cn.iocoder.yudao.module.iot.service.device.data; | 1 | +package cn.iocoder.yudao.module.iot.service.device.property; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; | 4 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; |
| 5 | -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 6 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | 5 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; |
| 7 | 6 | ||
| 8 | import javax.annotation.Nullable; | 7 | import javax.annotation.Nullable; |
| 9 | import java.time.LocalDateTime; | 8 | import java.time.LocalDateTime; |
| @@ -18,26 +17,12 @@ import java.util.Map; | @@ -18,26 +17,12 @@ import java.util.Map; | ||
| 18 | public interface IotDeviceLogService { | 17 | public interface IotDeviceLogService { |
| 19 | 18 | ||
| 20 | /** | 19 | /** |
| 21 | - * 初始化 TDengine 超级表 | ||
| 22 | - * | ||
| 23 | - * 系统启动时,会自动初始化一次 | ||
| 24 | - */ | ||
| 25 | - void defineDeviceLog(); | ||
| 26 | - | ||
| 27 | - /** | ||
| 28 | - * 插入设备日志 | ||
| 29 | - * | ||
| 30 | - * @param message 设备数据 | ||
| 31 | - */ | ||
| 32 | - void createDeviceLog(IotDeviceMessage message); | ||
| 33 | - | ||
| 34 | - /** | ||
| 35 | * 获得设备日志分页 | 20 | * 获得设备日志分页 |
| 36 | * | 21 | * |
| 37 | * @param pageReqVO 分页查询 | 22 | * @param pageReqVO 分页查询 |
| 38 | * @return 设备日志分页 | 23 | * @return 设备日志分页 |
| 39 | */ | 24 | */ |
| 40 | - PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); | 25 | + PageResult<IotDeviceMessageDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); |
| 41 | 26 | ||
| 42 | /** | 27 | /** |
| 43 | * 获得设备日志数量 | 28 | * 获得设备日志数量 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDeviceLogServiceImpl.java
| 1 | -package cn.iocoder.yudao.module.iot.service.device.data; | 1 | +package cn.iocoder.yudao.module.iot.service.device.property; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.date.LocalDateTimeUtil; | 3 | import cn.hutool.core.date.LocalDateTimeUtil; |
| 4 | import cn.hutool.core.map.MapUtil; | 4 | import cn.hutool.core.map.MapUtil; |
| 5 | -import cn.hutool.core.util.IdUtil; | ||
| 6 | -import cn.hutool.core.util.StrUtil; | ||
| 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 9 | -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 10 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; | 6 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; |
| 11 | -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 12 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 13 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | ||
| 14 | -import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper; | 7 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; |
| 8 | +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceMessageMapper; | ||
| 15 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 9 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 16 | import com.baomidou.mybatisplus.core.metadata.IPage; | 10 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 17 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | 11 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| @@ -40,39 +34,12 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { | @@ -40,39 +34,12 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { | ||
| 40 | private IotDeviceService deviceService; | 34 | private IotDeviceService deviceService; |
| 41 | 35 | ||
| 42 | @Resource | 36 | @Resource |
| 43 | - private IotDeviceLogMapper deviceLogMapper; | 37 | + private IotDeviceMessageMapper deviceLogMapper; |
| 44 | 38 | ||
| 45 | @Override | 39 | @Override |
| 46 | - public void defineDeviceLog() { | ||
| 47 | - if (StrUtil.isNotEmpty(deviceLogMapper.showDeviceLogSTable())) { | ||
| 48 | - log.info("[defineDeviceLog][设备日志超级表已存在,创建跳过]"); | ||
| 49 | - return; | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - log.info("[defineDeviceLog][设备日志超级表不存在,创建开始...]"); | ||
| 53 | - deviceLogMapper.createDeviceLogSTable(); | ||
| 54 | - log.info("[defineDeviceLog][设备日志超级表不存在,创建成功]"); | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | - @Override | ||
| 58 | - public void createDeviceLog(IotDeviceMessage message) { | ||
| 59 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 60 | - message.getProductKey(), message.getDeviceName()); | ||
| 61 | - if (device == null) { | ||
| 62 | - log.error("[createDeviceLog][设备({}/{}) 不存在]", message.getProductKey(), message.getDeviceName()); | ||
| 63 | - return; | ||
| 64 | - } | ||
| 65 | - IotDeviceLogDO log = BeanUtils.toBean(message, IotDeviceLogDO.class) | ||
| 66 | - .setId(IdUtil.fastSimpleUUID()) | ||
| 67 | - .setContent(JsonUtils.toJsonString(message.getData())) | ||
| 68 | - .setTenantId(device.getTenantId()); | ||
| 69 | - deviceLogMapper.insert(log); | ||
| 70 | - } | ||
| 71 | - | ||
| 72 | - @Override | ||
| 73 | - public PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { | 40 | + public PageResult<IotDeviceMessageDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { |
| 74 | try { | 41 | try { |
| 75 | - IPage<IotDeviceLogDO> page = deviceLogMapper.selectPage( | 42 | + IPage<IotDeviceMessageDO> page = deviceLogMapper.selectPage( |
| 76 | new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO); | 43 | new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO); |
| 77 | return new PageResult<>(page.getRecords(), page.getTotal()); | 44 | return new PageResult<>(page.getRecords(), page.getTotal()); |
| 78 | } catch (Exception exception) { | 45 | } catch (Exception exception) { |
| @@ -92,7 +59,8 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { | @@ -92,7 +59,8 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { | ||
| 92 | @Override | 59 | @Override |
| 93 | public List<Map<Long, Integer>> getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) { | 60 | public List<Map<Long, Integer>> getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) { |
| 94 | // TODO @super:不能只基于数据库统计。因为有一些小时,可能出现没数据的情况,导致前端展示的图是不全的。可以参考 CrmStatisticsCustomerService 来实现 | 61 | // TODO @super:不能只基于数据库统计。因为有一些小时,可能出现没数据的情况,导致前端展示的图是不全的。可以参考 CrmStatisticsCustomerService 来实现 |
| 95 | - List<Map<String, Object>> list = deviceLogMapper.selectDeviceLogUpCountByHour(deviceKey, startTime, endTime); | 62 | + // TODO @芋艿:这里实现,需要调整 |
| 63 | + List<Map<String, Object>> list = deviceLogMapper.selectDeviceLogUpCountByHour(0L, startTime, endTime); | ||
| 96 | return list.stream() | 64 | return list.stream() |
| 97 | .map(map -> { | 65 | .map(map -> { |
| 98 | // 从Timestamp获取时间戳 | 66 | // 从Timestamp获取时间戳 |
| @@ -108,7 +76,8 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { | @@ -108,7 +76,8 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { | ||
| 108 | // TODO @super:getDeviceLogDownCountByHour 融合到 getDeviceLogUpCountByHour | 76 | // TODO @super:getDeviceLogDownCountByHour 融合到 getDeviceLogUpCountByHour |
| 109 | @Override | 77 | @Override |
| 110 | public List<Map<Long, Integer>> getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) { | 78 | public List<Map<Long, Integer>> getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) { |
| 111 | - List<Map<String, Object>> list = deviceLogMapper.selectDeviceLogDownCountByHour(deviceKey, startTime, endTime); | 79 | + // TODO @芋艿:这里实现,需要调整 |
| 80 | + List<Map<String, Object>> list = deviceLogMapper.selectDeviceLogDownCountByHour(0L, startTime, endTime); | ||
| 112 | return list.stream() | 81 | return list.stream() |
| 113 | .map(map -> { | 82 | .map(map -> { |
| 114 | // 从Timestamp获取时间戳 | 83 | // 从Timestamp获取时间戳 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyService.java
| 1 | -package cn.iocoder.yudao.module.iot.service.device.data; | 1 | +package cn.iocoder.yudao.module.iot.service.device.property; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO; | 4 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO; |
| 5 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO; | 5 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO; |
| 6 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | 6 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 7 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; |
| 8 | import jakarta.validation.Valid; | 9 | import jakarta.validation.Valid; |
| 9 | 10 | ||
| @@ -30,9 +31,10 @@ public interface IotDevicePropertyService { | @@ -30,9 +31,10 @@ public interface IotDevicePropertyService { | ||
| 30 | /** | 31 | /** |
| 31 | * 保存设备数据 | 32 | * 保存设备数据 |
| 32 | * | 33 | * |
| 34 | + * @param device 设备 | ||
| 33 | * @param message 设备消息 | 35 | * @param message 设备消息 |
| 34 | */ | 36 | */ |
| 35 | - void saveDeviceProperty(IotDeviceMessage message); | 37 | + void saveDeviceProperty(IotDeviceDO device, IotDeviceMessage message); |
| 36 | 38 | ||
| 37 | /** | 39 | /** |
| 38 | * 获得设备属性最新数据 | 40 | * 获得设备属性最新数据 |
| @@ -79,14 +81,6 @@ public interface IotDevicePropertyService { | @@ -79,14 +81,6 @@ public interface IotDevicePropertyService { | ||
| 79 | void updateDeviceServerId(String productKey, String deviceName, String serverId); | 81 | void updateDeviceServerId(String productKey, String deviceName, String serverId); |
| 80 | 82 | ||
| 81 | /** | 83 | /** |
| 82 | - * 删除设备关联的网关 serverId | ||
| 83 | - * | ||
| 84 | - * @param productKey 产品标识 | ||
| 85 | - * @param deviceName 设备名称 | ||
| 86 | - */ | ||
| 87 | - void deleteDeviceServerId(String productKey, String deviceName); | ||
| 88 | - | ||
| 89 | - /** | ||
| 90 | * 获得设备关联的网关 serverId | 84 | * 获得设备关联的网关 serverId |
| 91 | * | 85 | * |
| 92 | * @param productKey 产品标识 | 86 | * @param productKey 产品标识 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java
| 1 | -package cn.iocoder.yudao.module.iot.service.device.data; | 1 | +package cn.iocoder.yudao.module.iot.service.device.property; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.date.LocalDateTimeUtil; | 4 | import cn.hutool.core.date.LocalDateTimeUtil; |
| 5 | import cn.hutool.core.map.MapUtil; | 5 | import cn.hutool.core.map.MapUtil; |
| 6 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | ||
| 9 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO; | 8 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO; |
| 10 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO; | 9 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO; |
| 11 | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; | 10 | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; |
| @@ -121,21 +120,13 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { | @@ -121,21 +120,13 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { | ||
| 121 | } | 120 | } |
| 122 | 121 | ||
| 123 | @Override | 122 | @Override |
| 124 | - @TenantIgnore | ||
| 125 | - public void saveDeviceProperty(IotDeviceMessage message) { | 123 | + public void saveDeviceProperty(IotDeviceDO device, IotDeviceMessage message) { |
| 126 | if (!(message.getData() instanceof Map)) { | 124 | if (!(message.getData() instanceof Map)) { |
| 127 | log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message); | 125 | log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message); |
| 128 | return; | 126 | return; |
| 129 | } | 127 | } |
| 130 | - // 1. 获得设备信息 | ||
| 131 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 132 | - message.getProductKey(), message.getDeviceName()); | ||
| 133 | - if (device == null) { | ||
| 134 | - log.error("[saveDeviceProperty][消息({}) 对应的设备不存在]", message); | ||
| 135 | - return; | ||
| 136 | - } | ||
| 137 | 128 | ||
| 138 | - // 2. 根据物模型,拼接合法的属性 | 129 | + // 1. 根据物模型,拼接合法的属性 |
| 139 | // TODO @芋艿:【待定 004】赋能后,属性到底以 thingModel 为准(ik),还是 db 的表结构为准(tl)? | 130 | // TODO @芋艿:【待定 004】赋能后,属性到底以 thingModel 为准(ik),还是 db 的表结构为准(tl)? |
| 140 | List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductKeyFromCache(device.getProductKey()); | 131 | List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductKeyFromCache(device.getProductKey()); |
| 141 | Map<String, Object> properties = new HashMap<>(); | 132 | Map<String, Object> properties = new HashMap<>(); |
| @@ -151,11 +142,11 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { | @@ -151,11 +142,11 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { | ||
| 151 | return; | 142 | return; |
| 152 | } | 143 | } |
| 153 | 144 | ||
| 154 | - // 3.1 保存设备属性【数据】 | 145 | + // 2.1 保存设备属性【数据】 |
| 155 | devicePropertyMapper.insert(device, properties, | 146 | devicePropertyMapper.insert(device, properties, |
| 156 | LocalDateTimeUtil.toEpochMilli(message.getReportTime())); | 147 | LocalDateTimeUtil.toEpochMilli(message.getReportTime())); |
| 157 | 148 | ||
| 158 | - // 3.2 保存设备属性【日志】 | 149 | + // 2.2 保存设备属性【日志】 |
| 159 | Map<String, IotDevicePropertyDO> properties2 = convertMap(properties.entrySet(), Map.Entry::getKey, entry -> | 150 | Map<String, IotDevicePropertyDO> properties2 = convertMap(properties.entrySet(), Map.Entry::getKey, entry -> |
| 160 | IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build()); | 151 | IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build()); |
| 161 | deviceDataRedisDAO.putAll(device.getProductKey(), device.getDeviceName(), properties2); | 152 | deviceDataRedisDAO.putAll(device.getProductKey(), device.getDeviceName(), properties2); |
| @@ -210,11 +201,6 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { | @@ -210,11 +201,6 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { | ||
| 210 | } | 201 | } |
| 211 | 202 | ||
| 212 | @Override | 203 | @Override |
| 213 | - public void deleteDeviceServerId(String productKey, String deviceName) { | ||
| 214 | - deviceServerIdRedisDAO.delete(productKey, deviceName); | ||
| 215 | - } | ||
| 216 | - | ||
| 217 | - @Override | ||
| 218 | public String getDeviceServerId(String productKey, String deviceName) { | 204 | public String getDeviceServerId(String productKey, String deviceName) { |
| 219 | return deviceServerIdRedisDAO.get(productKey, deviceName); | 205 | return deviceServerIdRedisDAO.get(productKey, deviceName); |
| 220 | } | 206 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
| @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc | @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc | ||
| 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 9 | import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; | 9 | import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; |
| 10 | import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; | 10 | import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; |
| 11 | -import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | 11 | +import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; |
| 12 | import com.baomidou.dynamic.datasource.annotation.DSTransactional; | 12 | import com.baomidou.dynamic.datasource.annotation.DSTransactional; |
| 13 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| 14 | import org.springframework.context.annotation.Lazy; | 14 | import org.springframework.context.annotation.Lazy; |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java
| @@ -309,8 +309,10 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | @@ -309,8 +309,10 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | ||
| 309 | private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) { | 309 | private List<IotRuleSceneDO> getMatchedRuleSceneListByMessage(IotDeviceMessage message) { |
| 310 | // 1. 匹配设备 | 310 | // 1. 匹配设备 |
| 311 | // TODO @芋艿:可能需要 getSelf(); 缓存 | 311 | // TODO @芋艿:可能需要 getSelf(); 缓存 |
| 312 | - List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( | ||
| 313 | - message.getProductKey(), message.getDeviceName()); | 312 | + List<IotRuleSceneDO> ruleScenes = null; |
| 313 | + // TODO @芋艿:这里需要适配 | ||
| 314 | +// List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( | ||
| 315 | +// message.getProductKey(), message.getDeviceName()); | ||
| 314 | if (CollUtil.isEmpty(ruleScenes)) { | 316 | if (CollUtil.isEmpty(ruleScenes)) { |
| 315 | return ruleScenes; | 317 | return ruleScenes; |
| 316 | } | 318 | } |
| @@ -329,10 +331,11 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | @@ -329,10 +331,11 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { | ||
| 329 | } | 331 | } |
| 330 | // 2.3 多个条件,只需要满足一个即可 | 332 | // 2.3 多个条件,只需要满足一个即可 |
| 331 | IotRuleSceneDO.TriggerCondition matchedCondition = CollUtil.findOne(trigger.getConditions(), condition -> { | 333 | IotRuleSceneDO.TriggerCondition matchedCondition = CollUtil.findOne(trigger.getConditions(), condition -> { |
| 332 | - if (ObjUtil.notEqual(message.getType(), condition.getType()) | ||
| 333 | - || ObjUtil.notEqual(message.getIdentifier(), condition.getIdentifier())) { | ||
| 334 | - return false; | ||
| 335 | - } | 334 | + // TODO @芋艿:这里的逻辑,需要适配 |
| 335 | +// if (ObjUtil.notEqual(message.getType(), condition.getType()) | ||
| 336 | +// || ObjUtil.notEqual(message.getIdentifier(), condition.getIdentifier())) { | ||
| 337 | +// return false; | ||
| 338 | +// } | ||
| 336 | // 多个条件参数,必须全部满足。所以,下面的逻辑就是找到一个不满足的条件参数 | 339 | // 多个条件参数,必须全部满足。所以,下面的逻辑就是找到一个不满足的条件参数 |
| 337 | IotRuleSceneDO.TriggerConditionParameter notMatchedParameter = CollUtil.findOne(condition.getParameters(), | 340 | IotRuleSceneDO.TriggerConditionParameter notMatchedParameter = CollUtil.findOne(condition.getParameters(), |
| 338 | parameter -> !isTriggerConditionParameterMatched(message, parameter, ruleScene, trigger)); | 341 | parameter -> !isTriggerConditionParameterMatched(message, parameter, ruleScene, trigger)); |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java
| 1 | package cn.iocoder.yudao.module.iot.service.rule.action; | 1 | package cn.iocoder.yudao.module.iot.service.rule.action; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 4 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; | ||
| 5 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | 4 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 5 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; |
| 8 | import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; | 7 | import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; |
| 9 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 8 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 10 | -import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService; | 9 | +import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; |
| 11 | import jakarta.annotation.Resource; | 10 | import jakarta.annotation.Resource; |
| 12 | import lombok.extern.slf4j.Slf4j; | 11 | import lombok.extern.slf4j.Slf4j; |
| 13 | import org.springframework.stereotype.Component; | 12 | import org.springframework.stereotype.Component; |
| @@ -22,9 +21,9 @@ import org.springframework.stereotype.Component; | @@ -22,9 +21,9 @@ import org.springframework.stereotype.Component; | ||
| 22 | public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction { | 21 | public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction { |
| 23 | 22 | ||
| 24 | @Resource | 23 | @Resource |
| 25 | - private IotDeviceDownstreamService deviceDownstreamService; | ||
| 26 | - @Resource | ||
| 27 | private IotDeviceService deviceService; | 24 | private IotDeviceService deviceService; |
| 25 | + @Resource | ||
| 26 | + private IotDeviceMessageService deviceMessageService; | ||
| 28 | 27 | ||
| 29 | @Override | 28 | @Override |
| 30 | public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { | 29 | public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { |
| @@ -38,9 +37,9 @@ public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction { | @@ -38,9 +37,9 @@ public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction { | ||
| 38 | return; | 37 | return; |
| 39 | } | 38 | } |
| 40 | try { | 39 | try { |
| 41 | - IotDeviceMessage downstreamMessage = deviceDownstreamService.downstreamDevice(new IotDeviceDownstreamReqVO() | ||
| 42 | - .setId(device.getId()).setType(control.getType()).setIdentifier(control.getIdentifier()) | ||
| 43 | - .setData(control.getData())); | 40 | + // TODO @芋艿:@puhui999:这块可能要改,从 type => method |
| 41 | + IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf( | ||
| 42 | + control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId())); | ||
| 44 | log.info("[execute][message({}) config({}) 下发消息({})成功]", message, config, downstreamMessage); | 43 | log.info("[execute][message({}) config({}) 下发消息({})成功]", message, config, downstreamMessage); |
| 45 | } catch (Exception e) { | 44 | } catch (Exception e) { |
| 46 | log.error("[execute][message({}) config({}) 下发消息失败]", message, config, e); | 45 | log.error("[execute][message({}) config({}) 下发消息失败]", message, config, e); |
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml renamed to yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMessageMapper.xml
| @@ -2,51 +2,62 @@ | @@ -2,51 +2,62 @@ | ||
| 2 | <!DOCTYPE mapper | 2 | <!DOCTYPE mapper |
| 3 | PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | 3 | PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
| 4 | "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | 4 | "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| 5 | -<mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper"> | 5 | +<mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceMessageMapper"> |
| 6 | 6 | ||
| 7 | - <update id="createDeviceLogSTable"> | ||
| 8 | - CREATE STABLE IF NOT EXISTS device_log ( | 7 | + <update id="createSTable"> |
| 8 | + CREATE STABLE IF NOT EXISTS device_message ( | ||
| 9 | ts TIMESTAMP, | 9 | ts TIMESTAMP, |
| 10 | id NCHAR(50), | 10 | id NCHAR(50), |
| 11 | - message_id NCHAR(50), | ||
| 12 | - type NCHAR(50), | ||
| 13 | - identifier NCHAR(255), | ||
| 14 | - content NCHAR(1024), | ||
| 15 | - code INT, | ||
| 16 | report_time TIMESTAMP, | 11 | report_time TIMESTAMP, |
| 17 | - tenant_id BIGINT | 12 | + device_id BIGINT, |
| 13 | + tenant_id BIGINT, | ||
| 14 | + server_id NCHAR(50), | ||
| 15 | + upstream BOOL, | ||
| 16 | + request_id NCHAR(50), | ||
| 17 | + method NCHAR(100), | ||
| 18 | + params NCHAR(2048), | ||
| 19 | + data NCHAR(2048), | ||
| 20 | + code INT | ||
| 18 | ) TAGS ( | 21 | ) TAGS ( |
| 19 | - product_key NCHAR(50), | ||
| 20 | - device_name NCHAR(50) | 22 | + device_id BIGINT |
| 21 | ) | 23 | ) |
| 22 | </update> | 24 | </update> |
| 23 | 25 | ||
| 24 | - <select id="showDeviceLogSTable" resultType="String"> | ||
| 25 | - SHOW STABLES LIKE 'device_log' | 26 | + <select id="showSTable" resultType="String"> |
| 27 | + SHOW STABLES LIKE 'device_message' | ||
| 26 | </select> | 28 | </select> |
| 27 | 29 | ||
| 28 | <insert id="insert"> | 30 | <insert id="insert"> |
| 29 | - INSERT INTO device_log_${productKey}_${deviceName} ( | ||
| 30 | - ts, id, message_id, type, identifier, | ||
| 31 | - content, code, report_time, tenant_id | 31 | + INSERT INTO device_message_${deviceId} ( |
| 32 | + ts, id, report_time, device_id, tenant_id, | ||
| 33 | + server_id, upstream, request_id, method, params, | ||
| 34 | + data, code | ||
| 32 | ) | 35 | ) |
| 33 | - USING device_log | ||
| 34 | - TAGS ('${productKey}', '${deviceName}') | 36 | + USING device_message |
| 37 | + TAGS (#{deviceId}) | ||
| 35 | VALUES ( | 38 | VALUES ( |
| 36 | - NOW, #{id}, #{messageId}, #{type}, #{identifier}, | ||
| 37 | - #{content}, #{code}, #{reportTime}, #{tenantId} | 39 | + #{ts}, #{id}, #{reportTime}, #{deviceId}, #{tenantId}, |
| 40 | + #{serverId}, #{upstream}, #{requestId}, #{method}, #{params}, | ||
| 41 | + #{data}, #{code} | ||
| 38 | ) | 42 | ) |
| 39 | </insert> | 43 | </insert> |
| 40 | 44 | ||
| 41 | - <select id="selectPage" resultType="cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO"> | ||
| 42 | - SELECT ts, id, device_key, product_key, type, identifier, content, report_time | ||
| 43 | - FROM device_log_${productKey}_${deviceName} | 45 | + <select id="selectPage" resultType="cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO"> |
| 46 | + SELECT ts, id, report_time, device_id, tenant_id, server_id, upstream, | ||
| 47 | + request_id, method, params, data, code | ||
| 48 | + FROM device_message_${reqVO.deviceId} | ||
| 44 | <where> | 49 | <where> |
| 45 | - <if test="reqVO.type != null and reqVO.type != ''"> | ||
| 46 | - AND type = #{reqVO.type} | 50 | + <if test="reqVO.method != null and reqVO.method != ''"> |
| 51 | + AND method = #{reqVO.method} | ||
| 47 | </if> | 52 | </if> |
| 48 | - <if test="reqVO.identifier != null and reqVO.identifier != ''"> | ||
| 49 | - AND identifier LIKE CONCAT('%',#{reqVO.identifier},'%') | 53 | + <if test="reqVO.upstream != null"> |
| 54 | + AND upstream = #{reqVO.upstream} | ||
| 55 | + </if> | ||
| 56 | + <if test="reqVO.startTime != null"> | ||
| 57 | + AND ts >= #{reqVO.startTime} | ||
| 58 | + </if> | ||
| 59 | + <if test="reqVO.endTime != null"> | ||
| 60 | + AND ts <= #{reqVO.endTime} | ||
| 50 | </if> | 61 | </if> |
| 51 | </where> | 62 | </where> |
| 52 | ORDER BY ts DESC | 63 | ORDER BY ts DESC |
| @@ -54,7 +65,7 @@ | @@ -54,7 +65,7 @@ | ||
| 54 | 65 | ||
| 55 | <select id="selectCountByCreateTime" resultType="Long"> | 66 | <select id="selectCountByCreateTime" resultType="Long"> |
| 56 | SELECT COUNT(*) | 67 | SELECT COUNT(*) |
| 57 | - FROM device_log | 68 | + FROM device_message |
| 58 | <where> | 69 | <where> |
| 59 | <if test="createTime != null"> | 70 | <if test="createTime != null"> |
| 60 | AND ts >= #{createTime} | 71 | AND ts >= #{createTime} |
| @@ -68,11 +79,11 @@ | @@ -68,11 +79,11 @@ | ||
| 68 | COUNT(*) as data | 79 | COUNT(*) as data |
| 69 | FROM | 80 | FROM |
| 70 | <choose> | 81 | <choose> |
| 71 | - <when test="deviceKey != null and deviceKey != ''"> | ||
| 72 | - device_log_${deviceKey} | 82 | + <when test="deviceId != null"> |
| 83 | + device_message_${deviceId} | ||
| 73 | </when> | 84 | </when> |
| 74 | <otherwise> | 85 | <otherwise> |
| 75 | - device_log | 86 | + device_message |
| 76 | </otherwise> | 87 | </otherwise> |
| 77 | </choose> | 88 | </choose> |
| 78 | <where> | 89 | <where> |
| @@ -82,9 +93,7 @@ | @@ -82,9 +93,7 @@ | ||
| 82 | <if test="endTime != null"> | 93 | <if test="endTime != null"> |
| 83 | AND ts <= #{endTime} | 94 | AND ts <= #{endTime} |
| 84 | </if> | 95 | </if> |
| 85 | - AND ( | ||
| 86 | - identifier IN ('online', 'offline', 'pull', 'progress', 'report', 'register', 'register_sub') | ||
| 87 | - ) | 96 | + AND upstream = true |
| 88 | </where> | 97 | </where> |
| 89 | GROUP BY TIMETRUNCATE(ts, 1h) | 98 | GROUP BY TIMETRUNCATE(ts, 1h) |
| 90 | ORDER BY time ASC | 99 | ORDER BY time ASC |
| @@ -96,11 +105,11 @@ | @@ -96,11 +105,11 @@ | ||
| 96 | COUNT(*) as data | 105 | COUNT(*) as data |
| 97 | FROM | 106 | FROM |
| 98 | <choose> | 107 | <choose> |
| 99 | - <when test="deviceKey != null and deviceKey != ''"> | ||
| 100 | - device_log_${deviceKey} | 108 | + <when test="deviceId != null"> |
| 109 | + device_message_${deviceId} | ||
| 101 | </when> | 110 | </when> |
| 102 | <otherwise> | 111 | <otherwise> |
| 103 | - device_log | 112 | + device_message |
| 104 | </otherwise> | 113 | </otherwise> |
| 105 | </choose> | 114 | </choose> |
| 106 | <where> | 115 | <where> |
| @@ -110,10 +119,10 @@ | @@ -110,10 +119,10 @@ | ||
| 110 | <if test="endTime != null"> | 119 | <if test="endTime != null"> |
| 111 | AND ts <= #{endTime} | 120 | AND ts <= #{endTime} |
| 112 | </if> | 121 | </if> |
| 113 | - AND identifier IN ('set', 'get', 'upgrade', 'unregister_sub', 'topology_add') | 122 | + AND upstream = false |
| 114 | </where> | 123 | </where> |
| 115 | GROUP BY TIMETRUNCATE(ts, 1h) | 124 | GROUP BY TIMETRUNCATE(ts, 1h) |
| 116 | ORDER BY time ASC | 125 | ORDER BY time ASC |
| 117 | </select> | 126 | </select> |
| 118 | 127 | ||
| 119 | -</mapper> | ||
| 120 | \ No newline at end of file | 128 | \ No newline at end of file |
| 129 | +</mapper> | ||
| 121 | \ No newline at end of file | 130 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageIdentifierEnum.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.core.enums; | ||
| 2 | - | ||
| 3 | -import lombok.Getter; | ||
| 4 | -import lombok.RequiredArgsConstructor; | ||
| 5 | - | ||
| 6 | -// TODO @芋艿:需要添加对应的 DTO,以及上下行的链路,网关、网关服务、设备等 | ||
| 7 | - | ||
| 8 | -/** | ||
| 9 | - * IoT 设备消息标识符枚举 | ||
| 10 | - */ | ||
| 11 | -@Getter | ||
| 12 | -@RequiredArgsConstructor | ||
| 13 | -public enum IotDeviceMessageIdentifierEnum { | ||
| 14 | - | ||
| 15 | - PROPERTY_GET("get"), // 下行 TODO 芋艿:【讨论】貌似这个“上行”更合理?device 主动拉取配置。和 IotDevicePropertyGetReqDTO 一样的配置 | ||
| 16 | - PROPERTY_SET("set"), // 下行 | ||
| 17 | - PROPERTY_REPORT("report"), // 上行 | ||
| 18 | - | ||
| 19 | - STATE_ONLINE("online"), // 上行 | ||
| 20 | - STATE_OFFLINE("offline"), // 上行 | ||
| 21 | - | ||
| 22 | - CONFIG_GET("get"), // 上行 TODO 芋艿:【讨论】暂时没有上行的场景 | ||
| 23 | - CONFIG_SET("set"), // 下行 | ||
| 24 | - | ||
| 25 | - SERVICE_INVOKE("${identifier}"), // 下行 | ||
| 26 | - SERVICE_REPLY_SUFFIX("_reply"), // 芋艿:TODO 芋艿:【讨论】上行 or 下行 | ||
| 27 | - | ||
| 28 | - OTA_UPGRADE("upgrade"), // 下行 | ||
| 29 | - OTA_PULL("pull"), // 上行 | ||
| 30 | - OTA_PROGRESS("progress"), // 上行 | ||
| 31 | - OTA_REPORT("report"), // 上行 | ||
| 32 | - | ||
| 33 | - REGISTER_REGISTER("register"), // 上行 | ||
| 34 | - REGISTER_REGISTER_SUB("register_sub"), // 上行 | ||
| 35 | - REGISTER_UNREGISTER_SUB("unregister_sub"), // 下行 | ||
| 36 | - | ||
| 37 | - TOPOLOGY_ADD("topology_add"), // 下行; | ||
| 38 | - ; | ||
| 39 | - | ||
| 40 | - /** | ||
| 41 | - * 标志符 | ||
| 42 | - */ | ||
| 43 | - private final String identifier; | ||
| 44 | - | ||
| 45 | -} | ||
| 46 | \ No newline at end of file | 0 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java
| 1 | package cn.iocoder.yudao.module.iot.core.enums; | 1 | package cn.iocoder.yudao.module.iot.core.enums; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.ArrayUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.core.ArrayValuable; | ||
| 3 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 4 | import lombok.Getter; | 6 | import lombok.Getter; |
| 5 | 7 | ||
| 8 | +import java.util.Arrays; | ||
| 9 | +import java.util.Set; | ||
| 10 | + | ||
| 6 | /** | 11 | /** |
| 7 | * IoT 设备消息的方法枚举 | 12 | * IoT 设备消息的方法枚举 |
| 8 | * | 13 | * |
| @@ -10,16 +15,47 @@ import lombok.Getter; | @@ -10,16 +15,47 @@ import lombok.Getter; | ||
| 10 | */ | 15 | */ |
| 11 | @Getter | 16 | @Getter |
| 12 | @AllArgsConstructor | 17 | @AllArgsConstructor |
| 13 | -public enum IotDeviceMessageMethodEnum { | 18 | +public enum IotDeviceMessageMethodEnum implements ArrayValuable<String> { |
| 14 | 19 | ||
| 15 | // ========== 设备状态 ========== | 20 | // ========== 设备状态 ========== |
| 16 | 21 | ||
| 17 | - STATE_ONLINE("thing.state.online"), | ||
| 18 | - STATE_OFFLINE("thing.state.offline"), | 22 | + STATE_ONLINE("thing.state.online", true), |
| 23 | + STATE_OFFLINE("thing.state.offline", true), | ||
| 24 | + | ||
| 25 | + // ========== 设备属性 ========== | ||
| 26 | + // 可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services | ||
| 27 | + PROPERTY_REPORT("thing.property.report", true), | ||
| 28 | + | ||
| 29 | + PROPERTY_SET("thing.property.set", false), | ||
| 30 | + PROPERTY_GET("thing.property.get", false), | ||
| 31 | + | ||
| 32 | + // | ||
| 19 | 33 | ||
| 20 | ; | 34 | ; |
| 21 | 35 | ||
| 36 | + public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageMethodEnum::getMethod).toArray(String[]::new); | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 不进行 reply 回复的方法集合 | ||
| 40 | + */ | ||
| 41 | + public static final Set<String> REPLY_DISABLED = Set.of(STATE_ONLINE.getMethod(), STATE_OFFLINE.getMethod()); | ||
| 42 | + | ||
| 22 | private final String method; | 43 | private final String method; |
| 23 | 44 | ||
| 45 | + private final Boolean upstream; | ||
| 46 | + | ||
| 47 | + @Override | ||
| 48 | + public String[] array() { | ||
| 49 | + return ARRAYS; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + public static IotDeviceMessageMethodEnum of(String method) { | ||
| 53 | + return ArrayUtil.firstMatch(item -> item.getMethod().equals(method), | ||
| 54 | + IotDeviceMessageMethodEnum.values()); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public static boolean isReplyDisabled(String method) { | ||
| 58 | + return REPLY_DISABLED.contains(method); | ||
| 59 | + } | ||
| 24 | 60 | ||
| 25 | } | 61 | } |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageTypeEnum.java
| @@ -14,7 +14,7 @@ import java.util.Arrays; | @@ -14,7 +14,7 @@ import java.util.Arrays; | ||
| 14 | public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> { | 14 | public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> { |
| 15 | 15 | ||
| 16 | STATE("state"), // 设备状态 | 16 | STATE("state"), // 设备状态 |
| 17 | - PROPERTY("property"), // 设备属性:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 | 17 | +// PROPERTY("property"), // 设备属性:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 |
| 18 | EVENT("event"), // 设备事件:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 | 18 | EVENT("event"), // 设备事件:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 |
| 19 | SERVICE("service"), // 设备服务:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 | 19 | SERVICE("service"), // 设备服务:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 |
| 20 | CONFIG("config"), // 设备配置:可参考 https://help.aliyun.com/zh/iot/user-guide/remote-configuration-1 远程配置 | 20 | CONFIG("config"), // 设备配置:可参考 https://help.aliyun.com/zh/iot/user-guide/remote-configuration-1 远程配置 |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java
| 1 | package cn.iocoder.yudao.module.iot.core.mq.message; | 1 | package cn.iocoder.yudao.module.iot.core.mq.message; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | ||
| 3 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; | 4 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; |
| 4 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; | 5 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; |
| 5 | import lombok.AllArgsConstructor; | 6 | import lombok.AllArgsConstructor; |
| @@ -43,6 +44,20 @@ public class IotDeviceMessage { | @@ -43,6 +44,20 @@ public class IotDeviceMessage { | ||
| 43 | */ | 44 | */ |
| 44 | private LocalDateTime reportTime; | 45 | private LocalDateTime reportTime; |
| 45 | 46 | ||
| 47 | + /** | ||
| 48 | + * 设备编号 | ||
| 49 | + */ | ||
| 50 | + private Long deviceId; | ||
| 51 | + /** | ||
| 52 | + * 租户编号 | ||
| 53 | + */ | ||
| 54 | + private Long tenantId; | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * 服务编号,该消息由哪个 server 发送 | ||
| 58 | + */ | ||
| 59 | + private String serverId; | ||
| 60 | + | ||
| 46 | // ========== codec(编解码)字段 ========== | 61 | // ========== codec(编解码)字段 ========== |
| 47 | 62 | ||
| 48 | /** | 63 | /** |
| @@ -72,84 +87,53 @@ public class IotDeviceMessage { | @@ -72,84 +87,53 @@ public class IotDeviceMessage { | ||
| 72 | * 响应错误码 | 87 | * 响应错误码 |
| 73 | */ | 88 | */ |
| 74 | private Integer code; | 89 | private Integer code; |
| 75 | - | ||
| 76 | - // ========== 后端字段 ========== | ||
| 77 | - | ||
| 78 | /** | 90 | /** |
| 79 | - * 设备编号 | 91 | + * 返回结果信息 |
| 80 | */ | 92 | */ |
| 81 | - private Long deviceId; | ||
| 82 | - /** | ||
| 83 | - * 租户编号 | ||
| 84 | - */ | ||
| 85 | - private Long tenantId; | 93 | + private String msg; |
| 86 | 94 | ||
| 87 | - /** | ||
| 88 | - * 服务编号,该消息由哪个 server 服务进行消费 | ||
| 89 | - */ | ||
| 90 | - private String serverId; | 95 | + // ========== 基础方法:只传递“codec(编解码)字段” ========== |
| 96 | + | ||
| 97 | + public static IotDeviceMessage requestOf(String method) { | ||
| 98 | + return requestOf(null, method, null); | ||
| 99 | + } | ||
| 91 | 100 | ||
| 92 | -// public IotDeviceMessage ofPropertyReport(Map<String, Object> properties) { | ||
| 93 | -// this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); | ||
| 94 | -// this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier()); | ||
| 95 | -// this.setData(properties); | ||
| 96 | -// return this; | ||
| 97 | -// } | ||
| 98 | -// | ||
| 99 | -// public IotDeviceMessage ofPropertySet(Map<String, Object> properties) { | ||
| 100 | -// this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); | ||
| 101 | -// this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()); | ||
| 102 | -// this.setData(properties); | ||
| 103 | -// return this; | ||
| 104 | -// } | ||
| 105 | -// | ||
| 106 | -// public IotDeviceMessage ofStateOnline() { | ||
| 107 | -// this.setType(IotDeviceMessageTypeEnum.STATE.getType()); | ||
| 108 | -// this.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier()); | ||
| 109 | -// return this; | ||
| 110 | -// } | ||
| 111 | -// | ||
| 112 | -// public IotDeviceMessage ofStateOffline() { | ||
| 113 | -// this.setType(IotDeviceMessageTypeEnum.STATE.getType()); | ||
| 114 | -// this.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier()); | ||
| 115 | -// return this; | ||
| 116 | -// } | ||
| 117 | -// | ||
| 118 | -// public static IotDeviceMessage of(String productKey, String deviceName) { | ||
| 119 | -// return of(productKey, deviceName, | ||
| 120 | -// null, null); | ||
| 121 | -// } | ||
| 122 | -// | ||
| 123 | -// public static IotDeviceMessage of(String productKey, String deviceName, | ||
| 124 | -// String serverId) { | ||
| 125 | -// return of(productKey, deviceName, | ||
| 126 | -// null, serverId); | ||
| 127 | -// } | ||
| 128 | -// | ||
| 129 | -// public static IotDeviceMessage of(String productKey, String deviceName, | ||
| 130 | -// LocalDateTime reportTime, String serverId) { | ||
| 131 | -// if (reportTime == null) { | ||
| 132 | -// reportTime = LocalDateTime.now(); | ||
| 133 | -// } | ||
| 134 | -// String messageId = IotDeviceMessageUtils.generateMessageId(); | ||
| 135 | -// return IotDeviceMessage.builder() | ||
| 136 | -// .messageId(messageId).reportTime(reportTime) | ||
| 137 | -// .productKey(productKey).deviceName(deviceName) | ||
| 138 | -// .serverId(serverId).build(); | ||
| 139 | -// } | ||
| 140 | - | ||
| 141 | - public static IotDeviceMessage of(String requestId, String method, Object params) { | ||
| 142 | - return of(requestId, method, params, null, null); | 101 | + public static IotDeviceMessage requestOf(String method, Object params) { |
| 102 | + return requestOf(null, method, params); | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + public static IotDeviceMessage requestOf(String requestId, String method, Object params) { | ||
| 106 | + return of(requestId, method, params, null, null, null); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + public static IotDeviceMessage replyOf(String requestId, String method, | ||
| 110 | + Object data, Integer code, String msg) { | ||
| 111 | + if (code == null) { | ||
| 112 | + code = GlobalErrorCodeConstants.SUCCESS.getCode(); | ||
| 113 | + msg = GlobalErrorCodeConstants.SUCCESS.getMsg(); | ||
| 114 | + } | ||
| 115 | + return of(requestId, method, null, data, code, msg); | ||
| 143 | } | 116 | } |
| 144 | 117 | ||
| 145 | public static IotDeviceMessage of(String requestId, String method, | 118 | public static IotDeviceMessage of(String requestId, String method, |
| 146 | - Object params, Object data, Integer code) { | 119 | + Object params, Object data, Integer code, String msg) { |
| 147 | // 通用参数 | 120 | // 通用参数 |
| 148 | IotDeviceMessage message = new IotDeviceMessage() | 121 | IotDeviceMessage message = new IotDeviceMessage() |
| 149 | .setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now()); | 122 | .setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now()); |
| 150 | // 当前参数 | 123 | // 当前参数 |
| 151 | - message.setRequestId(requestId).setMethod(method).setParams(params).setData(data).setCode(code); | 124 | + message.setRequestId(requestId).setMethod(method).setParams(params) |
| 125 | + .setData(data).setCode(code).setMsg(msg); | ||
| 152 | return message; | 126 | return message; |
| 153 | } | 127 | } |
| 154 | 128 | ||
| 129 | + // ========== 核心方法:在 of 基础方法之上,添加对应 method ========== | ||
| 130 | + | ||
| 131 | + public static IotDeviceMessage buildStateOnline() { | ||
| 132 | + return requestOf(IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod()); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + public static IotDeviceMessage buildStateOffline() { | ||
| 136 | + return requestOf(IotDeviceMessageMethodEnum.STATE_OFFLINE.getMethod()); | ||
| 137 | + } | ||
| 138 | + | ||
| 155 | } | 139 | } |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java
| 1 | package cn.iocoder.yudao.module.iot.core.util; | 1 | package cn.iocoder.yudao.module.iot.core.util; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 3 | import cn.hutool.core.util.IdUtil; | 4 | import cn.hutool.core.util.IdUtil; |
| 4 | -import cn.hutool.core.util.StrUtil; | ||
| 5 | import cn.hutool.system.SystemUtil; | 5 | import cn.hutool.system.SystemUtil; |
| 6 | +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; | ||
| 6 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | 7 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 7 | 8 | ||
| 8 | /** | 9 | /** |
| @@ -18,15 +19,28 @@ public class IotDeviceMessageUtils { | @@ -18,15 +19,28 @@ public class IotDeviceMessageUtils { | ||
| 18 | return IdUtil.fastSimpleUUID(); | 19 | return IdUtil.fastSimpleUUID(); |
| 19 | } | 20 | } |
| 20 | 21 | ||
| 21 | - // TODO @芋艿:需要优化下; | ||
| 22 | /** | 22 | /** |
| 23 | * 是否是上行消息:由设备发送 | 23 | * 是否是上行消息:由设备发送 |
| 24 | * | 24 | * |
| 25 | * @param message 消息 | 25 | * @param message 消息 |
| 26 | * @return 是否 | 26 | * @return 是否 |
| 27 | */ | 27 | */ |
| 28 | + @SuppressWarnings("SimplifiableConditionalExpression") | ||
| 28 | public static boolean isUpstreamMessage(IotDeviceMessage message) { | 29 | public static boolean isUpstreamMessage(IotDeviceMessage message) { |
| 29 | - return StrUtil.isNotEmpty(message.getServerId()); | 30 | + IotDeviceMessageMethodEnum methodEnum = IotDeviceMessageMethodEnum.of(message.getMethod()); |
| 31 | + Assert.notNull(methodEnum, "无法识别的消息方法:" + message.getMethod()); | ||
| 32 | + // 注意:回复消息时,需要取反 | ||
| 33 | + return !isReplyMessage(message) ? methodEnum.getUpstream() : !methodEnum.getUpstream(); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * 是否是回复消息,通过 {@link IotDeviceMessage#getCode()} 非空进行识别 | ||
| 38 | + * | ||
| 39 | + * @param message 消息 | ||
| 40 | + * @return 是否 | ||
| 41 | + */ | ||
| 42 | + public static boolean isReplyMessage(IotDeviceMessage message) { | ||
| 43 | + return message.getCode() != null; | ||
| 30 | } | 44 | } |
| 31 | 45 | ||
| 32 | // ========== Topic 相关 ========== | 46 | // ========== Topic 相关 ========== |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/alink/IotAlinkDeviceMessageCodec.java
| 1 | package cn.iocoder.yudao.module.iot.gateway.codec.alink; | 1 | package cn.iocoder.yudao.module.iot.gateway.codec.alink; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 5 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 5 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | 6 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 6 | import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec; | 7 | import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec; |
| @@ -48,18 +49,23 @@ public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec { | @@ -48,18 +49,23 @@ public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec { | ||
| 48 | * 响应结果 | 49 | * 响应结果 |
| 49 | */ | 50 | */ |
| 50 | private Object data; | 51 | private Object data; |
| 51 | - | ||
| 52 | /** | 52 | /** |
| 53 | * 响应错误码 | 53 | * 响应错误码 |
| 54 | */ | 54 | */ |
| 55 | private Integer code; | 55 | private Integer code; |
| 56 | + /** | ||
| 57 | + * 响应提示 | ||
| 58 | + * | ||
| 59 | + * 特殊:这里阿里云是 message,为了保持和项目的 {@link CommonResult#getMsg()} 一致。 | ||
| 60 | + */ | ||
| 61 | + private String msg; | ||
| 56 | 62 | ||
| 57 | } | 63 | } |
| 58 | 64 | ||
| 59 | @Override | 65 | @Override |
| 60 | public byte[] encode(IotDeviceMessage message) { | 66 | public byte[] encode(IotDeviceMessage message) { |
| 61 | AlinkMessage alinkMessage = new AlinkMessage(message.getRequestId(), AlinkMessage.VERSION_1, | 67 | AlinkMessage alinkMessage = new AlinkMessage(message.getRequestId(), AlinkMessage.VERSION_1, |
| 62 | - message.getMethod(), message.getParams(), message.getData(), message.getCode()); | 68 | + message.getMethod(), message.getParams(), message.getData(), message.getCode(), message.getMsg()); |
| 63 | return JsonUtils.toJsonByte(alinkMessage); | 69 | return JsonUtils.toJsonByte(alinkMessage); |
| 64 | } | 70 | } |
| 65 | 71 | ||
| @@ -69,8 +75,8 @@ public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec { | @@ -69,8 +75,8 @@ public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec { | ||
| 69 | AlinkMessage alinkMessage = JsonUtils.parseObject(bytes, AlinkMessage.class); | 75 | AlinkMessage alinkMessage = JsonUtils.parseObject(bytes, AlinkMessage.class); |
| 70 | Assert.notNull(alinkMessage, "消息不能为空"); | 76 | Assert.notNull(alinkMessage, "消息不能为空"); |
| 71 | Assert.equals(alinkMessage.getVersion(), AlinkMessage.VERSION_1, "消息版本号必须是 1.0"); | 77 | Assert.equals(alinkMessage.getVersion(), AlinkMessage.VERSION_1, "消息版本号必须是 1.0"); |
| 72 | - return IotDeviceMessage.of(alinkMessage.getId(), | ||
| 73 | - alinkMessage.getMethod(), alinkMessage.getParams(), alinkMessage.getData(), alinkMessage.getCode()); | 78 | + return IotDeviceMessage.of(alinkMessage.getId(), alinkMessage.getMethod(), alinkMessage.getParams(), |
| 79 | + alinkMessage.getData(), alinkMessage.getCode(), alinkMessage.getMsg()); | ||
| 74 | } | 80 | } |
| 75 | 81 | ||
| 76 | @Override | 82 | @Override |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java
| @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.gateway.config; | @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.gateway.config; | ||
| 3 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; | 3 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; |
| 4 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpDownstreamSubscriber; | 4 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpDownstreamSubscriber; |
| 5 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; | 5 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; |
| 6 | -import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttDownstreamSubscriber; | ||
| 7 | -import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttUpstreamProtocol; | ||
| 8 | import lombok.extern.slf4j.Slf4j; | 6 | import lombok.extern.slf4j.Slf4j; |
| 9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 10 | import org.springframework.boot.context.properties.EnableConfigurationProperties; | 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| @@ -44,16 +42,17 @@ public class IotGatewayConfiguration { | @@ -44,16 +42,17 @@ public class IotGatewayConfiguration { | ||
| 44 | @Slf4j | 42 | @Slf4j |
| 45 | public static class MqttProtocolConfiguration { | 43 | public static class MqttProtocolConfiguration { |
| 46 | 44 | ||
| 47 | - @Bean | ||
| 48 | - public IotMqttUpstreamProtocol iotMqttUpstreamProtocol(IotGatewayProperties gatewayProperties) { | ||
| 49 | - return new IotMqttUpstreamProtocol(gatewayProperties.getProtocol().getEmqx()); | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - @Bean | ||
| 53 | - public IotMqttDownstreamSubscriber iotMqttDownstreamSubscriber(IotMqttUpstreamProtocol mqttUpstreamProtocol, | ||
| 54 | - IotMessageBus messageBus) { | ||
| 55 | - return new IotMqttDownstreamSubscriber(mqttUpstreamProtocol, messageBus); | ||
| 56 | - } | 45 | + // TODO @haohao:临时注释,避免报错 |
| 46 | +// @Bean | ||
| 47 | +// public IotMqttUpstreamProtocol iotMqttUpstreamProtocol(IotGatewayProperties gatewayProperties) { | ||
| 48 | +// return new IotMqttUpstreamProtocol(gatewayProperties.getProtocol().getEmqx()); | ||
| 49 | +// } | ||
| 50 | +// | ||
| 51 | +// @Bean | ||
| 52 | +// public IotMqttDownstreamSubscriber iotMqttDownstreamSubscriber(IotMqttUpstreamProtocol mqttUpstreamProtocol, | ||
| 53 | +// IotMessageBus messageBus) { | ||
| 54 | +// return new IotMqttDownstreamSubscriber(mqttUpstreamProtocol, messageBus); | ||
| 55 | +// } | ||
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | } | 58 | } |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java
| 1 | package cn.iocoder.yudao.module.iot.gateway.protocol.http.router; | 1 | package cn.iocoder.yudao.module.iot.gateway.protocol.http.router; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 5 | import cn.hutool.core.map.MapUtil; | 4 | import cn.hutool.core.map.MapUtil; |
| 6 | import cn.hutool.core.text.StrPool; | 5 | import cn.hutool.core.text.StrPool; |
| 7 | -import cn.hutool.core.util.StrUtil; | ||
| 8 | import cn.hutool.extra.spring.SpringUtil; | 6 | import cn.hutool.extra.spring.SpringUtil; |
| 9 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 10 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | 8 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 11 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | 9 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; |
| 12 | -import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum; | ||
| 13 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; | 10 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; |
| 14 | import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService; | 11 | import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService; |
| 15 | -import io.vertx.core.json.JsonObject; | ||
| 16 | import io.vertx.ext.web.RoutingContext; | 12 | import io.vertx.ext.web.RoutingContext; |
| 17 | import lombok.RequiredArgsConstructor; | 13 | import lombok.RequiredArgsConstructor; |
| 18 | import lombok.extern.slf4j.Slf4j; | 14 | import lombok.extern.slf4j.Slf4j; |
| 19 | 15 | ||
| 20 | -import java.util.Map; | ||
| 21 | - | ||
| 22 | /** | 16 | /** |
| 23 | * IoT 网关 HTTP 协议的【上行】处理器 | 17 | * IoT 网关 HTTP 协议的【上行】处理器 |
| 24 | * | 18 | * |
| @@ -61,135 +55,4 @@ public class IotHttpUpstreamHandler extends IotHttpAbstractHandler { | @@ -61,135 +55,4 @@ public class IotHttpUpstreamHandler extends IotHttpAbstractHandler { | ||
| 61 | return CommonResult.success(MapUtil.of("messageId", message.getId())); | 55 | return CommonResult.success(MapUtil.of("messageId", message.getId())); |
| 62 | } | 56 | } |
| 63 | 57 | ||
| 64 | - /** | ||
| 65 | - * 判断是否是属性上报路径 | ||
| 66 | - * | ||
| 67 | - * @param path 路径 | ||
| 68 | - * @return 是否是属性上报路径 | ||
| 69 | - */ | ||
| 70 | - private boolean isPropertyPostPath(String path) { | ||
| 71 | - return StrUtil.endWith(path, IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic()); | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - /** | ||
| 75 | - * 判断是否是事件上报路径 | ||
| 76 | - * | ||
| 77 | - * @param path 路径 | ||
| 78 | - * @return 是否是事件上报路径 | ||
| 79 | - */ | ||
| 80 | - private boolean isEventPostPath(String path) { | ||
| 81 | - return StrUtil.contains(path, IotDeviceTopicEnum.EVENT_POST_TOPIC_PREFIX.getTopic()) | ||
| 82 | - && StrUtil.endWith(path, IotDeviceTopicEnum.EVENT_POST_TOPIC_SUFFIX.getTopic()); | ||
| 83 | - } | ||
| 84 | - | ||
| 85 | - /** | ||
| 86 | - * 处理属性上报请求 | ||
| 87 | - * | ||
| 88 | - * @param routingContext 路由上下文 | ||
| 89 | - * @param productKey 产品 Key | ||
| 90 | - * @param deviceName 设备名称 | ||
| 91 | - * @param body 请求体 | ||
| 92 | - */ | ||
| 93 | - private void handlePropertyPost(RoutingContext routingContext, String productKey, String deviceName, | ||
| 94 | - JsonObject body) { | ||
| 95 | - // 1.1 构建设备消息 | ||
| 96 | - IotDeviceMessage message = IotDeviceMessage.of(productKey, deviceName, protocol.getServerId()) | ||
| 97 | -// .ofPropertyReport(parsePropertiesFromBody(body)) | ||
| 98 | - ; | ||
| 99 | - // 1.2 发送消息 | ||
| 100 | - deviceMessageProducer.sendDeviceMessage(message); | ||
| 101 | - | ||
| 102 | -// // 2. 返回响应 | ||
| 103 | -// sendResponse(routingContext, null); | ||
| 104 | - } | ||
| 105 | - | ||
| 106 | - /** | ||
| 107 | - * 处理事件上报请求 | ||
| 108 | - * | ||
| 109 | - * @param routingContext 路由上下文 | ||
| 110 | - * @param productKey 产品 Key | ||
| 111 | - * @param deviceName 设备名称 | ||
| 112 | - * @param identifier 事件标识符 | ||
| 113 | - * @param body 请求体 | ||
| 114 | - */ | ||
| 115 | - private void handleEventPost(RoutingContext routingContext, String productKey, String deviceName, | ||
| 116 | - String identifier, JsonObject body) { | ||
| 117 | -// // 处理事件上报 | ||
| 118 | -// IotDeviceEventReportReqDTO reportReqDTO = parseEventReportRequest(productKey, deviceName, identifier, | ||
| 119 | -// requestId, body); | ||
| 120 | -// | ||
| 121 | -// // 事件上报 | ||
| 122 | -// CommonResult<Boolean> result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO); | ||
| 123 | - } | ||
| 124 | - | ||
| 125 | - // TODO @芋艿:这块在看看 | ||
| 126 | - /** | ||
| 127 | - * 从请求体解析属性 | ||
| 128 | - * | ||
| 129 | - * @param body 请求体 | ||
| 130 | - * @return 属性映射 | ||
| 131 | - */ | ||
| 132 | - private Map<String, Object> parsePropertiesFromBody(JsonObject body) { | ||
| 133 | - Map<String, Object> properties = MapUtil.newHashMap(); | ||
| 134 | - JsonObject params = body.getJsonObject("params"); | ||
| 135 | - if (CollUtil.isEmpty(params)) { | ||
| 136 | - return properties; | ||
| 137 | - } | ||
| 138 | - | ||
| 139 | - // 将标准格式的 params 转换为平台需要的 properties 格式 | ||
| 140 | - for (String key : params.fieldNames()) { | ||
| 141 | - Object valueObj = params.getValue(key); | ||
| 142 | - // 如果是复杂结构(包含 value 和 time) | ||
| 143 | - if (valueObj instanceof JsonObject) { | ||
| 144 | - JsonObject valueJson = (JsonObject) valueObj; | ||
| 145 | - properties.put(key, valueJson.containsKey("value") ? valueJson.getValue("value") : valueObj); | ||
| 146 | - } else { | ||
| 147 | - properties.put(key, valueObj); | ||
| 148 | - } | ||
| 149 | - } | ||
| 150 | - return properties; | ||
| 151 | - } | ||
| 152 | - | ||
| 153 | -// /** | ||
| 154 | -// * 解析事件上报请求 | ||
| 155 | -// * | ||
| 156 | -// * @param productKey 产品 Key | ||
| 157 | -// * @param deviceName 设备名称 | ||
| 158 | -// * @param identifier 事件标识符 | ||
| 159 | -// * @param requestId 请求 ID | ||
| 160 | -// * @param body 请求体 | ||
| 161 | -// * @return 事件上报请求 DTO | ||
| 162 | -// */ | ||
| 163 | -// private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, | ||
| 164 | -// String requestId, JsonObject body) { | ||
| 165 | -// // 解析参数 | ||
| 166 | -// Map<String, Object> params = parseParamsFromBody(body); | ||
| 167 | -// | ||
| 168 | -// // 构建事件上报请求 DTO | ||
| 169 | -// return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO() | ||
| 170 | -// .setRequestId(requestId) | ||
| 171 | -// .setProcessId(IotNetComponentCommonUtils.getProcessId()) | ||
| 172 | -// .setReportTime(LocalDateTime.now()) | ||
| 173 | -// .setProductKey(productKey) | ||
| 174 | -// .setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); | ||
| 175 | -// } | ||
| 176 | - | ||
| 177 | - /** | ||
| 178 | - * 从请求体解析参数 | ||
| 179 | - * | ||
| 180 | - * @param body 请求体 | ||
| 181 | - * @return 参数映射 | ||
| 182 | - */ | ||
| 183 | - private Map<String, Object> parseParamsFromBody(JsonObject body) { | ||
| 184 | - Map<String, Object> params = MapUtil.newHashMap(); | ||
| 185 | - JsonObject paramsJson = body.getJsonObject("params"); | ||
| 186 | - if (CollUtil.isEmpty(paramsJson)) { | ||
| 187 | - return params; | ||
| 188 | - } | ||
| 189 | - | ||
| 190 | - for (String key : paramsJson.fieldNames()) { | ||
| 191 | - params.put(key, paramsJson.getValue(key)); | ||
| 192 | - } | ||
| 193 | - return params; | ||
| 194 | - } | ||
| 195 | } | 58 | } |
| 196 | \ No newline at end of file | 59 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/message/IotDeviceMessageServiceImpl.java
| @@ -96,7 +96,7 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { | @@ -96,7 +96,7 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { | ||
| 96 | return null; | 96 | return null; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | - IotDeviceMessage message = IotDeviceMessage.of(null, | 99 | + IotDeviceMessage message = IotDeviceMessage.requestOf(null, |
| 100 | IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod(), null); | 100 | IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod(), null); |
| 101 | 101 | ||
| 102 | return appendDeviceMessage(message, deviceInfo, serverId); | 102 | return appendDeviceMessage(message, deviceInfo, serverId); |
| @@ -112,9 +112,8 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { | @@ -112,9 +112,8 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { | ||
| 112 | return null; | 112 | return null; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | - IotDeviceMessage message = IotDeviceMessage.of(null, | ||
| 116 | - IotDeviceMessageMethodEnum.STATE_OFFLINE.getMethod(), null); | ||
| 117 | - | 115 | + IotDeviceMessage message = IotDeviceMessage.requestOf(IotDeviceMessageMethodEnum.STATE_OFFLINE.getMethod(), |
| 116 | + null); | ||
| 118 | return appendDeviceMessage(message, deviceInfo, serverId); | 117 | return appendDeviceMessage(message, deviceInfo, serverId); |
| 119 | } | 118 | } |
| 120 | 119 | ||
| @@ -122,23 +121,18 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { | @@ -122,23 +121,18 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { | ||
| 122 | * 补充消息的后端字段 | 121 | * 补充消息的后端字段 |
| 123 | * | 122 | * |
| 124 | * @param message 消息 | 123 | * @param message 消息 |
| 125 | - * @param deviceInfo 设备信息 | 124 | + * @param device 设备信息 |
| 126 | * @param serverId 设备连接的 serverId | 125 | * @param serverId 设备连接的 serverId |
| 127 | * @return 消息 | 126 | * @return 消息 |
| 128 | */ | 127 | */ |
| 129 | private IotDeviceMessage appendDeviceMessage(IotDeviceMessage message, | 128 | private IotDeviceMessage appendDeviceMessage(IotDeviceMessage message, |
| 130 | - IotDeviceCacheService.DeviceInfo deviceInfo, String serverId) { | 129 | + IotDeviceCacheService.DeviceInfo device, String serverId) { |
| 131 | message.setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now()) | 130 | message.setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now()) |
| 132 | - .setDeviceId(deviceInfo.getDeviceId()).setTenantId(deviceInfo.getTenantId()).setServerId(serverId); | ||
| 133 | - | 131 | + .setDeviceId(device.getDeviceId()).setTenantId(device.getTenantId()).setServerId(serverId); |
| 134 | // 特殊:如果设备没有指定 requestId,则使用 messageId | 132 | // 特殊:如果设备没有指定 requestId,则使用 messageId |
| 135 | if (StrUtil.isEmpty(message.getRequestId())) { | 133 | if (StrUtil.isEmpty(message.getRequestId())) { |
| 136 | message.setRequestId(message.getId()); | 134 | message.setRequestId(message.getId()); |
| 137 | } | 135 | } |
| 138 | - | ||
| 139 | - log.debug("[appendDeviceMessage][消息字段补充完成][deviceId: {}][tenantId: {}]", | ||
| 140 | - deviceInfo.getDeviceId(), deviceInfo.getTenantId()); | ||
| 141 | - | ||
| 142 | return message; | 136 | return message; |
| 143 | } | 137 | } |
| 144 | 138 |