Bladeren bron

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

YunaiV 6 maanden geleden
bovenliggende
commit
8089f3a319
46 gewijzigde bestanden met toevoegingen van 645 en 787 verwijderingen
  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);