Browse Source

【功能优化】IoT:
1. DeviceDataApi => IotDeviceUpstreamApi,并新建 upstream 包
2. ThingModelMessage => IotDeviceMessage 设备消息
3. 基于 spring event 异步消费 IotDeviceMessage,并实现 IotDeviceLogMessageConsumer 记录日志

YunaiV 10 tháng trước cách đây
mục cha
commit
8089f3a319
46 tập tin đã thay đổi với 645 bổ sung787 xóa
  1. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
  2. 20 0
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
  3. 14 19
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java
  4. 3 19
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java
  5. 4 19
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java
  6. 3 18
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java
  7. 46 0
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java
  8. 22 0
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java
  9. 22 0
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java
  10. 9 7
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java
  11. 5 5
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java
  12. 2 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
  13. 27 9
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java
  14. 0 70
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java
  15. 8 24
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java
  16. 4 4
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
  17. 1 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java
  18. 29 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java
  19. 4 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java
  20. 2 2
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java
  21. 1 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java
  22. 30 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java
  23. 34 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java
  24. 0 41
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java
  25. 4 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java
  26. 66 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java
  27. 0 4
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java
  28. 6 7
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java
  29. 4 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java
  30. 0 77
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java
  31. 5 15
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java
  32. 60 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java
  33. 2 10
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java
  34. 12 48
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java
  35. 37 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java
  36. 103 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java
  37. 2 2
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
  38. 0 21
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java
  39. 0 277
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java
  40. 16 17
      yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml
  41. 22 59
      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
  42. 2 2
      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
  43. 2 2
      yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java
  44. 2 2
      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
  45. 2 2
      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
  46. 7 4
      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

+ 1 - 1
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;
 /**
  * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能
  *
- * @author
+ * @author 芋道源码
  */
 public class TenantDatabaseInterceptor implements TenantLineHandler {
 

+ 20 - 0
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 {
      *
      * @param tenantId 租户编号
      * @param callable 逻辑
+     * @return 结果
      */
     public static <V> V execute(Long tenantId, Callable<V> callable) {
         Long oldTenantId = TenantContextHolder.getTenantId();
@@ -78,6 +79,25 @@ public class TenantUtils {
         }
     }
 
+    /**
+     * 忽略租户,执行对应的逻辑
+     *
+     * @param callable 逻辑
+     * @return 结果
+     */
+    public static <V> V executeIgnore(Callable<V> callable) {
+        Boolean oldIgnore = TenantContextHolder.isIgnore();
+        try {
+            TenantContextHolder.setIgnore(true);
+            // 执行逻辑
+            return callable.call();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            TenantContextHolder.setIgnore(oldIgnore);
+        }
+    }
+
     /**
      * 将多租户编号,添加到 header 中
      *

+ 14 - 19
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java → 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;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
 import cn.iocoder.yudao.module.iot.enums.ApiConstants;
-import jakarta.annotation.security.PermitAll;
 import jakarta.validation.Valid;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 
-// TODO 芋艿:名字可能看情况改下
 /**
- * 设备数据 API
+ * 设备数据 Upstream 上行 API
+ *
+ * 目的:设备 -> 插件 -> 服务端
  *
  * @author haohao
  */
-public interface DeviceDataApi {
+public interface IotDeviceUpstreamApi {
 
-    // TODO @芋艿:可能会调整
-    String PREFIX = ApiConstants.PREFIX + "/device-data";
+    String PREFIX = ApiConstants.PREFIX + "/device/upstream";
 
     /**
      * 更新设备状态
      *
-     * @param updateReqDTO 更新请求
+     * @param updateReqDTO 更新设备状态 DTO
      */
     @PutMapping(PREFIX + "/update-status")
-    @PermitAll  // TODO 芋艿:后续看看怎么优化下
     CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqDTO updateReqDTO);
 
-    /**
-     * 上报设备事件数据
-     *
-     * @param reportReqDTO 设备事件
-     */
-    @PostMapping(PREFIX + "/report-event")
-    @PermitAll // TODO 芋艿:后续看看怎么优化下
-    CommonResult<Boolean> reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO);
-
     /**
      * 上报设备属性数据
      *
-     * @param reportReqDTO 设备数据
+     * @param reportReqDTO 上报设备属性数据 DTO
      */
     @PostMapping(PREFIX + "/report-property")
-    @PermitAll // TODO 芋艿:后续看看怎么优化下
     CommonResult<Boolean> reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO);
 
+    /**
+     * 上报设备事件数据
+     *
+     * @param reportReqDTO 设备事件
+     */
+    @PostMapping(PREFIX + "/report-event")
+    CommonResult<Boolean> reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO);
 
 }

+ 3 - 19
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java

@@ -1,10 +1,9 @@
 package cn.iocoder.yudao.module.iot.api.device.dto;
 
 import jakarta.validation.constraints.NotEmpty;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
 
 import java.util.Map;
 
@@ -12,24 +11,9 @@ import java.util.Map;
  * IoT 设备【事件】数据上报 Request DTO
  */
 @Data
+@SuperBuilder
 @NoArgsConstructor
-@AllArgsConstructor
-@Builder
-public class IotDeviceEventReportReqDTO {
-
-    // TODO 芋艿:要不要 id
-    // TODO 芋艿:要不要 time
-
-    /**
-     * 产品标识
-     */
-    @NotEmpty(message = "产品标识不能为空")
-    private String productKey;
-    /**
-     * 设备名称
-     */
-    @NotEmpty(message = "设备名称不能为空")
-    private String deviceName;
+public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
 
     /**
      * 事件标识

+ 4 - 19
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java

@@ -1,10 +1,9 @@
 package cn.iocoder.yudao.module.iot.api.device.dto;
 
 import jakarta.validation.constraints.NotEmpty;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
 
 import java.util.Map;
 
@@ -12,28 +11,14 @@ import java.util.Map;
  * IoT 设备【属性】数据上报 Request DTO
  */
 @Data
+@SuperBuilder
 @NoArgsConstructor
-@AllArgsConstructor
-@Builder
-public class IotDevicePropertyReportReqDTO {
+public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
 
-    // TODO 芋艿:要不要 id
-    // TODO 芋艿:要不要 time
-
-    /**
-     * 产品标识
-     */
-    @NotEmpty(message = "产品标识不能为空")
-    private String productKey;
-    /**
-     * 设备名称
-     */
-    @NotEmpty(message = "设备名称不能为空")
-    private String deviceName;
     /**
      * 属性参数
      */
     @NotEmpty(message = "属性参数不能为空")
-    private Map<String, Object> params;
+    private Map<String, Object> properties;
 
 }

+ 3 - 18
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;
 import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
 import jakarta.validation.constraints.NotEmpty;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
 
 /**
  * IoT 设备状态更新 Request DTO
  */
 @Data
+@SuperBuilder
 @NoArgsConstructor
-@AllArgsConstructor
-@Builder
-public class IotDeviceStatusUpdateReqDTO {
+public class IotDeviceStatusUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO {
 
-    // TODO 芋艿:要不要 id
-    // TODO 芋艿:要不要 time
-
-    /**
-     * 产品标识
-     */
-    @NotEmpty(message = "产品标识不能为空")
-    private String productKey;
-    /**
-     * 设备名称
-     */
-    @NotEmpty(message = "设备名称不能为空")
-    private String deviceName;
     /**
      * 设备状态
      */

+ 46 - 0
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java

@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.iot.api.device.dto;
+
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+
+import java.time.LocalDateTime;
+
+/**
+ * IoT 设备上行的抽象 Request DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+@SuperBuilder
+@NoArgsConstructor
+public abstract class IotDeviceUpstreamAbstractReqDTO {
+
+    /**
+     * 请求编号
+     */
+    private String requestId;
+
+    /**
+     * 插件标识
+     */
+    private String pluginKey;
+
+    /**
+     * 产品标识
+     */
+    @NotEmpty(message = "产品标识不能为空")
+    private String productKey;
+    /**
+     * 设备名称
+     */
+    @NotEmpty(message = "设备名称不能为空")
+    private String deviceName;
+
+    /**
+     * 上报时间
+     */
+    private LocalDateTime reportTime;
+
+}

+ 22 - 0
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.iot.enums.device;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * IoT 设备消息标识符枚举
+ */
+@Getter
+@RequiredArgsConstructor
+public enum IotDeviceMessageIdentifierEnum {
+
+    PROPERTY_GET("get"),
+    PROPERTY_SET("set"),
+    PROPERTY_REPORT("report");
+
+    /**
+     * 标志符
+     */
+    private final String identifier;
+
+}

+ 22 - 0
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.iot.enums.device;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * IoT 设备消息类型枚举
+ */
+@Getter
+@RequiredArgsConstructor
+public enum IotDeviceMessageTypeEnum {
+
+    STATE("state"), // 设备状态
+    PROPERTY("property"), // 设备属性
+    EVENT("event"); // 设备事件
+
+    /**
+     * 属性
+     */
+    private final String type;
+
+}

+ 9 - 7
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java → 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;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
-import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService;
+import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -13,28 +13,30 @@ import javax.annotation.Resource;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
 /**
- * 设备数据 API 实现类
+ *  * 设备数据 Upstream 上行 API 实现类
  */
 @RestController
 @Validated
-public class DeviceDataApiImpl implements DeviceDataApi {
+public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
 
     @Resource
-    private IotDevicePropertyDataService deviceDataService;
+    private IotDeviceUpstreamService deviceUpstreamService;
 
     @Override
     public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
+        deviceUpstreamService.updateDeviceStatus(updateReqDTO);
         return success(true);
     }
 
     @Override
-    public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) {
+    public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {
+        deviceUpstreamService.reportDevicePropertyData(reportReqDTO);
         return success(true);
     }
 
     @Override
-    public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {
-        deviceDataService.saveDeviceData(reportReqDTO);
+    public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) {
+        deviceUpstreamService.reportDeviceEventData(reportReqDTO);
         return success(true);
     }
 

+ 5 - 5
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;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
-import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService;
-import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService;
+import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
+import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.annotation.Resource;
@@ -27,13 +27,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 public class IotDeviceDataController {
 
     @Resource
-    private IotDevicePropertyDataService deviceDataService;
+    private IotDevicePropertyService deviceDataService;
 
     @Resource
-    private IotDeviceLogDataService iotDeviceLogDataService;
+    private IotDeviceLogService iotDeviceLogDataService;
 
     @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性
-    private IotDeviceLogDataService deviceLogDataService;
+    private IotDeviceLogService deviceLogDataService;
 
     // TODO @浩浩:这里的 /latest-list,包括方法名。
     @GetMapping("/latest")

+ 2 - 0
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 {
     private Long id;
     /**
      * 设备唯一标识符,全局唯一,用于识别设备
+     *
+     * 类似阿里云 <a href="https://help.aliyun.com/zh/iot/developer-reference/api-querydeviceinfo">QueryDeviceInfo</a> 的 IotInstanceId
      */
     private String deviceKey;
     /**

+ 27 - 9
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java

@@ -1,6 +1,10 @@
 package cn.iocoder.yudao.module.iot.dal.dataobject.device;
 
+import cn.hutool.core.util.IdUtil;
 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
+import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
@@ -19,37 +23,51 @@ import lombok.NoArgsConstructor;
 @AllArgsConstructor
 public class IotDeviceLogDO {
 
-    // TODO @芋艿:消息 ID 的生成逻辑
     /**
-     * 消息 ID
+     * 日志编号
+     *
+     * 通过 {@link IdUtil#fastSimpleUUID()} 生成
      */
     private String id;
 
+    /**
+     * 请求编号
+     *
+     * 对应 {@link IotDeviceMessage#getRequestId()} 字段
+     */
+    private String requestId;
+
     /**
      * 产品标识
      * <p>
      * 关联 {@link IotProductDO#getProductKey()}
      */
     private String productKey;
-
+    /**
+     * 设备名称
+     *
+     * 关联 {@link IotDeviceDO#getDeviceName()}
+     */
+    private String deviceName;
     /**
      * 设备标识
      * <p>
      * 关联 {@link IotDeviceDO#getDeviceKey()}}
      */
-    private String deviceKey;
+    private String deviceKey; // 非存储字段,用于 TDengine 的 TAG
 
-    // TODO @super:枚举类
     /**
      * 日志类型
+     *
+     * 枚举 {@link IotDeviceMessageTypeEnum}
      */
     private String type;
-
-    // TODO @super:枚举类
     /**
-     * 标识符:用于标识具体的属性、事件或服务
+     * 标识符
+     *
+     * 枚举 {@link IotDeviceMessageIdentifierEnum}
      */
-    private String subType;
+    private String identifier;
 
     /**
      * 数据内容

+ 0 - 70
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java

@@ -1,70 +0,0 @@
-package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 物模型消息
- */
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-@Builder
-public class ThingModelMessage {
-
-    /**
-     * 消息ID
-     */
-    private String id;
-
-    /**
-     * 扩展功能的参数
-     */
-    private Object sys;
-
-    /**
-     * 请求方法 例如:thing.event.property.post
-     */
-    private String method;
-
-    /**
-     * 请求参数
-     */
-    private Object params;
-
-    /**
-     * 属性上报时间戳
-     */
-    private Long time;
-
-    /**
-     * 设备信息
-     */
-    private String productKey;
-
-    /**
-     * 设备名称
-     */
-    private String deviceName;
-
-    /**
-     * 设备 key
-     */
-    private String deviceKey;
-
-    /**
-     * 转换为 Map 类型
-     */
-    public Map<String, Object> dataToMap() {
-        Map<String, Object> mapData = new HashMap<>();
-        if (params instanceof Map) {
-            ((Map<?, ?>) params).forEach((key, value) -> mapData.put(key.toString(), value));
-        }
-        return mapData;
-    }
-}

+ 8 - 24
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 {
      */
     void createDeviceLogSTable();
 
-    // TODO @super:单个参数,不用加 @Param
-    // TODO @芋艿:在瞅瞅
-    //讨论:艿菇这里有些特殊情况,我也学习了一下这块知识:
-    // 如果使用的是Java 8及以上版本,并且编译器保留了参数名(通过编译器选项-parameters启用),则可以去掉@Param注解。MyBatis会自动使用参数的实际名称
-    // 但在TDengine中 @Param去掉后TDengine会报错,以下是大模型的回答:
-    // 不用加 @Param在普通的 MySQL 场景下是正确的 - 对于 MyBatis,当方法只有一个参数时,确实可以不用添加 @Param 注解。
-    //但是在 TDengine 的场景下,情况不同:
-    //TDengine 的特殊性:
-    //TDengine 使用特殊的 SQL 语法
-    //需要处理超级表(STable)和子表的概念
-    //参数绑定的方式与普通 MySQL 不同
-    //为什么这里必须要 @Param:
-    //XML 中使用了 ${log.deviceKey} 这样的参数引用方式
-    //需要在 SQL 中动态构建表名(device_log_${log.deviceKey})
-    //没有 @Param("log") 的话,MyBatis 无法正确解析参数
+    /**
+     * 查询设备日志表是否存在
+     *
+     * @return 存在则返回表名;不存在则返回 null
+     */
+    String showDeviceLogSTable();
+
     /**
      * 插入设备日志数据
      *
@@ -44,7 +36,7 @@ public interface IotDeviceLogDataMapper {
      *
      * @param log 设备日志数据
      */
-    void insert(@Param("log") IotDeviceLogDO log);
+    void insert(IotDeviceLogDO log);
 
     /**
      * 获得设备日志分页
@@ -62,12 +54,4 @@ public interface IotDeviceLogDataMapper {
      */
     Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO);
 
-    // TODO @芋艿:这个方法名,后续看看叫啥好
-    /**
-     * 查询设备日志表是否存在
-     *
-     * @return 不存在返回 null
-     */
-    Object checkDeviceLogSTableExists();
-
 }

+ 4 - 4
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.iot.emq.service;
 
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
-import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService;
+import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.eclipse.paho.client.mqttv3.MqttClient;
@@ -20,7 +20,7 @@ import org.springframework.scheduling.annotation.Async;
 public class EmqxServiceImpl implements EmqxService {
 
     @Resource
-    private IotDevicePropertyDataService iotDeviceDataService;
+    private IotDevicePropertyService iotDeviceDataService;
 
     // TODO 多线程处理消息
     @Override
@@ -35,8 +35,8 @@ public class EmqxServiceImpl implements EmqxService {
             String deviceName = topic.split("/")[3];
             String message = new String(mqttMessage.getPayload());
             IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder()
-                    .productKey(productKey)
-                    .deviceName(deviceName)
+//                    .productKey(productKey)
+//                    .deviceName(deviceName)
 //                    .properties(message) // TODO 芋艿:临时去掉,看看
                     .build();
             iotDeviceDataService.saveDeviceData(createDTO);

+ 1 - 0
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;
 import java.sql.Timestamp;
 import java.util.Map;
 
+// TODO @haohao:这个还需要的么?
 /**
  * TaosAspect 是一个处理 Taos 数据库返回值的切面。
  */

+ 29 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.iot.framework.security.config;
+
+import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
+import cn.iocoder.yudao.module.iot.enums.ApiConstants;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
+
+/**
+ * IoT 模块的 Security 配置
+ */
+@Configuration(proxyBeanMethods = false, value = "iotSecurityConfiguration")
+public class SecurityConfiguration {
+
+    @Bean("iotAuthorizeRequestsCustomizer")
+    public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
+        return new AuthorizeRequestsCustomizer() {
+
+            @Override
+            public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
+                // RPC 服务的安全配置
+                registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
+            }
+
+        };
+    }
+
+}

+ 4 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 占位
+ */
+package cn.iocoder.yudao.module.iot.framework.security.core;

+ 2 - 2
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.module.iot.framework.tdengine.config;
 
-import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService;
+import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.ApplicationArguments;
@@ -17,7 +17,7 @@ import org.springframework.context.annotation.Configuration;
 @RequiredArgsConstructor
 public class TDengineTableInitConfiguration implements ApplicationRunner {
 
-    private final IotDeviceLogDataService deviceLogService;
+    private final IotDeviceLogService deviceLogService;
 
     @Override
     public void run(ApplicationArguments args) {

+ 1 - 0
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;
 import javax.annotation.Resource;
 import java.util.concurrent.TimeUnit;
 
+// TODO 芋艿:后续再看看
 /**
  * 插件实例 Job
  *

+ 30 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.iot.mq.consumer.device;
+
+import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
+import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+/**
+ * 针对 {@link IotDeviceMessage} 的消费者,记录设备日志
+ *
+ * @author 芋道源码
+ */
+@Component
+@Slf4j
+public class IotDeviceLogMessageConsumer {
+
+    @Resource
+    private IotDeviceLogService deviceLogService;
+
+    @EventListener
+    @Async
+    public void onMessage(IotDeviceMessage message) {
+        log.info("[onMessage][消息内容({})]", message);
+        deviceLogService.createDeviceLog(message);
+    }
+
+}

+ 34 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.iot.mq.consumer.device;
+
+import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
+import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 针对 {@link IotDeviceMessage} 的消费者,记录设备属性
+ *
+ * @author alwayssuper
+ */
+@Component
+@Slf4j
+public class IotDevicePropertyMessageConsumer {
+
+    @Resource
+    private IotDevicePropertyService deviceDataService;
+
+    @EventListener
+    @Async
+    public void onMessage(IotDeviceMessage message) {
+        log.info("[onMessage][消息内容({})]", message);
+
+        // 设备日志记录
+        // TODO @芋艿:重新写下
+//        deviceLogDataService.createDeviceLog(message);
+    }
+
+}

+ 0 - 41
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java

@@ -1,41 +0,0 @@
-package cn.iocoder.yudao.module.iot.mq.consumer.deviceconsumer;
-
-
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
-import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService;
-import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.event.EventListener;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link ThingModelMessage} 的消费者
- *
- * @author alwayssuper
- */
-@Component
-@Slf4j
-public class DeviceConsumer {
-
-    @Resource
-    private IotDeviceLogDataService deviceLogDataService;
-    @Resource
-    private IotDevicePropertyDataService deviceDataService;
-
-    // TODO @芋艿:这块先用ThingModelMessage,后续看看用啥替代
-    @EventListener
-    @Async
-    public void onMessage(ThingModelMessage message) {
-        log.info("[onMessage][消息内容({})]", message);
-        //TODO:数据插入这块整体写的比较混乱,整体借鉴了浩浩哥之前写的逻辑,目前是通过模拟设备科插入数据了,但之前的逻辑有大量弃用的部分,后续看看怎么完善
-
-        // 设备数据记录
-        deviceDataService.saveDeviceDataTest(message);
-        // 设备日志记录
-        deviceLogDataService.saveDeviceLog(message);
-    }
-
-}

+ 4 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * TODO 芋艿:未来实现一个 IotRuleMessageConsumer
+ */
+package cn.iocoder.yudao.module.iot.mq.consumer.rule;

+ 66 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java

@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.iot.mq.message;
+
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 设备消息
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class IotDeviceMessage {
+
+    /**
+     * 请求编号
+     */
+    private String requestId;
+
+    /**
+     * 设备信息
+     */
+    private String productKey;
+    /**
+     * 设备名称
+     */
+    private String deviceName;
+    /**
+     * 设备标识
+     */
+    private String deviceKey;
+
+    /**
+     * 消息类型
+     *
+     * 枚举 {@link IotDeviceMessageTypeEnum}
+     */
+    private String type;
+    /**
+     * 标识符
+     *
+     * 枚举 {@link IotDeviceMessageIdentifierEnum}
+     */
+    private String identifier;
+
+    /**
+     * 请求参数
+     *
+     * 例如说:属性上报的 properties、事件上报的 params
+     */
+    private Object data;
+
+    /**
+     * 上报时间
+     */
+    private LocalDateTime reportTime;
+
+    // TODO @芋艿 code;
+
+}

+ 0 - 4
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 消息队列的消息
- */
-package cn.iocoder.yudao.module.iot.mq.message;

+ 6 - 7
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java → yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java

@@ -1,31 +1,30 @@
-package cn.iocoder.yudao.module.iot.mq.producer.simulatesend;
+package cn.iocoder.yudao.module.iot.mq.producer.device;
 
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
+import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.ApplicationContext;
 import org.springframework.stereotype.Component;
 
-// TODO @芋艿:@alwayssuper:是不是还没用起来哈?Producer 最好属于某个模块;
 /**
- * SimulateSend 模拟设备上报的 Producer
+ * Iot 设备相关消息的 Producer
  *
  * @author alwayssuper
  * @since 2024/12/17 16:35
  */
 @Slf4j
 @Component
-public class SimulateSendProducer {
+public class IotDeviceProducer {
 
     @Resource
     private ApplicationContext applicationContext;
 
     /**
-     * 发送 {@link ThingModelMessage} 消息
+     * 发送 {@link IotDeviceMessage} 消息
      *
      * @param thingModelMessage 物模型消息
      */
-    public void sendSimulateMessage(ThingModelMessage thingModelMessage) {
+    public void sendDeviceMessage(IotDeviceMessage thingModelMessage) {
         applicationContext.publishEvent(thingModelMessage);
     }
 

+ 4 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * TODO 芋艿:临时占位
+ */
+package cn.iocoder.yudao.module.iot.mq.producer;

+ 0 - 77
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java

@@ -1,77 +0,0 @@
-package cn.iocoder.yudao.module.iot.service.device;
-
-import cn.hutool.json.JSONUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
-import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.List;
-
-/**
- * IoT 设备日志数据 Service 实现了
- *
- * @author alwayssuper
- */
-@Service
-@Slf4j
-@Validated
-public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{
-
-    @Resource
-    private IotDeviceLogDataMapper deviceLogDataMapper;
-
-    @Override
-    public void defineDeviceLog() {
-        if (deviceLogDataMapper.checkDeviceLogSTableExists() != null) {
-            log.info("[defineDeviceLog][设备日志超级表已存在,跳过创建]");
-            return;
-        }
-
-        log.info("[defineDeviceLog][设备日志超级表不存在,开始创建]");
-        deviceLogDataMapper.createDeviceLogSTable();
-        log.info("[defineDeviceLog][设备日志超级表不存在,创建完成]");
-    }
-
-    @Override
-    public void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) {
-        // 1. 转换请求对象为 DO
-        IotDeviceLogDO iotDeviceLogDO = BeanUtils.toBean(simulatorReqVO, IotDeviceLogDO.class);
-
-        // 2. 处理时间字段
-//        iotDeviceLogDO.setTs(currentTime); // TODO @super:TS在SQL中直接NOW   咱们的TS数据获取是走哪一种;走 now()
-
-        // 3. 插入数据
-        deviceLogDataMapper.insert(iotDeviceLogDO);
-    }
-
-    @Override
-    public PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) {
-        // TODO @芋艿:增加一个表不存在的 try catch
-        List<IotDeviceLogDO> list = deviceLogDataMapper.selectPage(pageReqVO);
-        Long total = deviceLogDataMapper.selectCount(pageReqVO);
-        return new PageResult<>(list, total);
-    }
-
-    @Override
-    public void saveDeviceLog(ThingModelMessage message) {
-        IotDeviceLogDO log = IotDeviceLogDO.builder()
-                .id(message.getId())
-                .deviceKey(message.getDeviceKey())
-                .productKey(message.getProductKey())
-                .type(message.getMethod())               // 消息类型,使用method作为类型 TODO 芋艿:在看看
-                .subType("property")                 // TODO 芋艿:这块先写死,后续优化
-                .content(JSONUtil.toJsonStr(message))   // TODO 芋艿:后续优化
-                .reportTime(message.getTime()) // 上报时间 TODO 芋艿:在想想时间
-                .build();
-        deviceLogDataMapper.insert(log);
-    }
-
-}

+ 5 - 15
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java → yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java

@@ -1,17 +1,16 @@
-package cn.iocoder.yudao.module.iot.service.device;
+package cn.iocoder.yudao.module.iot.service.device.data;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
+import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
 
 /**
  * IoT 设备日志数据 Service 接口
  *
  * @author alwayssuper
  */
-public interface IotDeviceLogDataService {
+public interface IotDeviceLogService {
 
     /**
      * 初始化 TDengine 超级表
@@ -23,11 +22,9 @@ public interface IotDeviceLogDataService {
     /**
      * 插入设备日志
      *
-     * 当该设备第一次插入日志时,自动创建该设备的设备日志子表
-     *
-     * @param simulatorReqVO 设备日志模拟数据
+     * @param message 设备数据
      */
-    void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO);
+    void createDeviceLog(IotDeviceMessage message);
 
     /**
      * 获得设备日志分页
@@ -37,11 +34,4 @@ public interface IotDeviceLogDataService {
      */
     PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO);
 
-    /**
-     * 插入设备日志
-     *
-     * @param message 设备数据
-     */
-    void saveDeviceLog(ThingModelMessage message);
-
 }

+ 60 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java

@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.iot.service.device.data;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
+import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper;
+import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.List;
+
+/**
+ * IoT 设备日志数据 Service 实现类
+ *
+ * @author alwayssuper
+ */
+@Service
+@Slf4j
+@Validated
+public class IotDeviceLogServiceImpl implements IotDeviceLogService {
+
+    @Resource
+    private IotDeviceLogDataMapper deviceLogDataMapper;
+
+    @Override
+    public void defineDeviceLog() {
+        if (StrUtil.isNotEmpty(deviceLogDataMapper.showDeviceLogSTable())) {
+            log.info("[defineDeviceLog][设备日志超级表已存在,创建跳过]");
+            return;
+        }
+
+        log.info("[defineDeviceLog][设备日志超级表不存在,创建开始...]");
+        deviceLogDataMapper.createDeviceLogSTable();
+        log.info("[defineDeviceLog][设备日志超级表不存在,创建成功]");
+    }
+
+    @Override
+    public void createDeviceLog(IotDeviceMessage message) {
+        IotDeviceLogDO log = BeanUtils.toBean(message, IotDeviceLogDO.class)
+                .setId(IdUtil.fastSimpleUUID())
+                .setContent(JsonUtils.toJsonString(message.getData()));
+        deviceLogDataMapper.insert(log);
+    }
+
+    @Override
+    public PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) {
+        // TODO @芋艿:增加一个表不存在的 try catch
+        List<IotDeviceLogDO> list = deviceLogDataMapper.selectPage(pageReqVO);
+        Long total = deviceLogDataMapper.selectCount(pageReqVO);
+        return new PageResult<>(list, total);
+    }
+
+}

+ 2 - 10
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java → yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java

@@ -1,11 +1,10 @@
-package cn.iocoder.yudao.module.iot.service.device;
+package cn.iocoder.yudao.module.iot.service.device.data;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
 import jakarta.validation.Valid;
 
 import java.util.List;
@@ -16,7 +15,7 @@ import java.util.Map;
  *
  * @author 芋道源码
  */
-public interface IotDevicePropertyDataService {
+public interface IotDevicePropertyService {
 
     /**
      * 定义设备属性数据的结构
@@ -32,13 +31,6 @@ public interface IotDevicePropertyDataService {
      */
     void saveDeviceData(IotDevicePropertyReportReqDTO createDTO);
 
-    /**
-     * 保存设备数据
-     *
-     * @param thingModelMessage 设备数据
-     */
-    void saveDeviceDataTest(ThingModelMessage thingModelMessage);
-
     /**
      * 模拟设备
      *

+ 12 - 48
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java → yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java

@@ -1,9 +1,8 @@
-package cn.iocoder.yudao.module.iot.service.device;
+package cn.iocoder.yudao.module.iot.service.device.data;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
@@ -16,18 +15,15 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
 import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;
 import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper;
-import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper;
 import cn.iocoder.yudao.module.iot.enums.IotConstants;
 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
 import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField;
-import cn.iocoder.yudao.module.iot.mq.producer.simulatesend.SimulateSendProducer;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
-import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService;
 import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
 import jakarta.annotation.Resource;
 import jakarta.validation.Valid;
@@ -53,7 +49,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_C
  */
 @Service
 @Slf4j
-public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataService {
+public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
 
     /**
      * 物模型的数据类型,与 TDengine 数据类型的映射关系
@@ -76,25 +72,16 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe
     @Resource
     private IotDeviceService deviceService;
     @Resource
-    private IotThingModelMessageService thingModelMessageService;
-    @Resource
     private IotThingModelService thingModelService;
     @Resource
     private IotProductService productService;
 
-    @Resource
-    private SimulateSendProducer simulateSendProducer;
-
-    @Resource
-    private TdEngineDMLMapper tdEngineDMLMapper;
-
     @Resource
     private DeviceDataRedisDAO deviceDataRedisDAO;
 
     @Resource
     private IotDevicePropertyDataMapper devicePropertyDataMapper;
 
-
     @Override
     public void defineDevicePropertyData(Long productId) {
         // 1.1 查询产品和物模型
@@ -144,28 +131,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe
         // 1. 根据产品 key 和设备名称,获得设备信息
         IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName());
         // 2. 解析消息,保存数据
-        JSONObject jsonObject = new JSONObject(createDTO.getParams());
+        JSONObject jsonObject = new JSONObject(createDTO.getProperties());
         log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject);
-        ThingModelMessage thingModelMessage = ThingModelMessage.builder()
-                .id(jsonObject.getStr("id"))
-                .sys(jsonObject.get("sys"))
-                .method(jsonObject.getStr("method"))
-                .params(jsonObject.get("params"))
-                .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time"))
-                .productKey(createDTO.getProductKey())
-                .deviceName(createDTO.getDeviceName())
-                .deviceKey(device.getDeviceKey())
-                .build();
-        thingModelMessageService.saveThingModelMessage(device, thingModelMessage);
-    }
-
-    //TODO @芋艿:后续捋一捋这块逻辑,先借鉴一下目前的代码
-    @Override
-    public void saveDeviceDataTest(ThingModelMessage thingModelMessage) {
-        // 1. 根据产品 key 和设备名称,获得设备信息
-        IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(thingModelMessage.getProductKey(), thingModelMessage.getDeviceName());
-        // 2. 保存数据
-        thingModelMessageService.saveThingModelMessage(device, thingModelMessage);
     }
 
     //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化
@@ -182,20 +149,17 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe
             throw exception(DEVICE_DATA_CONTENT_JSON_PARSE_ERROR);
         }
 
+        // TODO @芋艿:后续优化
         // 3. 构建物模型消息
-        ThingModelMessage thingModelMessage = ThingModelMessage.builder()
-                .id(IdUtil.fastSimpleUUID()) // TODO:后续优化
-                .sys(null)// TODO:这块先写死,后续优化
-                .method("thing.event.property.post") // TODO:这块先写死,后续优化
-                .params(contentJson) // 将 content 作为 params
-                .time(simulatorReqVO.getReportTime()) // 使用上报时间
-                .productKey(simulatorReqVO.getProductKey())
-                .deviceName(device.getDeviceName())
-                .deviceKey(device.getDeviceKey())
-                .build();
+//        IotDeviceMessage thingModelMessage = IotDeviceMessage.builder()
+//                .params(contentJson) // 将 content 作为 params
+//                .time(simulatorReqVO.getReportTime()) // 使用上报时间
+//                .productKey(simulatorReqVO.getProductKey())
+//                .deviceName(device.getDeviceName())
+//                .build();
 
         // 4. 发送模拟消息
-        simulateSendProducer.sendSimulateMessage(thingModelMessage);
+//        simulateSendProducer.sendDeviceMessage(thingModelMessage);
     }
 
     @Override

+ 37 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.iot.service.device.upstream;
+
+import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
+
+/**
+ * 设备上行 Service 接口
+ *
+ * 目的:设备 -> 插件 -> 服务端
+ *
+ * @author 芋道源码
+ */
+public interface IotDeviceUpstreamService {
+
+    /**
+     * 更新设备状态
+     *
+     * @param updateReqDTO 更新设备状态 DTO
+     */
+    void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO);
+
+    /**
+     * 上报设备属性数据
+     *
+     * @param reportReqDTO 上报设备属性数据 DTO
+     */
+    void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO);
+
+    /**
+     * 上报设备事件数据
+     *
+     * @param reportReqDTO 设备事件
+     */
+    void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO);
+
+}

+ 103 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java

@@ -0,0 +1,103 @@
+package cn.iocoder.yudao.module.iot.service.device.upstream;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
+import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceUpstreamAbstractReqDTO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
+import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
+import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+
+/**
+ * 设备上行 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+@Slf4j
+public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
+
+    @Resource
+    private IotDeviceService deviceService;
+
+    @Resource
+    private IotDeviceProducer deviceProducer;
+
+    @Override
+    public void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
+        log.info("[updateDeviceStatus][更新设备状态: {}]", updateReqDTO);
+        // TODO 芋艿:插件状态
+    }
+
+    @Override
+    public void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {
+        // 1.1 获得设备
+        log.info("[reportDevicePropertyData][上报设备属性数据: {}]", reportReqDTO);
+        IotDeviceDO device = getDevice(reportReqDTO);
+        if (device == null) {
+            log.error("[reportDevicePropertyData][设备({}/{})不存在]",
+                    reportReqDTO.getProductKey(), reportReqDTO.getDeviceName());
+            return;
+        }
+        // 1.2 记录设备的最后时间
+        updateDeviceLastTime(device, reportReqDTO);
+
+        // 2. 发送设备消息
+        IotDeviceMessage message = BeanUtils.toBean(reportReqDTO, IotDeviceMessage.class)
+                .setType(IotDeviceMessageTypeEnum.PROPERTY.getType())
+                .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())
+                .setData(reportReqDTO.getProperties());
+        sendDeviceMessage(message, device);
+    }
+
+    @Override
+    public void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) {
+        log.info("[reportDeviceEventData][上报设备事件数据: {}]", reportReqDTO);
+
+        // TODO 芋艿:待实现
+    }
+
+    private IotDeviceDO getDevice(IotDeviceUpstreamAbstractReqDTO reqDTO) {
+        return TenantUtils.executeIgnore(() -> // 需要忽略租户,因为请求时,未带租户编号
+                deviceService.getDeviceByProductKeyAndDeviceName(reqDTO.getProductKey(), reqDTO.getDeviceName()));
+    }
+
+    private void updateDeviceLastTime(IotDeviceDO deviceDO, IotDeviceUpstreamAbstractReqDTO reqDTO) {
+        // TODO 芋艿:插件状态
+        // TODO 芋艿:操作时间
+    }
+
+    private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) {
+        // 1. 完善消息
+        message.setDeviceKey(device.getDeviceKey());
+        if (StrUtil.isEmpty(message.getRequestId())) {
+            message.setRequestId(IdUtil.fastSimpleUUID());
+        }
+        if (message.getReportTime() == null) {
+            message.setReportTime(LocalDateTime.now());
+        }
+
+        // 2. 发送消息
+        try {
+            deviceProducer.sendDeviceMessage(message);
+            log.info("[sendDeviceMessage][message({}) 发送消息成功]", message);
+        } catch (Exception e) {
+            log.error("[sendDeviceMessage][message({}) 发送消息失败]", message, e);
+        }
+    }
+
+}

+ 2 - 2
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
 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
 import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper;
 import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
-import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService;
+import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Lazy;
@@ -35,7 +35,7 @@ public class IotProductServiceImpl implements IotProductService {
 
     @Resource
     @Lazy  // 延迟加载,解决循环依赖
-    private IotDevicePropertyDataService devicePropertyDataService;
+    private IotDevicePropertyService devicePropertyDataService;
 
     @Override
     public Long createProduct(IotProductSaveReqVO createReqVO) {

+ 0 - 21
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java

@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.iot.service.tdengine;
-
-import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
-
-/**
- * 物模型消息 Service
- */
-public interface IotThingModelMessageService {
-
-    /**
-     * 保存物模型消息
-     *
-     * @param device            设备
-     * @param thingModelMessage 物模型消息
-     */
-    void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage);
-
-
-
-}

+ 0 - 277
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java

@@ -1,277 +0,0 @@
-package cn.iocoder.yudao.module.iot.service.tdengine;
-
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
-import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
-import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;
-import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper;
-import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper;
-import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper;
-import cn.iocoder.yudao.module.iot.enums.IotConstants;
-import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
-import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
-import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
-import cn.iocoder.yudao.module.iot.service.product.IotProductService;
-import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
-
-/**
- * 物模型消息 Service 实现类
- */
-@Slf4j
-@Service
-public class IotThingModelMessageServiceImpl implements IotThingModelMessageService {
-
-    private static final String TAG_NOTE = "TAG";
-    private static final String NOTE = "note";
-    private static final String TIME = "time";
-    private static final String DEVICE_KEY = "device_key";
-    private static final String DEVICE_NAME = "device_name";
-    private static final String PRODUCT_KEY = "product_key";
-    private static final String DEVICE_TYPE = "device_type";
-
-    @Value("${spring.datasource.dynamic.datasource.tdengine.url}")
-    private String url;
-
-    @Resource
-    private IotThingModelService iotThingModelService;
-    @Resource
-    private IotDeviceService iotDeviceService;
-    @Resource
-    private IotProductService productService;
-
-    @Resource
-    private TdEngineDDLMapper tdEngineDDLMapper;
-    @Resource
-    private TdEngineDMLMapper tdEngineDMLMapper;
-
-    @Resource
-    private IotDevicePropertyDataMapper iotDevicePropertyDataMapper;
-
-    @Resource
-    private DeviceDataRedisDAO deviceDataRedisDAO;
-    
-    // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感
-    @Override
-    @TenantIgnore
-    public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) {
-        // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态
-        if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) {
-            // 1.1 创建设备表
-//            createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
-            iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO()
-                    .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus()));
-        }
-
-        // 2. 获取设备属性并进行物模型校验,过滤非物模型属性
-        Map<String, Object> params = thingModelMessage.dataToMap();
-        List<IotThingModelDO> thingModelList = getValidThingModelList(thingModelMessage.getProductKey());
-        if (thingModelList.isEmpty()) {
-            return;
-        }
-
-        // 3. 过滤并收集有效的属性字段,缓存设备属性
-        List<TdFieldDO> schemaFieldValues = filterAndCollectValidFields(params, thingModelList, device, thingModelMessage.getTime());
-        if (schemaFieldValues.size() == 0) { // 没有字段,无需保存
-            return;
-        }
-
-        // 4. 构建并保存设备属性数据
-//        tdEngineDMLMapper.insertData(TdTableDO.builder()
-//                .dataBaseName(getDatabaseName())
-//                .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()))
-//                .columns(schemaFieldValues)
-//                .build());
-        // TODO:复用了旧逻辑,先过渡一下
-        iotDevicePropertyDataMapper.insertDevicePropertyData(TdTableDO.builder()
-                .productKey(device.getProductKey())
-                .deviceKey(device.getDeviceKey())
-                .columns(schemaFieldValues)
-                .build());
-    }
-
-    private List<IotThingModelDO> getValidThingModelList(String productKey) {
-        return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey),
-                thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType()));
-    }
-
-//    @Override
-//    @TenantIgnore
-//    public void createSuperTable(Long productId) {
-//        // 1. 查询产品
-//        IotProductDO product = productService.getProduct(productId);
-//        // 2. 创建日志超级表
-//        tdThingModelMessageMapper.createSuperTable(product.getProductKey());
-//
-//        // 2. 获取超级表的名称和数据库名称
-//        // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法
-////        String databaseName = IotTdDatabaseUtils.getDatabaseName(url);
-////        String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey());
-////
-////        // 解析物模型,获取字段列表
-////        List<TdFieldDO> schemaFields = List.of(
-////                TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(),
-////                TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(),
-////                TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(),
-////                TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(),
-////                TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build()
-////        );
-////        // 设置超级表的标签
-////        List<TdFieldDO> tagsFields = List.of(
-////                TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build()
-////        );
-////        // 3. 创建超级表
-////        tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields));
-//    }
-
-    private List<IotThingModelDO> getValidFunctionList(String productKey) {
-        return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey),
-                thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType()));
-    }
-
-    private List<TdFieldDO> filterAndCollectValidFields(Map<String, Object> params, List<IotThingModelDO> thingModelList, IotDeviceDO device, Long time) {
-        // 1. 获取属性标识符集合
-        Set<String> propertyIdentifiers = convertSet(thingModelList, IotThingModelDO::getIdentifier);
-
-        // 2. 构建属性标识符和属性的映射
-        Map<String, IotThingModelDO> thingModelMap = convertMap(thingModelList, IotThingModelDO::getIdentifier);
-
-        // 3. 过滤并收集有效的属性字段
-        List<TdFieldDO> schemaFieldValues = new ArrayList<>();
-        //TODO:新版本是使用ts字段
-//        schemaFieldValues.add(new TdFieldDO(TIME, time));
-        params.forEach((key, val) -> {
-            if (propertyIdentifiers.contains(key)) {
-                schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val));
-                // 缓存设备属性
-                // TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读
-                setDeviceDataCache(device, thingModelMap.get(key), val, time);
-            }
-        });
-        return schemaFieldValues;
-    }
-
-    /**
-     * 缓存设备属性
-     *
-     * @param device                 设备信息
-     * @param iotThingModelDO 物模型属性
-     * @param val                    属性值
-     * @param time                   时间
-     */
-    private void setDeviceDataCache(IotDeviceDO device, IotThingModelDO iotThingModelDO, Object val, Long time) {
-        IotDeviceDataDO deviceData = IotDeviceDataDO.builder()
-                .productKey(device.getProductKey())
-                .deviceName(device.getDeviceName())
-                .identifier(iotThingModelDO.getIdentifier())
-                .value(val != null ? val.toString() : null)
-                .updateTime(DateUtil.toLocalDateTime(new Date(time)))
-                .deviceId(device.getId())
-                .thingModelId(iotThingModelDO.getId())
-                .name(iotThingModelDO.getName())
-                .dataType(iotThingModelDO.getProperty().getDataType())
-                .build();
-        deviceDataRedisDAO.set(deviceData);
-    }
-
-    /**
-     * 创建设备数据表
-     *
-     * @param deviceType 设备类型
-     * @param productKey 产品 Key
-     * @param deviceName 设备名称
-     * @param deviceKey  设备 Key
-     */
-    private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) {
-        // 1. 获取超级表名和数据库名
-        String superTableName = getProductPropertySTableName(deviceType, productKey);
-        String dataBaseName = getDatabaseName();
-
-        // 2. 获取超级表的结构信息
-        List<Map<String, Object>> maps = tdEngineDDLMapper.describeSuperTable(new TdTableDO(dataBaseName, superTableName));
-        List<TdFieldDO> tagsFieldValues = new ArrayList<>();
-        if (maps != null) {
-            // 2.1 过滤出 TAG 类型的字段
-            List<Map<String, Object>> taggedNotesList = CollectionUtils.filterList(maps, map -> TAG_NOTE.equals(map.get(NOTE)));
-
-            // 2.2 解析字段信息
-            tagsFieldValues = FieldParser.parse(taggedNotesList.stream()
-                    .map(map -> List.of(map.get("field"), map.get("type"), map.get("length")))
-                    .collect(Collectors.toList()));
-
-            // 2.3 设置 TAG 字段的值
-            for (TdFieldDO tagsFieldValue : tagsFieldValues) {
-                switch (tagsFieldValue.getFieldName()) {
-                    case PRODUCT_KEY -> tagsFieldValue.setFieldValue(productKey);
-                    case DEVICE_KEY -> tagsFieldValue.setFieldValue(deviceKey);
-                    case DEVICE_NAME -> tagsFieldValue.setFieldValue(deviceName);
-                    case DEVICE_TYPE -> tagsFieldValue.setFieldValue(deviceType);
-                }
-            }
-        }
-
-        // 3. 创建设备数据表
-        String tableName = getDeviceTableName(productKey, deviceName);
-        tdEngineDDLMapper.createTable(TdTableDO.builder().build()
-                .setDataBaseName(dataBaseName)
-                .setSuperTableName(superTableName)
-                .setTableName(tableName)
-                .setTags(tagsFieldValues));
-    }
-
-
-
-    /**
-     * 获取数据库名称
-     *
-     * @return 数据库名称
-     */
-    private String getDatabaseName() {
-        return StrUtil.subAfter(url, "/", true);
-    }
-
-    /**
-     * 获取产品属性表名
-     *
-     * @param deviceType 设备类型
-     * @param productKey 产品 Key
-     * @return 产品属性表名
-     */
-    private static String getProductPropertySTableName(Integer deviceType, String productKey) {
-        // TODO @haohao:枚举下,会好点哈。
-        return switch (deviceType) {
-            case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase();
-            case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase();
-            default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase();
-        };
-    }
-
-    /**
-     * 获取设备表名
-     *
-     * @param productKey 产品 Key
-     * @param deviceName 设备名称
-     * @return 设备表名
-     */
-    private static String getDeviceTableName(String productKey, String deviceName) {
-        return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase());
-    }
-
-}

+ 16 - 17
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml

@@ -9,8 +9,9 @@
                 ts TIMESTAMP,
                 id NCHAR(50),
                 product_key NCHAR(50),
+                device_name NCHAR(50),
                 type NCHAR(50),
-                sub_type NCHAR(50),
+                identifier NCHAR(255),
                 content NCHAR(1024),
                 report_time TIMESTAMP
             ) TAGS (
@@ -18,18 +19,23 @@
             )
     </update>
 
+    <select id="showDeviceLogSTable" resultType="String">
+        SHOW STABLES LIKE 'device_log'
+    </select>
+
     <insert id="insert">
-        INSERT INTO device_log_${log.deviceKey} (ts, id, product_key, type, subType, content, report_time)
+        INSERT INTO device_log_${deviceKey} (ts, id, product_key, device_name, type, identifier, content, report_time)
         USING device_log
-        TAGS ('${log.deviceKey}')
+        TAGS ('${deviceKey}')
         VALUES (
             NOW,
-            #{log.id},
-            #{log.productKey},
-            #{log.type},
-            #{log.subType},
-            #{log.content},
-            #{log.reportTime}
+            #{id},
+            #{productKey},
+            #{deviceName},
+            #{type},
+            #{identifier},
+            #{content},
+            #{reportTime}
         )
     </insert>
 
@@ -51,6 +57,7 @@
         LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo}
     </select>
 
+    <!-- TODO 芋艿:看看能不能复用 mybatis-plus 的 selectCount 方法 -->
     <select id="selectCount" resultType="Long">
         SELECT COUNT(*)
         FROM device_log_${reqVO.deviceKey}
@@ -67,12 +74,4 @@
         </where>
     </select>
 
-    <select id="checkDeviceLogSTableExists" resultType="Object">
-        SHOW STABLES LIKE 'device_log'
-    </select>
-
-    <select id="checkDeviceLogTableExists" resultType="Object">
-        SHOW TABLES LIKE 'device_log_${deviceKey}'
-    </select>
-
 </mapper>

+ 22 - 59
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,99 +1,62 @@
 package cn.iocoder.yudao.module.iot.plugin.common.api;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
+import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
-import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.client.RestTemplate;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
-/**
- * 用于通过 {@link RestTemplate} 向远程 IoT 服务发送设备数据相关的请求,
- * 包括设备状态更新、事件数据上报、属性数据上报等操作。
- */
+// TODO @haohao:类注释,写一下,比较好
+// TODO @haohao:类名要改下
 @Slf4j
-@RequiredArgsConstructor
-public class DeviceDataApiClient implements DeviceDataApi {
+public class DeviceDataApiClient implements IotDeviceUpstreamApi {
 
-    /**
-     * 用于发送 HTTP 请求的工具
-     */
-    private final RestTemplate restTemplate;
+    public static final String URL_PREFIX = "/rpc-api/iot/device/upstream";
 
-    /**
-     * 远程 IoT 服务的基础 URL
-     * 例如:http://127.0.0.1:8080
-     */
+    private final RestTemplate restTemplate;
     private final String deviceDataUrl;
 
+    // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来
+    // TODO @haohao:可以用 lombok 简化
+    public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) {
+        this.restTemplate = restTemplate;
+        this.deviceDataUrl = deviceDataUrl;
+    }
+
     // TODO @haohao:返回结果,不用 CommonResult 哈。
     @Override
     public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
-        String url = deviceDataUrl + "/rpc-api/iot/device-data/update-status";
+        String url = deviceDataUrl + URL_PREFIX + "/update-status";
         return doPost(url, updateReqDTO, "updateDeviceStatus");
     }
 
     @Override
     public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) {
-        String url = deviceDataUrl + "/rpc-api/iot/device-data/report-event";
+        String url = deviceDataUrl + URL_PREFIX + "/report-event";
         return doPost(url, reportReqDTO, "reportDeviceEventData");
     }
 
     @Override
     public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {
-        String url = deviceDataUrl + "/rpc-api/iot/device-data/report-property";
+        String url = deviceDataUrl + URL_PREFIX + "/report-property";
         return doPost(url, reportReqDTO, "reportDevicePropertyData");
     }
 
-    
-    /**
-     * 发送 GET 请求
-     *
-     * @param <T>         请求体类型
-     * @param url         请求 URL
-     * @param requestBody 请求体
-     * @param actionName  操作名称
-     * @return 响应结果
-     */
-    private <T> CommonResult<Boolean> doGet(String url, T requestBody, String actionName) {
-        log.info("[{}] Sending request to URL: {}", actionName, url);
-        try {
-            CommonResult<?> response = restTemplate.getForObject(url, CommonResult.class);
-            if (response != null && response.isSuccess()) {
-                return success(true);
-            } else {
-                log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response);
-                return CommonResult.error(500, "Request failed");
-            }
-        } catch (Exception e) {
-            log.error("[{}] Error sending request to URL: {}", actionName, url, e);
-            return CommonResult.error(400, "Request error: " + e.getMessage());
-        }
-    }
-
+    // TODO @haohao:未来可能有 get 类型哈
     /**
-     * 发送 POST 请求
-     *
-     * @param <T>         请求体类型
-     * @param url         请求 URL
-     * @param requestBody 请求体
-     * @param actionName  操作名称
-     * @return 响应结果
+     * 将与远程服务交互的通用逻辑抽取成一个私有方法
      */
     private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) {
         log.info("[{}] Sending request to URL: {}", actionName, url);
         try {
-            CommonResult<?> response = restTemplate.postForObject(url, requestBody, CommonResult.class);
-            if (response != null && response.isSuccess()) {
-                return success(true);
-            } else {
-                log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response);
-                return CommonResult.error(500, "Request failed");
-            }
+            // 这里指定返回类型为 CommonResult<?>,根据后台服务返回的实际结构做调整
+            restTemplate.postForObject(url, requestBody, CommonResult.class);
+            // TODO @haohao:check 结果,是否成功
+            return success(true);
         } catch (Exception e) {
             log.error("[{}] Error sending request to URL: {}", actionName, url, e);
             return CommonResult.error(400, "Request error: " + e.getMessage());

+ 2 - 2
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,6 +1,6 @@
 package cn.iocoder.yudao.module.iot.plugin.common.config;
 
-import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
+import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
 import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -43,7 +43,7 @@ public class YudaoDeviceDataApiAutoConfiguration {
      * @return DeviceDataApi 实例
      */
     @Bean
-    public DeviceDataApi deviceDataApi(RestTemplate restTemplate) {
+    public IotDeviceUpstreamApi deviceDataApi(RestTemplate restTemplate) {
         return new DeviceDataApiClient(restTemplate, deviceDataUrl);
     }
 

+ 2 - 2
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.iot.plugin;
 
 import cn.hutool.extra.spring.SpringUtil;
-import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
+import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
 import lombok.extern.slf4j.Slf4j;
 import org.pf4j.Plugin;
 import org.pf4j.PluginWrapper;
@@ -27,7 +27,7 @@ public class EmqxPlugin extends Plugin {
             executorService = Executors.newSingleThreadExecutor();
         }
 
-        DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class);
+        IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class);
         if (deviceDataApi == null) {
             log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!");
             return;

+ 2 - 2
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;
 
 import cn.hutool.core.lang.Assert;
 import cn.hutool.extra.spring.SpringUtil;
-import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
+import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
 import lombok.extern.slf4j.Slf4j;
 import org.pf4j.PluginWrapper;
 import org.pf4j.spring.SpringPlugin;
@@ -64,7 +64,7 @@ public class HttpVertxPlugin extends SpringPlugin {
             protected void prepareRefresh() {
                 // 在刷新容器前注册主程序中的 Bean
                 ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
-                DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class);
+                IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class);
                 beanFactory.registerSingleton("deviceDataApi", deviceDataApi);
                 super.prepareRefresh();
             }

+ 2 - 2
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,6 +1,6 @@
 package cn.iocoder.yudao.module.iot.plugin.http.config;
 
-import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
+import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
 import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler;
 import io.vertx.core.Vertx;
 import io.vertx.ext.web.Router;
@@ -61,7 +61,7 @@ public class HttpVertxPluginConfiguration {
      * @return HttpVertxHandler 实例
      */
     @Bean
-    public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) {
+    public HttpVertxHandler httpVertxHandler(IotDeviceUpstreamApi deviceDataApi) {
         return new HttpVertxHandler(deviceDataApi);
     }
 

+ 7 - 4
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;
 
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
+import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
 import io.vertx.core.Handler;
 import io.vertx.ext.web.RequestBody;
 import io.vertx.ext.web.RoutingContext;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.Map;
+
 @Slf4j
 public class HttpVertxHandler implements Handler<RoutingContext> {
 
-    private final DeviceDataApi deviceDataApi;
+    private final IotDeviceUpstreamApi deviceDataApi;
 
-    public HttpVertxHandler(DeviceDataApi deviceDataApi) {
+    public HttpVertxHandler(IotDeviceUpstreamApi deviceDataApi) {
         this.deviceDataApi = deviceDataApi;
     }
 
@@ -23,6 +25,7 @@ public class HttpVertxHandler implements Handler<RoutingContext> {
         String productKey = ctx.pathParam("productKey");
         String deviceName = ctx.pathParam("deviceName");
 
+        // TODO @haohao:requestBody.asJsonObject() 貌似天然就是 json 对象哈?
         RequestBody requestBody = ctx.body();
         JSONObject jsonData;
         try {
@@ -43,7 +46,7 @@ public class HttpVertxHandler implements Handler<RoutingContext> {
             IotDevicePropertyReportReqDTO reportReqDTO = IotDevicePropertyReportReqDTO.builder()
                     .productKey(productKey)
                     .deviceName(deviceName)
-                    .params(jsonData)
+                    .properties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties"))
                     .build();
 
             deviceDataApi.reportDevicePropertyData(reportReqDTO);