Commit 8089f3a319efb919fce809b8e144c3fcc0694b4f

Authored by YunaiV
1 parent f4ad3e9d

【功能优化】IoT:

1. DeviceDataApi => IotDeviceUpstreamApi,并新建 upstream 包
2. ThingModelMessage => IotDeviceMessage 设备消息
3. 基于 spring event 异步消费 IotDeviceMessage,并实现 IotDeviceLogMessageConsumer 记录日志
Showing 42 changed files with 538 additions and 680 deletions
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
@@ -13,7 +13,7 @@ import java.util.Set; @@ -13,7 +13,7 @@ import java.util.Set;
13 /** 13 /**
14 * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能 14 * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能
15 * 15 *
16 - * @author 16 + * @author 芋道源码
17 */ 17 */
18 public class TenantDatabaseInterceptor implements TenantLineHandler { 18 public class TenantDatabaseInterceptor implements TenantLineHandler {
19 19
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
@@ -45,6 +45,7 @@ public class TenantUtils { @@ -45,6 +45,7 @@ public class TenantUtils {
45 * 45 *
46 * @param tenantId 租户编号 46 * @param tenantId 租户编号
47 * @param callable 逻辑 47 * @param callable 逻辑
  48 + * @return 结果
48 */ 49 */
49 public static <V> V execute(Long tenantId, Callable<V> callable) { 50 public static <V> V execute(Long tenantId, Callable<V> callable) {
50 Long oldTenantId = TenantContextHolder.getTenantId(); 51 Long oldTenantId = TenantContextHolder.getTenantId();
@@ -79,6 +80,25 @@ public class TenantUtils { @@ -79,6 +80,25 @@ public class TenantUtils {
79 } 80 }
80 81
81 /** 82 /**
  83 + * 忽略租户,执行对应的逻辑
  84 + *
  85 + * @param callable 逻辑
  86 + * @return 结果
  87 + */
  88 + public static <V> V executeIgnore(Callable<V> callable) {
  89 + Boolean oldIgnore = TenantContextHolder.isIgnore();
  90 + try {
  91 + TenantContextHolder.setIgnore(true);
  92 + // 执行逻辑
  93 + return callable.call();
  94 + } catch (Exception e) {
  95 + throw new RuntimeException(e);
  96 + } finally {
  97 + TenantContextHolder.setIgnore(oldIgnore);
  98 + }
  99 + }
  100 +
  101 + /**
82 * 将多租户编号,添加到 header 中 102 * 将多租户编号,添加到 header 中
83 * 103 *
84 * @param headers HTTP 请求 headers 104 * @param headers HTTP 请求 headers
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java
@@ -5,49 +5,44 @@ import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; @@ -5,49 +5,44 @@ import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; 5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; 6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
7 import cn.iocoder.yudao.module.iot.enums.ApiConstants; 7 import cn.iocoder.yudao.module.iot.enums.ApiConstants;
8 -import jakarta.annotation.security.PermitAll;  
9 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
10 import org.springframework.web.bind.annotation.PostMapping; 9 import org.springframework.web.bind.annotation.PostMapping;
11 import org.springframework.web.bind.annotation.PutMapping; 10 import org.springframework.web.bind.annotation.PutMapping;
12 import org.springframework.web.bind.annotation.RequestBody; 11 import org.springframework.web.bind.annotation.RequestBody;
13 12
14 -// TODO 芋艿:名字可能看情况改下  
15 /** 13 /**
16 - * 设备数据 API 14 + * 设备数据 Upstream 上行 API
  15 + *
  16 + * 目的:设备 -> 插件 -> 服务端
17 * 17 *
18 * @author haohao 18 * @author haohao
19 */ 19 */
20 -public interface DeviceDataApi { 20 +public interface IotDeviceUpstreamApi {
21 21
22 - // TODO @芋艿:可能会调整  
23 - String PREFIX = ApiConstants.PREFIX + "/device-data"; 22 + String PREFIX = ApiConstants.PREFIX + "/device/upstream";
24 23
25 /** 24 /**
26 * 更新设备状态 25 * 更新设备状态
27 * 26 *
28 - * @param updateReqDTO 更新请求 27 + * @param updateReqDTO 更新设备状态 DTO
29 */ 28 */
30 @PutMapping(PREFIX + "/update-status") 29 @PutMapping(PREFIX + "/update-status")
31 - @PermitAll // TODO 芋艿:后续看看怎么优化下  
32 CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqDTO updateReqDTO); 30 CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqDTO updateReqDTO);
33 31
34 /** 32 /**
35 - * 上报设备事件数据  
36 - *  
37 - * @param reportReqDTO 设备事件  
38 - */  
39 - @PostMapping(PREFIX + "/report-event")  
40 - @PermitAll // TODO 芋艿:后续看看怎么优化下  
41 - CommonResult<Boolean> reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO);  
42 -  
43 - /**  
44 * 上报设备属性数据 33 * 上报设备属性数据
45 * 34 *
46 - * @param reportReqDTO 设备数据 35 + * @param reportReqDTO 上报设备属性数据 DTO
47 */ 36 */
48 @PostMapping(PREFIX + "/report-property") 37 @PostMapping(PREFIX + "/report-property")
49 - @PermitAll // TODO 芋艿:后续看看怎么优化下  
50 CommonResult<Boolean> reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO); 38 CommonResult<Boolean> reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO);
51 39
  40 + /**
  41 + * 上报设备事件数据
  42 + *
  43 + * @param reportReqDTO 设备事件
  44 + */
  45 + @PostMapping(PREFIX + "/report-event")
  46 + CommonResult<Boolean> reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO);
52 47
53 } 48 }
54 \ No newline at end of file 49 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java
1 package cn.iocoder.yudao.module.iot.api.device.dto; 1 package cn.iocoder.yudao.module.iot.api.device.dto;
2 2
3 import jakarta.validation.constraints.NotEmpty; 3 import jakarta.validation.constraints.NotEmpty;
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Builder;  
6 import lombok.Data; 4 import lombok.Data;
7 import lombok.NoArgsConstructor; 5 import lombok.NoArgsConstructor;
  6 +import lombok.experimental.SuperBuilder;
8 7
9 import java.util.Map; 8 import java.util.Map;
10 9
@@ -12,24 +11,9 @@ import java.util.Map; @@ -12,24 +11,9 @@ import java.util.Map;
12 * IoT 设备【事件】数据上报 Request DTO 11 * IoT 设备【事件】数据上报 Request DTO
13 */ 12 */
14 @Data 13 @Data
  14 +@SuperBuilder
15 @NoArgsConstructor 15 @NoArgsConstructor
16 -@AllArgsConstructor  
17 -@Builder  
18 -public class IotDeviceEventReportReqDTO {  
19 -  
20 - // TODO 芋艿:要不要 id  
21 - // TODO 芋艿:要不要 time  
22 -  
23 - /**  
24 - * 产品标识  
25 - */  
26 - @NotEmpty(message = "产品标识不能为空")  
27 - private String productKey;  
28 - /**  
29 - * 设备名称  
30 - */  
31 - @NotEmpty(message = "设备名称不能为空")  
32 - private String deviceName; 16 +public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
33 17
34 /** 18 /**
35 * 事件标识 19 * 事件标识
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java
1 package cn.iocoder.yudao.module.iot.api.device.dto; 1 package cn.iocoder.yudao.module.iot.api.device.dto;
2 2
3 import jakarta.validation.constraints.NotEmpty; 3 import jakarta.validation.constraints.NotEmpty;
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Builder;  
6 import lombok.Data; 4 import lombok.Data;
7 import lombok.NoArgsConstructor; 5 import lombok.NoArgsConstructor;
  6 +import lombok.experimental.SuperBuilder;
8 7
9 import java.util.Map; 8 import java.util.Map;
10 9
@@ -12,28 +11,14 @@ import java.util.Map; @@ -12,28 +11,14 @@ import java.util.Map;
12 * IoT 设备【属性】数据上报 Request DTO 11 * IoT 设备【属性】数据上报 Request DTO
13 */ 12 */
14 @Data 13 @Data
  14 +@SuperBuilder
15 @NoArgsConstructor 15 @NoArgsConstructor
16 -@AllArgsConstructor  
17 -@Builder  
18 -public class IotDevicePropertyReportReqDTO { 16 +public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
19 17
20 - // TODO 芋艿:要不要 id  
21 - // TODO 芋艿:要不要 time  
22 -  
23 - /**  
24 - * 产品标识  
25 - */  
26 - @NotEmpty(message = "产品标识不能为空")  
27 - private String productKey;  
28 - /**  
29 - * 设备名称  
30 - */  
31 - @NotEmpty(message = "设备名称不能为空")  
32 - private String deviceName;  
33 /** 18 /**
34 * 属性参数 19 * 属性参数
35 */ 20 */
36 @NotEmpty(message = "属性参数不能为空") 21 @NotEmpty(message = "属性参数不能为空")
37 - private Map<String, Object> params; 22 + private Map<String, Object> properties;
38 23
39 } 24 }
40 \ No newline at end of file 25 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java
@@ -3,33 +3,18 @@ package cn.iocoder.yudao.module.iot.api.device.dto; @@ -3,33 +3,18 @@ package cn.iocoder.yudao.module.iot.api.device.dto;
3 import cn.iocoder.yudao.framework.common.validation.InEnum; 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
4 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; 4 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
5 import jakarta.validation.constraints.NotEmpty; 5 import jakarta.validation.constraints.NotEmpty;
6 -import lombok.AllArgsConstructor;  
7 -import lombok.Builder;  
8 import lombok.Data; 6 import lombok.Data;
9 import lombok.NoArgsConstructor; 7 import lombok.NoArgsConstructor;
  8 +import lombok.experimental.SuperBuilder;
10 9
11 /** 10 /**
12 * IoT 设备状态更新 Request DTO 11 * IoT 设备状态更新 Request DTO
13 */ 12 */
14 @Data 13 @Data
  14 +@SuperBuilder
15 @NoArgsConstructor 15 @NoArgsConstructor
16 -@AllArgsConstructor  
17 -@Builder  
18 -public class IotDeviceStatusUpdateReqDTO { 16 +public class IotDeviceStatusUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO {
19 17
20 - // TODO 芋艿:要不要 id  
21 - // TODO 芋艿:要不要 time  
22 -  
23 - /**  
24 - * 产品标识  
25 - */  
26 - @NotEmpty(message = "产品标识不能为空")  
27 - private String productKey;  
28 - /**  
29 - * 设备名称  
30 - */  
31 - @NotEmpty(message = "设备名称不能为空")  
32 - private String deviceName;  
33 /** 18 /**
34 * 设备状态 19 * 设备状态
35 */ 20 */
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +import lombok.experimental.SuperBuilder;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +/**
  11 + * IoT 设备上行的抽象 Request DTO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Data
  16 +@SuperBuilder
  17 +@NoArgsConstructor
  18 +public abstract class IotDeviceUpstreamAbstractReqDTO {
  19 +
  20 + /**
  21 + * 请求编号
  22 + */
  23 + private String requestId;
  24 +
  25 + /**
  26 + * 插件标识
  27 + */
  28 + private String pluginKey;
  29 +
  30 + /**
  31 + * 产品标识
  32 + */
  33 + @NotEmpty(message = "产品标识不能为空")
  34 + private String productKey;
  35 + /**
  36 + * 设备名称
  37 + */
  38 + @NotEmpty(message = "设备名称不能为空")
  39 + private String deviceName;
  40 +
  41 + /**
  42 + * 上报时间
  43 + */
  44 + private LocalDateTime reportTime;
  45 +
  46 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.device;
  2 +
  3 +import lombok.Getter;
  4 +import lombok.RequiredArgsConstructor;
  5 +
  6 +/**
  7 + * IoT 设备消息标识符枚举
  8 + */
  9 +@Getter
  10 +@RequiredArgsConstructor
  11 +public enum IotDeviceMessageIdentifierEnum {
  12 +
  13 + PROPERTY_GET("get"),
  14 + PROPERTY_SET("set"),
  15 + PROPERTY_REPORT("report");
  16 +
  17 + /**
  18 + * 标志符
  19 + */
  20 + private final String identifier;
  21 +
  22 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.device;
  2 +
  3 +import lombok.Getter;
  4 +import lombok.RequiredArgsConstructor;
  5 +
  6 +/**
  7 + * IoT 设备消息类型枚举
  8 + */
  9 +@Getter
  10 +@RequiredArgsConstructor
  11 +public enum IotDeviceMessageTypeEnum {
  12 +
  13 + STATE("state"), // 设备状态
  14 + PROPERTY("property"), // 设备属性
  15 + EVENT("event"); // 设备事件
  16 +
  17 + /**
  18 + * 属性
  19 + */
  20 + private final String type;
  21 +
  22 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java
@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; 4 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; 5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; 6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
7 -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; 7 +import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService;
8 import org.springframework.validation.annotation.Validated; 8 import org.springframework.validation.annotation.Validated;
9 import org.springframework.web.bind.annotation.RestController; 9 import org.springframework.web.bind.annotation.RestController;
10 10
@@ -13,28 +13,30 @@ import javax.annotation.Resource; @@ -13,28 +13,30 @@ import javax.annotation.Resource;
13 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 13 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
14 14
15 /** 15 /**
16 - * 设备数据 API 实现类 16 + * * 设备数据 Upstream 上行 API 实现类
17 */ 17 */
18 @RestController 18 @RestController
19 @Validated 19 @Validated
20 -public class DeviceDataApiImpl implements DeviceDataApi { 20 +public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
21 21
22 @Resource 22 @Resource
23 - private IotDevicePropertyDataService deviceDataService; 23 + private IotDeviceUpstreamService deviceUpstreamService;
24 24
25 @Override 25 @Override
26 public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { 26 public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
  27 + deviceUpstreamService.updateDeviceStatus(updateReqDTO);
27 return success(true); 28 return success(true);
28 } 29 }
29 30
30 @Override 31 @Override
31 - public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { 32 + public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {
  33 + deviceUpstreamService.reportDevicePropertyData(reportReqDTO);
32 return success(true); 34 return success(true);
33 } 35 }
34 36
35 @Override 37 @Override
36 - public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {  
37 - deviceDataService.saveDeviceData(reportReqDTO); 38 + public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) {
  39 + deviceUpstreamService.reportDeviceEventData(reportReqDTO);
38 return success(true); 40 return success(true);
39 } 41 }
40 42
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java
@@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; 6 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*;
7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; 8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
9 -import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService;  
10 -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; 9 +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
  10 +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
11 import io.swagger.v3.oas.annotations.Operation; 11 import io.swagger.v3.oas.annotations.Operation;
12 import io.swagger.v3.oas.annotations.tags.Tag; 12 import io.swagger.v3.oas.annotations.tags.Tag;
13 import jakarta.annotation.Resource; 13 import jakarta.annotation.Resource;
@@ -27,13 +27,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -27,13 +27,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
27 public class IotDeviceDataController { 27 public class IotDeviceDataController {
28 28
29 @Resource 29 @Resource
30 - private IotDevicePropertyDataService deviceDataService; 30 + private IotDevicePropertyService deviceDataService;
31 31
32 @Resource 32 @Resource
33 - private IotDeviceLogDataService iotDeviceLogDataService; 33 + private IotDeviceLogService iotDeviceLogDataService;
34 34
35 @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性 35 @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性
36 - private IotDeviceLogDataService deviceLogDataService; 36 + private IotDeviceLogService deviceLogDataService;
37 37
38 // TODO @浩浩:这里的 /latest-list,包括方法名。 38 // TODO @浩浩:这里的 /latest-list,包括方法名。
39 @GetMapping("/latest") 39 @GetMapping("/latest")
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
@@ -36,6 +36,8 @@ public class IotDeviceDO extends BaseDO { @@ -36,6 +36,8 @@ public class IotDeviceDO extends BaseDO {
36 private Long id; 36 private Long id;
37 /** 37 /**
38 * 设备唯一标识符,全局唯一,用于识别设备 38 * 设备唯一标识符,全局唯一,用于识别设备
  39 + *
  40 + * 类似阿里云 <a href="https://help.aliyun.com/zh/iot/developer-reference/api-querydeviceinfo">QueryDeviceInfo</a> 的 IotInstanceId
39 */ 41 */
40 private String deviceKey; 42 private String deviceKey;
41 /** 43 /**
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.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.dal.dataobject.product.IotProductDO; 4 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  5 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
  6 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  7 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
4 import lombok.AllArgsConstructor; 8 import lombok.AllArgsConstructor;
5 import lombok.Builder; 9 import lombok.Builder;
6 import lombok.Data; 10 import lombok.Data;
@@ -19,37 +23,51 @@ import lombok.NoArgsConstructor; @@ -19,37 +23,51 @@ import lombok.NoArgsConstructor;
19 @AllArgsConstructor 23 @AllArgsConstructor
20 public class IotDeviceLogDO { 24 public class IotDeviceLogDO {
21 25
22 - // TODO @芋艿:消息 ID 的生成逻辑  
23 /** 26 /**
24 - * 消息 ID 27 + * 日志编号
  28 + *
  29 + * 通过 {@link IdUtil#fastSimpleUUID()} 生成
25 */ 30 */
26 private String id; 31 private String id;
27 32
28 /** 33 /**
  34 + * 请求编号
  35 + *
  36 + * 对应 {@link IotDeviceMessage#getRequestId()} 字段
  37 + */
  38 + private String requestId;
  39 +
  40 + /**
29 * 产品标识 41 * 产品标识
30 * <p> 42 * <p>
31 * 关联 {@link IotProductDO#getProductKey()} 43 * 关联 {@link IotProductDO#getProductKey()}
32 */ 44 */
33 private String productKey; 45 private String productKey;
34 - 46 + /**
  47 + * 设备名称
  48 + *
  49 + * 关联 {@link IotDeviceDO#getDeviceName()}
  50 + */
  51 + private String deviceName;
35 /** 52 /**
36 * 设备标识 53 * 设备标识
37 * <p> 54 * <p>
38 * 关联 {@link IotDeviceDO#getDeviceKey()}} 55 * 关联 {@link IotDeviceDO#getDeviceKey()}}
39 */ 56 */
40 - private String deviceKey; 57 + private String deviceKey; // 非存储字段,用于 TDengine 的 TAG
41 58
42 - // TODO @super:枚举类  
43 /** 59 /**
44 * 日志类型 60 * 日志类型
  61 + *
  62 + * 枚举 {@link IotDeviceMessageTypeEnum}
45 */ 63 */
46 private String type; 64 private String type;
47 -  
48 - // TODO @super:枚举类  
49 /** 65 /**
50 - * 标识符:用于标识具体的属性、事件或服务 66 + * 标识符
  67 + *
  68 + * 枚举 {@link IotDeviceMessageIdentifierEnum}
51 */ 69 */
52 - private String subType; 70 + private String identifier;
53 71
54 /** 72 /**
55 * 数据内容 73 * 数据内容
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java
@@ -22,21 +22,13 @@ public interface IotDeviceLogDataMapper { @@ -22,21 +22,13 @@ public interface IotDeviceLogDataMapper {
22 */ 22 */
23 void createDeviceLogSTable(); 23 void createDeviceLogSTable();
24 24
25 - // TODO @super:单个参数,不用加 @Param  
26 - // TODO @芋艿:在瞅瞅  
27 - //讨论:艿菇这里有些特殊情况,我也学习了一下这块知识:  
28 - // 如果使用的是Java 8及以上版本,并且编译器保留了参数名(通过编译器选项-parameters启用),则可以去掉@Param注解。MyBatis会自动使用参数的实际名称  
29 - // 但在TDengine中 @Param去掉后TDengine会报错,以下是大模型的回答:  
30 - // 不用加 @Param在普通的 MySQL 场景下是正确的 - 对于 MyBatis,当方法只有一个参数时,确实可以不用添加 @Param 注解。  
31 - //但是在 TDengine 的场景下,情况不同:  
32 - //TDengine 的特殊性:  
33 - //TDengine 使用特殊的 SQL 语法  
34 - //需要处理超级表(STable)和子表的概念  
35 - //参数绑定的方式与普通 MySQL 不同  
36 - //为什么这里必须要 @Param:  
37 - //XML 中使用了 ${log.deviceKey} 这样的参数引用方式  
38 - //需要在 SQL 中动态构建表名(device_log_${log.deviceKey})  
39 - //没有 @Param("log") 的话,MyBatis 无法正确解析参数 25 + /**
  26 + * 查询设备日志表是否存在
  27 + *
  28 + * @return 存在则返回表名;不存在则返回 null
  29 + */
  30 + String showDeviceLogSTable();
  31 +
40 /** 32 /**
41 * 插入设备日志数据 33 * 插入设备日志数据
42 * 34 *
@@ -44,7 +36,7 @@ public interface IotDeviceLogDataMapper { @@ -44,7 +36,7 @@ public interface IotDeviceLogDataMapper {
44 * 36 *
45 * @param log 设备日志数据 37 * @param log 设备日志数据
46 */ 38 */
47 - void insert(@Param("log") IotDeviceLogDO log); 39 + void insert(IotDeviceLogDO log);
48 40
49 /** 41 /**
50 * 获得设备日志分页 42 * 获得设备日志分页
@@ -62,12 +54,4 @@ public interface IotDeviceLogDataMapper { @@ -62,12 +54,4 @@ public interface IotDeviceLogDataMapper {
62 */ 54 */
63 Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); 55 Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO);
64 56
65 - // TODO @芋艿:这个方法名,后续看看叫啥好  
66 - /**  
67 - * 查询设备日志表是否存在  
68 - *  
69 - * @return 不存在返回 null  
70 - */  
71 - Object checkDeviceLogSTableExists();  
72 -  
73 } 57 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
1 package cn.iocoder.yudao.module.iot.emq.service; 1 package cn.iocoder.yudao.module.iot.emq.service;
2 2
3 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; 3 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
4 -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; 4 +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
5 import jakarta.annotation.Resource; 5 import jakarta.annotation.Resource;
6 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
7 import org.eclipse.paho.client.mqttv3.MqttClient; 7 import org.eclipse.paho.client.mqttv3.MqttClient;
@@ -20,7 +20,7 @@ import org.springframework.scheduling.annotation.Async; @@ -20,7 +20,7 @@ import org.springframework.scheduling.annotation.Async;
20 public class EmqxServiceImpl implements EmqxService { 20 public class EmqxServiceImpl implements EmqxService {
21 21
22 @Resource 22 @Resource
23 - private IotDevicePropertyDataService iotDeviceDataService; 23 + private IotDevicePropertyService iotDeviceDataService;
24 24
25 // TODO 多线程处理消息 25 // TODO 多线程处理消息
26 @Override 26 @Override
@@ -35,8 +35,8 @@ public class EmqxServiceImpl implements EmqxService { @@ -35,8 +35,8 @@ public class EmqxServiceImpl implements EmqxService {
35 String deviceName = topic.split("/")[3]; 35 String deviceName = topic.split("/")[3];
36 String message = new String(mqttMessage.getPayload()); 36 String message = new String(mqttMessage.getPayload());
37 IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() 37 IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder()
38 - .productKey(productKey)  
39 - .deviceName(deviceName) 38 +// .productKey(productKey)
  39 +// .deviceName(deviceName)
40 // .properties(message) // TODO 芋艿:临时去掉,看看 40 // .properties(message) // TODO 芋艿:临时去掉,看看
41 .build(); 41 .build();
42 iotDeviceDataService.saveDeviceData(createDTO); 42 iotDeviceDataService.saveDeviceData(createDTO);
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java
@@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component;
9 import java.sql.Timestamp; 9 import java.sql.Timestamp;
10 import java.util.Map; 10 import java.util.Map;
11 11
  12 +// TODO @haohao:这个还需要的么?
12 /** 13 /**
13 * TaosAspect 是一个处理 Taos 数据库返回值的切面。 14 * TaosAspect 是一个处理 Taos 数据库返回值的切面。
14 */ 15 */
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.framework.security.config;
  2 +
  3 +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
  4 +import cn.iocoder.yudao.module.iot.enums.ApiConstants;
  5 +import org.springframework.context.annotation.Bean;
  6 +import org.springframework.context.annotation.Configuration;
  7 +import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  8 +import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
  9 +
  10 +/**
  11 + * IoT 模块的 Security 配置
  12 + */
  13 +@Configuration(proxyBeanMethods = false, value = "iotSecurityConfiguration")
  14 +public class SecurityConfiguration {
  15 +
  16 + @Bean("iotAuthorizeRequestsCustomizer")
  17 + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
  18 + return new AuthorizeRequestsCustomizer() {
  19 +
  20 + @Override
  21 + public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
  22 + // RPC 服务的安全配置
  23 + registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
  24 + }
  25 +
  26 + };
  27 + }
  28 +
  29 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java
1 /** 1 /**
2 - * 消息队列的消息 2 + * 占位
3 */ 3 */
4 -package cn.iocoder.yudao.module.iot.mq.message; 4 +package cn.iocoder.yudao.module.iot.framework.security.core;
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.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.IotDeviceLogDataService; 3 +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
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,7 +17,7 @@ import org.springframework.context.annotation.Configuration; @@ -17,7 +17,7 @@ import org.springframework.context.annotation.Configuration;
17 @RequiredArgsConstructor 17 @RequiredArgsConstructor
18 public class TDengineTableInitConfiguration implements ApplicationRunner { 18 public class TDengineTableInitConfiguration implements ApplicationRunner {
19 19
20 - private final IotDeviceLogDataService deviceLogService; 20 + private final IotDeviceLogService deviceLogService;
21 21
22 @Override 22 @Override
23 public void run(ApplicationArguments args) { 23 public void run(ApplicationArguments args) {
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java
@@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component;
8 import javax.annotation.Resource; 8 import javax.annotation.Resource;
9 import java.util.concurrent.TimeUnit; 9 import java.util.concurrent.TimeUnit;
10 10
  11 +// TODO 芋艿:后续再看看
11 /** 12 /**
12 * 插件实例 Job 13 * 插件实例 Job
13 * 14 *
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.mq.consumer.device;
  2 +
  3 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
  4 +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
  5 +import jakarta.annotation.Resource;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.springframework.context.event.EventListener;
  8 +import org.springframework.scheduling.annotation.Async;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +/**
  12 + * 针对 {@link IotDeviceMessage} 的消费者,记录设备日志
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Component
  17 +@Slf4j
  18 +public class IotDeviceLogMessageConsumer {
  19 +
  20 + @Resource
  21 + private IotDeviceLogService deviceLogService;
  22 +
  23 + @EventListener
  24 + @Async
  25 + public void onMessage(IotDeviceMessage message) {
  26 + log.info("[onMessage][消息内容({})]", message);
  27 + deviceLogService.createDeviceLog(message);
  28 + }
  29 +
  30 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java
1 -package cn.iocoder.yudao.module.iot.mq.consumer.deviceconsumer; 1 +package cn.iocoder.yudao.module.iot.mq.consumer.device;
2 2
3 -  
4 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;  
5 -import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService;  
6 -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; 3 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
  4 +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
7 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
8 import org.springframework.context.event.EventListener; 6 import org.springframework.context.event.EventListener;
9 import org.springframework.scheduling.annotation.Async; 7 import org.springframework.scheduling.annotation.Async;
@@ -12,30 +10,25 @@ import org.springframework.stereotype.Component; @@ -12,30 +10,25 @@ import org.springframework.stereotype.Component;
12 import javax.annotation.Resource; 10 import javax.annotation.Resource;
13 11
14 /** 12 /**
15 - * 针对 {@link ThingModelMessage} 的消费者 13 + * 针对 {@link IotDeviceMessage} 的消费者,记录设备属性
16 * 14 *
17 * @author alwayssuper 15 * @author alwayssuper
18 */ 16 */
19 @Component 17 @Component
20 @Slf4j 18 @Slf4j
21 -public class DeviceConsumer { 19 +public class IotDevicePropertyMessageConsumer {
22 20
23 @Resource 21 @Resource
24 - private IotDeviceLogDataService deviceLogDataService;  
25 - @Resource  
26 - private IotDevicePropertyDataService deviceDataService; 22 + private IotDevicePropertyService deviceDataService;
27 23
28 - // TODO @芋艿:这块先用ThingModelMessage,后续看看用啥替代  
29 @EventListener 24 @EventListener
30 @Async 25 @Async
31 - public void onMessage(ThingModelMessage message) { 26 + public void onMessage(IotDeviceMessage message) {
32 log.info("[onMessage][消息内容({})]", message); 27 log.info("[onMessage][消息内容({})]", message);
33 - //TODO:数据插入这块整体写的比较混乱,整体借鉴了浩浩哥之前写的逻辑,目前是通过模拟设备科插入数据了,但之前的逻辑有大量弃用的部分,后续看看怎么完善  
34 28
35 - // 设备数据记录  
36 - deviceDataService.saveDeviceDataTest(message);  
37 // 设备日志记录 29 // 设备日志记录
38 - deviceLogDataService.saveDeviceLog(message); 30 + // TODO @芋艿:重新写下
  31 +// deviceLogDataService.createDeviceLog(message);
39 } 32 }
40 33
41 } 34 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java 0 → 100644
  1 +/**
  2 + * TODO 芋艿:未来实现一个 IotRuleMessageConsumer
  3 + */
  4 +package cn.iocoder.yudao.module.iot.mq.consumer.rule;
0 \ No newline at end of file 5 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java
1 -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; 1 +package cn.iocoder.yudao.module.iot.mq.message;
2 2
  3 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
3 import lombok.AllArgsConstructor; 5 import lombok.AllArgsConstructor;
4 import lombok.Builder; 6 import lombok.Builder;
5 import lombok.Data; 7 import lombok.Data;
6 import lombok.NoArgsConstructor; 8 import lombok.NoArgsConstructor;
7 9
8 -import java.util.HashMap;  
9 -import java.util.Map; 10 +import java.time.LocalDateTime;
10 11
11 /** 12 /**
12 - * 物模型消息 13 + * 设备消息
13 */ 14 */
14 @Data 15 @Data
15 @NoArgsConstructor 16 @NoArgsConstructor
16 @AllArgsConstructor 17 @AllArgsConstructor
17 @Builder 18 @Builder
18 -public class ThingModelMessage { 19 +public class IotDeviceMessage {
19 20
20 /** 21 /**
21 - * 消息ID 22 + * 请求编号
22 */ 23 */
23 - private String id; 24 + private String requestId;
24 25
25 /** 26 /**
26 - * 扩展功能的参数 27 + * 设备信息
27 */ 28 */
28 - private Object sys;  
29 - 29 + private String productKey;
30 /** 30 /**
31 - * 请求方法 例如:thing.event.property.post 31 + * 设备名称
32 */ 32 */
33 - private String method;  
34 - 33 + private String deviceName;
35 /** 34 /**
36 - * 请求参数 35 + * 设备标识
37 */ 36 */
38 - private Object params; 37 + private String deviceKey;
39 38
40 /** 39 /**
41 - * 属性上报时间戳 40 + * 消息类型
  41 + *
  42 + * 枚举 {@link IotDeviceMessageTypeEnum}
42 */ 43 */
43 - private Long time;  
44 - 44 + private String type;
45 /** 45 /**
46 - * 设备信息 46 + * 标识符
  47 + *
  48 + * 枚举 {@link IotDeviceMessageIdentifierEnum}
47 */ 49 */
48 - private String productKey; 50 + private String identifier;
49 51
50 /** 52 /**
51 - * 设备名称 53 + * 请求参数
  54 + *
  55 + * 例如说:属性上报的 properties、事件上报的 params
52 */ 56 */
53 - private String deviceName; 57 + private Object data;
54 58
55 /** 59 /**
56 - * 设备 key 60 + * 上报时间
57 */ 61 */
58 - private String deviceKey; 62 + private LocalDateTime reportTime;
  63 +
  64 + // TODO @芋艿 code;
59 65
60 - /**  
61 - * 转换为 Map 类型  
62 - */  
63 - public Map<String, Object> dataToMap() {  
64 - Map<String, Object> mapData = new HashMap<>();  
65 - if (params instanceof Map) {  
66 - ((Map<?, ?>) params).forEach((key, value) -> mapData.put(key.toString(), value));  
67 - }  
68 - return mapData;  
69 - }  
70 } 66 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java
1 -package cn.iocoder.yudao.module.iot.mq.producer.simulatesend; 1 +package cn.iocoder.yudao.module.iot.mq.producer.device;
2 2
3 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; 3 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
4 import jakarta.annotation.Resource; 4 import jakarta.annotation.Resource;
5 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
6 import org.springframework.context.ApplicationContext; 6 import org.springframework.context.ApplicationContext;
7 import org.springframework.stereotype.Component; 7 import org.springframework.stereotype.Component;
8 8
9 -// TODO @芋艿:@alwayssuper:是不是还没用起来哈?Producer 最好属于某个模块;  
10 /** 9 /**
11 - * SimulateSend 模拟设备上报的 Producer 10 + * Iot 设备相关消息的 Producer
12 * 11 *
13 * @author alwayssuper 12 * @author alwayssuper
14 * @since 2024/12/17 16:35 13 * @since 2024/12/17 16:35
15 */ 14 */
16 @Slf4j 15 @Slf4j
17 @Component 16 @Component
18 -public class SimulateSendProducer { 17 +public class IotDeviceProducer {
19 18
20 @Resource 19 @Resource
21 private ApplicationContext applicationContext; 20 private ApplicationContext applicationContext;
22 21
23 /** 22 /**
24 - * 发送 {@link ThingModelMessage} 消息 23 + * 发送 {@link IotDeviceMessage} 消息
25 * 24 *
26 * @param thingModelMessage 物模型消息 25 * @param thingModelMessage 物模型消息
27 */ 26 */
28 - public void sendSimulateMessage(ThingModelMessage thingModelMessage) { 27 + public void sendDeviceMessage(IotDeviceMessage thingModelMessage) {
29 applicationContext.publishEvent(thingModelMessage); 28 applicationContext.publishEvent(thingModelMessage);
30 } 29 }
31 30
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java 0 → 100644
  1 +/**
  2 + * TODO 芋艿:临时占位
  3 + */
  4 +package cn.iocoder.yudao.module.iot.mq.producer;
0 \ No newline at end of file 5 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java
1 -package cn.iocoder.yudao.module.iot.service.device; 1 +package cn.iocoder.yudao.module.iot.service.device.data;
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.deviceData.IotDeviceDataSimulatorSaveReqVO;  
5 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; 4 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO;
6 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; 5 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
7 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; 6 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
8 7
9 /** 8 /**
10 * IoT 设备日志数据 Service 接口 9 * IoT 设备日志数据 Service 接口
11 * 10 *
12 * @author alwayssuper 11 * @author alwayssuper
13 */ 12 */
14 -public interface IotDeviceLogDataService { 13 +public interface IotDeviceLogService {
15 14
16 /** 15 /**
17 * 初始化 TDengine 超级表 16 * 初始化 TDengine 超级表
@@ -23,11 +22,9 @@ public interface IotDeviceLogDataService { @@ -23,11 +22,9 @@ public interface IotDeviceLogDataService {
23 /** 22 /**
24 * 插入设备日志 23 * 插入设备日志
25 * 24 *
26 - * 当该设备第一次插入日志时,自动创建该设备的设备日志子表  
27 - *  
28 - * @param simulatorReqVO 设备日志模拟数据 25 + * @param message 设备数据
29 */ 26 */
30 - void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO); 27 + void createDeviceLog(IotDeviceMessage message);
31 28
32 /** 29 /**
33 * 获得设备日志分页 30 * 获得设备日志分页
@@ -37,11 +34,4 @@ public interface IotDeviceLogDataService { @@ -37,11 +34,4 @@ public interface IotDeviceLogDataService {
37 */ 34 */
38 PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); 35 PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO);
39 36
40 - /**  
41 - * 插入设备日志  
42 - *  
43 - * @param message 设备数据  
44 - */  
45 - void saveDeviceLog(ThingModelMessage message);  
46 -  
47 } 37 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java
1 -package cn.iocoder.yudao.module.iot.service.device; 1 +package cn.iocoder.yudao.module.iot.service.device.data;
2 2
3 -import cn.hutool.json.JSONUtil; 3 +import cn.hutool.core.util.IdUtil;
  4 +import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO;  
7 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; 8 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO;
8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; 9 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
9 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;  
10 import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; 10 import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper;
  11 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
11 import jakarta.annotation.Resource; 12 import jakarta.annotation.Resource;
12 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
13 import org.springframework.stereotype.Service; 14 import org.springframework.stereotype.Service;
@@ -16,40 +17,36 @@ import org.springframework.validation.annotation.Validated; @@ -16,40 +17,36 @@ import org.springframework.validation.annotation.Validated;
16 import java.util.List; 17 import java.util.List;
17 18
18 /** 19 /**
19 - * IoT 设备日志数据 Service 实现了 20 + * IoT 设备日志数据 Service 实现类
20 * 21 *
21 * @author alwayssuper 22 * @author alwayssuper
22 */ 23 */
23 @Service 24 @Service
24 @Slf4j 25 @Slf4j
25 @Validated 26 @Validated
26 -public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ 27 +public class IotDeviceLogServiceImpl implements IotDeviceLogService {
27 28
28 @Resource 29 @Resource
29 private IotDeviceLogDataMapper deviceLogDataMapper; 30 private IotDeviceLogDataMapper deviceLogDataMapper;
30 31
31 @Override 32 @Override
32 public void defineDeviceLog() { 33 public void defineDeviceLog() {
33 - if (deviceLogDataMapper.checkDeviceLogSTableExists() != null) {  
34 - log.info("[defineDeviceLog][设备日志超级表已存在,跳过创建]"); 34 + if (StrUtil.isNotEmpty(deviceLogDataMapper.showDeviceLogSTable())) {
  35 + log.info("[defineDeviceLog][设备日志超级表已存在,创建跳过]");
35 return; 36 return;
36 } 37 }
37 38
38 - log.info("[defineDeviceLog][设备日志超级表不存在,开始创建]"); 39 + log.info("[defineDeviceLog][设备日志超级表不存在,创建开始...]");
39 deviceLogDataMapper.createDeviceLogSTable(); 40 deviceLogDataMapper.createDeviceLogSTable();
40 - log.info("[defineDeviceLog][设备日志超级表不存在,创建完成]"); 41 + log.info("[defineDeviceLog][设备日志超级表不存在,创建成功]");
41 } 42 }
42 43
43 @Override 44 @Override
44 - public void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) {  
45 - // 1. 转换请求对象为 DO  
46 - IotDeviceLogDO iotDeviceLogDO = BeanUtils.toBean(simulatorReqVO, IotDeviceLogDO.class);  
47 -  
48 - // 2. 处理时间字段  
49 -// iotDeviceLogDO.setTs(currentTime); // TODO @super:TS在SQL中直接NOW 咱们的TS数据获取是走哪一种;走 now()  
50 -  
51 - // 3. 插入数据  
52 - deviceLogDataMapper.insert(iotDeviceLogDO); 45 + public void createDeviceLog(IotDeviceMessage message) {
  46 + IotDeviceLogDO log = BeanUtils.toBean(message, IotDeviceLogDO.class)
  47 + .setId(IdUtil.fastSimpleUUID())
  48 + .setContent(JsonUtils.toJsonString(message.getData()));
  49 + deviceLogDataMapper.insert(log);
53 } 50 }
54 51
55 @Override 52 @Override
@@ -60,18 +57,4 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ @@ -60,18 +57,4 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{
60 return new PageResult<>(list, total); 57 return new PageResult<>(list, total);
61 } 58 }
62 59
63 - @Override  
64 - public void saveDeviceLog(ThingModelMessage message) {  
65 - IotDeviceLogDO log = IotDeviceLogDO.builder()  
66 - .id(message.getId())  
67 - .deviceKey(message.getDeviceKey())  
68 - .productKey(message.getProductKey())  
69 - .type(message.getMethod()) // 消息类型,使用method作为类型 TODO 芋艿:在看看  
70 - .subType("property") // TODO 芋艿:这块先写死,后续优化  
71 - .content(JSONUtil.toJsonStr(message)) // TODO 芋艿:后续优化  
72 - .reportTime(message.getTime()) // 上报时间 TODO 芋艿:在想想时间  
73 - .build();  
74 - deviceLogDataMapper.insert(log);  
75 - }  
76 -  
77 } 60 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java
1 -package cn.iocoder.yudao.module.iot.service.device; 1 +package cn.iocoder.yudao.module.iot.service.device.data;
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.api.device.dto.IotDevicePropertyReportReqDTO; 4 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
5 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; 5 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO;
6 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; 6 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO;
7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
8 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;  
9 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
10 9
11 import java.util.List; 10 import java.util.List;
@@ -16,7 +15,7 @@ import java.util.Map; @@ -16,7 +15,7 @@ import java.util.Map;
16 * 15 *
17 * @author 芋道源码 16 * @author 芋道源码
18 */ 17 */
19 -public interface IotDevicePropertyDataService { 18 +public interface IotDevicePropertyService {
20 19
21 /** 20 /**
22 * 定义设备属性数据的结构 21 * 定义设备属性数据的结构
@@ -33,13 +32,6 @@ public interface IotDevicePropertyDataService { @@ -33,13 +32,6 @@ public interface IotDevicePropertyDataService {
33 void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); 32 void saveDeviceData(IotDevicePropertyReportReqDTO createDTO);
34 33
35 /** 34 /**
36 - * 保存设备数据  
37 - *  
38 - * @param thingModelMessage 设备数据  
39 - */  
40 - void saveDeviceDataTest(ThingModelMessage thingModelMessage);  
41 -  
42 - /**  
43 * 模拟设备 35 * 模拟设备
44 * 36 *
45 * @param simulatorReqVO 设备数据 37 * @param simulatorReqVO 设备数据
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java
1 -package cn.iocoder.yudao.module.iot.service.device; 1 +package cn.iocoder.yudao.module.iot.service.device.data;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.date.DateUtil; 4 import cn.hutool.core.date.DateUtil;
5 import cn.hutool.core.map.MapUtil; 5 import cn.hutool.core.map.MapUtil;
6 -import cn.hutool.core.util.IdUtil;  
7 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
8 import cn.hutool.json.JSONObject; 7 import cn.hutool.json.JSONObject;
9 import cn.hutool.json.JSONUtil; 8 import cn.hutool.json.JSONUtil;
@@ -16,18 +15,15 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -16,18 +15,15 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
16 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; 15 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
17 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; 16 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
18 import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; 17 import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO;
19 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;  
20 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; 18 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
21 import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; 19 import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;
22 import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; 20 import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper;
23 -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper;  
24 import cn.iocoder.yudao.module.iot.enums.IotConstants; 21 import cn.iocoder.yudao.module.iot.enums.IotConstants;
25 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; 22 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
26 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; 23 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
27 import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; 24 import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField;
28 -import cn.iocoder.yudao.module.iot.mq.producer.simulatesend.SimulateSendProducer; 25 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
29 import cn.iocoder.yudao.module.iot.service.product.IotProductService; 26 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
30 -import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService;  
31 import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; 27 import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
32 import jakarta.annotation.Resource; 28 import jakarta.annotation.Resource;
33 import jakarta.validation.Valid; 29 import jakarta.validation.Valid;
@@ -53,7 +49,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_C @@ -53,7 +49,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_C
53 */ 49 */
54 @Service 50 @Service
55 @Slf4j 51 @Slf4j
56 -public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataService { 52 +public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
57 53
58 /** 54 /**
59 * 物模型的数据类型,与 TDengine 数据类型的映射关系 55 * 物模型的数据类型,与 TDengine 数据类型的映射关系
@@ -76,25 +72,16 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe @@ -76,25 +72,16 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe
76 @Resource 72 @Resource
77 private IotDeviceService deviceService; 73 private IotDeviceService deviceService;
78 @Resource 74 @Resource
79 - private IotThingModelMessageService thingModelMessageService;  
80 - @Resource  
81 private IotThingModelService thingModelService; 75 private IotThingModelService thingModelService;
82 @Resource 76 @Resource
83 private IotProductService productService; 77 private IotProductService productService;
84 78
85 @Resource 79 @Resource
86 - private SimulateSendProducer simulateSendProducer;  
87 -  
88 - @Resource  
89 - private TdEngineDMLMapper tdEngineDMLMapper;  
90 -  
91 - @Resource  
92 private DeviceDataRedisDAO deviceDataRedisDAO; 80 private DeviceDataRedisDAO deviceDataRedisDAO;
93 81
94 @Resource 82 @Resource
95 private IotDevicePropertyDataMapper devicePropertyDataMapper; 83 private IotDevicePropertyDataMapper devicePropertyDataMapper;
96 84
97 -  
98 @Override 85 @Override
99 public void defineDevicePropertyData(Long productId) { 86 public void defineDevicePropertyData(Long productId) {
100 // 1.1 查询产品和物模型 87 // 1.1 查询产品和物模型
@@ -144,28 +131,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe @@ -144,28 +131,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe
144 // 1. 根据产品 key 和设备名称,获得设备信息 131 // 1. 根据产品 key 和设备名称,获得设备信息
145 IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName()); 132 IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName());
146 // 2. 解析消息,保存数据 133 // 2. 解析消息,保存数据
147 - JSONObject jsonObject = new JSONObject(createDTO.getParams()); 134 + JSONObject jsonObject = new JSONObject(createDTO.getProperties());
148 log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); 135 log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject);
149 - ThingModelMessage thingModelMessage = ThingModelMessage.builder()  
150 - .id(jsonObject.getStr("id"))  
151 - .sys(jsonObject.get("sys"))  
152 - .method(jsonObject.getStr("method"))  
153 - .params(jsonObject.get("params"))  
154 - .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time"))  
155 - .productKey(createDTO.getProductKey())  
156 - .deviceName(createDTO.getDeviceName())  
157 - .deviceKey(device.getDeviceKey())  
158 - .build();  
159 - thingModelMessageService.saveThingModelMessage(device, thingModelMessage);  
160 - }  
161 -  
162 - //TODO @芋艿:后续捋一捋这块逻辑,先借鉴一下目前的代码  
163 - @Override  
164 - public void saveDeviceDataTest(ThingModelMessage thingModelMessage) {  
165 - // 1. 根据产品 key 和设备名称,获得设备信息  
166 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(thingModelMessage.getProductKey(), thingModelMessage.getDeviceName());  
167 - // 2. 保存数据  
168 - thingModelMessageService.saveThingModelMessage(device, thingModelMessage);  
169 } 136 }
170 137
171 //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 138 //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化
@@ -182,20 +149,17 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe @@ -182,20 +149,17 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe
182 throw exception(DEVICE_DATA_CONTENT_JSON_PARSE_ERROR); 149 throw exception(DEVICE_DATA_CONTENT_JSON_PARSE_ERROR);
183 } 150 }
184 151
  152 + // TODO @芋艿:后续优化
185 // 3. 构建物模型消息 153 // 3. 构建物模型消息
186 - ThingModelMessage thingModelMessage = ThingModelMessage.builder()  
187 - .id(IdUtil.fastSimpleUUID()) // TODO:后续优化  
188 - .sys(null)// TODO:这块先写死,后续优化  
189 - .method("thing.event.property.post") // TODO:这块先写死,后续优化  
190 - .params(contentJson) // 将 content 作为 params  
191 - .time(simulatorReqVO.getReportTime()) // 使用上报时间  
192 - .productKey(simulatorReqVO.getProductKey())  
193 - .deviceName(device.getDeviceName())  
194 - .deviceKey(device.getDeviceKey())  
195 - .build(); 154 +// IotDeviceMessage thingModelMessage = IotDeviceMessage.builder()
  155 +// .params(contentJson) // 将 content 作为 params
  156 +// .time(simulatorReqVO.getReportTime()) // 使用上报时间
  157 +// .productKey(simulatorReqVO.getProductKey())
  158 +// .deviceName(device.getDeviceName())
  159 +// .build();
196 160
197 // 4. 发送模拟消息 161 // 4. 发送模拟消息
198 - simulateSendProducer.sendSimulateMessage(thingModelMessage); 162 +// simulateSendProducer.sendDeviceMessage(thingModelMessage);
199 } 163 }
200 164
201 @Override 165 @Override
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.device.upstream;
  2 +
  3 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
  4 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
  5 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
  6 +
  7 +/**
  8 + * 设备上行 Service 接口
  9 + *
  10 + * 目的:设备 -> 插件 -> 服务端
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +public interface IotDeviceUpstreamService {
  15 +
  16 + /**
  17 + * 更新设备状态
  18 + *
  19 + * @param updateReqDTO 更新设备状态 DTO
  20 + */
  21 + void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO);
  22 +
  23 + /**
  24 + * 上报设备属性数据
  25 + *
  26 + * @param reportReqDTO 上报设备属性数据 DTO
  27 + */
  28 + void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO);
  29 +
  30 + /**
  31 + * 上报设备事件数据
  32 + *
  33 + * @param reportReqDTO 设备事件
  34 + */
  35 + void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO);
  36 +
  37 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.device.upstream;
  2 +
  3 +import cn.hutool.core.util.IdUtil;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
  7 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
  8 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
  9 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
  10 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceUpstreamAbstractReqDTO;
  11 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  12 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
  13 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  14 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
  15 +import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
  16 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  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 +/**
  25 + * 设备上行 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +@Slf4j
  32 +public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
  33 +
  34 + @Resource
  35 + private IotDeviceService deviceService;
  36 +
  37 + @Resource
  38 + private IotDeviceProducer deviceProducer;
  39 +
  40 + @Override
  41 + public void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
  42 + log.info("[updateDeviceStatus][更新设备状态: {}]", updateReqDTO);
  43 + // TODO 芋艿:插件状态
  44 + }
  45 +
  46 + @Override
  47 + public void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {
  48 + // 1.1 获得设备
  49 + log.info("[reportDevicePropertyData][上报设备属性数据: {}]", reportReqDTO);
  50 + IotDeviceDO device = getDevice(reportReqDTO);
  51 + if (device == null) {
  52 + log.error("[reportDevicePropertyData][设备({}/{})不存在]",
  53 + reportReqDTO.getProductKey(), reportReqDTO.getDeviceName());
  54 + return;
  55 + }
  56 + // 1.2 记录设备的最后时间
  57 + updateDeviceLastTime(device, reportReqDTO);
  58 +
  59 + // 2. 发送设备消息
  60 + IotDeviceMessage message = BeanUtils.toBean(reportReqDTO, IotDeviceMessage.class)
  61 + .setType(IotDeviceMessageTypeEnum.PROPERTY.getType())
  62 + .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())
  63 + .setData(reportReqDTO.getProperties());
  64 + sendDeviceMessage(message, device);
  65 + }
  66 +
  67 + @Override
  68 + public void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) {
  69 + log.info("[reportDeviceEventData][上报设备事件数据: {}]", reportReqDTO);
  70 +
  71 + // TODO 芋艿:待实现
  72 + }
  73 +
  74 + private IotDeviceDO getDevice(IotDeviceUpstreamAbstractReqDTO reqDTO) {
  75 + return TenantUtils.executeIgnore(() -> // 需要忽略租户,因为请求时,未带租户编号
  76 + deviceService.getDeviceByProductKeyAndDeviceName(reqDTO.getProductKey(), reqDTO.getDeviceName()));
  77 + }
  78 +
  79 + private void updateDeviceLastTime(IotDeviceDO deviceDO, IotDeviceUpstreamAbstractReqDTO reqDTO) {
  80 + // TODO 芋艿:插件状态
  81 + // TODO 芋艿:操作时间
  82 + }
  83 +
  84 + private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) {
  85 + // 1. 完善消息
  86 + message.setDeviceKey(device.getDeviceKey());
  87 + if (StrUtil.isEmpty(message.getRequestId())) {
  88 + message.setRequestId(IdUtil.fastSimpleUUID());
  89 + }
  90 + if (message.getReportTime() == null) {
  91 + message.setReportTime(LocalDateTime.now());
  92 + }
  93 +
  94 + // 2. 发送消息
  95 + try {
  96 + deviceProducer.sendDeviceMessage(message);
  97 + log.info("[sendDeviceMessage][message({}) 发送消息成功]", message);
  98 + } catch (Exception e) {
  99 + log.error("[sendDeviceMessage][message({}) 发送消息失败]", message, e);
  100 + }
  101 + }
  102 +
  103 +}
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.IotDevicePropertyDataService; 11 +import cn.iocoder.yudao.module.iot.service.device.data.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;
@@ -35,7 +35,7 @@ public class IotProductServiceImpl implements IotProductService { @@ -35,7 +35,7 @@ public class IotProductServiceImpl implements IotProductService {
35 35
36 @Resource 36 @Resource
37 @Lazy // 延迟加载,解决循环依赖 37 @Lazy // 延迟加载,解决循环依赖
38 - private IotDevicePropertyDataService devicePropertyDataService; 38 + private IotDevicePropertyService devicePropertyDataService;
39 39
40 @Override 40 @Override
41 public Long createProduct(IotProductSaveReqVO createReqVO) { 41 public Long createProduct(IotProductSaveReqVO createReqVO) {
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java deleted
1 -package cn.iocoder.yudao.module.iot.service.tdengine;  
2 -  
3 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;  
4 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;  
5 -  
6 -/**  
7 - * 物模型消息 Service  
8 - */  
9 -public interface IotThingModelMessageService {  
10 -  
11 - /**  
12 - * 保存物模型消息  
13 - *  
14 - * @param device 设备  
15 - * @param thingModelMessage 物模型消息  
16 - */  
17 - void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage);  
18 -  
19 -  
20 -  
21 -}  
22 \ No newline at end of file 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java deleted
1 -package cn.iocoder.yudao.module.iot.service.tdengine;  
2 -  
3 -import cn.hutool.core.date.DateUtil;  
4 -import cn.hutool.core.util.StrUtil;  
5 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
6 -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;  
7 -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO;  
8 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;  
9 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;  
10 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser;  
11 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;  
12 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO;  
13 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;  
14 -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;  
15 -import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;  
16 -import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper;  
17 -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper;  
18 -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper;  
19 -import cn.iocoder.yudao.module.iot.enums.IotConstants;  
20 -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;  
21 -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;  
22 -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;  
23 -import cn.iocoder.yudao.module.iot.service.product.IotProductService;  
24 -import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;  
25 -import jakarta.annotation.Resource;  
26 -import lombok.extern.slf4j.Slf4j;  
27 -import org.springframework.beans.factory.annotation.Value;  
28 -import org.springframework.stereotype.Service;  
29 -  
30 -import java.util.*;  
31 -import java.util.stream.Collectors;  
32 -  
33 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;  
34 -  
35 -/**  
36 - * 物模型消息 Service 实现类  
37 - */  
38 -@Slf4j  
39 -@Service  
40 -public class IotThingModelMessageServiceImpl implements IotThingModelMessageService {  
41 -  
42 - private static final String TAG_NOTE = "TAG";  
43 - private static final String NOTE = "note";  
44 - private static final String TIME = "time";  
45 - private static final String DEVICE_KEY = "device_key";  
46 - private static final String DEVICE_NAME = "device_name";  
47 - private static final String PRODUCT_KEY = "product_key";  
48 - private static final String DEVICE_TYPE = "device_type";  
49 -  
50 - @Value("${spring.datasource.dynamic.datasource.tdengine.url}")  
51 - private String url;  
52 -  
53 - @Resource  
54 - private IotThingModelService iotThingModelService;  
55 - @Resource  
56 - private IotDeviceService iotDeviceService;  
57 - @Resource  
58 - private IotProductService productService;  
59 -  
60 - @Resource  
61 - private TdEngineDDLMapper tdEngineDDLMapper;  
62 - @Resource  
63 - private TdEngineDMLMapper tdEngineDMLMapper;  
64 -  
65 - @Resource  
66 - private IotDevicePropertyDataMapper iotDevicePropertyDataMapper;  
67 -  
68 - @Resource  
69 - private DeviceDataRedisDAO deviceDataRedisDAO;  
70 -  
71 - // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感  
72 - @Override  
73 - @TenantIgnore  
74 - public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) {  
75 - // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态  
76 - if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) {  
77 - // 1.1 创建设备表  
78 -// createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());  
79 - iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO()  
80 - .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus()));  
81 - }  
82 -  
83 - // 2. 获取设备属性并进行物模型校验,过滤非物模型属性  
84 - Map<String, Object> params = thingModelMessage.dataToMap();  
85 - List<IotThingModelDO> thingModelList = getValidThingModelList(thingModelMessage.getProductKey());  
86 - if (thingModelList.isEmpty()) {  
87 - return;  
88 - }  
89 -  
90 - // 3. 过滤并收集有效的属性字段,缓存设备属性  
91 - List<TdFieldDO> schemaFieldValues = filterAndCollectValidFields(params, thingModelList, device, thingModelMessage.getTime());  
92 - if (schemaFieldValues.size() == 0) { // 没有字段,无需保存  
93 - return;  
94 - }  
95 -  
96 - // 4. 构建并保存设备属性数据  
97 -// tdEngineDMLMapper.insertData(TdTableDO.builder()  
98 -// .dataBaseName(getDatabaseName())  
99 -// .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()))  
100 -// .columns(schemaFieldValues)  
101 -// .build());  
102 - // TODO:复用了旧逻辑,先过渡一下  
103 - iotDevicePropertyDataMapper.insertDevicePropertyData(TdTableDO.builder()  
104 - .productKey(device.getProductKey())  
105 - .deviceKey(device.getDeviceKey())  
106 - .columns(schemaFieldValues)  
107 - .build());  
108 - }  
109 -  
110 - private List<IotThingModelDO> getValidThingModelList(String productKey) {  
111 - return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey),  
112 - thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType()));  
113 - }  
114 -  
115 -// @Override  
116 -// @TenantIgnore  
117 -// public void createSuperTable(Long productId) {  
118 -// // 1. 查询产品  
119 -// IotProductDO product = productService.getProduct(productId);  
120 -// // 2. 创建日志超级表  
121 -// tdThingModelMessageMapper.createSuperTable(product.getProductKey());  
122 -//  
123 -// // 2. 获取超级表的名称和数据库名称  
124 -// // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法  
125 -//// String databaseName = IotTdDatabaseUtils.getDatabaseName(url);  
126 -//// String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey());  
127 -////  
128 -//// // 解析物模型,获取字段列表  
129 -//// List<TdFieldDO> schemaFields = List.of(  
130 -//// TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(),  
131 -//// TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(),  
132 -//// TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(),  
133 -//// TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(),  
134 -//// TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build()  
135 -//// );  
136 -//// // 设置超级表的标签  
137 -//// List<TdFieldDO> tagsFields = List.of(  
138 -//// TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build()  
139 -//// );  
140 -//// // 3. 创建超级表  
141 -//// tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields));  
142 -// }  
143 -  
144 - private List<IotThingModelDO> getValidFunctionList(String productKey) {  
145 - return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey),  
146 - thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType()));  
147 - }  
148 -  
149 - private List<TdFieldDO> filterAndCollectValidFields(Map<String, Object> params, List<IotThingModelDO> thingModelList, IotDeviceDO device, Long time) {  
150 - // 1. 获取属性标识符集合  
151 - Set<String> propertyIdentifiers = convertSet(thingModelList, IotThingModelDO::getIdentifier);  
152 -  
153 - // 2. 构建属性标识符和属性的映射  
154 - Map<String, IotThingModelDO> thingModelMap = convertMap(thingModelList, IotThingModelDO::getIdentifier);  
155 -  
156 - // 3. 过滤并收集有效的属性字段  
157 - List<TdFieldDO> schemaFieldValues = new ArrayList<>();  
158 - //TODO:新版本是使用ts字段  
159 -// schemaFieldValues.add(new TdFieldDO(TIME, time));  
160 - params.forEach((key, val) -> {  
161 - if (propertyIdentifiers.contains(key)) {  
162 - schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val));  
163 - // 缓存设备属性  
164 - // TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读  
165 - setDeviceDataCache(device, thingModelMap.get(key), val, time);  
166 - }  
167 - });  
168 - return schemaFieldValues;  
169 - }  
170 -  
171 - /**  
172 - * 缓存设备属性  
173 - *  
174 - * @param device 设备信息  
175 - * @param iotThingModelDO 物模型属性  
176 - * @param val 属性值  
177 - * @param time 时间  
178 - */  
179 - private void setDeviceDataCache(IotDeviceDO device, IotThingModelDO iotThingModelDO, Object val, Long time) {  
180 - IotDeviceDataDO deviceData = IotDeviceDataDO.builder()  
181 - .productKey(device.getProductKey())  
182 - .deviceName(device.getDeviceName())  
183 - .identifier(iotThingModelDO.getIdentifier())  
184 - .value(val != null ? val.toString() : null)  
185 - .updateTime(DateUtil.toLocalDateTime(new Date(time)))  
186 - .deviceId(device.getId())  
187 - .thingModelId(iotThingModelDO.getId())  
188 - .name(iotThingModelDO.getName())  
189 - .dataType(iotThingModelDO.getProperty().getDataType())  
190 - .build();  
191 - deviceDataRedisDAO.set(deviceData);  
192 - }  
193 -  
194 - /**  
195 - * 创建设备数据表  
196 - *  
197 - * @param deviceType 设备类型  
198 - * @param productKey 产品 Key  
199 - * @param deviceName 设备名称  
200 - * @param deviceKey 设备 Key  
201 - */  
202 - private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) {  
203 - // 1. 获取超级表名和数据库名  
204 - String superTableName = getProductPropertySTableName(deviceType, productKey);  
205 - String dataBaseName = getDatabaseName();  
206 -  
207 - // 2. 获取超级表的结构信息  
208 - List<Map<String, Object>> maps = tdEngineDDLMapper.describeSuperTable(new TdTableDO(dataBaseName, superTableName));  
209 - List<TdFieldDO> tagsFieldValues = new ArrayList<>();  
210 - if (maps != null) {  
211 - // 2.1 过滤出 TAG 类型的字段  
212 - List<Map<String, Object>> taggedNotesList = CollectionUtils.filterList(maps, map -> TAG_NOTE.equals(map.get(NOTE)));  
213 -  
214 - // 2.2 解析字段信息  
215 - tagsFieldValues = FieldParser.parse(taggedNotesList.stream()  
216 - .map(map -> List.of(map.get("field"), map.get("type"), map.get("length")))  
217 - .collect(Collectors.toList()));  
218 -  
219 - // 2.3 设置 TAG 字段的值  
220 - for (TdFieldDO tagsFieldValue : tagsFieldValues) {  
221 - switch (tagsFieldValue.getFieldName()) {  
222 - case PRODUCT_KEY -> tagsFieldValue.setFieldValue(productKey);  
223 - case DEVICE_KEY -> tagsFieldValue.setFieldValue(deviceKey);  
224 - case DEVICE_NAME -> tagsFieldValue.setFieldValue(deviceName);  
225 - case DEVICE_TYPE -> tagsFieldValue.setFieldValue(deviceType);  
226 - }  
227 - }  
228 - }  
229 -  
230 - // 3. 创建设备数据表  
231 - String tableName = getDeviceTableName(productKey, deviceName);  
232 - tdEngineDDLMapper.createTable(TdTableDO.builder().build()  
233 - .setDataBaseName(dataBaseName)  
234 - .setSuperTableName(superTableName)  
235 - .setTableName(tableName)  
236 - .setTags(tagsFieldValues));  
237 - }  
238 -  
239 -  
240 -  
241 - /**  
242 - * 获取数据库名称  
243 - *  
244 - * @return 数据库名称  
245 - */  
246 - private String getDatabaseName() {  
247 - return StrUtil.subAfter(url, "/", true);  
248 - }  
249 -  
250 - /**  
251 - * 获取产品属性表名  
252 - *  
253 - * @param deviceType 设备类型  
254 - * @param productKey 产品 Key  
255 - * @return 产品属性表名  
256 - */  
257 - private static String getProductPropertySTableName(Integer deviceType, String productKey) {  
258 - // TODO @haohao:枚举下,会好点哈。  
259 - return switch (deviceType) {  
260 - case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase();  
261 - case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase();  
262 - default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase();  
263 - };  
264 - }  
265 -  
266 - /**  
267 - * 获取设备表名  
268 - *  
269 - * @param productKey 产品 Key  
270 - * @param deviceName 设备名称  
271 - * @return 设备表名  
272 - */  
273 - private static String getDeviceTableName(String productKey, String deviceName) {  
274 - return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase());  
275 - }  
276 -  
277 -}  
278 \ No newline at end of file 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml
@@ -9,8 +9,9 @@ @@ -9,8 +9,9 @@
9 ts TIMESTAMP, 9 ts TIMESTAMP,
10 id NCHAR(50), 10 id NCHAR(50),
11 product_key NCHAR(50), 11 product_key NCHAR(50),
  12 + device_name NCHAR(50),
12 type NCHAR(50), 13 type NCHAR(50),
13 - sub_type NCHAR(50), 14 + identifier NCHAR(255),
14 content NCHAR(1024), 15 content NCHAR(1024),
15 report_time TIMESTAMP 16 report_time TIMESTAMP
16 ) TAGS ( 17 ) TAGS (
@@ -18,18 +19,23 @@ @@ -18,18 +19,23 @@
18 ) 19 )
19 </update> 20 </update>
20 21
  22 + <select id="showDeviceLogSTable" resultType="String">
  23 + SHOW STABLES LIKE 'device_log'
  24 + </select>
  25 +
21 <insert id="insert"> 26 <insert id="insert">
22 - INSERT INTO device_log_${log.deviceKey} (ts, id, product_key, type, subType, content, report_time) 27 + INSERT INTO device_log_${deviceKey} (ts, id, product_key, device_name, type, identifier, content, report_time)
23 USING device_log 28 USING device_log
24 - TAGS ('${log.deviceKey}') 29 + TAGS ('${deviceKey}')
25 VALUES ( 30 VALUES (
26 NOW, 31 NOW,
27 - #{log.id},  
28 - #{log.productKey},  
29 - #{log.type},  
30 - #{log.subType},  
31 - #{log.content},  
32 - #{log.reportTime} 32 + #{id},
  33 + #{productKey},
  34 + #{deviceName},
  35 + #{type},
  36 + #{identifier},
  37 + #{content},
  38 + #{reportTime}
33 ) 39 )
34 </insert> 40 </insert>
35 41
@@ -51,6 +57,7 @@ @@ -51,6 +57,7 @@
51 LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo} 57 LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo}
52 </select> 58 </select>
53 59
  60 + <!-- TODO 芋艿:看看能不能复用 mybatis-plus 的 selectCount 方法 -->
54 <select id="selectCount" resultType="Long"> 61 <select id="selectCount" resultType="Long">
55 SELECT COUNT(*) 62 SELECT COUNT(*)
56 FROM device_log_${reqVO.deviceKey} 63 FROM device_log_${reqVO.deviceKey}
@@ -67,12 +74,4 @@ @@ -67,12 +74,4 @@
67 </where> 74 </where>
68 </select> 75 </select>
69 76
70 - <select id="checkDeviceLogSTableExists" resultType="Object">  
71 - SHOW STABLES LIKE 'device_log'  
72 - </select>  
73 -  
74 - <select id="checkDeviceLogTableExists" resultType="Object">  
75 - SHOW TABLES LIKE 'device_log_${deviceKey}'  
76 - </select>  
77 -  
78 </mapper> 77 </mapper>
79 \ No newline at end of file 78 \ No newline at end of file
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java
1 package cn.iocoder.yudao.module.iot.plugin.common.api; 1 package cn.iocoder.yudao.module.iot.plugin.common.api;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; 4 +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; 5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; 6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
7 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; 7 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
8 -import lombok.RequiredArgsConstructor;  
9 import lombok.extern.slf4j.Slf4j; 8 import lombok.extern.slf4j.Slf4j;
10 import org.springframework.web.client.RestTemplate; 9 import org.springframework.web.client.RestTemplate;
11 10
12 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 11 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
13 12
14 -/**  
15 - * 用于通过 {@link RestTemplate} 向远程 IoT 服务发送设备数据相关的请求,  
16 - * 包括设备状态更新、事件数据上报、属性数据上报等操作。  
17 - */ 13 +// TODO @haohao:类注释,写一下,比较好
  14 +// TODO @haohao:类名要改下
18 @Slf4j 15 @Slf4j
19 -@RequiredArgsConstructor  
20 -public class DeviceDataApiClient implements DeviceDataApi { 16 +public class DeviceDataApiClient implements IotDeviceUpstreamApi {
21 17
22 - /**  
23 - * 用于发送 HTTP 请求的工具  
24 - */  
25 - private final RestTemplate restTemplate; 18 + public static final String URL_PREFIX = "/rpc-api/iot/device/upstream";
26 19
27 - /**  
28 - * 远程 IoT 服务的基础 URL  
29 - * 例如:http://127.0.0.1:8080  
30 - */ 20 + private final RestTemplate restTemplate;
31 private final String deviceDataUrl; 21 private final String deviceDataUrl;
32 22
  23 + // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来
  24 + // TODO @haohao:可以用 lombok 简化
  25 + public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) {
  26 + this.restTemplate = restTemplate;
  27 + this.deviceDataUrl = deviceDataUrl;
  28 + }
  29 +
33 // TODO @haohao:返回结果,不用 CommonResult 哈。 30 // TODO @haohao:返回结果,不用 CommonResult 哈。
34 @Override 31 @Override
35 public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { 32 public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
36 - String url = deviceDataUrl + "/rpc-api/iot/device-data/update-status"; 33 + String url = deviceDataUrl + URL_PREFIX + "/update-status";
37 return doPost(url, updateReqDTO, "updateDeviceStatus"); 34 return doPost(url, updateReqDTO, "updateDeviceStatus");
38 } 35 }
39 36
40 @Override 37 @Override
41 public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { 38 public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) {
42 - String url = deviceDataUrl + "/rpc-api/iot/device-data/report-event"; 39 + String url = deviceDataUrl + URL_PREFIX + "/report-event";
43 return doPost(url, reportReqDTO, "reportDeviceEventData"); 40 return doPost(url, reportReqDTO, "reportDeviceEventData");
44 } 41 }
45 42
46 @Override 43 @Override
47 public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { 44 public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {
48 - String url = deviceDataUrl + "/rpc-api/iot/device-data/report-property"; 45 + String url = deviceDataUrl + URL_PREFIX + "/report-property";
49 return doPost(url, reportReqDTO, "reportDevicePropertyData"); 46 return doPost(url, reportReqDTO, "reportDevicePropertyData");
50 } 47 }
51 48
52 -  
53 - /**  
54 - * 发送 GET 请求  
55 - *  
56 - * @param <T> 请求体类型  
57 - * @param url 请求 URL  
58 - * @param requestBody 请求体  
59 - * @param actionName 操作名称  
60 - * @return 响应结果  
61 - */  
62 - private <T> CommonResult<Boolean> doGet(String url, T requestBody, String actionName) {  
63 - log.info("[{}] Sending request to URL: {}", actionName, url);  
64 - try {  
65 - CommonResult<?> response = restTemplate.getForObject(url, CommonResult.class);  
66 - if (response != null && response.isSuccess()) {  
67 - return success(true);  
68 - } else {  
69 - log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response);  
70 - return CommonResult.error(500, "Request failed");  
71 - }  
72 - } catch (Exception e) {  
73 - log.error("[{}] Error sending request to URL: {}", actionName, url, e);  
74 - return CommonResult.error(400, "Request error: " + e.getMessage());  
75 - }  
76 - }  
77 - 49 + // TODO @haohao:未来可能有 get 类型哈
78 /** 50 /**
79 - * 发送 POST 请求  
80 - *  
81 - * @param <T> 请求体类型  
82 - * @param url 请求 URL  
83 - * @param requestBody 请求体  
84 - * @param actionName 操作名称  
85 - * @return 响应结果 51 + * 将与远程服务交互的通用逻辑抽取成一个私有方法
86 */ 52 */
87 private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) { 53 private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) {
88 log.info("[{}] Sending request to URL: {}", actionName, url); 54 log.info("[{}] Sending request to URL: {}", actionName, url);
89 try { 55 try {
90 - CommonResult<?> response = restTemplate.postForObject(url, requestBody, CommonResult.class);  
91 - if (response != null && response.isSuccess()) {  
92 - return success(true);  
93 - } else {  
94 - log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response);  
95 - return CommonResult.error(500, "Request failed");  
96 - } 56 + // 这里指定返回类型为 CommonResult<?>,根据后台服务返回的实际结构做调整
  57 + restTemplate.postForObject(url, requestBody, CommonResult.class);
  58 + // TODO @haohao:check 结果,是否成功
  59 + return success(true);
97 } catch (Exception e) { 60 } catch (Exception e) {
98 log.error("[{}] Error sending request to URL: {}", actionName, url, e); 61 log.error("[{}] Error sending request to URL: {}", actionName, url, e);
99 return CommonResult.error(400, "Request error: " + e.getMessage()); 62 return CommonResult.error(400, "Request error: " + e.getMessage());
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java
1 package cn.iocoder.yudao.module.iot.plugin.common.config; 1 package cn.iocoder.yudao.module.iot.plugin.common.config;
2 2
3 -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; 3 +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
4 import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; 4 import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient;
5 import org.springframework.beans.factory.annotation.Value; 5 import org.springframework.beans.factory.annotation.Value;
6 import org.springframework.boot.autoconfigure.AutoConfiguration; 6 import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -43,7 +43,7 @@ public class YudaoDeviceDataApiAutoConfiguration { @@ -43,7 +43,7 @@ public class YudaoDeviceDataApiAutoConfiguration {
43 * @return DeviceDataApi 实例 43 * @return DeviceDataApi 实例
44 */ 44 */
45 @Bean 45 @Bean
46 - public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { 46 + public IotDeviceUpstreamApi deviceDataApi(RestTemplate restTemplate) {
47 return new DeviceDataApiClient(restTemplate, deviceDataUrl); 47 return new DeviceDataApiClient(restTemplate, deviceDataUrl);
48 } 48 }
49 49
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java
1 package cn.iocoder.yudao.module.iot.plugin; 1 package cn.iocoder.yudao.module.iot.plugin;
2 2
3 import cn.hutool.extra.spring.SpringUtil; 3 import cn.hutool.extra.spring.SpringUtil;
4 -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; 4 +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
5 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
6 import org.pf4j.Plugin; 6 import org.pf4j.Plugin;
7 import org.pf4j.PluginWrapper; 7 import org.pf4j.PluginWrapper;
@@ -27,7 +27,7 @@ public class EmqxPlugin extends Plugin { @@ -27,7 +27,7 @@ public class EmqxPlugin extends Plugin {
27 executorService = Executors.newSingleThreadExecutor(); 27 executorService = Executors.newSingleThreadExecutor();
28 } 28 }
29 29
30 - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); 30 + IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class);
31 if (deviceDataApi == null) { 31 if (deviceDataApi == null) {
32 log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); 32 log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!");
33 return; 33 return;
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java
@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.config;
2 2
3 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
4 import cn.hutool.extra.spring.SpringUtil; 4 import cn.hutool.extra.spring.SpringUtil;
5 -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; 5 +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
6 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
7 import org.pf4j.PluginWrapper; 7 import org.pf4j.PluginWrapper;
8 import org.pf4j.spring.SpringPlugin; 8 import org.pf4j.spring.SpringPlugin;
@@ -64,7 +64,7 @@ public class HttpVertxPlugin extends SpringPlugin { @@ -64,7 +64,7 @@ public class HttpVertxPlugin extends SpringPlugin {
64 protected void prepareRefresh() { 64 protected void prepareRefresh() {
65 // 在刷新容器前注册主程序中的 Bean 65 // 在刷新容器前注册主程序中的 Bean
66 ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); 66 ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
67 - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); 67 + IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class);
68 beanFactory.registerSingleton("deviceDataApi", deviceDataApi); 68 beanFactory.registerSingleton("deviceDataApi", deviceDataApi);
69 super.prepareRefresh(); 69 super.prepareRefresh();
70 } 70 }
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java
1 package cn.iocoder.yudao.module.iot.plugin.http.config; 1 package cn.iocoder.yudao.module.iot.plugin.http.config;
2 2
3 -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; 3 +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
4 import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler; 4 import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler;
5 import io.vertx.core.Vertx; 5 import io.vertx.core.Vertx;
6 import io.vertx.ext.web.Router; 6 import io.vertx.ext.web.Router;
@@ -61,7 +61,7 @@ public class HttpVertxPluginConfiguration { @@ -61,7 +61,7 @@ public class HttpVertxPluginConfiguration {
61 * @return HttpVertxHandler 实例 61 * @return HttpVertxHandler 实例
62 */ 62 */
63 @Bean 63 @Bean
64 - public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) { 64 + public HttpVertxHandler httpVertxHandler(IotDeviceUpstreamApi deviceDataApi) {
65 return new HttpVertxHandler(deviceDataApi); 65 return new HttpVertxHandler(deviceDataApi);
66 } 66 }
67 67
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java
@@ -2,19 +2,21 @@ package cn.iocoder.yudao.module.iot.plugin.http.service; @@ -2,19 +2,21 @@ package cn.iocoder.yudao.module.iot.plugin.http.service;
2 2
3 import cn.hutool.json.JSONObject; 3 import cn.hutool.json.JSONObject;
4 import cn.hutool.json.JSONUtil; 4 import cn.hutool.json.JSONUtil;
5 -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; 5 +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; 6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
7 import io.vertx.core.Handler; 7 import io.vertx.core.Handler;
8 import io.vertx.ext.web.RequestBody; 8 import io.vertx.ext.web.RequestBody;
9 import io.vertx.ext.web.RoutingContext; 9 import io.vertx.ext.web.RoutingContext;
10 import lombok.extern.slf4j.Slf4j; 10 import lombok.extern.slf4j.Slf4j;
11 11
  12 +import java.util.Map;
  13 +
12 @Slf4j 14 @Slf4j
13 public class HttpVertxHandler implements Handler<RoutingContext> { 15 public class HttpVertxHandler implements Handler<RoutingContext> {
14 16
15 - private final DeviceDataApi deviceDataApi; 17 + private final IotDeviceUpstreamApi deviceDataApi;
16 18
17 - public HttpVertxHandler(DeviceDataApi deviceDataApi) { 19 + public HttpVertxHandler(IotDeviceUpstreamApi deviceDataApi) {
18 this.deviceDataApi = deviceDataApi; 20 this.deviceDataApi = deviceDataApi;
19 } 21 }
20 22
@@ -23,6 +25,7 @@ public class HttpVertxHandler implements Handler&lt;RoutingContext&gt; { @@ -23,6 +25,7 @@ public class HttpVertxHandler implements Handler&lt;RoutingContext&gt; {
23 String productKey = ctx.pathParam("productKey"); 25 String productKey = ctx.pathParam("productKey");
24 String deviceName = ctx.pathParam("deviceName"); 26 String deviceName = ctx.pathParam("deviceName");
25 27
  28 + // TODO @haohao:requestBody.asJsonObject() 貌似天然就是 json 对象哈?
26 RequestBody requestBody = ctx.body(); 29 RequestBody requestBody = ctx.body();
27 JSONObject jsonData; 30 JSONObject jsonData;
28 try { 31 try {
@@ -43,7 +46,7 @@ public class HttpVertxHandler implements Handler&lt;RoutingContext&gt; { @@ -43,7 +46,7 @@ public class HttpVertxHandler implements Handler&lt;RoutingContext&gt; {
43 IotDevicePropertyReportReqDTO reportReqDTO = IotDevicePropertyReportReqDTO.builder() 46 IotDevicePropertyReportReqDTO reportReqDTO = IotDevicePropertyReportReqDTO.builder()
44 .productKey(productKey) 47 .productKey(productKey)
45 .deviceName(deviceName) 48 .deviceName(deviceName)
46 - .params(jsonData) 49 + .properties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties"))
47 .build(); 50 .build();
48 51
49 deviceDataApi.reportDevicePropertyData(reportReqDTO); 52 deviceDataApi.reportDevicePropertyData(reportReqDTO);