Commit 66b42367cb7c0178e756398144ec4254ed86fbc1

Authored by YunaiV
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
1 -package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;  
2 -  
3 -import lombok.Data;  
4 -  
5 -/**  
6 - * IoT 设备【注册】自己 Request DTO  
7 - *  
8 - * @author 芋道源码  
9 - */  
10 -@Data  
11 -public class IotDeviceRegisterReqDTO extends IotDeviceUpstreamAbstractReqDTO {  
12 -}  
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&lt;Iot @@ -54,53 +51,49 @@ public class IotDeviceStateMessageSubscriber implements IotMessageSubscriber&lt;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 &lt;= #{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 &lt;= #{endTime} 94 AND ts &lt;= #{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 &lt;= #{endTime} 120 AND ts &lt;= #{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