params;
-
- /**
- * 设备信息
- */
- @Data
- public static class Device {
-
- /**
- * 产品标识
- */
- @NotEmpty(message = "产品标识不能为空")
- private String productKey;
-
- /**
- * 设备名称
- */
- @NotEmpty(message = "设备名称不能为空")
- private String deviceName;
-
- // TODO @芋艿:阿里云还有 sign 签名
-
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java
deleted file mode 100644
index a0c8ce92ac..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
-
-import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import jakarta.validation.constraints.NotEmpty;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-/**
- * IoT 设备上行的抽象 Request DTO
- *
- * @author 芋道源码
- */
-@Data
-public abstract class IotDeviceUpstreamAbstractReqDTO {
-
- /**
- * 请求编号
- */
- private String requestId;
-
- /**
- * 插件实例的进程编号
- */
- private String processId;
-
- /**
- * 产品标识
- */
- @NotEmpty(message = "产品标识不能为空")
- private String productKey;
- /**
- * 设备名称
- */
- @NotEmpty(message = "设备名称不能为空")
- private String deviceName;
-
- /**
- * 上报时间
- */
- @JsonSerialize(using = TimestampLocalDateTimeSerializer.class) // 解决 iot plugins 序列化 LocalDateTime 是数组,导致无法解析的问题
- private LocalDateTime reportTime;
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotPluginInstanceHeartbeatReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotPluginInstanceHeartbeatReqDTO.java
deleted file mode 100644
index 9125b5f242..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotPluginInstanceHeartbeatReqDTO.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
-
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-
-/**
- * IoT 插件实例心跳 Request DTO
- *
- * @author 芋道源码
- */
-@Data
-public class IotPluginInstanceHeartbeatReqDTO {
-
- /**
- * 请求编号
- */
- @NotEmpty(message = "请求编号不能为空")
- private String processId;
-
- /**
- * 插件包标识符
- */
- @NotEmpty(message = "插件包标识符不能为空")
- private String pluginKey;
-
- /**
- * 插件实例所在 IP
- */
- @NotEmpty(message = "插件实例所在 IP 不能为空")
- private String hostIp;
- /**
- * 插件实例的进程编号
- */
- @NotNull(message = "插件实例的进程编号不能为空")
- private Integer downstreamPort;
-
- /**
- * 是否在线
- */
- @NotNull(message = "是否在线不能为空")
- private Boolean online;
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/package-info.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/package-info.java
deleted file mode 100644
index cb946cd894..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * TODO 芋艿:占位
- */
-package cn.iocoder.yudao.module.iot.api.device.dto;
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
deleted file mode 100644
index 7da0c665ba..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * 占位
- *
- * TODO 芋艿:后续删除
- */
-package cn.iocoder.yudao.module.iot.api;
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java
deleted file mode 100644
index 2c4147be1f..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums;
-
-import cn.iocoder.yudao.framework.common.enums.RpcConstants;
-
-/**
- * API 相关的枚举
- *
- * @author 芋道源码
- */
-public class ApiConstants {
-
- public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/iot";
-
- public static final String VERSION = "1.0.0";
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java
deleted file mode 100644
index d8f0cc60d2..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums;
-
-/**
- * IoT 字典类型的枚举类
- *
- * @author 芋道源码
- */
-public class DictTypeConstants {
-
- public static final String PRODUCT_STATUS = "iot_product_status";
- public static final String PRODUCT_DEVICE_TYPE = "iot_product_device_type";
- public static final String NET_TYPE = "iot_net_type";
- public static final String PROTOCOL_TYPE = "iot_protocol_type";
- public static final String DATA_FORMAT = "iot_data_format";
- public static final String VALIDATE_TYPE = "iot_validate_type";
-
- public static final String DEVICE_STATE = "iot_device_state";
-
- public static final String IOT_DATA_BRIDGE_DIRECTION_ENUM = "iot_data_bridge_direction_enum";
- public static final String IOT_DATA_BRIDGE_TYPE_ENUM = "iot_data_bridge_type_enum";
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
deleted file mode 100644
index 230baca3f1..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums;
-
-import cn.iocoder.yudao.framework.common.exception.ErrorCode;
-
-/**
- * iot 错误码枚举类
- *
- * iot 系统,使用 1-050-000-000 段
- */
-public interface ErrorCodeConstants {
-
- // ========== 产品相关 1-050-001-000 ============
- ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在");
- ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在");
- ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除");
- ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型");
-
- // ========== 产品物模型 1-050-002-000 ============
- ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
- ErrorCode THING_MODEL_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
- ErrorCode THING_MODEL_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。");
- ErrorCode THING_MODEL_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。");
- ErrorCode THING_MODEL_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效");
-
- // ========== 设备 1-050-003-000 ============
- ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在");
- ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一");
- ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除");
- ErrorCode DEVICE_KEY_EXISTS = new ErrorCode(1_050_003_003, "设备标识已经存在");
- ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在");
- ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备");
- ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!");
- ErrorCode DEVICE_DOWNSTREAM_FAILED = new ErrorCode(1_050_003_007, "执行失败,原因:{}");
-
- // ========== 产品分类 1-050-004-000 ==========
- ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在");
-
- // ========== 设备分组 1-050-005-000 ==========
- ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在");
- ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除");
-
- // ========== 插件配置 1-050-006-000 ==========
- ErrorCode PLUGIN_CONFIG_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件配置不存在");
- ErrorCode PLUGIN_INSTALL_FAILED = new ErrorCode(1_050_006_001, "插件安装失败");
- ErrorCode PLUGIN_INSTALL_FAILED_FILE_NAME_NOT_MATCH = new ErrorCode(1_050_006_002, "插件安装失败,文件名与原插件id不匹配");
- ErrorCode PLUGIN_CONFIG_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件");
- ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效");
- ErrorCode PLUGIN_CONFIG_KEY_DUPLICATE = new ErrorCode(1_050_006_005, "插件标识已存在");
- ErrorCode PLUGIN_START_FAILED = new ErrorCode(1_050_006_006, "插件启动失败");
- ErrorCode PLUGIN_STOP_FAILED = new ErrorCode(1_050_006_007, "插件停止失败");
-
- // ========== 插件实例 1-050-007-000 ==========
-
- // ========== 固件相关 1-050-008-000 ==========
-
- ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在");
- ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复");
-
- ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在");
- ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "升级任务名称重复");
- ErrorCode OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY = new ErrorCode(1_050_008_102, "设备编号列表不能为空");
- ErrorCode OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY = new ErrorCode(1_050_008_103, "设备列表不能为空");
- ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_104, "升级任务不能取消");
-
- ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在");
- ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复");
- ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试");
-
- // ========== MQTT 通信相关 1-050-009-000 ==========
- ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal");
-
- // ========== IoT 数据桥梁 1-050-010-000 ==========
- ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在");
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java
deleted file mode 100644
index 78af16cb20..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.ota;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import java.util.Arrays;
-
-/**
- * IoT OTA 升级任务的范围枚举
- *
- * @author haohao
- */
-@RequiredArgsConstructor
-@Getter
-public enum IotOtaUpgradeTaskStatusEnum implements ArrayValuable {
-
- IN_PROGRESS(10), // 进行中:升级中
- COMPLETED(20), // 已完成:已结束,全部升级完成
- INCOMPLETE(21), // 未完成:已结束,部分升级完成
- CANCELED(30),; // 已取消:一般是主动取消任务
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskStatusEnum::getStatus).toArray(Integer[]::new);
-
- /**
- * 范围
- */
- private final Integer status;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java
deleted file mode 100644
index b6ef4f0cc3..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.plugin;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import java.util.Arrays;
-
-/**
- * IoT 部署方式枚举
- *
- * @author haohao
- */
-@RequiredArgsConstructor
-@Getter
-public enum IotPluginDeployTypeEnum implements ArrayValuable {
-
- JAR(0, "JAR 部署"),
- STANDALONE(1, "独立部署");
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginDeployTypeEnum::getDeployType).toArray(Integer[]::new);
-
- /**
- * 部署方式
- */
- private final Integer deployType;
- /**
- * 部署方式名
- */
- private final String name;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java
deleted file mode 100644
index 7e3fa657e2..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.plugin;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import java.util.Arrays;
-
-/**
- * IoT 插件状态枚举
- *
- * @author haohao
- */
-@RequiredArgsConstructor
-@Getter
-public enum IotPluginStatusEnum implements ArrayValuable {
-
- STOPPED(0, "停止"),
- RUNNING(1, "运行");
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginStatusEnum::getStatus).toArray(Integer[]::new);
-
- /**
- * 状态
- */
- private final Integer status;
- /**
- * 状态名
- */
- private final String name;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java
deleted file mode 100644
index ec0b72f9fd..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.plugin;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * IoT 插件类型枚举
- *
- * @author haohao
- */
-@AllArgsConstructor
-@Getter
-public enum IotPluginTypeEnum implements ArrayValuable {
-
- NORMAL(0, "普通插件"),
- DEVICE(1, "设备插件");
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginTypeEnum::getType).toArray(Integer[]::new);
-
- /**
- * 类型
- */
- private final Integer type;
- /**
- * 类型名
- */
- private final String name;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java
deleted file mode 100644
index 0cfe1c9f48..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.product;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * 产品数据格式枚举类
- *
- * @author ahh
- * @see 阿里云 - 什么是消息解析
- */
-@AllArgsConstructor
-@Getter
-public enum IotDataFormatEnum implements ArrayValuable {
-
- JSON(0, "标准数据格式(JSON)"),
- CUSTOMIZE(1, "透传/自定义");
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataFormatEnum::getType).toArray(Integer[]::new);
-
- /**
- * 类型
- */
- private final Integer type;
- /**
- * 描述
- */
- private final String description;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java
deleted file mode 100644
index d24dea92ee..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.product;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * IoT 接入网关协议枚举类
- *
- * @author ahh
- */
-@AllArgsConstructor
-@Getter
-public enum IotProtocolTypeEnum implements ArrayValuable {
-
- CUSTOM(0, "自定义"),
- MODBUS(1, "Modbus"),
- OPC_UA(2, "OPC UA"),
- ZIGBEE(3, "ZigBee"),
- BLE(4, "BLE");
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProtocolTypeEnum::getType).toArray(Integer[]::new);
-
- /**
- * 类型
- */
- private final Integer type;
- /**
- * 描述
- */
- private final String description;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java
deleted file mode 100644
index 78fc8452eb..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.rule;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import java.util.Arrays;
-
-/**
- * IoT 数据桥接的类型枚举
- *
- * @author 芋道源码
- */
-@RequiredArgsConstructor
-@Getter
-public enum IotDataBridgeTypeEnum implements ArrayValuable {
-
- HTTP(1, "HTTP"),
- TCP(2, "TCP"),
- WEBSOCKET(3, "WEBSOCKET"),
-
- MQTT(10, "MQTT"),
-
- DATABASE(20, "DATABASE"),
- REDIS_STREAM(21, "REDIS_STREAM"),
-
- ROCKETMQ(30, "ROCKETMQ"),
- RABBITMQ(31, "RABBITMQ"),
- KAFKA(32, "KAFKA");
-
- private final Integer type;
-
- private final String name;
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeTypeEnum::getType).toArray(Integer[]::new);
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java
deleted file mode 100644
index 2bdf7d0ede..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.rule;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import java.util.Arrays;
-
-/**
- * IoT 规则场景的触发类型枚举
- *
- * 设备触发,定时触发
- */
-@RequiredArgsConstructor
-@Getter
-public enum IotRuleSceneActionTypeEnum implements ArrayValuable {
-
- DEVICE_CONTROL(1), // 设备执行
- ALERT(2), // 告警执行
- DATA_BRIDGE(3); // 桥接执行
-
- private final Integer type;
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneActionTypeEnum::getType).toArray(Integer[]::new);
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java
deleted file mode 100644
index a420a21d5b..0000000000
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.iot.enums.rule;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import java.util.Arrays;
-
-/**
- * IoT 场景流转的触发类型枚举
- *
- * @author 芋道源码
- */
-@RequiredArgsConstructor
-@Getter
-public enum IotRuleSceneTriggerTypeEnum implements ArrayValuable {
-
- DEVICE(1), // 设备触发
- TIMER(2); // 定时触发
-
- private final Integer type;
-
- public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerTypeEnum::getType).toArray(Integer[]::new);
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml
index ba92a0e3aa..1f83a7acb2 100644
--- a/yudao-module-iot/yudao-module-iot-biz/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml
@@ -1,7 +1,6 @@
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
yudao-module-iot
cn.iocoder.boot
@@ -15,7 +14,7 @@
${project.artifactId}
物联网 模块,主要实现 产品管理、设备管理、协议管理等功能。
-
+
@@ -26,7 +25,7 @@
cn.iocoder.boot
- yudao-module-iot-api
+ yudao-module-iot-core
${revision}
@@ -75,10 +74,11 @@
+
org.apache.rocketmq
rocketmq-spring-boot-starter
- true
+
org.springframework.kafka
@@ -91,47 +91,17 @@
true
-
- org.pf4j
- pf4j-spring
-
-
-
-
- org.apache.groovy
- groovy-all
- 4.0.25
- pom
-
-
-
-
- org.graalvm.js
- js
- 24.1.2
- pom
-
-
- org.graalvm.js
- js-scriptengine
- 24.1.2
-
-
-
-
+
-
-
+
+
+
-
-
+
+
+
-
-
-
-
-
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java
deleted file mode 100644
index 9f54d60e80..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package cn.iocoder.yudao.module.iot;
-
-import cn.hutool.script.ScriptUtil;
-import javax.script.Bindings;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
-/**
- * TODO 芋艿:测试脚本的接入
- */
-public class ScriptTest {
-
- public static void main2(String[] args) {
- // 创建一个 Groovy 脚本引擎
- ScriptEngine engine = ScriptUtil.createGroovyEngine();
-
- // 创建绑定参数
- Bindings bindings = engine.createBindings();
- bindings.put("name", "Alice");
- bindings.put("age", 30);
-
- // 定义一个稍微复杂的 Groovy 脚本
- String script = "def greeting = 'Hello, ' + name + '!';\n" +
- "def ageInFiveYears = age + 5;\n" +
- "def message = greeting + ' In five years, you will be ' + ageInFiveYears + ' years old.';\n" +
- "return message.toUpperCase();\n";
-
- try {
- // 执行脚本并获取结果
- Object result = engine.eval(script, bindings);
- System.out.println(result); // 输出: HELLO, ALICE! IN FIVE YEARS, YOU WILL BE 35 YEARS OLD.
- } catch (ScriptException e) {
- e.printStackTrace();
- }
- }
-
- public static void main(String[] args) {
- // 创建一个 JavaScript 脚本引擎
- ScriptEngine jsEngine = ScriptUtil.createJsEngine();
-
- // 创建绑定参数
- Bindings jsBindings = jsEngine.createBindings();
- jsBindings.put("name", "Bob");
- jsBindings.put("age", 25);
-
- // 定义一个简单的 JavaScript 脚本
- String jsScript = "var greeting = 'Hello, ' + name + '!';\n" +
- "var ageInTenYears = age + 10;\n" +
- "var message = greeting + ' In ten years, you will be ' + ageInTenYears + ' years old.';\n" +
- "message.toUpperCase();\n";
-
- try {
- // 执行脚本并获取结果
- Object jsResult = jsEngine.eval(jsScript, jsBindings);
- System.out.println(jsResult); // 输出: HELLO, BOB! IN TEN YEARS, YOU WILL BE 35 YEARS OLD.
- } catch (ScriptException e) {
- e.printStackTrace();
- }
- }
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java
new file mode 100644
index 0000000000..eb55b1852a
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java
@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.iot.api.device;
+
+import cn.iocoder.yudao.framework.common.enums.RpcConstants;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceGetReqDTO;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
+import cn.iocoder.yudao.module.iot.service.product.IotProductService;
+import jakarta.annotation.Resource;
+import jakarta.annotation.security.PermitAll;
+import org.springframework.context.annotation.Primary;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * IoT 设备 API 实现类
+ *
+ * @author haohao
+ */
+@RestController
+@Validated
+@Primary // 保证优先匹配,因为 yudao-iot-gateway 也有 IotDeviceCommonApi 的实现,并且也可能会被 biz 引入
+public class IoTDeviceApiImpl implements IotDeviceCommonApi {
+
+ @Resource
+ private IotDeviceService deviceService;
+ @Resource
+ private IotProductService productService;
+
+ @Override
+ @PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/auth")
+ @PermitAll
+ public CommonResult authDevice(@RequestBody IotDeviceAuthReqDTO authReqDTO) {
+ return success(deviceService.authDevice(authReqDTO));
+ }
+
+ @Override
+ @PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/get") // 特殊:方便调用,暂时使用 POST,实际更推荐 GET
+ @PermitAll
+ public CommonResult getDevice(@RequestBody IotDeviceGetReqDTO getReqDTO) {
+ IotDeviceDO device = getReqDTO.getId() != null ? deviceService.getDeviceFromCache(getReqDTO.getId())
+ : deviceService.getDeviceFromCache(getReqDTO.getProductKey(), getReqDTO.getDeviceName());
+ return success(BeanUtils.toBean(device, IotDeviceRespDTO.class, deviceDTO -> {
+ IotProductDO product = productService.getProductFromCache(deviceDTO.getProductId());
+ if (product != null) {
+ deviceDTO.setCodecType(product.getCodecType());
+ }
+ }));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java
deleted file mode 100644
index 25faa1a6b6..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package cn.iocoder.yudao.module.iot.api.device;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
-import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
-import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
-import jakarta.annotation.Resource;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RestController;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * * 设备数据 Upstream 上行 API 实现类
- */
-@RestController
-@Validated
-public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
-
- @Resource
- private IotDeviceUpstreamService deviceUpstreamService;
- @Resource
- private IotPluginInstanceService pluginInstanceService;
-
- // ========== 设备相关 ==========
-
- @Override
- public CommonResult updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
- deviceUpstreamService.updateDeviceState(updateReqDTO);
- return success(true);
- }
-
- @Override
- public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) {
- deviceUpstreamService.reportDeviceProperty(reportReqDTO);
- return success(true);
- }
-
- @Override
- public CommonResult reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) {
- deviceUpstreamService.reportDeviceEvent(reportReqDTO);
- return success(true);
- }
-
- @Override
- public CommonResult registerDevice(IotDeviceRegisterReqDTO registerReqDTO) {
- deviceUpstreamService.registerDevice(registerReqDTO);
- return success(true);
- }
-
- @Override
- public CommonResult registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) {
- deviceUpstreamService.registerSubDevice(registerReqDTO);
- return success(true);
- }
-
- @Override
- public CommonResult addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) {
- deviceUpstreamService.addDeviceTopology(addReqDTO);
- return success(true);
- }
-
- @Override
- public CommonResult authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
- boolean result = deviceUpstreamService.authenticateEmqxConnection(authReqDTO);
- return success(result);
- }
-
- // ========== 插件相关 ==========
-
- @Override
- public CommonResult heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) {
- pluginInstanceService.heartbeatPluginInstance(heartbeatReqDTO);
- return success(true);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
index 07852180d4..63bca16371 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
@@ -1,6 +1,4 @@
/**
- * 占位
- *
- * TODO 芋艿:后续删除
+ * iot API 包,定义并实现提供给其它模块的 API
*/
package cn.iocoder.yudao.module.iot.api;
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java
new file mode 100644
index 0000000000..b6d225f6df
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java
@@ -0,0 +1,105 @@
+package cn.iocoder.yudao.module.iot.controller.admin.alert;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+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.alert.vo.config.IotAlertConfigPageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO;
+import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "管理后台 - IoT 告警配置")
+@RestController
+@RequestMapping("/iot/alert-config")
+@Validated
+public class IotAlertConfigController {
+
+ @Resource
+ private IotAlertConfigService alertConfigService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建告警配置")
+ @PreAuthorize("@ss.hasPermission('iot:alert-config:create')")
+ public CommonResult createAlertConfig(@Valid @RequestBody IotAlertConfigSaveReqVO createReqVO) {
+ return success(alertConfigService.createAlertConfig(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新告警配置")
+ @PreAuthorize("@ss.hasPermission('iot:alert-config:update')")
+ public CommonResult updateAlertConfig(@Valid @RequestBody IotAlertConfigSaveReqVO updateReqVO) {
+ alertConfigService.updateAlertConfig(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除告警配置")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('iot:alert-config:delete')")
+ public CommonResult deleteAlertConfig(@RequestParam("id") Long id) {
+ alertConfigService.deleteAlertConfig(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得告警配置")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('iot:alert-config:query')")
+ public CommonResult getAlertConfig(@RequestParam("id") Long id) {
+ IotAlertConfigDO alertConfig = alertConfigService.getAlertConfig(id);
+ return success(BeanUtils.toBean(alertConfig, IotAlertConfigRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得告警配置分页")
+ @PreAuthorize("@ss.hasPermission('iot:alert-config:query')")
+ public CommonResult> getAlertConfigPage(@Valid IotAlertConfigPageReqVO pageReqVO) {
+ PageResult pageResult = alertConfigService.getAlertConfigPage(pageReqVO);
+
+ // 转换返回
+ Map userMap = adminUserApi.getUserMap(
+ convertSetByFlatMap(pageResult.getList(), config -> config.getReceiveUserIds().stream()));
+ return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class, vo -> {
+ vo.setReceiveUserNames(vo.getReceiveUserIds().stream()
+ .map(userMap::get)
+ .filter(Objects::nonNull)
+ .map(AdminUserRespDTO::getNickname)
+ .collect(Collectors.toList()));
+ }));
+ }
+
+ @GetMapping("/simple-list")
+ @Operation(summary = "获得告警配置简单列表", description = "只包含被开启的告警配置,主要用于前端的下拉选项")
+ @PreAuthorize("@ss.hasPermission('iot:alert-config:query')")
+ public CommonResult> getAlertConfigSimpleList() {
+ List list = alertConfigService.getAlertConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ return success(convertList(list, config -> // 只返回 id、name 字段
+ new IotAlertConfigRespVO().setId(config.getId()).setName(config.getName())));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java
new file mode 100644
index 0000000000..91f15b989c
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java
@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.iot.controller.admin.alert;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+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.alert.vo.recrod.IotAlertRecordPageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordRespVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO;
+import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static java.util.Collections.singleton;
+
+@Tag(name = "管理后台 - IoT 告警记录")
+@RestController
+@RequestMapping("/iot/alert-record")
+@Validated
+public class IotAlertRecordController {
+
+ @Resource
+ private IotAlertRecordService alertRecordService;
+
+ @GetMapping("/get")
+ @Operation(summary = "获得告警记录")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('iot:alert-record:query')")
+ public CommonResult getAlertRecord(@RequestParam("id") Long id) {
+ IotAlertRecordDO alertRecord = alertRecordService.getAlertRecord(id);
+ return success(BeanUtils.toBean(alertRecord, IotAlertRecordRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得告警记录分页")
+ @PreAuthorize("@ss.hasPermission('iot:alert-record:query')")
+ public CommonResult> getAlertRecordPage(@Valid IotAlertRecordPageReqVO pageReqVO) {
+ PageResult pageResult = alertRecordService.getAlertRecordPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, IotAlertRecordRespVO.class));
+ }
+
+ @PutMapping("/process")
+ @Operation(summary = "处理告警记录")
+ @PreAuthorize("@ss.hasPermission('iot:alert-record:process')")
+ public CommonResult processAlertRecord(@Valid @RequestBody IotAlertRecordProcessReqVO processReqVO) {
+ alertRecordService.processAlertRecordList(singleton(processReqVO.getId()), processReqVO.getProcessRemark());
+ return success(true);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigPageReqVO.java
new file mode 100644
index 0000000000..0f9a1e9ce1
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigPageReqVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - IoT 告警配置分页 Request VO")
+@Data
+public class IotAlertConfigPageReqVO extends PageParam {
+
+ @Schema(description = "配置名称", example = "赵六")
+ private String name;
+
+ @Schema(description = "配置状态", example = "1")
+ private Integer status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java
new file mode 100644
index 0000000000..e68a7b7851
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - IoT 告警配置 Response VO")
+@Data
+public class IotAlertConfigRespVO {
+
+ @Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3566")
+ private Long id;
+
+ @Schema(description = "配置名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
+ private String name;
+
+ @Schema(description = "配置描述", example = "你猜")
+ private String description;
+
+ @Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer level;
+
+ @Schema(description = "配置状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer status;
+
+ @Schema(description = "关联的场景联动规则编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
+ private List sceneRuleIds;
+
+ @Schema(description = "接收的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "100,200")
+ private List receiveUserIds;
+
+ @Schema(description = "接收的用户名称数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三,李四")
+ private List receiveUserNames;
+
+ @Schema(description = "接收的类型数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
+ private List receiveTypes;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java
new file mode 100644
index 0000000000..694e8bfdf7
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java
@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - IoT 告警配置新增/修改 Request VO")
+@Data
+public class IotAlertConfigSaveReqVO {
+
+ @Schema(description = "配置编号", example = "3566")
+ private Long id;
+
+ @Schema(description = "配置名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
+ @NotEmpty(message = "配置名称不能为空")
+ private String name;
+
+ @Schema(description = "配置描述", example = "你猜")
+ private String description;
+
+ @Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "告警级别不能为空")
+ private Integer level;
+
+ @Schema(description = "配置状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "配置状态不能为空")
+ @InEnum(CommonStatusEnum.class)
+ private Integer status;
+
+ @Schema(description = "关联的场景联动规则编号数组")
+ @NotEmpty(message = "关联的场景联动规则编号数组不能为空")
+ private List sceneRuleIds;
+
+ @Schema(description = "接收的用户编号数组")
+ @NotEmpty(message = "接收的用户编号数组不能为空")
+ private List receiveUserIds;
+
+ @Schema(description = "接收的类型数组")
+ @NotEmpty(message = "接收的类型数组不能为空")
+ private List receiveTypes;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordPageReqVO.java
new file mode 100644
index 0000000000..109f240917
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordPageReqVO.java
@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - IoT 告警记录分页 Request VO")
+@Data
+public class IotAlertRecordPageReqVO extends PageParam {
+
+ @Schema(description = "告警配置编号", example = "29320")
+ private Long configId;
+
+ @Schema(description = "告警级别", example = "1")
+ private Integer level;
+
+ @Schema(description = "产品编号", example = "2050")
+ private Long productId;
+
+ @Schema(description = "设备编号", example = "21727")
+ private String deviceId;
+
+ @Schema(description = "是否处理", example = "true")
+ private Boolean processStatus;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordProcessReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordProcessReqVO.java
new file mode 100644
index 0000000000..b64f66c5b9
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordProcessReqVO.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - IoT 告警记录处理 Request VO")
+@Data
+public class IotAlertRecordProcessReqVO {
+
+ @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "记录编号不能为空")
+ private Long id;
+
+ @Schema(description = "处理结果(备注)", requiredMode = Schema.RequiredMode.REQUIRED, example = "已处理告警,问题已解决")
+ private String processRemark;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordRespVO.java
new file mode 100644
index 0000000000..97ccf6cca4
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordRespVO.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
+
+import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - IoT 告警记录 Response VO")
+@Data
+public class IotAlertRecordRespVO {
+
+ @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19904")
+ private Long id;
+
+ @Schema(description = "告警配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29320")
+ private Long configId;
+
+ @Schema(description = "告警名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+ private String configName;
+
+ @Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer configLevel;
+
+ @Schema(description = "产品编号", example = "2050")
+ private Long productId;
+
+ @Schema(description = "设备编号", example = "21727")
+ private Long deviceId;
+
+ @Schema(description = "触发的设备消息")
+ private IotDeviceMessage deviceMessage;
+
+ @Schema(description = "是否处理", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Boolean processStatus;
+
+ @Schema(description = "处理结果(备注)", example = "你说的对")
+ private String processRemark;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http
deleted file mode 100644
index c1190cec16..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http
+++ /dev/null
@@ -1,75 +0,0 @@
-### 请求 /iot/device/downstream 接口(服务调用) => 成功
-POST {{baseUrl}}/iot/device/downstream
-Content-Type: application/json
-tenant-id: {{adminTenentId}}
-Authorization: Bearer {{token}}
-
-{
- "id": 25,
- "type": "service",
- "identifier": "temperature",
- "data": {
- "xx": "yy"
- }
-}
-
-### 请求 /iot/device/downstream 接口(属性设置) => 成功
-POST {{baseUrl}}/iot/device/downstream
-Content-Type: application/json
-tenant-id: {{adminTenentId}}
-Authorization: Bearer {{token}}
-
-{
- "id": 25,
- "type": "property",
- "identifier": "set",
- "data": {
- "xx": "yy"
- }
-}
-
-### 请求 /iot/device/downstream 接口(属性获取) => 成功
-POST {{baseUrl}}/iot/device/downstream
-Content-Type: application/json
-tenant-id: {{adminTenentId}}
-Authorization: Bearer {{token}}
-
-{
- "id": 25,
- "type": "property",
- "identifier": "get",
- "data": ["xx", "yy"]
-}
-
-### 请求 /iot/device/downstream 接口(配置设置) => 成功
-POST {{baseUrl}}/iot/device/downstream
-Content-Type: application/json
-tenant-id: {{adminTenentId}}
-Authorization: Bearer {{token}}
-
-{
- "id": 25,
- "type": "config",
- "identifier": "set"
-}
-
-### 请求 /iot/device/downstream 接口(OTA 升级) => 成功
-POST {{baseUrl}}/iot/device/downstream
-Content-Type: application/json
-tenant-id: {{adminTenentId}}
-Authorization: Bearer {{token}}
-
-{
- "id": 25,
- "type": "ota",
- "identifier": "upgrade",
- "data": {
- "firmwareId": 1,
- "version": "1.0.0",
- "signMethod": "MD5",
- "fileSign": "d41d8cd98f00b204e9800998ecf8427e",
- "fileSize": 1024,
- "fileUrl": "http://example.com/firmware.bin",
- "information": "{\"desc\":\"升级到最新版本\"}"
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
index 08fc244b15..f8f78aa63d 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
@@ -6,15 +6,13 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import cn.iocoder.yudao.module.iot.enums.product.IotLocationTypeEnum;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
-import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService;
-import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
@@ -41,10 +39,6 @@ public class IotDeviceController {
@Resource
private IotDeviceService deviceService;
- @Resource
- private IotDeviceUpstreamService deviceUpstreamService;
- @Resource
- private IotDeviceDownstreamService deviceDownstreamService;
@PostMapping("/create")
@Operation(summary = "创建设备")
@@ -111,7 +105,7 @@ public class IotDeviceController {
@PreAuthorize("@ss.hasPermission('iot:device:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportDeviceExcel(@Valid IotDevicePageReqVO exportReqVO,
- HttpServletResponse response) throws IOException {
+ HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
CommonResult> result = getDevicePage(exportReqVO);
// 导出 Excel
@@ -129,12 +123,17 @@ public class IotDeviceController {
@GetMapping("/simple-list")
@Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项")
- @Parameter(name = "deviceType", description = "设备类型", example = "1")
- public CommonResult> getSimpleDeviceList(
- @RequestParam(value = "deviceType", required = false) Integer deviceType) {
- List list = deviceService.getDeviceListByDeviceType(deviceType);
- return success(convertList(list, device -> // 只返回 id、name 字段
- new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName())));
+ @Parameters({
+ @Parameter(name = "deviceType", description = "设备类型", example = "1"),
+ @Parameter(name = "productId", description = "产品编号", example = "1024")
+ })
+ public CommonResult> getDeviceSimpleList(
+ @RequestParam(value = "deviceType", required = false) Integer deviceType,
+ @RequestParam(value = "productId", required = false) Long productId) {
+ List list = deviceService.getDeviceListByCondition(deviceType, productId);
+ return success(convertList(list, device -> // 只返回 id、name、productId 字段
+ new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName())
+ .setProductId(device.getProductId()).setState(device.getState())));
}
@PostMapping("/import")
@@ -154,35 +153,28 @@ public class IotDeviceController {
// 手动创建导出 demo
List list = Arrays.asList(
IotDeviceImportExcelVO.builder().deviceName("温度传感器001").parentDeviceName("gateway110")
- .productKey("1de24640dfe").groupNames("灰度分组,生产分组").build(),
- IotDeviceImportExcelVO.builder().deviceName("biubiu")
- .productKey("YzvHxd4r67sT4s2B").groupNames("").build());
+ .productKey("1de24640dfe").groupNames("灰度分组,生产分组")
+ .locationType(IotLocationTypeEnum.IP.getType()).build(),
+ IotDeviceImportExcelVO.builder().deviceName("biubiu").productKey("YzvHxd4r67sT4s2B")
+ .groupNames("").locationType(IotLocationTypeEnum.MANUAL.getType()).build());
// 输出
ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list);
}
- @PostMapping("/upstream")
- @Operation(summary = "设备上行", description = "可用于设备模拟")
- @PreAuthorize("@ss.hasPermission('iot:device:upstream')")
- public CommonResult upstreamDevice(@Valid @RequestBody IotDeviceUpstreamReqVO upstreamReqVO) {
- deviceUpstreamService.upstreamDevice(upstreamReqVO);
- return success(true);
+ @GetMapping("/get-auth-info")
+ @Operation(summary = "获得设备连接信息")
+ @PreAuthorize("@ss.hasPermission('iot:device:auth-info')")
+ public CommonResult getDeviceAuthInfo(@RequestParam("id") Long id) {
+ return success(deviceService.getDeviceAuthInfo(id));
}
- @PostMapping("/downstream")
- @Operation(summary = "设备下行", description = "可用于设备模拟")
- @PreAuthorize("@ss.hasPermission('iot:device:downstream')")
- public CommonResult downstreamDevice(@Valid @RequestBody IotDeviceDownstreamReqVO downstreamReqVO) {
- deviceDownstreamService.downstreamDevice(downstreamReqVO);
- return success(true);
+ // TODO @haohao:可以使用 @RequestParam("productKey") String productKey, @RequestParam("deviceNames") List deviceNames 来接收哇?
+ @GetMapping("/list-by-product-key-and-names")
+ @Operation(summary = "通过产品标识和设备名称列表获取设备")
+ @PreAuthorize("@ss.hasPermission('iot:device:query')")
+ public CommonResult> getDevicesByProductKeyAndNames(@Valid IotDeviceByProductKeyAndNamesReqVO reqVO) {
+ List devices = deviceService.getDeviceListByProductKeyAndNames(reqVO.getProductKey(), reqVO.getDeviceNames());
+ return success(BeanUtils.toBean(devices, IotDeviceRespVO.class));
}
- // TODO @haohao:是不是默认详情接口,不返回 secret,然后这个接口,用于统一返回。然后接口名可以更通用一点。
- @GetMapping("/mqtt-connection-params")
- @Operation(summary = "获取 MQTT 连接参数")
- @PreAuthorize("@ss.hasPermission('iot:device:mqtt-connection-params')")
- public CommonResult getMqttConnectionParams(@RequestParam("deviceId") Long deviceId) {
- return success(deviceService.getMqttConnectionParams(deviceId));
- }
-
-}
\ No newline at end of file
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java
deleted file mode 100644
index 81d1bff945..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.device;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-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.data.IotDeviceLogPageReqVO;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogRespVO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
-import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "管理后台 - IoT 设备日志")
-@RestController
-@RequestMapping("/iot/device/log")
-@Validated
-public class IotDeviceLogController {
-
- @Resource
- private IotDeviceLogService deviceLogService;
-
- @GetMapping("/page")
- @Operation(summary = "获得设备日志分页")
- @PreAuthorize("@ss.hasPermission('iot:device:log-query')")
- public CommonResult> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) {
- PageResult pageResult = deviceLogService.getDeviceLogPage(pageReqVO);
- return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceMessageController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceMessageController.http
new file mode 100644
index 0000000000..93c86e146b
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceMessageController.http
@@ -0,0 +1,101 @@
+### 请求 /iot/device/message/send 接口(属性上报)=> 成功
+POST {{baseUrl}}/iot/device/message/send
+Content-Type: application/json
+tenant-id: {{adminTenantId}}
+Authorization: Bearer {{token}}
+
+{
+ "deviceId": 25,
+ "method": "thing.property.post",
+ "params": {
+ "width": 1,
+ "height": "2",
+ "oneThree": "3"
+ }
+}
+
+### 请求 /iot/device/downstream 接口(服务调用)=> 成功 TODO 芋艿:未更新为最新
+POST {{baseUrl}}/iot/device/downstream
+Content-Type: application/json
+tenant-id: {{adminTenantId}}
+Authorization: Bearer {{token}}
+
+{
+ "id": 25,
+ "type": "service",
+ "identifier": "temperature",
+ "data": {
+ "xx": "yy"
+ }
+}
+
+### 请求 /iot/device/downstream 接口(属性设置)=> 成功 TODO 芋艿:未更新为最新
+POST {{baseUrl}}/iot/device/downstream
+Content-Type: application/json
+tenant-id: {{adminTenantId}}
+Authorization: Bearer {{token}}
+
+{
+ "id": 25,
+ "type": "property",
+ "identifier": "set",
+ "data": {
+ "xx": "yy"
+ }
+}
+
+### 请求 /iot/device/downstream 接口(属性获取)=> 成功 TODO 芋艿:未更新为最新
+POST {{baseUrl}}/iot/device/downstream
+Content-Type: application/json
+tenant-id: {{adminTenantId}}
+Authorization: Bearer {{token}}
+
+{
+ "id": 25,
+ "type": "property",
+ "identifier": "get",
+ "data": ["xx", "yy"]
+}
+
+### 请求 /iot/device/downstream 接口(配置设置)=> 成功 TODO 芋艿:未更新为最新
+POST {{baseUrl}}/iot/device/downstream
+Content-Type: application/json
+tenant-id: {{adminTenantId}}
+Authorization: Bearer {{token}}
+
+{
+ "id": 25,
+ "type": "config",
+ "identifier": "set"
+}
+
+### 请求 /iot/device/downstream 接口(OTA 升级)=> 成功 TODO 芋艿:未更新为最新
+POST {{baseUrl}}/iot/device/downstream
+Content-Type: application/json
+tenant-id: {{adminTenantId}}
+Authorization: Bearer {{token}}
+
+{
+ "id": 25,
+ "type": "ota",
+ "identifier": "upgrade",
+ "data": {
+ "firmwareId": 1,
+ "version": "1.0.0",
+ "signMethod": "MD5",
+ "fileSign": "d41d8cd98f00b204e9800998ecf8427e",
+ "fileSize": 1024,
+ "fileUrl": "http://example.com/firmware.bin",
+ "information": "{\"desc\":\"升级到最新版本\"}"
+ }
+}
+
+### 查询设备消息对分页 - 基础查询(设备编号25)
+GET {{baseUrl}}/iot/device/message/pair-page?deviceId=25&pageNo=1&pageSize=10
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenantId}}
+
+### 查询设备消息对分页 - 按标识符过滤(identifier=eat)
+GET {{baseUrl}}/iot/device/message/pair-page?deviceId=25&identifier=eat&pageNo=1&pageSize=10
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenantId}}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceMessageController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceMessageController.java
new file mode 100644
index 0000000000..8e9d148c9c
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceMessageController.java
@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+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.message.IotDeviceMessagePageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageRespPairVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageSendReqVO;
+import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO;
+import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceMessageMapper;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
+import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService;
+import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+
+@Tag(name = "管理后台 - IoT 设备消息")
+@RestController
+@RequestMapping("/iot/device/message")
+@Validated
+public class IotDeviceMessageController {
+
+ @Resource
+ private IotDeviceMessageService deviceMessageService;
+ @Resource
+ private IotDeviceService deviceService;
+ @Resource
+ private IotThingModelService thingModelService;
+ @Resource
+ private IotDeviceMessageMapper deviceMessageMapper;
+
+ @GetMapping("/page")
+ @Operation(summary = "获得设备消息分页")
+ @PreAuthorize("@ss.hasPermission('iot:device:message-query')")
+ public CommonResult> getDeviceMessagePage(
+ @Valid IotDeviceMessagePageReqVO pageReqVO) {
+ PageResult pageResult = deviceMessageService.getDeviceMessagePage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, IotDeviceMessageRespVO.class));
+ }
+
+ @GetMapping("/pair-page")
+ @Operation(summary = "获得设备消息对分页")
+ @PreAuthorize("@ss.hasPermission('iot:device:message-query')")
+ public CommonResult> getDeviceMessagePairPage(
+ @Valid IotDeviceMessagePageReqVO pageReqVO) {
+ // 1.1 先按照条件,查询 request 的消息(非 reply)
+ pageReqVO.setReply(false);
+ PageResult requestMessagePageResult = deviceMessageService.getDeviceMessagePage(pageReqVO);
+ if (CollUtil.isEmpty(requestMessagePageResult.getList())) {
+ return success(PageResult.empty());
+ }
+ // 1.2 接着按照 requestIds,批量查询 reply 消息
+ List requestIds = convertList(requestMessagePageResult.getList(), IotDeviceMessageDO::getRequestId);
+ List replyMessageList = deviceMessageService.getDeviceMessageListByRequestIdsAndReply(
+ pageReqVO.getDeviceId(), requestIds, true);
+ Map replyMessages = convertMap(replyMessageList, IotDeviceMessageDO::getRequestId);
+
+ // 2. 组装结果
+ List pairMessages = convertList(requestMessagePageResult.getList(),
+ requestMessage -> {
+ IotDeviceMessageDO replyMessage = replyMessages.get(requestMessage.getRequestId());
+ return new IotDeviceMessageRespPairVO()
+ .setRequest(BeanUtils.toBean(requestMessage, IotDeviceMessageRespVO.class))
+ .setReply(BeanUtils.toBean(replyMessage, IotDeviceMessageRespVO.class));
+ });
+ return success(new PageResult<>(pairMessages, requestMessagePageResult.getTotal()));
+ }
+
+ @PostMapping("/send")
+ @Operation(summary = "发送消息", description = "可用于设备模拟")
+ @PreAuthorize("@ss.hasPermission('iot:device:message-end')")
+ public CommonResult sendDeviceMessage(@Valid @RequestBody IotDeviceMessageSendReqVO sendReqVO) {
+ deviceMessageService.sendDeviceMessage(BeanUtils.toBean(sendReqVO, IotDeviceMessage.class));
+ return success(true);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java
index 47bf325dda..4988efbeb3 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java
@@ -1,22 +1,21 @@
package cn.iocoder.yudao.module.iot.controller.admin.device;
-import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
-import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO;
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyDetailRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyHistoryListReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
+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.device.data.IotDevicePropertyService;
+import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService;
import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@@ -46,50 +45,45 @@ public class IotDevicePropertyController {
@Resource
private IotDeviceService deviceService;
- @GetMapping("/latest")
+ @GetMapping("/get-latest")
@Operation(summary = "获取设备属性最新属性")
- @Parameters({
- @Parameter(name = "deviceId", description = "设备编号", required = true),
- @Parameter(name = "identifier", description = "标识符"),
- @Parameter(name = "name", description = "名称")
- })
+ @Parameter(name = "deviceId", description = "设备编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:device:property-query')")
- public CommonResult> getLatestDeviceProperties(
- @RequestParam("deviceId") Long deviceId,
- @RequestParam(value = "identifier", required = false) String identifier,
- @RequestParam(value = "name", required = false) String name) {
- Map properties = devicePropertyService.getLatestDeviceProperties(deviceId);
-
- // 拼接数据
+ public CommonResult> getLatestDeviceProperties(
+ @RequestParam("deviceId") Long deviceId) {
+ // 1.1 获取设备信息
IotDeviceDO device = deviceService.getDevice(deviceId);
Assert.notNull(device, "设备不存在");
- List thingModels = thingModelService.getThingModelListByProductId(device.getProductId());
- return success(convertList(properties.entrySet(), entry -> {
- IotThingModelDO thingModel = CollUtil.findOne(thingModels,
- item -> item.getIdentifier().equals(entry.getKey()));
- if (thingModel == null || thingModel.getProperty() == null) {
- return null;
+ // 1.2 获取设备最新属性
+ Map properties = devicePropertyService.getLatestDeviceProperties(deviceId);
+ // 1.3 根据 productId + type 查询属性类型的物模型
+ List thingModels = thingModelService.getThingModelListByProductIdAndType(
+ device.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
+
+ // 2. 基于 thingModels 遍历,拼接 properties
+ return success(convertList(thingModels, thingModel -> {
+ ThingModelProperty thingModelProperty = thingModel.getProperty();
+ Assert.notNull(thingModelProperty, "属性不能为空");
+ IotDevicePropertyDetailRespVO result = new IotDevicePropertyDetailRespVO()
+ .setName(thingModel.getName()).setDataType(thingModelProperty.getDataType())
+ .setDataSpecs(thingModelProperty.getDataSpecs())
+ .setDataSpecsList(thingModelProperty.getDataSpecsList());
+ result.setIdentifier(thingModel.getIdentifier());
+ IotDevicePropertyDO property = properties.get(thingModel.getIdentifier());
+ if (property != null) {
+ result.setValue(property.getValue())
+ .setUpdateTime(LocalDateTimeUtil.toEpochMilli(property.getUpdateTime()));
}
- if (StrUtil.isNotEmpty(identifier) && !StrUtil.contains(thingModel.getIdentifier(), identifier)) {
- return null;
- }
- if (StrUtil.isNotEmpty(name) && !StrUtil.contains(thingModel.getName(), name)) {
- return null;
- }
- // 构建对象
- IotDevicePropertyDO property = entry.getValue();
- return new IotDevicePropertyRespVO().setProperty(thingModel.getProperty())
- .setValue(property.getValue()).setUpdateTime(LocalDateTimeUtil.toEpochMilli(property.getUpdateTime()));
+ return result;
}));
}
- @GetMapping("/history-page")
- @Operation(summary = "获取设备属性历史数据")
+ @GetMapping("/history-list")
+ @Operation(summary = "获取设备属性历史数据列表")
@PreAuthorize("@ss.hasPermission('iot:device:property-query')")
- public CommonResult> getHistoryDevicePropertyPage(
- @Valid IotDevicePropertyHistoryPageReqVO pageReqVO) {
- Assert.notEmpty(pageReqVO.getIdentifier(), "标识符不能为空");
- return success(devicePropertyService.getHistoryDevicePropertyPage(pageReqVO));
+ public CommonResult> getHistoryDevicePropertyList(
+ @Valid IotDevicePropertyHistoryListReqVO listReqVO) {
+ return success(devicePropertyService.getHistoryDevicePropertyList(listReqVO));
}
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java
deleted file mode 100644
index eefaeffebc..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
-
-import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-
-@Schema(description = "管理后台 - IoT 设备下行 Request VO") // 服务调用、属性设置、属性获取等
-@Data
-public class IotDeviceDownstreamReqVO {
-
- @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
- @NotNull(message = "设备编号不能为空")
- private Long id;
-
- @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
- @NotEmpty(message = "消息类型不能为空")
- @InEnum(IotDeviceMessageTypeEnum.class)
- private String type;
-
- @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
- @NotEmpty(message = "标识符不能为空")
- private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
-
- @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
- private Object data; // 例如说:服务调用的 params、属性设置的 properties
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java
deleted file mode 100644
index 778d75bba8..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
-
-import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-
-@Schema(description = "管理后台 - IoT 设备上行 Request VO") // 属性上报、事件上报、状态变更等
-@Data
-public class IotDeviceUpstreamReqVO {
-
- @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
- @NotNull(message = "设备编号不能为空")
- private Long id;
-
- @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
- @NotEmpty(message = "消息类型不能为空")
- @InEnum(IotDeviceMessageTypeEnum.class)
- private String type;
-
- @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
- @NotEmpty(message = "标识符不能为空")
- private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
-
- @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
- private Object data; // 例如说:属性上报的 properties、事件上报的 params
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogPageReqVO.java
deleted file mode 100644
index fcf36994fc..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogPageReqVO.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotEmpty;
-import lombok.Data;
-
-@Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO")
-@Data
-public class IotDeviceLogPageReqVO extends PageParam {
-
- @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
- @NotEmpty(message = "设备标识不能为空")
- private String deviceKey;
-
- @Schema(description = "消息类型", example = "property")
- private String type; // 参见 IotDeviceMessageTypeEnum 枚举,精准匹配
-
- @Schema(description = "标识符", example = "temperature")
- private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举,模糊匹配
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogRespVO.java
deleted file mode 100644
index 6e6639ede9..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogRespVO.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-@Schema(description = "管理后台 - IoT 设备日志 Response VO")
-@Data
-public class IotDeviceLogRespVO {
-
- @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
- private String id;
-
- @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123")
- private String productKey;
-
- @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
- private String deviceKey;
-
- @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
- private String type;
-
- @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
- private String identifier;
-
- @Schema(description = "日志内容", requiredMode = Schema.RequiredMode.REQUIRED)
- private String content;
-
- @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
- private LocalDateTime reportTime;
-
- @Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
- private LocalDateTime ts;
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceAuthInfoRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceAuthInfoRespVO.java
new file mode 100644
index 0000000000..acd65ad800
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceAuthInfoRespVO.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+@Schema(description = "管理后台 - IoT 设备认证信息 Response VO")
+@Data
+public class IotDeviceAuthInfoRespVO {
+
+ @Schema(description = "客户端 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123.device001")
+ @NotBlank(message = "客户端 ID 不能为空")
+ private String clientId;
+
+ @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "device001&product123")
+ @NotBlank(message = "用户名不能为空")
+ private String username;
+
+ @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1a2b3c4d5e6f7890abcdef1234567890")
+ @NotBlank(message = "密码不能为空")
+ private String password;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceByProductKeyAndNamesReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceByProductKeyAndNamesReqVO.java
new file mode 100644
index 0000000000..e617cad935
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceByProductKeyAndNamesReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 通过产品标识和设备名称列表获取设备 Request VO")
+@Data
+public class IotDeviceByProductKeyAndNamesReqVO {
+
+ @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1de24640dfe")
+ @NotBlank(message = "产品标识不能为空")
+ private String productKey;
+
+ @Schema(description = "设备名称列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "device001,device002")
+ @NotEmpty(message = "设备名称列表不能为空")
+ private List deviceNames;
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java
index 74585be565..55f7a98c60 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java
@@ -1,8 +1,11 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
import cn.idev.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.iot.enums.product.IotLocationTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -34,4 +37,9 @@ public class IotDeviceImportExcelVO {
@ExcelProperty("设备分组")
private String groupNames;
+ @ExcelProperty("上报方式(1:IP 定位, 2:设备上报,3:手动定位)")
+ @NotNull(message = "上报方式不能为空")
+ @InEnum(IotLocationTypeEnum.class)
+ private Integer locationType;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java
deleted file mode 100644
index 39d80c527d..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
-
-import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
-import cn.idev.excel.annotation.ExcelProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Schema(description = "管理后台 - IoT 设备 MQTT 连接参数 Response VO")
-@Data
-@ExcelIgnoreUnannotated
-public class IotDeviceMqttConnectionParamsRespVO {
-
- @Schema(description = "MQTT 客户端 ID", example = "24602")
- @ExcelProperty("MQTT 客户端 ID")
- private String mqttClientId;
-
- @Schema(description = "MQTT 用户名", example = "芋艿")
- @ExcelProperty("MQTT 用户名")
- private String mqttUsername;
-
- @Schema(description = "MQTT 密码")
- @ExcelProperty("MQTT 密码")
- private String mqttPassword;
-
-}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java
index 6862677328..f7d515df96 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java
@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
+import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java
index 74ef173afc..ecb8f81c45 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java
@@ -1,12 +1,14 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
-import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
-import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.iot.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Set;
@@ -20,10 +22,6 @@ public class IotDeviceRespVO {
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
private Long id;
- @Schema(description = "设备唯一标识符", requiredMode = Schema.RequiredMode.REQUIRED)
- @ExcelProperty("设备唯一标识符")
- private String deviceKey;
-
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@ExcelProperty("设备名称")
private String deviceName;
@@ -86,8 +84,19 @@ public class IotDeviceRespVO {
@Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
private String config;
+ @Schema(description = "定位方式", example = "2")
+ @ExcelProperty(value = "定位方式", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.LOCATION_TYPE)
+ private Integer locationType;
+
+ @Schema(description = "设备位置的纬度", example = "45.000000")
+ private BigDecimal latitude;
+
+ @Schema(description = "设备位置的经度", example = "45.000000")
+ private BigDecimal longitude;
+
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
-}
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java
index b9ea9b99fa..7c8ecadb11 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java
@@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.iot.enums.product.IotLocationTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.Size;
import lombok.Data;
+import java.math.BigDecimal;
import java.util.Set;
@Schema(description = "管理后台 - IoT 设备新增/修改 Request VO")
@@ -13,10 +15,6 @@ public class IotDeviceSaveReqVO {
@Schema(description = "设备编号", example = "177")
private Long id;
- @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177")
- @Size(max = 50, message = "设备编号长度不能超过 50 个字符")
- private String deviceKey;
-
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.AUTO, example = "王五")
private String deviceName;
@@ -41,4 +39,14 @@ public class IotDeviceSaveReqVO {
@Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
private String config;
+ @Schema(description = "定位类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @InEnum(value = IotLocationTypeEnum.class, message = "定位方式必须是 {value}")
+ private Integer locationType;
+
+ @Schema(description = "设备位置的纬度", example = "16380")
+ private BigDecimal latitude;
+
+ @Schema(description = "设备位置的经度", example = "16380")
+ private BigDecimal longitude;
+
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessagePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessagePageReqVO.java
new file mode 100644
index 0000000000..1894dc9d7e
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessagePageReqVO.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - IoT 设备消息分页查询 Request VO")
+@Data
+public class IotDeviceMessagePageReqVO extends PageParam {
+
+ @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "设备编号不能为空")
+ private Long deviceId;
+
+ @Schema(description = "消息类型", example = "property")
+ @InEnum(IotDeviceMessageMethodEnum.class)
+ private String method;
+
+ @Schema(description = "是否上行", example = "true")
+ private Boolean upstream;
+
+ @Schema(description = "是否回复", example = "true")
+ private Boolean reply;
+
+ @Schema(description = "标识符", example = "temperature")
+ private String identifier;
+
+ @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ @Size(min = 2, max = 2, message = "请选择时间范围")
+ private LocalDateTime[] times;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageRespPairVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageRespPairVO.java
new file mode 100644
index 0000000000..119dd02777
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageRespPairVO.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - IoT 设备消息对 Response VO")
+@Data
+public class IotDeviceMessageRespPairVO {
+
+ @Schema(description = "请求消息", requiredMode = Schema.RequiredMode.REQUIRED)
+ private IotDeviceMessageRespVO request;
+
+ @Schema(description = "响应消息")
+ private IotDeviceMessageRespVO reply; // 通过 requestId 配对
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageRespVO.java
new file mode 100644
index 0000000000..e53f5acb60
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageRespVO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - IoT 设备消息 Response VO")
+@Data
+public class IotDeviceMessageRespVO {
+
+ @Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private String id;
+
+ @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime reportTime;
+
+ @Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime ts;
+
+ @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
+ private Long deviceId;
+
+ @Schema(description = "服务编号", example = "server_123")
+ private String serverId;
+
+ @Schema(description = "是否上行消息", example = "true", examples = "false")
+ private Boolean upstream;
+
+ @Schema(description = "是否回复消息", example = "false", examples = "true")
+ private Boolean reply;
+
+ @Schema(description = "标识符", example = "temperature")
+ private String identifier;
+
+ // ========== codec(编解码)字段 ==========
+
+ @Schema(description = "请求编号", example = "req_123")
+ private String requestId;
+
+ @Schema(description = "请求方法", requiredMode = Schema.RequiredMode.REQUIRED, example = "thing.property.report")
+ private String method;
+
+ @Schema(description = "请求参数")
+ private Object params;
+
+ @Schema(description = "响应结果")
+ private Object data;
+
+ @Schema(description = "响应错误码", example = "200")
+ private Integer code;
+
+ @Schema(description = "响应提示", example = "操作成功")
+ private String msg;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageSendReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageSendReqVO.java
new file mode 100644
index 0000000000..e93cabbd93
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageSendReqVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - IoT 设备消息发送 Request VO") // 属性上报、事件上报、状态变更等
+@Data
+public class IotDeviceMessageSendReqVO {
+
+ @Schema(description = "请求方法", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
+ @NotEmpty(message = "请求方法不能为空")
+ @InEnum(IotDeviceMessageMethodEnum.class)
+ private String method;
+
+ @Schema(description = "请求参数")
+ private Object params; // 例如说:属性上报的 properties、事件上报的 params
+
+ @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
+ @NotNull(message = "设备编号不能为空")
+ private Long deviceId;
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyDetailRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyDetailRespVO.java
new file mode 100644
index 0000000000..57712691f8
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyDetailRespVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.property;
+
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDataSpecs;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - IoT 设备属性详细 Response VO") // 额外增加 来自 ThingModelProperty 的变量 属性
+@Data
+public class IotDevicePropertyDetailRespVO extends IotDevicePropertyRespVO {
+
+ @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String name;
+
+ @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int")
+ private String dataType;
+
+ @Schema(description = "数据定义")
+ private ThingModelDataSpecs dataSpecs;
+
+ @Schema(description = "数据定义列表")
+ private List dataSpecsList;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyHistoryListReqVO.java
similarity index 72%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyHistoryListReqVO.java
index 0de45e4a71..eb737fac14 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyHistoryListReqVO.java
@@ -1,6 +1,5 @@
-package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.property;
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@@ -12,17 +11,14 @@ import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-@Schema(description = "管理后台 - IoT 设备属性历史分页 Request VO")
+@Schema(description = "管理后台 - IoT 设备属性历史列表 Request VO")
@Data
-public class IotDevicePropertyHistoryPageReqVO extends PageParam {
+public class IotDevicePropertyHistoryListReqVO {
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
@NotNull(message = "设备编号不能为空")
private Long deviceId;
- @Schema(description = "设备 Key", hidden = true)
- private String deviceKey; // 非前端传递,后端自己查询设置
-
@Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "属性标识符不能为空")
private String identifier;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyRespVO.java
similarity index 55%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyRespVO.java
index dd7a0d6ad2..841b1f1db4 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyRespVO.java
@@ -1,6 +1,5 @@
-package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo.property;
-import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -8,10 +7,10 @@ import lombok.Data;
@Data
public class IotDevicePropertyRespVO {
- @Schema(description = "属性定义", requiredMode = Schema.RequiredMode.REQUIRED)
- private ThingModelProperty property;
+ @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String identifier;
- @Schema(description = "最新值", requiredMode = Schema.RequiredMode.REQUIRED)
+ @Schema(description = "属性值", requiredMode = Schema.RequiredMode.REQUIRED)
private Object value;
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java
index 38407333ea..7c3a5b78f4 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java
@@ -3,13 +3,14 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
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.ota.vo.firmware.IotOtaFirmwareCreateReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareRespVO;
-import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService;
-import com.fhs.core.trans.anno.TransMethodResult;
+import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
@@ -22,12 +23,14 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - IoT OTA 固件")
@RestController
-@RequestMapping("/iot/ota-firmware")
+@RequestMapping("/iot/ota/firmware")
@Validated
public class IotOtaFirmwareController {
@Resource
private IotOtaFirmwareService otaFirmwareService;
+ @Resource
+ private IotProductService productService;
@PostMapping("/create")
@Operation(summary = "创建 OTA 固件")
@@ -47,10 +50,17 @@ public class IotOtaFirmwareController {
@GetMapping("/get")
@Operation(summary = "获得 OTA 固件")
@PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')")
- @TransMethodResult
public CommonResult getOtaFirmware(@RequestParam("id") Long id) {
- IotOtaFirmwareDO otaFirmware = otaFirmwareService.getOtaFirmware(id);
- return success(BeanUtils.toBean(otaFirmware, IotOtaFirmwareRespVO.class));
+ IotOtaFirmwareDO firmware = otaFirmwareService.getOtaFirmware(id);
+ if (firmware == null) {
+ return success(null);
+ }
+ return success(BeanUtils.toBean(firmware, IotOtaFirmwareRespVO.class, o -> {
+ IotProductDO product = productService.getProduct(firmware.getProductId());
+ if (product != null) {
+ o.setProductName(product.getName());
+ }
+ }));
}
@GetMapping("/page")
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskController.java
new file mode 100644
index 0000000000..807f96993b
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskController.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.iot.controller.admin.ota;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+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.ota.vo.task.IotOtaTaskPageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskCreateReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO;
+import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - IoT OTA 升级任务")
+@RestController
+@RequestMapping("/iot/ota/task")
+@Validated
+public class IotOtaTaskController {
+
+ @Resource
+ private IotOtaTaskService otaTaskService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建 OTA 升级任务")
+ @PreAuthorize(value = "@ss.hasPermission('iot:ota-task:create')")
+ public CommonResult createOtaTask(@Valid @RequestBody IotOtaTaskCreateReqVO createReqVO) {
+ return success(otaTaskService.createOtaTask(createReqVO));
+ }
+
+ @PostMapping("/cancel")
+ @Operation(summary = "取消 OTA 升级任务")
+ @Parameter(name = "id", description = "升级任务编号", required = true)
+ @PreAuthorize(value = "@ss.hasPermission('iot:ota-task:cancel')")
+ public CommonResult cancelOtaTask(@RequestParam("id") Long id) {
+ otaTaskService.cancelOtaTask(id);
+ return success(true);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得 OTA 升级任务分页")
+ @PreAuthorize(value = "@ss.hasPermission('iot:ota-task:query')")
+ public CommonResult> getOtaTaskPage(@Valid IotOtaTaskPageReqVO pageReqVO) {
+ PageResult pageResult = otaTaskService.getOtaTaskPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, IotOtaTaskRespVO.class));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得 OTA 升级任务")
+ @Parameter(name = "id", description = "升级任务编号", required = true, example = "1024")
+ @PreAuthorize(value = "@ss.hasPermission('iot:ota-task:query')")
+ public CommonResult getOtaTask(@RequestParam("id") Long id) {
+ IotOtaTaskDO upgradeTask = otaTaskService.getOtaTask(id);
+ return success(BeanUtils.toBean(upgradeTask, IotOtaTaskRespVO.class));
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java
new file mode 100644
index 0000000000..81ccea9b98
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java
@@ -0,0 +1,103 @@
+package cn.iocoder.yudao.module.iot.controller.admin.ota;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordRespVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
+import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService;
+import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskRecordService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.dromara.hutool.core.collection.CollUtil;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - IoT OTA 升级任务记录")
+@RestController
+@RequestMapping("/iot/ota/task/record")
+@Validated
+public class IotOtaTaskRecordController {
+
+ @Resource
+ private IotOtaTaskRecordService otaTaskRecordService;
+ @Resource
+ private IotDeviceService deviceService;
+ @Resource
+ private IotOtaFirmwareService otaFirmwareService;
+
+ @GetMapping("/get-status-statistics")
+ @Operation(summary = "获得 OTA 升级记录状态统计")
+ @Parameters({
+ @Parameter(name = "firmwareId", description = "固件编号", example = "1024"),
+ @Parameter(name = "taskId", description = "升级任务编号", example = "2048")
+ })
+ @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')")
+ public CommonResult