Commit eb7269083ab691f49ccbb81b513c0a344d8125c7

Authored by YunaiV
2 parents d597d005 638976da

Merge branch 'feature/iot' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17

Showing 340 changed files with 18037 additions and 1854 deletions

Too many changes.

To preserve performance only 100 of 340 files are displayed.

.gitignore
... ... @@ -51,3 +51,4 @@ rebel.xml
51 51 application-my.yaml
52 52  
53 53 /yudao-ui-app/unpackage/
  54 +**/.DS_Store
... ...
... ... @@ -16,7 +16,7 @@
16 16 <module>yudao-module-system</module>
17 17 <module>yudao-module-infra</module>
18 18 <!-- <module>yudao-module-member</module>-->
19   -<!-- <module>yudao-module-bpm</module>-->
  19 + <module>yudao-module-bpm</module>
20 20 <!-- <module>yudao-module-report</module>-->
21 21 <!-- <module>yudao-module-mp</module>-->
22 22 <!-- <module>yudao-module-pay</module>-->
... ... @@ -24,7 +24,7 @@
24 24 <!-- <module>yudao-module-crm</module>-->
25 25 <!-- <module>yudao-module-erp</module>-->
26 26 <!-- <module>yudao-module-ai</module>-->
27   -<!-- <module>yudao-module-iot</module>-->
  27 + <module>yudao-module-iot</module>
28 28 </modules>
29 29  
30 30 <name>${project.artifactId}</name>
... ...
yudao-dependencies/pom.xml
... ... @@ -32,8 +32,9 @@
32 32 <dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
33 33 <kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
34 34 <opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
  35 + <taos.version>3.3.3</taos.version>
35 36 <!-- 消息队列 -->
36   - <rocketmq-spring.version>2.3.1</rocketmq-spring.version>
  37 + <rocketmq-spring.version>2.3.2</rocketmq-spring.version>
37 38 <!-- 服务保障相关 -->
38 39 <lock4j.version>2.2.7</lock4j.version>
39 40 <!-- 监控相关 -->
... ... @@ -65,6 +66,8 @@
65 66 <bizlog-sdk.version>3.0.6</bizlog-sdk.version>
66 67 <netty.version>4.1.116.Final</netty.version>
67 68 <mqtt.version>1.2.5</mqtt.version>
  69 + <pf4j-spring.version>0.9.0</pf4j-spring.version>
  70 + <vertx.version>4.5.13</vertx.version>
68 71 <!-- 三方云服务相关 -->
69 72 <commons-io.version>2.17.0</commons-io.version>
70 73 <commons-compress.version>1.27.1</commons-compress.version>
... ... @@ -263,6 +266,12 @@
263 266 <version>${kingbase.jdbc.version}</version>
264 267 </dependency>
265 268  
  269 + <dependency>
  270 + <groupId>com.taosdata.jdbc</groupId>
  271 + <artifactId>taos-jdbcdriver</artifactId>
  272 + <version>${taos.version}</version>
  273 + </dependency>
  274 +
266 275 <!-- Job 定时任务相关 -->
267 276 <dependency>
268 277 <groupId>cn.iocoder.boot</groupId>
... ... @@ -276,7 +285,6 @@
276 285 <artifactId>yudao-spring-boot-starter-mq</artifactId>
277 286 <version>${revision}</version>
278 287 </dependency>
279   -
280 288 <dependency>
281 289 <groupId>org.apache.rocketmq</groupId>
282 290 <artifactId>rocketmq-spring-boot-starter</artifactId>
... ... @@ -591,6 +599,36 @@
591 599 </exclusions>
592 600 </dependency>
593 601  
  602 + <!-- PF4J -->
  603 + <dependency>
  604 + <groupId>org.pf4j</groupId>
  605 + <artifactId>pf4j-spring</artifactId>
  606 + <version>${pf4j-spring.version}</version>
  607 + <exclusions>
  608 + <exclusion>
  609 + <groupId>org.slf4j</groupId>
  610 + <artifactId>slf4j-log4j12</artifactId>
  611 + </exclusion>
  612 + </exclusions>
  613 + </dependency>
  614 +
  615 + <!-- Vert.x -->
  616 + <dependency>
  617 + <groupId>io.vertx</groupId>
  618 + <artifactId>vertx-core</artifactId>
  619 + <version>${vertx.version}</version>
  620 + </dependency>
  621 + <dependency>
  622 + <groupId>io.vertx</groupId>
  623 + <artifactId>vertx-web</artifactId>
  624 + <version>${vertx.version}</version>
  625 + </dependency>
  626 + <dependency>
  627 + <groupId>io.vertx</groupId>
  628 + <artifactId>vertx-mqtt</artifactId>
  629 + <version>${vertx.version}</version>
  630 + </dependency>
  631 +
594 632 <!-- MQTT -->
595 633 <dependency>
596 634 <groupId>org.eclipse.paho</groupId>
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/RpcConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.common.enums;
  2 +
  3 +/**
  4 + * RPC 相关的枚举
  5 + *
  6 + * 虽然放在 yudao-spring-boot-starter-rpc 会相对合适,但是每个 API 模块需要使用到,所以暂时只好放在此处
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public class RpcConstants {
  11 +
  12 + /**
  13 + * RPC API 的前缀
  14 + */
  15 + public static final String RPC_API_PREFIX = "/rpc-api";
  16 +
  17 +}
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java
... ... @@ -7,13 +7,15 @@ import cn.hutool.core.util.ReflectUtil;
7 7 import cn.hutool.core.util.StrUtil;
8 8 import cn.hutool.http.HttpRequest;
9 9 import cn.hutool.http.HttpResponse;
  10 +import jakarta.servlet.http.HttpServletRequest;
10 11 import org.springframework.util.StringUtils;
11 12 import org.springframework.web.util.UriComponents;
12 13 import org.springframework.web.util.UriComponentsBuilder;
13 14  
14   -import jakarta.servlet.http.HttpServletRequest;
15 15 import java.net.URI;
  16 +import java.net.URLEncoder;
16 17 import java.nio.charset.Charset;
  18 +import java.nio.charset.StandardCharsets;
17 19 import java.util.Map;
18 20  
19 21 /**
... ... @@ -23,6 +25,16 @@ import java.util.Map;
23 25 */
24 26 public class HttpUtils {
25 27  
  28 + /**
  29 + * 编码 URL 参数
  30 + *
  31 + * @param value 参数
  32 + * @return 编码后的参数
  33 + */
  34 + public static String encodeUtf8(String value) {
  35 + return URLEncoder.encode(value, StandardCharsets.UTF_8);
  36 + }
  37 +
26 38 @SuppressWarnings("unchecked")
27 39 public static String replaceUrlQuery(String url, String key, String value) {
28 40 UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java
1 1 package cn.iocoder.yudao.framework.common.util.number;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.hutool.core.util.NumberUtil;
4 5 import cn.hutool.core.util.StrUtil;
5 6  
6 7 import java.math.BigDecimal;
  8 +import java.util.List;
7 9  
8 10 /**
9 11 * 数字的工具类,补全 {@link cn.hutool.core.util.NumberUtil} 的功能
... ... @@ -20,6 +22,18 @@ public class NumberUtils {
20 22 return StrUtil.isNotEmpty(str) ? Integer.valueOf(str) : null;
21 23 }
22 24  
  25 + public static boolean isAllNumber(List<String> values) {
  26 + if (CollUtil.isEmpty(values)) {
  27 + return false;
  28 + }
  29 + for (String value : values) {
  30 + if (!NumberUtil.isNumber(value)) {
  31 + return false;
  32 + }
  33 + }
  34 + return true;
  35 + }
  36 +
23 37 /**
24 38 * 通过经纬度获取地球上两点之间的距离
25 39 *
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
... ... @@ -98,4 +98,8 @@ public class ServletUtils {
98 98 return JakartaServletUtil.getParamMap(request);
99 99 }
100 100  
  101 + public static Map<String, String> getHeaderMap(HttpServletRequest request) {
  102 + return JakartaServletUtil.getHeaderMap(request);
  103 + }
  104 +
101 105 }
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java
... ... @@ -97,12 +97,26 @@ public class SpringExpressionUtils {
97 97 * @return 执行界面
98 98 */
99 99 public static Object parseExpression(String expressionString) {
  100 + return parseExpression(expressionString, null);
  101 + }
  102 +
  103 + /**
  104 + * 从 Bean 工厂,解析 EL 表达式的结果
  105 + *
  106 + * @param expressionString EL 表达式
  107 + * @param variables 变量
  108 + * @return 执行界面
  109 + */
  110 + public static Object parseExpression(String expressionString, Map<String, Object> variables) {
100 111 if (StrUtil.isBlank(expressionString)) {
101 112 return null;
102 113 }
103 114 Expression expression = EXPRESSION_PARSER.parseExpression(expressionString);
104 115 StandardEvaluationContext context = new StandardEvaluationContext();
105 116 context.setBeanResolver(new BeanFactoryResolver(SpringUtil.getApplicationContext()));
  117 + if (MapUtil.isNotEmpty(variables)) {
  118 + context.setVariables(variables);
  119 + }
106 120 return expression.getValue(context);
107 121 }
108 122  
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
... ... @@ -45,6 +45,7 @@ public class TenantUtils {
45 45 *
46 46 * @param tenantId 租户编号
47 47 * @param callable 逻辑
  48 + * @return 结果
48 49 */
49 50 public static <V> V execute(Long tenantId, Callable<V> callable) {
50 51 Long oldTenantId = TenantContextHolder.getTenantId();
... ... @@ -79,6 +80,25 @@ public class TenantUtils {
79 80 }
80 81  
81 82 /**
  83 + * 忽略租户,执行对应的逻辑
  84 + *
  85 + * @param callable 逻辑
  86 + * @return 结果
  87 + */
  88 + public static <V> V executeIgnore(Callable<V> callable) {
  89 + Boolean oldIgnore = TenantContextHolder.isIgnore();
  90 + try {
  91 + TenantContextHolder.setIgnore(true);
  92 + // 执行逻辑
  93 + return callable.call();
  94 + } catch (Exception e) {
  95 + throw new RuntimeException(e);
  96 + } finally {
  97 + TenantContextHolder.setIgnore(oldIgnore);
  98 + }
  99 + }
  100 +
  101 + /**
82 102 * 将多租户编号,添加到 header 中
83 103 *
84 104 * @param headers HTTP 请求 headers
... ...
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
1 1 package cn.iocoder.yudao.framework.excel.core.util;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
3 4 import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
4 5 import com.alibaba.excel.EasyExcel;
5 6 import com.alibaba.excel.converters.longconverter.LongStringConverter;
... ... @@ -8,8 +9,6 @@ import jakarta.servlet.http.HttpServletResponse;
8 9 import org.springframework.web.multipart.MultipartFile;
9 10  
10 11 import java.io.IOException;
11   -import java.net.URLEncoder;
12   -import java.nio.charset.StandardCharsets;
13 12 import java.util.List;
14 13  
15 14 /**
... ... @@ -40,7 +39,7 @@ public class ExcelUtils {
40 39 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
41 40 .sheet(sheetName).doWrite(data);
42 41 // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了
43   - response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
  42 + response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
44 43 response.setContentType("application/vnd.ms-excel;charset=UTF-8");
45 44 }
46 45  
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
... ... @@ -63,6 +63,11 @@
63 63 <artifactId>opengauss-jdbc</artifactId>
64 64 <optional>true</optional>
65 65 </dependency>
  66 + <dependency>
  67 + <groupId>com.taosdata.jdbc</groupId>
  68 + <artifactId>taos-jdbcdriver</artifactId>
  69 + <optional>true</optional>
  70 + </dependency>
66 71  
67 72 <dependency>
68 73 <groupId>com.alibaba</groupId>
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongSetTypeHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mybatis.core.type;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.string.StrUtils;
  5 +import org.apache.ibatis.type.JdbcType;
  6 +import org.apache.ibatis.type.MappedJdbcTypes;
  7 +import org.apache.ibatis.type.MappedTypes;
  8 +import org.apache.ibatis.type.TypeHandler;
  9 +
  10 +import java.sql.CallableStatement;
  11 +import java.sql.PreparedStatement;
  12 +import java.sql.ResultSet;
  13 +import java.sql.SQLException;
  14 +import java.util.List;
  15 +import java.util.Set;
  16 +
  17 +/**
  18 + * Set<Long> 的类型转换器实现类,对应数据库的 varchar 类型
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@MappedJdbcTypes(JdbcType.VARCHAR)
  23 +@MappedTypes(List.class)
  24 +public class LongSetTypeHandler implements TypeHandler<Set<Long>> {
  25 +
  26 + private static final String COMMA = ",";
  27 +
  28 + @Override
  29 + public void setParameter(PreparedStatement ps, int i, Set<Long> strings, JdbcType jdbcType) throws SQLException {
  30 + // 设置占位符
  31 + ps.setString(i, CollUtil.join(strings, COMMA));
  32 + }
  33 +
  34 + @Override
  35 + public Set<Long> getResult(ResultSet rs, String columnName) throws SQLException {
  36 + String value = rs.getString(columnName);
  37 + return getResult(value);
  38 + }
  39 +
  40 + @Override
  41 + public Set<Long> getResult(ResultSet rs, int columnIndex) throws SQLException {
  42 + String value = rs.getString(columnIndex);
  43 + return getResult(value);
  44 + }
  45 +
  46 + @Override
  47 + public Set<Long> getResult(CallableStatement cs, int columnIndex) throws SQLException {
  48 + String value = cs.getString(columnIndex);
  49 + return getResult(value);
  50 + }
  51 +
  52 + private Set<Long> getResult(String value) {
  53 + if (value == null) {
  54 + return null;
  55 + }
  56 + return StrUtils.splitToLongSet(value, COMMA);
  57 + }
  58 +}
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java
... ... @@ -62,9 +62,9 @@ public class BannerApplicationRunner implements ApplicationRunner {
62 62 if (isNotPresent("cn.iocoder.yudao.module.ai.framework.web.config.AiWebConfiguration")) {
63 63 System.out.println("[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]");
64 64 }
65   - // IOT 物联网
  65 + // IoT 物联网
66 66 if (isNotPresent("cn.iocoder.yudao.module.iot.framework.web.config.IotWebConfiguration")) {
67   - System.out.println("[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]");
  67 + System.out.println("[IoT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]");
68 68 }
69 69 });
70 70 }
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
... ... @@ -395,11 +395,11 @@ public class GlobalExceptionHandler {
395 395 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
396 396 "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
397 397 }
398   - // 9. IOT 物联网
  398 + // 9. IoT 物联网
399 399 if (message.contains("iot_")) {
400   - log.error("[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
  400 + log.error("[IoT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
401 401 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
402   - "[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
  402 + "[IoT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
403 403 }
404 404 return null;
405 405 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java
... ... @@ -66,7 +66,9 @@ public class CrmReceivableDO extends BaseDO {
66 66 */
67 67 private LocalDateTime returnTime;
68 68 /**
69   - * 回款方式,关联枚举{@link CrmReceivableReturnTypeEnum}
  69 + * 回款方式
  70 + *
  71 + * 枚举 {@link CrmReceivableReturnTypeEnum}
70 72 */
71 73 private Integer returnType;
72 74 /**
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java
... ... @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.infra.framework.file.core.utils;
2 2  
3 3 import cn.hutool.core.io.IoUtil;
4 4 import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
5 6 import com.alibaba.ttl.TransmittableThreadLocal;
6 7 import jakarta.servlet.http.HttpServletResponse;
7 8 import lombok.SneakyThrows;
8 9 import org.apache.tika.Tika;
9 10  
10 11 import java.io.IOException;
11   -import java.net.URLEncoder;
12 12  
13 13 /**
14 14 * 文件类型 Utils
... ... @@ -60,7 +60,7 @@ public class FileTypeUtils {
60 60 */
61 61 public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
62 62 // 设置 header 和 contentType
63   - response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
  63 + response.setHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
64 64 String contentType = getMineType(content, filename);
65 65 response.setContentType(contentType);
66 66 // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题
... ...
yudao-module-iot/pom.xml
... ... @@ -10,6 +10,7 @@
10 10 <modules>
11 11 <module>yudao-module-iot-api</module>
12 12 <module>yudao-module-iot-biz</module>
  13 + <module>yudao-module-iot-plugins</module>
13 14 </modules>
14 15 <modelVersion>4.0.0</modelVersion>
15 16  
... ...
yudao-module-iot/yudao-module-iot-api/pom.xml
... ... @@ -12,6 +12,7 @@
12 12 <packaging>jar</packaging>
13 13  
14 14 <name>${project.artifactId}</name>
  15 + <!-- TODO 芋艿:需要在整理下,特别是 PF4J -->
15 16 <description>
16 17 物联网 模块 API,暴露给其它模块调用
17 18 </description>
... ... @@ -21,6 +22,32 @@
21 22 <groupId>cn.iocoder.boot</groupId>
22 23 <artifactId>yudao-common</artifactId>
23 24 </dependency>
  25 +
  26 + <!-- Web 相关 -->
  27 + <dependency>
  28 + <groupId>org.springframework</groupId>
  29 + <artifactId>spring-web</artifactId>
  30 + <scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
  31 + </dependency>
  32 +
  33 + <!-- 工具类相关 -->
  34 + <dependency>
  35 + <groupId>com.fasterxml.jackson.core</groupId>
  36 + <artifactId>jackson-databind</artifactId>
  37 + <scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
  38 + </dependency>
  39 +
  40 + <dependency>
  41 + <groupId>org.pf4j</groupId> <!-- PF4J:内置插件机制 -->
  42 + <artifactId>pf4j-spring</artifactId>
  43 + </dependency>
  44 +
  45 + <!-- 参数校验 -->
  46 + <dependency>
  47 + <groupId>org.springframework.boot</groupId>
  48 + <artifactId>spring-boot-starter-validation</artifactId>
  49 + <optional>true</optional>
  50 + </dependency>
24 51 </dependencies>
25 52  
26 53 </project>
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
  5 +import cn.iocoder.yudao.module.iot.enums.ApiConstants;
  6 +import jakarta.validation.Valid;
  7 +import org.springframework.web.bind.annotation.PostMapping;
  8 +import org.springframework.web.bind.annotation.RequestBody;
  9 +
  10 +/**
  11 + * 设备数据 Upstream 上行 API
  12 + *
  13 + * 目的:设备 -> 插件 -> 服务端
  14 + *
  15 + * @author haohao
  16 + */
  17 +public interface IotDeviceUpstreamApi {
  18 +
  19 + String PREFIX = ApiConstants.PREFIX + "/device/upstream";
  20 +
  21 + // ========== 设备相关 ==========
  22 +
  23 + /**
  24 + * 更新设备状态
  25 + *
  26 + * @param updateReqDTO 更新设备状态 DTO
  27 + */
  28 + @PostMapping(PREFIX + "/update-state")
  29 + CommonResult<Boolean> updateDeviceState(@Valid @RequestBody IotDeviceStateUpdateReqDTO updateReqDTO);
  30 +
  31 + /**
  32 + * 上报设备属性数据
  33 + *
  34 + * @param reportReqDTO 上报设备属性数据 DTO
  35 + */
  36 + @PostMapping(PREFIX + "/report-property")
  37 + CommonResult<Boolean> reportDeviceProperty(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO);
  38 +
  39 + /**
  40 + * 上报设备事件数据
  41 + *
  42 + * @param reportReqDTO 设备事件
  43 + */
  44 + @PostMapping(PREFIX + "/report-event")
  45 + CommonResult<Boolean> reportDeviceEvent(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO);
  46 +
  47 + // TODO @芋艿:这个需要 plugins 接入下
  48 + /**
  49 + * 注册设备
  50 + *
  51 + * @param registerReqDTO 注册设备 DTO
  52 + */
  53 + @PostMapping(PREFIX + "/register")
  54 + CommonResult<Boolean> registerDevice(@Valid @RequestBody IotDeviceRegisterReqDTO registerReqDTO);
  55 +
  56 + // TODO @芋艿:这个需要 plugins 接入下
  57 + /**
  58 + * 注册子设备
  59 + *
  60 + * @param registerReqDTO 注册子设备 DTO
  61 + */
  62 + @PostMapping(PREFIX + "/register-sub")
  63 + CommonResult<Boolean> registerSubDevice(@Valid @RequestBody IotDeviceRegisterSubReqDTO registerReqDTO);
  64 +
  65 + // TODO @芋艿:这个需要 plugins 接入下
  66 + /**
  67 + * 注册设备拓扑
  68 + *
  69 + * @param addReqDTO 注册设备拓扑 DTO
  70 + */
  71 + @PostMapping(PREFIX + "/add-topology")
  72 + CommonResult<Boolean> addDeviceTopology(@Valid @RequestBody IotDeviceTopologyAddReqDTO addReqDTO);
  73 +
  74 + // TODO @芋艿:考虑 http 认证
  75 + /**
  76 + * 认证 Emqx 连接
  77 + *
  78 + * @param authReqDTO 认证 Emqx 连接 DTO
  79 + */
  80 + @PostMapping(PREFIX + "/authenticate-emqx-connection")
  81 + CommonResult<Boolean> authenticateEmqxConnection(@Valid @RequestBody IotDeviceEmqxAuthReqDTO authReqDTO);
  82 +
  83 + // ========== 插件相关 ==========
  84 +
  85 + /**
  86 + * 心跳插件实例
  87 + *
  88 + * @param heartbeatReqDTO 心跳插件实例 DTO
  89 + */
  90 + @PostMapping(PREFIX + "/heartbeat-plugin-instance")
  91 + CommonResult<Boolean> heartbeatPluginInstance(@Valid @RequestBody IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO);
  92 +
  93 +}
0 94 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceConfigSetReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotNull;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【配置】设置 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceConfigSetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 配置
  18 + */
  19 + @NotNull(message = "配置不能为空")
  20 + private Map<String, Object> config;
  21 +
  22 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceDownstreamAbstractReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +/**
  7 + * IoT 设备下行的抽象 Request DTO
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Data
  12 +public abstract class IotDeviceDownstreamAbstractReqDTO {
  13 +
  14 + /**
  15 + * 请求编号
  16 + */
  17 + private String requestId;
  18 +
  19 + /**
  20 + * 产品标识
  21 + */
  22 + @NotEmpty(message = "产品标识不能为空")
  23 + private String productKey;
  24 + /**
  25 + * 设备名称
  26 + */
  27 + @NotEmpty(message = "设备名称不能为空")
  28 + private String deviceName;
  29 +
  30 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceOtaUpgradeReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import cn.hutool.core.map.MapUtil;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【OTA】升级下发 Request DTO(更新固件消息)
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceOtaUpgradeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 固件编号
  18 + */
  19 + private Long firmwareId;
  20 + /**
  21 + * 固件版本
  22 + */
  23 + private String version;
  24 +
  25 + /**
  26 + * 签名方式
  27 + *
  28 + * 例如说:MD5、SHA256
  29 + */
  30 + private String signMethod;
  31 + /**
  32 + * 固件文件签名
  33 + */
  34 + private String fileSign;
  35 + /**
  36 + * 固件文件大小
  37 + */
  38 + private Long fileSize;
  39 + /**
  40 + * 固件文件 URL
  41 + */
  42 + private String fileUrl;
  43 +
  44 + /**
  45 + * 自定义信息,建议使用 JSON 格式
  46 + */
  47 + private String information;
  48 +
  49 + public static IotDeviceOtaUpgradeReqDTO build(Map<?, ?> map) {
  50 + return new IotDeviceOtaUpgradeReqDTO()
  51 + .setFirmwareId(MapUtil.getLong(map, "firmwareId")).setVersion((String) map.get("version"))
  52 + .setSignMethod((String) map.get("signMethod")).setFileSign((String) map.get("fileSign"))
  53 + .setFileSize(MapUtil.getLong(map, "fileSize")).setFileUrl((String) map.get("fileUrl"))
  54 + .setInformation((String) map.get("information"));
  55 + }
  56 +
  57 + public static Map<?, ?> build(IotDeviceOtaUpgradeReqDTO dto) {
  58 + return MapUtil.builder()
  59 + .put("firmwareId", dto.getFirmwareId()).put("version", dto.getVersion())
  60 + .put("signMethod", dto.getSignMethod()).put("fileSign", dto.getFileSign())
  61 + .put("fileSize", dto.getFileSize()).put("fileUrl", dto.getFileUrl())
  62 + .put("information", dto.getInformation())
  63 + .build();
  64 + }
  65 +
  66 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.List;
  7 +
  8 +// TODO @芋艿:从 server => plugin => device 是否有必要?从阿里云 iot 来看,没有这个功能?!
  9 +// TODO @芋艿:是不是改成 read 更好?在看看阿里云的 topic 设计
  10 +/**
  11 + * IoT 设备【属性】获取 Request DTO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Data
  16 +public class IotDevicePropertyGetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  17 +
  18 + /**
  19 + * 属性标识数组
  20 + */
  21 + @NotEmpty(message = "属性标识数组不能为空")
  22 + private List<String> identifiers;
  23 +
  24 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertySetReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【属性】设置 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDevicePropertySetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 属性参数
  18 + */
  19 + @NotEmpty(message = "属性参数不能为空")
  20 + private Map<String, Object> properties;
  21 +
  22 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceServiceInvokeReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【服务】调用 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceServiceInvokeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 服务标识
  18 + */
  19 + @NotEmpty(message = "服务标识不能为空")
  20 + private String identifier;
  21 + /**
  22 + * 调用参数
  23 + */
  24 + private Map<String, Object> params;
  25 +
  26 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +// TODO @芋艿:要不要继承 IotDeviceUpstreamAbstractReqDTO
  7 +// TODO @芋艿:@haohao:后续其它认证的设计
  8 +/**
  9 + * IoT 认证 Emqx 连接 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceEmqxAuthReqDTO {
  15 +
  16 + /**
  17 + * 客户端 ID
  18 + */
  19 + @NotEmpty(message = "客户端 ID 不能为空")
  20 + private String clientId;
  21 +
  22 + /**
  23 + * 用户名
  24 + */
  25 + @NotEmpty(message = "用户名不能为空")
  26 + private String username;
  27 +
  28 + /**
  29 + * 密码
  30 + */
  31 + @NotEmpty(message = "密码不能为空")
  32 + private String password;
  33 +
  34 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【事件】上报 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 事件标识
  18 + */
  19 + @NotEmpty(message = "事件标识不能为空")
  20 + private String identifier;
  21 + /**
  22 + * 事件参数
  23 + */
  24 + private Map<String, Object> params;
  25 +
  26 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaProgressReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import lombok.Data;
  4 +
  5 +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/progress
  6 +/**
  7 + * IoT 设备【OTA】升级进度 Request DTO(上报更新固件进度)
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Data
  12 +public class IotDeviceOtaProgressReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  13 +
  14 + /**
  15 + * 固件编号
  16 + */
  17 + private Long firmwareId;
  18 +
  19 + /**
  20 + * 升级状态
  21 + *
  22 + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum}
  23 + */
  24 + private Integer status;
  25 + /**
  26 + * 升级进度,百分比
  27 + */
  28 + private Integer progress;
  29 +
  30 + /**
  31 + * 升级进度描述
  32 + */
  33 + private String description;
  34 +
  35 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaPullReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/pull
  4 +/**
  5 + * IoT 设备【OTA】升级下拉 Request DTO(拉取固件更新)
  6 + *
  7 + * @author 芋道源码
  8 + */
  9 +public class IotDeviceOtaPullReqDTO {
  10 +
  11 + /**
  12 + * 固件编号
  13 + */
  14 + private Long firmwareId;
  15 +
  16 + /**
  17 + * 固件版本
  18 + */
  19 + private String version;
  20 +
  21 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaReportReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/report
  4 +/**
  5 + * IoT 设备【OTA】上报 Request DTO(上报固件版本)
  6 + *
  7 + * @author 芋道源码
  8 + */
  9 +public class IotDeviceOtaReportReqDTO {
  10 +
  11 + /**
  12 + * 固件编号
  13 + */
  14 + private Long firmwareId;
  15 +
  16 + /**
  17 + * 固件版本
  18 + */
  19 + private String version;
  20 +
  21 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【属性】上报 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 属性参数
  18 + */
  19 + @NotEmpty(message = "属性参数不能为空")
  20 + private Map<String, Object> properties;
  21 +
  22 +}
0 23 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * IoT 设备【注册】自己 Request DTO
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +@Data
  11 +public class IotDeviceRegisterReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  12 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.List;
  7 +
  8 +/**
  9 + * IoT 设备【注册】子设备 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceRegisterSubReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  15 +
  16 + // TODO @芋艿:看看要不要优化命名
  17 + /**
  18 + * 子设备数组
  19 + */
  20 + @NotEmpty(message = "子设备不能为空")
  21 + private List<Device> params;
  22 +
  23 + /**
  24 + * 设备信息
  25 + */
  26 + @Data
  27 + public static class Device {
  28 +
  29 + /**
  30 + * 产品标识
  31 + */
  32 + @NotEmpty(message = "产品标识不能为空")
  33 + private String productKey;
  34 +
  35 + /**
  36 + * 设备名称
  37 + */
  38 + @NotEmpty(message = "设备名称不能为空")
  39 + private String deviceName;
  40 +
  41 + }
  42 +
  43 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceStateUpdateReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +/**
  9 + * IoT 设备【状态】更新 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceStateUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 设备状态
  18 + */
  19 + @NotNull(message = "设备状态不能为空")
  20 + @InEnum(IotDeviceStateEnum.class) // 只使用:在线、离线
  21 + private Integer state;
  22 +
  23 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.List;
  7 +
  8 +// TODO @芋艿:要写清楚,是来自设备网关,还是设备。
  9 +/**
  10 + * IoT 设备【拓扑】添加 Request DTO
  11 + */
  12 +@Data
  13 +public class IotDeviceTopologyAddReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  14 +
  15 + // TODO @芋艿:看看要不要优化命名
  16 + /**
  17 + * 子设备数组
  18 + */
  19 + @NotEmpty(message = "子设备不能为空")
  20 + private List<IotDeviceRegisterSubReqDTO.Device> params;
  21 +
  22 + /**
  23 + * 设备信息
  24 + */
  25 + @Data
  26 + public static class Device {
  27 +
  28 + /**
  29 + * 产品标识
  30 + */
  31 + @NotEmpty(message = "产品标识不能为空")
  32 + private String productKey;
  33 +
  34 + /**
  35 + * 设备名称
  36 + */
  37 + @NotEmpty(message = "设备名称不能为空")
  38 + private String deviceName;
  39 +
  40 + // TODO @芋艿:阿里云还有 sign 签名
  41 +
  42 + }
  43 +
  44 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
  4 +import com.fasterxml.jackson.databind.annotation.JsonSerialize;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import lombok.Data;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +/**
  11 + * IoT 设备上行的抽象 Request DTO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Data
  16 +public abstract class IotDeviceUpstreamAbstractReqDTO {
  17 +
  18 + /**
  19 + * 请求编号
  20 + */
  21 + private String requestId;
  22 +
  23 + /**
  24 + * 插件实例的进程编号
  25 + */
  26 + private String processId;
  27 +
  28 + /**
  29 + * 产品标识
  30 + */
  31 + @NotEmpty(message = "产品标识不能为空")
  32 + private String productKey;
  33 + /**
  34 + * 设备名称
  35 + */
  36 + @NotEmpty(message = "设备名称不能为空")
  37 + private String deviceName;
  38 +
  39 + /**
  40 + * 上报时间
  41 + */
  42 + @JsonSerialize(using = TimestampLocalDateTimeSerializer.class) // 解决 iot plugins 序列化 LocalDateTime 是数组,导致无法解析的问题
  43 + private LocalDateTime reportTime;
  44 +
  45 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotPluginInstanceHeartbeatReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import jakarta.validation.constraints.NotNull;
  5 +import lombok.Data;
  6 +
  7 +/**
  8 + * IoT 插件实例心跳 Request DTO
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +public class IotPluginInstanceHeartbeatReqDTO {
  14 +
  15 + /**
  16 + * 请求编号
  17 + */
  18 + @NotEmpty(message = "请求编号不能为空")
  19 + private String processId;
  20 +
  21 + /**
  22 + * 插件包标识符
  23 + */
  24 + @NotEmpty(message = "插件包标识符不能为空")
  25 + private String pluginKey;
  26 +
  27 + /**
  28 + * 插件实例所在 IP
  29 + */
  30 + @NotEmpty(message = "插件实例所在 IP 不能为空")
  31 + private String hostIp;
  32 + /**
  33 + * 插件实例的进程编号
  34 + */
  35 + @NotNull(message = "插件实例的进程编号不能为空")
  36 + private Integer downstreamPort;
  37 +
  38 + /**
  39 + * 是否在线
  40 + */
  41 + @NotNull(message = "是否在线不能为空")
  42 + private Boolean online;
  43 +
  44 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/package-info.java 0 → 100644
  1 +/**
  2 + * TODO 芋艿:占位
  3 + */
  4 +package cn.iocoder.yudao.module.iot.api.device.dto;
0 5 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.RpcConstants;
  4 +
  5 +/**
  6 + * API 相关的枚举
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public class ApiConstants {
  11 +
  12 + public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/iot";
  13 +
  14 + public static final String VERSION = "1.0.0";
  15 +
  16 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums;
  2 +
  3 +/**
  4 + * IoT 字典类型的枚举类
  5 + *
  6 + * @author 芋道源码
  7 + */
  8 +public class DictTypeConstants {
  9 +
  10 + public static final String PRODUCT_STATUS = "iot_product_status";
  11 + public static final String PRODUCT_DEVICE_TYPE = "iot_product_device_type";
  12 + public static final String NET_TYPE = "iot_net_type";
  13 + public static final String PROTOCOL_TYPE = "iot_protocol_type";
  14 + public static final String DATA_FORMAT = "iot_data_format";
  15 + public static final String VALIDATE_TYPE = "iot_validate_type";
  16 +
  17 + public static final String DEVICE_STATE = "iot_device_state";
  18 +
  19 + public static final String IOT_DATA_BRIDGE_DIRECTION_ENUM = "iot_data_bridge_direction_enum";
  20 + public static final String IOT_DATA_BRIDGE_TYPE_ENUM = "iot_data_bridge_type_enum";
  21 +
  22 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
... ... @@ -9,24 +9,67 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
9 9 */
10 10 public interface ErrorCodeConstants {
11 11  
12   - // ========== IoT 产品相关 1-050-001-000 ============
  12 + // ========== 产品相关 1-050-001-000 ============
13 13 ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在");
14   - ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在");
  14 + ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在");
15 15 ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除");
  16 + ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型");
16 17  
17   - // ========== IoT 产品物模型 1-050-002-000 ============
18   - ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
19   - ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
20   - ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。");
21   - ErrorCode THINK_MODEL_FUNCTION_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。");
22   - ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效");
  18 + // ========== 产品物模型 1-050-002-000 ============
  19 + ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
  20 + ErrorCode THING_MODEL_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
  21 + ErrorCode THING_MODEL_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。");
  22 + ErrorCode THING_MODEL_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。");
  23 + ErrorCode THING_MODEL_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效");
23 24  
24   - // ========== IoT 设备 1-050-003-000 ============
  25 + // ========== 设备 1-050-003-000 ============
25 26 ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在");
26 27 ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一");
27 28 ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除");
28   - ErrorCode DEVICE_NAME_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_003, "设备名称不能修改");
29   - ErrorCode DEVICE_PRODUCT_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_004, "产品不能修改");
30   - ErrorCode DEVICE_INVALID_DEVICE_STATUS = new ErrorCode(1_050_003_005, "无效的设备状态");
  29 + ErrorCode DEVICE_KEY_EXISTS = new ErrorCode(1_050_003_003, "设备标识已经存在");
  30 + ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在");
  31 + ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备");
  32 + ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!");
  33 + ErrorCode DEVICE_DOWNSTREAM_FAILED = new ErrorCode(1_050_003_007, "执行失败,原因:{}");
31 34  
32   -}
  35 + // ========== 产品分类 1-050-004-000 ==========
  36 + ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在");
  37 +
  38 + // ========== 设备分组 1-050-005-000 ==========
  39 + ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在");
  40 + ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除");
  41 +
  42 + // ========== 插件配置 1-050-006-000 ==========
  43 + ErrorCode PLUGIN_CONFIG_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件配置不存在");
  44 + ErrorCode PLUGIN_INSTALL_FAILED = new ErrorCode(1_050_006_001, "插件安装失败");
  45 + ErrorCode PLUGIN_INSTALL_FAILED_FILE_NAME_NOT_MATCH = new ErrorCode(1_050_006_002, "插件安装失败,文件名与原插件id不匹配");
  46 + ErrorCode PLUGIN_CONFIG_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件");
  47 + ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效");
  48 + ErrorCode PLUGIN_CONFIG_KEY_DUPLICATE = new ErrorCode(1_050_006_005, "插件标识已存在");
  49 + ErrorCode PLUGIN_START_FAILED = new ErrorCode(1_050_006_006, "插件启动失败");
  50 + ErrorCode PLUGIN_STOP_FAILED = new ErrorCode(1_050_006_007, "插件停止失败");
  51 +
  52 + // ========== 插件实例 1-050-007-000 ==========
  53 +
  54 + // ========== 固件相关 1-050-008-000 ==========
  55 +
  56 + ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在");
  57 + ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复");
  58 +
  59 + ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在");
  60 + ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "升级任务名称重复");
  61 + ErrorCode OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY = new ErrorCode(1_050_008_102, "设备编号列表不能为空");
  62 + ErrorCode OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY = new ErrorCode(1_050_008_103, "设备列表不能为空");
  63 + ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_104, "升级任务不能取消");
  64 +
  65 + ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在");
  66 + ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复");
  67 + ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试");
  68 +
  69 + // ========== MQTT 通信相关 1-050-009-000 ==========
  70 + ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal");
  71 +
  72 + // ========== IoT 数据桥梁 1-050-010-000 ==========
  73 + ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在");
  74 +
  75 +}
33 76 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.device;
  2 +
  3 +import lombok.Getter;
  4 +import lombok.RequiredArgsConstructor;
  5 +
  6 +// TODO @芋艿:需要添加对应的 DTO,以及上下行的链路,网关、网关服务、设备等
  7 +/**
  8 + * IoT 设备消息标识符枚举
  9 + */
  10 +@Getter
  11 +@RequiredArgsConstructor
  12 +public enum IotDeviceMessageIdentifierEnum {
  13 +
  14 + PROPERTY_GET("get"), // 下行 TODO 芋艿:【讨论】貌似这个“上行”更合理?device 主动拉取配置。和 IotDevicePropertyGetReqDTO 一样的配置
  15 + PROPERTY_SET("set"), // 下行
  16 + PROPERTY_REPORT("report"), // 上行
  17 +
  18 + STATE_ONLINE("online"), // 上行
  19 + STATE_OFFLINE("offline"), // 上行
  20 +
  21 + CONFIG_GET("get"), // 上行 TODO 芋艿:【讨论】暂时没有上行的场景
  22 + CONFIG_SET("set"), // 下行
  23 +
  24 + SERVICE_INVOKE("${identifier}"), // 下行
  25 + SERVICE_REPLY_SUFFIX("_reply"), // 芋艿:TODO 芋艿:【讨论】上行 or 下行
  26 +
  27 + OTA_UPGRADE("upgrade"), // 下行
  28 + OTA_PULL("pull"), // 上行
  29 + OTA_PROGRESS("progress"), // 上行
  30 + OTA_REPORT("report"), // 上行
  31 +
  32 + REGISTER_REGISTER("register"), // 上行
  33 + REGISTER_REGISTER_SUB("register_sub"), // 上行
  34 + REGISTER_UNREGISTER_SUB("unregister_sub"), // 下行
  35 +
  36 + TOPOLOGY_ADD("topology_add"), // 下行;
  37 + ;
  38 +
  39 + /**
  40 + * 标志符
  41 + */
  42 + private final String identifier;
  43 +
  44 +}
0 45 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 设备消息类型枚举
  11 + */
  12 +@Getter
  13 +@RequiredArgsConstructor
  14 +public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> {
  15 +
  16 + STATE("state"), // 设备状态
  17 + PROPERTY("property"), // 设备属性:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
  18 + EVENT("event"), // 设备事件:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
  19 + SERVICE("service"), // 设备服务:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
  20 + CONFIG("config"), // 设备配置:可参考 https://help.aliyun.com/zh/iot/user-guide/remote-configuration-1 远程配置
  21 + OTA("ota"), // 设备 OTA:可参考 https://help.aliyun.com/zh/iot/user-guide/ota-update OTA 升级
  22 + REGISTER("register"), // 设备注册:可参考 https://help.aliyun.com/zh/iot/user-guide/register-devices 设备身份注册
  23 + TOPOLOGY("topology"),; // 设备拓扑:可参考 https://help.aliyun.com/zh/iot/user-guide/manage-topological-relationships 设备拓扑
  24 +
  25 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new);
  26 +
  27 + /**
  28 + * 属性
  29 + */
  30 + private final String type;
  31 +
  32 + @Override
  33 + public String[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStateEnum.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.enums.device;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4 4 import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
5 6  
6 7 import java.util.Arrays;
7 8  
... ... @@ -10,46 +11,32 @@ import java.util.Arrays;
10 11 *
11 12 * @author haohao
12 13 */
  14 +@RequiredArgsConstructor
13 15 @Getter
14   -public enum IotDeviceStatusEnum implements ArrayValuable<Integer> {
  16 +public enum IotDeviceStateEnum implements ArrayValuable<Integer> {
15 17  
16 18 INACTIVE(0, "未激活"),
17 19 ONLINE(1, "在线"),
18   - OFFLINE(2, "离线"),
19   - DISABLED(3, "已禁用");
  20 + OFFLINE(2, "离线");
20 21  
21   - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDeviceStatusEnum::getStatus).toArray(Integer[]::new);
  22 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDeviceStateEnum::getState).toArray(Integer[]::new);
22 23  
23 24 /**
24 25 * 状态
25 26 */
26   - private final Integer status;
  27 + private final Integer state;
27 28 /**
28 29 * 状态名
29 30 */
30 31 private final String name;
31 32  
32   - IotDeviceStatusEnum(Integer status, String name) {
33   - this.status = status;
34   - this.name = name;
35   - }
36   -
37   - public static IotDeviceStatusEnum fromStatus(Integer status) {
38   - for (IotDeviceStatusEnum value : values()) {
39   - if (value.getStatus().equals(status)) {
40   - return value;
41   - }
42   - }
43   - return null;
44   - }
45   -
46   - public static boolean isValidStatus(Integer status) {
47   - return fromStatus(status) != null;
48   - }
49   -
50 33 @Override
51 34 public Integer[] array() {
52 35 return ARRAYS;
53 36 }
54 37  
  38 + public static boolean isOnline(Integer state) {
  39 + return ONLINE.getState().equals(state);
  40 + }
  41 +
55 42 }
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.ota;
  2 +
  3 +
  4 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  5 +import lombok.Getter;
  6 +import lombok.RequiredArgsConstructor;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +/**
  11 + * IoT OTA 升级记录的范围枚举
  12 + *
  13 + * @author haohao
  14 + */
  15 +@RequiredArgsConstructor
  16 +@Getter
  17 +public enum IotOtaUpgradeRecordStatusEnum implements ArrayValuable<Integer> {
  18 +
  19 + PENDING(0), // 待推送
  20 + PUSHED(10), // 已推送
  21 + UPGRADING(20), // 升级中
  22 + SUCCESS(30), // 升级成功
  23 + FAILURE(40), // 升级失败
  24 + CANCELED(50),; // 已取消
  25 +
  26 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeRecordStatusEnum::getStatus).toArray(Integer[]::new);
  27 +
  28 + /**
  29 + * 范围
  30 + */
  31 + private final Integer status;
  32 +
  33 + @Override
  34 + public Integer[] array() {
  35 + return ARRAYS;
  36 + }
  37 +
  38 +}
0 39 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT OTA 升级任务的范围枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotOtaUpgradeTaskScopeEnum implements ArrayValuable<Integer> {
  17 +
  18 + ALL(1), // 全部设备:只包括当前产品下的设备,不包括未来创建的设备
  19 + SELECT(2); // 指定设备
  20 +
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskScopeEnum::getScope).toArray(Integer[]::new);
  22 +
  23 + /**
  24 + * 范围
  25 + */
  26 + private final Integer scope;
  27 +
  28 + @Override
  29 + public Integer[] array() {
  30 + return ARRAYS;
  31 + }
  32 +
  33 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT OTA 升级任务的范围枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotOtaUpgradeTaskStatusEnum implements ArrayValuable<Integer> {
  17 +
  18 + IN_PROGRESS(10), // 进行中:升级中
  19 + COMPLETED(20), // 已完成:已结束,全部升级完成
  20 + INCOMPLETE(21), // 未完成:已结束,部分升级完成
  21 + CANCELED(30),; // 已取消:一般是主动取消任务
  22 +
  23 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskStatusEnum::getStatus).toArray(Integer[]::new);
  24 +
  25 + /**
  26 + * 范围
  27 + */
  28 + private final Integer status;
  29 +
  30 + @Override
  31 + public Integer[] array() {
  32 + return ARRAYS;
  33 + }
  34 +
  35 +}
0 36 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.plugin;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 部署方式枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotPluginDeployTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + JAR(0, "JAR 部署"),
  19 + STANDALONE(1, "独立部署");
  20 +
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginDeployTypeEnum::getDeployType).toArray(Integer[]::new);
  22 +
  23 + /**
  24 + * 部署方式
  25 + */
  26 + private final Integer deployType;
  27 + /**
  28 + * 部署方式名
  29 + */
  30 + private final String name;
  31 +
  32 + @Override
  33 + public Integer[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.plugin;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 插件状态枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotPluginStatusEnum implements ArrayValuable<Integer> {
  17 +
  18 + STOPPED(0, "停止"),
  19 + RUNNING(1, "运行");
  20 +
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginStatusEnum::getStatus).toArray(Integer[]::new);
  22 +
  23 + /**
  24 + * 状态
  25 + */
  26 + private final Integer status;
  27 + /**
  28 + * 状态名
  29 + */
  30 + private final String name;
  31 +
  32 + @Override
  33 + public Integer[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.plugin;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 插件类型枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotPluginTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + NORMAL(0, "普通插件"),
  19 + DEVICE(1, "设备插件");
  20 +
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginTypeEnum::getType).toArray(Integer[]::new);
  22 +
  23 + /**
  24 + * 类型
  25 + */
  26 + private final Integer type;
  27 + /**
  28 + * 类型名
  29 + */
  30 + private final String name;
  31 +
  32 + @Override
  33 + public Integer[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java
... ... @@ -7,7 +7,7 @@ import lombok.Getter;
7 7 import java.util.Arrays;
8 8  
9 9 /**
10   - * IOT 联网方式枚举类
  10 + * IoT 联网方式枚举类
11 11 *
12 12 * @author ahh
13 13 */
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java
... ... @@ -7,7 +7,7 @@ import lombok.Getter;
7 7 import java.util.Arrays;
8 8  
9 9 /**
10   - * IOT 产品的设备类型
  10 + * IoT 产品的设备类型
11 11 *
12 12 * @author ahh
13 13 */
... ... @@ -16,7 +16,7 @@ import java.util.Arrays;
16 16 public enum IotProductDeviceTypeEnum implements ArrayValuable<Integer> {
17 17  
18 18 DIRECT(0, "直连设备"),
19   - GATEWAY_CHILD(1, "网关子设备"),
  19 + GATEWAY_SUB(1, "网关子设备"),
20 20 GATEWAY(2, "网关设备");
21 21  
22 22 /**
... ... @@ -36,4 +36,24 @@ public enum IotProductDeviceTypeEnum implements ArrayValuable&lt;Integer&gt; {
36 36 return ARRAYS;
37 37 }
38 38  
  39 + /**
  40 + * 判断是否是网关
  41 + *
  42 + * @param type 类型
  43 + * @return 是否是网关
  44 + */
  45 + public static boolean isGateway(Integer type) {
  46 + return GATEWAY.getType().equals(type);
  47 + }
  48 +
  49 + /**
  50 + * 判断是否是网关子设备
  51 + *
  52 + * @param type 类型
  53 + * @return 是否是网关子设备
  54 + */
  55 + public static boolean isGatewaySub(Integer type) {
  56 + return GATEWAY_SUB.getType().equals(type);
  57 + }
  58 +
39 59 }
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java
... ... @@ -7,7 +7,7 @@ import lombok.Getter;
7 7 import java.util.Arrays;
8 8  
9 9 /**
10   - * IOT 产品的状态枚举类
  10 + * IoT 产品的状态枚举类
11 11 *
12 12 * @author ahh
13 13 */
... ... @@ -18,12 +18,12 @@ public enum IotProductStatusEnum implements ArrayValuable&lt;Integer&gt; {
18 18 UNPUBLISHED(0, "开发中"),
19 19 PUBLISHED(1, "已发布");
20 20  
21   - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProductStatusEnum::getType).toArray(Integer[]::new);
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProductStatusEnum::getStatus).toArray(Integer[]::new);
22 22  
23 23 /**
24 24 * 类型
25 25 */
26   - private final Integer type;
  26 + private final Integer status;
27 27 /**
28 28 * 描述
29 29 */
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java
... ... @@ -7,7 +7,7 @@ import lombok.Getter;
7 7 import java.util.Arrays;
8 8  
9 9 /**
10   - * IOT 接入网关协议枚举类
  10 + * IoT 接入网关协议枚举类
11 11 *
12 12 * @author ahh
13 13 */
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java
... ... @@ -7,7 +7,7 @@ import lombok.Getter;
7 7 import java.util.Arrays;
8 8  
9 9 /**
10   - * IOT 数据校验级别枚举类
  10 + * IoT 数据校验级别枚举类
11 11 *
12 12 * @author ahh
13 13 */
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 告警配置的接收方式枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotAlertConfigReceiveTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + SMS(1), // 短信
  19 + MAIL(2), // 邮箱
  20 + NOTIFY(3); // 通知
  21 +
  22 + private final Integer type;
  23 +
  24 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotAlertConfigReceiveTypeEnum::getType).toArray(Integer[]::new);
  25 +
  26 + @Override
  27 + public Integer[] array() {
  28 + return ARRAYS;
  29 + }
  30 +
  31 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 数据桥接的方向枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotDataBridgeDirectionEnum implements ArrayValuable<Integer> {
  17 +
  18 + INPUT(1), // 输入
  19 + OUTPUT(2); // 输出
  20 +
  21 + private final Integer type;
  22 +
  23 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeDirectionEnum::getType).toArray(Integer[]::new);
  24 +
  25 + @Override
  26 + public Integer[] array() {
  27 + return ARRAYS;
  28 + }
  29 +
  30 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 数据桥接的类型枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotDataBridgeTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + HTTP(1, "HTTP"),
  19 + TCP(2, "TCP"),
  20 + WEBSOCKET(3, "WEBSOCKET"),
  21 +
  22 + MQTT(10, "MQTT"),
  23 +
  24 + DATABASE(20, "DATABASE"),
  25 + REDIS_STREAM(21, "REDIS_STREAM"),
  26 +
  27 + ROCKETMQ(30, "ROCKETMQ"),
  28 + RABBITMQ(31, "RABBITMQ"),
  29 + KAFKA(32, "KAFKA");
  30 +
  31 + private final Integer type;
  32 +
  33 + private final String name;
  34 +
  35 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeTypeEnum::getType).toArray(Integer[]::new);
  36 +
  37 + @Override
  38 + public Integer[] array() {
  39 + return ARRAYS;
  40 + }
  41 +
  42 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 规则场景的触发类型枚举
  11 + *
  12 + * 设备触发,定时触发
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotRuleSceneActionTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + DEVICE_CONTROL(1), // 设备执行
  19 + ALERT(2), // 告警执行
  20 + DATA_BRIDGE(3); // 桥接执行
  21 +
  22 + private final Integer type;
  23 +
  24 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneActionTypeEnum::getType).toArray(Integer[]::new);
  25 +
  26 + @Override
  27 + public Integer[] array() {
  28 + return ARRAYS;
  29 + }
  30 +
  31 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  5 +import lombok.Getter;
  6 +import lombok.RequiredArgsConstructor;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +/**
  11 + * IoT 场景触发条件参数的操作符枚举
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@RequiredArgsConstructor
  16 +@Getter
  17 +public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayValuable<String> {
  18 +
  19 + EQUALS("=", "#source == #value"),
  20 + NOT_EQUALS("!=", "!(#source == #value)"),
  21 +
  22 + GREATER_THAN(">", "#source > #value"),
  23 + GREATER_THAN_OR_EQUALS(">=", "#source >= #value"),
  24 +
  25 + LESS_THAN("<", "#source < #value"),
  26 + LESS_THAN_OR_EQUALS("<=", "#source <= #value"),
  27 +
  28 + IN("in", "#values.contains(#source)"),
  29 + NOT_IN("not in", "!(#values.contains(#source))"),
  30 +
  31 + BETWEEN("between", "(#source >= #values.get(0)) && (#source <= #values.get(1))"),
  32 + NOT_BETWEEN("not between", "(#source < #values.get(0)) || (#source > #values.get(1))"),
  33 +
  34 + LIKE("like", "#source.contains(#value)"), // 字符串匹配
  35 + NOT_NULL("not null", "#source != null && #source.length() > 0"); // 非空
  36 +
  37 + private final String operator;
  38 + private final String springExpression;
  39 +
  40 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerConditionParameterOperatorEnum::getOperator).toArray(String[]::new);
  41 +
  42 + /**
  43 + * Spring 表达式 - 原始值
  44 + */
  45 + public static final String SPRING_EXPRESSION_SOURCE = "source";
  46 + /**
  47 + * Spring 表达式 - 目标值
  48 + */
  49 + public static final String SPRING_EXPRESSION_VALUE = "value";
  50 + /**
  51 + * Spring 表达式 - 目标值数组
  52 + */
  53 + public static final String SPRING_EXPRESSION_VALUE_List = "values";
  54 +
  55 + public static IotRuleSceneTriggerConditionParameterOperatorEnum operatorOf(String operator) {
  56 + return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values());
  57 + }
  58 +
  59 + @Override
  60 + public String[] array() {
  61 + return ARRAYS;
  62 + }
  63 +
  64 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 场景流转的触发类型枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotRuleSceneTriggerTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + DEVICE(1), // 设备触发
  19 + TIMER(2); // 定时触发
  20 +
  21 + private final Integer type;
  22 +
  23 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerTypeEnum::getType).toArray(Integer[]::new);
  24 +
  25 + @Override
  26 + public Integer[] array() {
  27 + return ARRAYS;
  28 + }
  29 +
  30 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 数据定义的数据类型枚举类
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotDataSpecsDataTypeEnum implements ArrayValuable<String> {
  17 +
  18 + INT("int"),
  19 + FLOAT("float"),
  20 + DOUBLE("double"),
  21 + ENUM("enum"),
  22 + BOOL("bool"),
  23 + TEXT("text"),
  24 + DATE("date"),
  25 + STRUCT("struct"),
  26 + ARRAY("array");
  27 +
  28 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotDataSpecsDataTypeEnum::getDataType).toArray(String[]::new);
  29 +
  30 + private final String dataType;
  31 +
  32 + @Override
  33 + public String[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java
1   -package cn.iocoder.yudao.module.iot.enums.product;
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
2 2  
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
3 4 import lombok.AllArgsConstructor;
4 5 import lombok.Getter;
5 6  
  7 +import java.util.Arrays;
  8 +
6 9 /**
7   - * IOT 访问方式枚举类
  10 + * IoT 产品物模型属性读取类型枚举
8 11 *
9 12 * @author ahh
10 13 */
11 14 @AllArgsConstructor
12 15 @Getter
13   -public enum IotAccessModeEnum {
  16 +public enum IotThingModelAccessModeEnum implements ArrayValuable<String> {
14 17  
15   - READ("r"),
16   - WRITE("w"),
  18 + READ_ONLY("r"),
17 19 READ_WRITE("rw");
18 20  
  21 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelAccessModeEnum::getMode).toArray(String[]::new);
  22 +
19 23 private final String mode;
20 24  
  25 + @Override
  26 + public String[] array() {
  27 + return ARRAYS;
  28 + }
  29 +
21 30 }
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +
  10 +/**
  11 + * IoT 产品物模型参数是输入参数还是输出参数枚举
  12 + *
  13 + * @author HUIHUI
  14 + */
  15 +@AllArgsConstructor
  16 +@Getter
  17 +public enum IotThingModelParamDirectionEnum implements ArrayValuable<String> {
  18 +
  19 + INPUT("input"), // 输入参数
  20 + OUTPUT("output"); // 输出参数
  21 +
  22 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelParamDirectionEnum::getDirection).toArray(String[]::new);
  23 +
  24 + private final String direction;
  25 +
  26 + @Override
  27 + public String[] array() {
  28 + return ARRAYS;
  29 + }
  30 +
  31 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 产品物模型服务调用方式枚举
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotThingModelServiceCallTypeEnum implements ArrayValuable<String> {
  17 +
  18 + ASYNC("async"), // 异步调用
  19 + SYNC("sync"); // 同步调用
  20 +
  21 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelServiceCallTypeEnum::getType).toArray(String[]::new);
  22 +
  23 + private final String type;
  24 +
  25 + @Override
  26 + public String[] array() {
  27 + return ARRAYS;
  28 + }
  29 +
  30 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 产品物模型事件类型枚举
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotThingModelServiceEventTypeEnum implements ArrayValuable<String> {
  17 +
  18 + INFO("info"), // 信息
  19 + ALERT("alert"), // 告警
  20 + ERROR("error"); // 故障
  21 +
  22 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelServiceEventTypeEnum::getType).toArray(String[]::new);
  23 +
  24 + private final String type;
  25 +
  26 + @Override
  27 + public String[] array() {
  28 + return ARRAYS;
  29 + }
  30 +
  31 +}
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java
1   -package cn.iocoder.yudao.module.iot.enums.product;
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4 4 import lombok.AllArgsConstructor;
... ... @@ -7,19 +7,19 @@ import lombok.Getter;
7 7 import java.util.Arrays;
8 8  
9 9 /**
10   - * IOT 产品功能(物模型)类型枚举类
  10 + * IoT 产品功能(物模型)类型枚举类
11 11 *
12 12 * @author ahh
13 13 */
14 14 @AllArgsConstructor
15 15 @Getter
16   -public enum IotProductFunctionTypeEnum implements ArrayValuable<Integer> {
  16 +public enum IotThingModelTypeEnum implements ArrayValuable<Integer> {
17 17  
18 18 PROPERTY(1, "属性"),
19 19 SERVICE(2, "服务"),
20 20 EVENT(3, "事件");
21 21  
22   - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProductFunctionTypeEnum::getType).toArray(Integer[]::new);
  22 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotThingModelTypeEnum::getType).toArray(Integer[]::new);
23 23  
24 24 /**
25 25 * 类型
... ...
yudao-module-iot/yudao-module-iot-biz/pom.xml
... ... @@ -25,6 +25,11 @@
25 25 <version>${revision}</version>
26 26 </dependency>
27 27  
  28 + <dependency>
  29 + <groupId>cn.iocoder.boot</groupId>
  30 + <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
  31 + </dependency>
  32 +
28 33 <!-- Web 相关 -->
29 34 <dependency>
30 35 <groupId>cn.iocoder.boot</groupId>
... ... @@ -38,10 +43,20 @@
38 43  
39 44 <!-- DB 相关 -->
40 45 <dependency>
  46 + <groupId>com.taosdata.jdbc</groupId>
  47 + <artifactId>taos-jdbcdriver</artifactId>
  48 + </dependency>
  49 +
  50 + <dependency>
41 51 <groupId>cn.iocoder.boot</groupId>
42 52 <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
43 53 </dependency>
44 54  
  55 + <dependency>
  56 + <groupId>cn.iocoder.boot</groupId>
  57 + <artifactId>yudao-spring-boot-starter-redis</artifactId>
  58 + </dependency>
  59 +
45 60 <!-- Test 测试相关 -->
46 61 <dependency>
47 62 <groupId>cn.iocoder.boot</groupId>
... ... @@ -54,11 +69,64 @@
54 69 <artifactId>yudao-spring-boot-starter-excel</artifactId>
55 70 </dependency>
56 71  
57   - <!-- MQTT -->
  72 + <!-- 消息队列相关 -->
  73 + <dependency>
  74 + <groupId>org.apache.rocketmq</groupId>
  75 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  76 + <optional>true</optional>
  77 + </dependency>
  78 + <dependency>
  79 + <groupId>org.springframework.kafka</groupId>
  80 + <artifactId>spring-kafka</artifactId>
  81 + <optional>true</optional>
  82 + </dependency>
  83 + <dependency>
  84 + <groupId>org.springframework.boot</groupId>
  85 + <artifactId>spring-boot-starter-amqp</artifactId>
  86 + <optional>true</optional>
  87 + </dependency>
  88 +
  89 + <dependency>
  90 + <groupId>org.pf4j</groupId> <!-- PF4J:内置插件机制 -->
  91 + <artifactId>pf4j-spring</artifactId>
  92 + </dependency>
  93 +
  94 + <!-- TODO @芋艿:bom 管理 -->
58 95 <dependency>
59   - <groupId>org.eclipse.paho</groupId>
60   - <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
  96 + <groupId>org.apache.groovy</groupId>
  97 + <artifactId>groovy-all</artifactId>
  98 + <version>4.0.25</version>
  99 + <type>pom</type>
61 100 </dependency>
  101 +
  102 + <!-- TODO @芋艿:bom 管理 -->
  103 + <dependency>
  104 + <groupId>org.graalvm.js</groupId>
  105 + <artifactId>js</artifactId>
  106 + <version>24.1.2</version>
  107 + <type>pom</type>
  108 + </dependency>
  109 + <dependency>
  110 + <groupId>org.graalvm.js</groupId>
  111 + <artifactId>js-scriptengine</artifactId>
  112 + <version>24.1.2</version>
  113 + </dependency>
  114 +
  115 + <!-- TODO @芋艿:合理注释 -->
  116 + <!-- IoT 数据桥梁的执行器所需消息队列。如果您只需要使用 rocketmq 那么则注释掉其它消息队列即可 -->
  117 + <!-- <dependency>-->
  118 + <!-- <groupId>org.apache.rocketmq</groupId>-->
  119 + <!-- <artifactId>rocketmq-spring-boot-starter</artifactId>-->
  120 + <!-- </dependency>-->
  121 + <!-- <dependency>-->
  122 + <!-- <groupId>org.springframework.kafka</groupId>-->
  123 + <!-- <artifactId>spring-kafka</artifactId>-->
  124 + <!-- </dependency>-->
  125 + <!-- <dependency>-->
  126 + <!-- <groupId>org.springframework.boot</groupId>-->
  127 + <!-- <artifactId>spring-boot-starter-amqp</artifactId>-->
  128 + <!-- </dependency>-->
  129 +
62 130 </dependencies>
63 131  
64 132 </project>
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot;
  2 +
  3 +import cn.hutool.script.ScriptUtil;
  4 +import javax.script.Bindings;
  5 +import javax.script.ScriptEngine;
  6 +import javax.script.ScriptException;
  7 +
  8 +/**
  9 + * TODO 芋艿:测试脚本的接入
  10 + */
  11 +public class ScriptTest {
  12 +
  13 + public static void main2(String[] args) {
  14 + // 创建一个 Groovy 脚本引擎
  15 + ScriptEngine engine = ScriptUtil.createGroovyEngine();
  16 +
  17 + // 创建绑定参数
  18 + Bindings bindings = engine.createBindings();
  19 + bindings.put("name", "Alice");
  20 + bindings.put("age", 30);
  21 +
  22 + // 定义一个稍微复杂的 Groovy 脚本
  23 + String script = "def greeting = 'Hello, ' + name + '!';\n" +
  24 + "def ageInFiveYears = age + 5;\n" +
  25 + "def message = greeting + ' In five years, you will be ' + ageInFiveYears + ' years old.';\n" +
  26 + "return message.toUpperCase();\n";
  27 +
  28 + try {
  29 + // 执行脚本并获取结果
  30 + Object result = engine.eval(script, bindings);
  31 + System.out.println(result); // 输出: HELLO, ALICE! IN FIVE YEARS, YOU WILL BE 35 YEARS OLD.
  32 + } catch (ScriptException e) {
  33 + e.printStackTrace();
  34 + }
  35 + }
  36 +
  37 + public static void main(String[] args) {
  38 + // 创建一个 JavaScript 脚本引擎
  39 + ScriptEngine jsEngine = ScriptUtil.createJsEngine();
  40 +
  41 + // 创建绑定参数
  42 + Bindings jsBindings = jsEngine.createBindings();
  43 + jsBindings.put("name", "Bob");
  44 + jsBindings.put("age", 25);
  45 +
  46 + // 定义一个简单的 JavaScript 脚本
  47 + String jsScript = "var greeting = 'Hello, ' + name + '!';\n" +
  48 + "var ageInTenYears = age + 10;\n" +
  49 + "var message = greeting + ' In ten years, you will be ' + ageInTenYears + ' years old.';\n" +
  50 + "message.toUpperCase();\n";
  51 +
  52 + try {
  53 + // 执行脚本并获取结果
  54 + Object jsResult = jsEngine.eval(jsScript, jsBindings);
  55 + System.out.println(jsResult); // 输出: HELLO, BOB! IN TEN YEARS, YOU WILL BE 35 YEARS OLD.
  56 + } catch (ScriptException e) {
  57 + e.printStackTrace();
  58 + }
  59 + }
  60 +
  61 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
  5 +import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
  6 +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
  7 +import jakarta.annotation.Resource;
  8 +import org.springframework.validation.annotation.Validated;
  9 +import org.springframework.web.bind.annotation.RestController;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  12 +
  13 +/**
  14 + * * 设备数据 Upstream 上行 API 实现类
  15 + */
  16 +@RestController
  17 +@Validated
  18 +public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
  19 +
  20 + @Resource
  21 + private IotDeviceUpstreamService deviceUpstreamService;
  22 + @Resource
  23 + private IotPluginInstanceService pluginInstanceService;
  24 +
  25 + // ========== 设备相关 ==========
  26 +
  27 + @Override
  28 + public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
  29 + deviceUpstreamService.updateDeviceState(updateReqDTO);
  30 + return success(true);
  31 + }
  32 +
  33 + @Override
  34 + public CommonResult<Boolean> reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) {
  35 + deviceUpstreamService.reportDeviceProperty(reportReqDTO);
  36 + return success(true);
  37 + }
  38 +
  39 + @Override
  40 + public CommonResult<Boolean> reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) {
  41 + deviceUpstreamService.reportDeviceEvent(reportReqDTO);
  42 + return success(true);
  43 + }
  44 +
  45 + @Override
  46 + public CommonResult<Boolean> registerDevice(IotDeviceRegisterReqDTO registerReqDTO) {
  47 + deviceUpstreamService.registerDevice(registerReqDTO);
  48 + return success(true);
  49 + }
  50 +
  51 + @Override
  52 + public CommonResult<Boolean> registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) {
  53 + deviceUpstreamService.registerSubDevice(registerReqDTO);
  54 + return success(true);
  55 + }
  56 +
  57 + @Override
  58 + public CommonResult<Boolean> addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) {
  59 + deviceUpstreamService.addDeviceTopology(addReqDTO);
  60 + return success(true);
  61 + }
  62 +
  63 + @Override
  64 + public CommonResult<Boolean> authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
  65 + boolean result = deviceUpstreamService.authenticateEmqxConnection(authReqDTO);
  66 + return success(result);
  67 + }
  68 +
  69 + // ========== 插件相关 ==========
  70 +
  71 + @Override
  72 + public CommonResult<Boolean> heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) {
  73 + pluginInstanceService.heartbeatPluginInstance(heartbeatReqDTO);
  74 + return success(true);
  75 + }
  76 +
  77 +}
0 78 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java 0 → 100644
  1 +/**
  2 + * 占位
  3 + *
  4 + * TODO 芋艿:后续删除
  5 + */
  6 +package cn.iocoder.yudao.module.iot.api;
0 7 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http 0 → 100644
  1 +### 请求 /iot/device/downstream 接口(服务调用) => 成功
  2 +POST {{baseUrl}}/iot/device/downstream
  3 +Content-Type: application/json
  4 +tenant-id: {{adminTenentId}}
  5 +Authorization: Bearer {{token}}
  6 +
  7 +{
  8 + "id": 25,
  9 + "type": "service",
  10 + "identifier": "temperature",
  11 + "data": {
  12 + "xx": "yy"
  13 + }
  14 +}
  15 +
  16 +### 请求 /iot/device/downstream 接口(属性设置) => 成功
  17 +POST {{baseUrl}}/iot/device/downstream
  18 +Content-Type: application/json
  19 +tenant-id: {{adminTenentId}}
  20 +Authorization: Bearer {{token}}
  21 +
  22 +{
  23 + "id": 25,
  24 + "type": "property",
  25 + "identifier": "set",
  26 + "data": {
  27 + "xx": "yy"
  28 + }
  29 +}
  30 +
  31 +### 请求 /iot/device/downstream 接口(属性获取) => 成功
  32 +POST {{baseUrl}}/iot/device/downstream
  33 +Content-Type: application/json
  34 +tenant-id: {{adminTenentId}}
  35 +Authorization: Bearer {{token}}
  36 +
  37 +{
  38 + "id": 25,
  39 + "type": "property",
  40 + "identifier": "get",
  41 + "data": ["xx", "yy"]
  42 +}
  43 +
  44 +### 请求 /iot/device/downstream 接口(配置设置) => 成功
  45 +POST {{baseUrl}}/iot/device/downstream
  46 +Content-Type: application/json
  47 +tenant-id: {{adminTenentId}}
  48 +Authorization: Bearer {{token}}
  49 +
  50 +{
  51 + "id": 25,
  52 + "type": "config",
  53 + "identifier": "set"
  54 +}
  55 +
  56 +### 请求 /iot/device/downstream 接口(OTA 升级) => 成功
  57 +POST {{baseUrl}}/iot/device/downstream
  58 +Content-Type: application/json
  59 +tenant-id: {{adminTenentId}}
  60 +Authorization: Bearer {{token}}
  61 +
  62 +{
  63 + "id": 25,
  64 + "type": "ota",
  65 + "identifier": "upgrade",
  66 + "data": {
  67 + "firmwareId": 1,
  68 + "version": "1.0.0",
  69 + "signMethod": "MD5",
  70 + "fileSign": "d41d8cd98f00b204e9800998ecf8427e",
  71 + "fileSize": 1024,
  72 + "fileUrl": "http://example.com/firmware.bin",
  73 + "information": "{\"desc\":\"升级到最新版本\"}"
  74 + }
  75 +}
0 76 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
1 1 package cn.iocoder.yudao.module.iot.controller.admin.device;
2 2  
  3 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
7   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO;
8   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
9   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO;
  8 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO;
  11 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
10 12 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
11 13 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  14 +import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService;
  15 +import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
12 16 import io.swagger.v3.oas.annotations.Operation;
13 17 import io.swagger.v3.oas.annotations.Parameter;
14 18 import io.swagger.v3.oas.annotations.tags.Tag;
15 19 import jakarta.annotation.Resource;
  20 +import jakarta.servlet.http.HttpServletResponse;
16 21 import jakarta.validation.Valid;
17 22 import org.springframework.security.access.prepost.PreAuthorize;
18 23 import org.springframework.validation.annotation.Validated;
19 24 import org.springframework.web.bind.annotation.*;
  25 +import org.springframework.web.multipart.MultipartFile;
20 26  
  27 +import java.io.IOException;
  28 +import java.util.Arrays;
  29 +import java.util.Collection;
  30 +import java.util.List;
  31 +
  32 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
21 33 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
22 35  
23 36 @Tag(name = "管理后台 - IoT 设备")
24 37 @RestController
... ... @@ -28,6 +41,10 @@ public class IotDeviceController {
28 41  
29 42 @Resource
30 43 private IotDeviceService deviceService;
  44 + @Resource
  45 + private IotDeviceUpstreamService deviceUpstreamService;
  46 + @Resource
  47 + private IotDeviceDownstreamService deviceDownstreamService;
31 48  
32 49 @PostMapping("/create")
33 50 @Operation(summary = "创建设备")
... ... @@ -36,14 +53,6 @@ public class IotDeviceController {
36 53 return success(deviceService.createDevice(createReqVO));
37 54 }
38 55  
39   - @PutMapping("/update-status")
40   - @Operation(summary = "更新设备状态")
41   - @PreAuthorize("@ss.hasPermission('iot:device:update')")
42   - public CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqVO updateReqVO) {
43   - deviceService.updateDeviceStatus(updateReqVO);
44   - return success(true);
45   - }
46   -
47 56 @PutMapping("/update")
48 57 @Operation(summary = "更新设备")
49 58 @PreAuthorize("@ss.hasPermission('iot:device:update')")
... ... @@ -52,8 +61,18 @@ public class IotDeviceController {
52 61 return success(true);
53 62 }
54 63  
  64 + // TODO @芋艿:参考阿里云:1)绑定网关;2)解绑网关
  65 +
  66 + @PutMapping("/update-group")
  67 + @Operation(summary = "更新设备分组")
  68 + @PreAuthorize("@ss.hasPermission('iot:device:update')")
  69 + public CommonResult<Boolean> updateDeviceGroup(@Valid @RequestBody IotDeviceUpdateGroupReqVO updateReqVO) {
  70 + deviceService.updateDeviceGroup(updateReqVO);
  71 + return success(true);
  72 + }
  73 +
55 74 @DeleteMapping("/delete")
56   - @Operation(summary = "删除设备")
  75 + @Operation(summary = "删除单个设备")
57 76 @Parameter(name = "id", description = "编号", required = true)
58 77 @PreAuthorize("@ss.hasPermission('iot:device:delete')")
59 78 public CommonResult<Boolean> deleteDevice(@RequestParam("id") Long id) {
... ... @@ -61,6 +80,15 @@ public class IotDeviceController {
61 80 return success(true);
62 81 }
63 82  
  83 + @DeleteMapping("/delete-list")
  84 + @Operation(summary = "删除多个设备")
  85 + @Parameter(name = "ids", description = "编号数组", required = true)
  86 + @PreAuthorize("@ss.hasPermission('iot:device:delete')")
  87 + public CommonResult<Boolean> deleteDeviceList(@RequestParam("ids") Collection<Long> ids) {
  88 + deviceService.deleteDeviceList(ids);
  89 + return success(true);
  90 + }
  91 +
64 92 @GetMapping("/get")
65 93 @Operation(summary = "获得设备")
66 94 @Parameter(name = "id", description = "编号", required = true, example = "1024")
... ... @@ -78,6 +106,19 @@ public class IotDeviceController {
78 106 return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class));
79 107 }
80 108  
  109 + @GetMapping("/export-excel")
  110 + @Operation(summary = "导出设备 Excel")
  111 + @PreAuthorize("@ss.hasPermission('iot:device:export')")
  112 + @ApiAccessLog(operateType = EXPORT)
  113 + public void exportDeviceExcel(@Valid IotDevicePageReqVO exportReqVO,
  114 + HttpServletResponse response) throws IOException {
  115 + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  116 + CommonResult<PageResult<IotDeviceRespVO>> result = getDevicePage(exportReqVO);
  117 + // 导出 Excel
  118 + ExcelUtils.write(response, "设备.xls", "数据", IotDeviceRespVO.class,
  119 + result.getData().getList());
  120 + }
  121 +
81 122 @GetMapping("/count")
82 123 @Operation(summary = "获得设备数量")
83 124 @Parameter(name = "productId", description = "产品编号", example = "1")
... ... @@ -86,4 +127,62 @@ public class IotDeviceController {
86 127 return success(deviceService.getDeviceCountByProductId(productId));
87 128 }
88 129  
  130 + @GetMapping("/simple-list")
  131 + @Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项")
  132 + @Parameter(name = "deviceType", description = "设备类型", example = "1")
  133 + public CommonResult<List<IotDeviceRespVO>> getSimpleDeviceList(
  134 + @RequestParam(value = "deviceType", required = false) Integer deviceType) {
  135 + List<IotDeviceDO> list = deviceService.getDeviceListByDeviceType(deviceType);
  136 + return success(convertList(list, device -> // 只返回 id、name 字段
  137 + new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName())));
  138 + }
  139 +
  140 + @PostMapping("/import")
  141 + @Operation(summary = "导入设备")
  142 + @PreAuthorize("@ss.hasPermission('iot:device:import')")
  143 + public CommonResult<IotDeviceImportRespVO> importDevice(
  144 + @RequestParam("file") MultipartFile file,
  145 + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport)
  146 + throws Exception {
  147 + List<IotDeviceImportExcelVO> list = ExcelUtils.read(file, IotDeviceImportExcelVO.class);
  148 + return success(deviceService.importDevice(list, updateSupport));
  149 + }
  150 +
  151 + @GetMapping("/get-import-template")
  152 + @Operation(summary = "获得导入设备模板")
  153 + public void importTemplate(HttpServletResponse response) throws IOException {
  154 + // 手动创建导出 demo
  155 + List<IotDeviceImportExcelVO> list = Arrays.asList(
  156 + IotDeviceImportExcelVO.builder().deviceName("温度传感器001").parentDeviceName("gateway110")
  157 + .productKey("1de24640dfe").groupNames("灰度分组,生产分组").build(),
  158 + IotDeviceImportExcelVO.builder().deviceName("biubiu")
  159 + .productKey("YzvHxd4r67sT4s2B").groupNames("").build());
  160 + // 输出
  161 + ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list);
  162 + }
  163 +
  164 + @PostMapping("/upstream")
  165 + @Operation(summary = "设备上行", description = "可用于设备模拟")
  166 + @PreAuthorize("@ss.hasPermission('iot:device:upstream')")
  167 + public CommonResult<Boolean> upstreamDevice(@Valid @RequestBody IotDeviceUpstreamReqVO upstreamReqVO) {
  168 + deviceUpstreamService.upstreamDevice(upstreamReqVO);
  169 + return success(true);
  170 + }
  171 +
  172 + @PostMapping("/downstream")
  173 + @Operation(summary = "设备下行", description = "可用于设备模拟")
  174 + @PreAuthorize("@ss.hasPermission('iot:device:downstream')")
  175 + public CommonResult<Boolean> downstreamDevice(@Valid @RequestBody IotDeviceDownstreamReqVO downstreamReqVO) {
  176 + deviceDownstreamService.downstreamDevice(downstreamReqVO);
  177 + return success(true);
  178 + }
  179 +
  180 + // TODO @haohao:是不是默认详情接口,不返回 secret,然后这个接口,用于统一返回。然后接口名可以更通用一点。
  181 + @GetMapping("/mqtt-connection-params")
  182 + @Operation(summary = "获取 MQTT 连接参数")
  183 + @PreAuthorize("@ss.hasPermission('iot:device:mqtt-connection-params')")
  184 + public CommonResult<IotDeviceMqttConnectionParamsRespVO> getMqttConnectionParams(@RequestParam("deviceId") Long deviceId) {
  185 + return success(deviceService.getMqttConnectionParams(deviceId));
  186 + }
  187 +
89 188 }
90 189 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceGroupController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupRespVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupSaveReqVO;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO;
  11 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceGroupService;
  12 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  13 +import io.swagger.v3.oas.annotations.Operation;
  14 +import io.swagger.v3.oas.annotations.Parameter;
  15 +import io.swagger.v3.oas.annotations.tags.Tag;
  16 +import jakarta.annotation.Resource;
  17 +import jakarta.validation.Valid;
  18 +import org.springframework.security.access.prepost.PreAuthorize;
  19 +import org.springframework.validation.annotation.Validated;
  20 +import org.springframework.web.bind.annotation.*;
  21 +
  22 +import java.util.List;
  23 +
  24 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  25 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  26 +
  27 +@Tag(name = "管理后台 - IoT 设备分组")
  28 +@RestController
  29 +@RequestMapping("/iot/device-group")
  30 +@Validated
  31 +public class IotDeviceGroupController {
  32 +
  33 + @Resource
  34 + private IotDeviceGroupService deviceGroupService;
  35 + @Resource
  36 + private IotDeviceService deviceService;
  37 +
  38 + @PostMapping("/create")
  39 + @Operation(summary = "创建设备分组")
  40 + @PreAuthorize("@ss.hasPermission('iot:device-group:create')")
  41 + public CommonResult<Long> createDeviceGroup(@Valid @RequestBody IotDeviceGroupSaveReqVO createReqVO) {
  42 + return success(deviceGroupService.createDeviceGroup(createReqVO));
  43 + }
  44 +
  45 + @PutMapping("/update")
  46 + @Operation(summary = "更新设备分组")
  47 + @PreAuthorize("@ss.hasPermission('iot:device-group:update')")
  48 + public CommonResult<Boolean> updateDeviceGroup(@Valid @RequestBody IotDeviceGroupSaveReqVO updateReqVO) {
  49 + deviceGroupService.updateDeviceGroup(updateReqVO);
  50 + return success(true);
  51 + }
  52 +
  53 + @DeleteMapping("/delete")
  54 + @Operation(summary = "删除设备分组")
  55 + @Parameter(name = "id", description = "编号", required = true)
  56 + @PreAuthorize("@ss.hasPermission('iot:device-group:delete')")
  57 + public CommonResult<Boolean> deleteDeviceGroup(@RequestParam("id") Long id) {
  58 + deviceGroupService.deleteDeviceGroup(id);
  59 + return success(true);
  60 + }
  61 +
  62 + @GetMapping("/get")
  63 + @Operation(summary = "获得设备分组")
  64 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  65 + @PreAuthorize("@ss.hasPermission('iot:device-group:query')")
  66 + public CommonResult<IotDeviceGroupRespVO> getDeviceGroup(@RequestParam("id") Long id) {
  67 + IotDeviceGroupDO deviceGroup = deviceGroupService.getDeviceGroup(id);
  68 + return success(BeanUtils.toBean(deviceGroup, IotDeviceGroupRespVO.class));
  69 + }
  70 +
  71 + @GetMapping("/page")
  72 + @Operation(summary = "获得设备分组分页")
  73 + @PreAuthorize("@ss.hasPermission('iot:device-group:query')")
  74 + public CommonResult<PageResult<IotDeviceGroupRespVO>> getDeviceGroupPage(@Valid IotDeviceGroupPageReqVO pageReqVO) {
  75 + PageResult<IotDeviceGroupDO> pageResult = deviceGroupService.getDeviceGroupPage(pageReqVO);
  76 + return success(BeanUtils.toBean(pageResult, IotDeviceGroupRespVO.class,
  77 + group -> group.setDeviceCount(deviceService.getDeviceCountByGroupId(group.getId()))));
  78 + }
  79 +
  80 + @GetMapping("/simple-list")
  81 + @Operation(summary = "获取设备分组的精简信息列表", description = "只包含被开启的分组,主要用于前端的下拉选项")
  82 + public CommonResult<List<IotDeviceGroupRespVO>> getSimpleDeviceGroupList() {
  83 + List<IotDeviceGroupDO> list = deviceGroupService.getDeviceGroupListByStatus(CommonStatusEnum.ENABLE.getStatus());
  84 + return success(convertList(list, group -> // 只返回 id、name 字段
  85 + new IotDeviceGroupRespVO().setId(group.getId()).setName(group.getName())));
  86 + }
  87 +
  88 +}
0 89 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogRespVO;
  8 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
  9 +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +import io.swagger.v3.oas.annotations.tags.Tag;
  12 +import jakarta.annotation.Resource;
  13 +import jakarta.validation.Valid;
  14 +import org.springframework.security.access.prepost.PreAuthorize;
  15 +import org.springframework.validation.annotation.Validated;
  16 +import org.springframework.web.bind.annotation.GetMapping;
  17 +import org.springframework.web.bind.annotation.RequestMapping;
  18 +import org.springframework.web.bind.annotation.RestController;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +
  22 +@Tag(name = "管理后台 - IoT 设备日志")
  23 +@RestController
  24 +@RequestMapping("/iot/device/log")
  25 +@Validated
  26 +public class IotDeviceLogController {
  27 +
  28 + @Resource
  29 + private IotDeviceLogService deviceLogService;
  30 +
  31 + @GetMapping("/page")
  32 + @Operation(summary = "获得设备日志分页")
  33 + @PreAuthorize("@ss.hasPermission('iot:device:log-query')")
  34 + public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) {
  35 + PageResult<IotDeviceLogDO> pageResult = deviceLogService.getDeviceLogPage(pageReqVO);
  36 + return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class));
  37 + }
  38 +
  39 +}
0 40 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.date.LocalDateTimeUtil;
  5 +import cn.hutool.core.lang.Assert;
  6 +import cn.hutool.core.util.StrUtil;
  7 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO;
  11 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  12 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
  13 +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
  14 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  15 +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
  16 +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
  17 +import io.swagger.v3.oas.annotations.Operation;
  18 +import io.swagger.v3.oas.annotations.Parameter;
  19 +import io.swagger.v3.oas.annotations.Parameters;
  20 +import io.swagger.v3.oas.annotations.tags.Tag;
  21 +import jakarta.annotation.Resource;
  22 +import jakarta.validation.Valid;
  23 +import org.springframework.security.access.prepost.PreAuthorize;
  24 +import org.springframework.validation.annotation.Validated;
  25 +import org.springframework.web.bind.annotation.GetMapping;
  26 +import org.springframework.web.bind.annotation.RequestMapping;
  27 +import org.springframework.web.bind.annotation.RequestParam;
  28 +import org.springframework.web.bind.annotation.RestController;
  29 +
  30 +import java.util.List;
  31 +import java.util.Map;
  32 +
  33 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  35 +
  36 +@Tag(name = "管理后台 - IoT 设备属性")
  37 +@RestController
  38 +@RequestMapping("/iot/device/property")
  39 +@Validated
  40 +public class IotDevicePropertyController {
  41 +
  42 + @Resource
  43 + private IotDevicePropertyService devicePropertyService;
  44 + @Resource
  45 + private IotThingModelService thingModelService;
  46 + @Resource
  47 + private IotDeviceService deviceService;
  48 +
  49 + @GetMapping("/latest")
  50 + @Operation(summary = "获取设备属性最新属性")
  51 + @Parameters({
  52 + @Parameter(name = "deviceId", description = "设备编号", required = true),
  53 + @Parameter(name = "identifier", description = "标识符"),
  54 + @Parameter(name = "name", description = "名称")
  55 + })
  56 + @PreAuthorize("@ss.hasPermission('iot:device:property-query')")
  57 + public CommonResult<List<IotDevicePropertyRespVO>> getLatestDeviceProperties(
  58 + @RequestParam("deviceId") Long deviceId,
  59 + @RequestParam(value = "identifier", required = false) String identifier,
  60 + @RequestParam(value = "name", required = false) String name) {
  61 + Map<String, IotDevicePropertyDO> properties = devicePropertyService.getLatestDeviceProperties(deviceId);
  62 +
  63 + // 拼接数据
  64 + IotDeviceDO device = deviceService.getDevice(deviceId);
  65 + Assert.notNull(device, "设备不存在");
  66 + List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductId(device.getProductId());
  67 + return success(convertList(properties.entrySet(), entry -> {
  68 + IotThingModelDO thingModel = CollUtil.findOne(thingModels,
  69 + item -> item.getIdentifier().equals(entry.getKey()));
  70 + if (thingModel == null || thingModel.getProperty() == null) {
  71 + return null;
  72 + }
  73 + if (StrUtil.isNotEmpty(identifier) && !StrUtil.contains(thingModel.getIdentifier(), identifier)) {
  74 + return null;
  75 + }
  76 + if (StrUtil.isNotEmpty(name) && !StrUtil.contains(thingModel.getName(), name)) {
  77 + return null;
  78 + }
  79 + // 构建对象
  80 + IotDevicePropertyDO property = entry.getValue();
  81 + return new IotDevicePropertyRespVO().setProperty(thingModel.getProperty())
  82 + .setValue(property.getValue()).setUpdateTime(LocalDateTimeUtil.toEpochMilli(property.getUpdateTime()));
  83 + }));
  84 + }
  85 +
  86 + @GetMapping("/history-page")
  87 + @Operation(summary = "获取设备属性历史数据")
  88 + @PreAuthorize("@ss.hasPermission('iot:device:property-query')")
  89 + public CommonResult<PageResult<IotDevicePropertyRespVO>> getHistoryDevicePropertyPage(
  90 + @Valid IotDevicePropertyHistoryPageReqVO pageReqVO) {
  91 + Assert.notEmpty(pageReqVO.getIdentifier(), "标识符不能为空");
  92 + return success(devicePropertyService.getHistoryDevicePropertyPage(pageReqVO));
  93 + }
  94 +
  95 +}
0 96 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java deleted
1   -package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageParam;
4   -import cn.iocoder.yudao.framework.common.validation.InEnum;
5   -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
6   -import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
7   -import io.swagger.v3.oas.annotations.media.Schema;
8   -import lombok.Data;
9   -import lombok.EqualsAndHashCode;
10   -import lombok.ToString;
11   -import org.springframework.format.annotation.DateTimeFormat;
12   -
13   -import java.math.BigDecimal;
14   -import java.time.LocalDateTime;
15   -
16   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
17   -
18   -@Schema(description = "管理后台 - IoT 设备分页 Request VO")
19   -@Data
20   -@EqualsAndHashCode(callSuper = true)
21   -@ToString(callSuper = true)
22   -public class IotDevicePageReqVO extends PageParam {
23   -
24   - // TODO @芋艿:需要去掉一些多余的字段;
25   -
26   - @Schema(description = "设备唯一标识符", example = "24602")
27   - private String deviceKey;
28   -
29   - @Schema(description = "设备名称", example = "王五")
30   - private String deviceName;
31   -
32   - @Schema(description = "备注名称", example = "张三")
33   - private String nickname;
34   -
35   - @Schema(description = "产品编号", example = "26202")
36   - private Long productId;
37   -
38   - @Schema(description = "产品标识")
39   - private String productKey;
40   -
41   - @Schema(description = "设备类型", example = "1")
42   - @InEnum(IotProductDeviceTypeEnum.class)
43   - private Integer deviceType;
44   -
45   - @Schema(description = "网关设备 ID", example = "16380")
46   - private Long gatewayId;
47   -
48   - @Schema(description = "设备状态", example = "1")
49   - @InEnum(IotDeviceStatusEnum.class)
50   - private Integer status;
51   -
52   - @Schema(description = "设备状态最后更新时间")
53   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
54   - private LocalDateTime[] statusLastUpdateTime;
55   -
56   - @Schema(description = "最后上线时间")
57   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
58   - private LocalDateTime[] lastOnlineTime;
59   -
60   - @Schema(description = "最后离线时间")
61   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
62   - private LocalDateTime[] lastOfflineTime;
63   -
64   - @Schema(description = "设备激活时间")
65   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
66   - private LocalDateTime[] activeTime;
67   -
68   - @Schema(description = "设备密钥,用于设备认证,需安全存储")
69   - private String deviceSecret;
70   -
71   - @Schema(description = "MQTT 客户端 ID", example = "24602")
72   - private String mqttClientId;
73   -
74   - @Schema(description = "MQTT 用户名", example = "芋艿")
75   - private String mqttUsername;
76   -
77   - @Schema(description = "MQTT 密码")
78   - private String mqttPassword;
79   -
80   - @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
81   - private String authType;
82   -
83   - @Schema(description = "创建时间")
84   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
85   - private LocalDateTime[] createTime;
86   -
87   -}
88 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java deleted
1   -package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
2   -
3   -import cn.iocoder.yudao.framework.common.validation.InEnum;
4   -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
5   -import io.swagger.v3.oas.annotations.media.Schema;
6   -import jakarta.validation.constraints.NotNull;
7   -import lombok.Data;
8   -
9   -@Schema(description = "管理后台 - IoT 设备状态更新 Request VO")
10   -@Data
11   -public class IotDeviceStatusUpdateReqVO {
12   -
13   - @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
14   - @NotNull(message = "设备编号不能为空")
15   - private Long id;
16   -
17   - @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
18   - @NotNull(message = "设备状态不能为空")
19   - @InEnum(IotDeviceStatusEnum.class)
20   - private Integer status;
21   -}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotEmpty;
  7 +import jakarta.validation.constraints.NotNull;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - IoT 设备下行 Request VO") // 服务调用、属性设置、属性获取等
  11 +@Data
  12 +public class IotDeviceDownstreamReqVO {
  13 +
  14 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  15 + @NotNull(message = "设备编号不能为空")
  16 + private Long id;
  17 +
  18 + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
  19 + @NotEmpty(message = "消息类型不能为空")
  20 + @InEnum(IotDeviceMessageTypeEnum.class)
  21 + private String type;
  22 +
  23 + @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
  24 + @NotEmpty(message = "标识符不能为空")
  25 + private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
  26 +
  27 + @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + private Object data; // 例如说:服务调用的 params、属性设置的 properties
  29 +
  30 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotEmpty;
  7 +import jakarta.validation.constraints.NotNull;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - IoT 设备上行 Request VO") // 属性上报、事件上报、状态变更等
  11 +@Data
  12 +public class IotDeviceUpstreamReqVO {
  13 +
  14 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  15 + @NotNull(message = "设备编号不能为空")
  16 + private Long id;
  17 +
  18 + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
  19 + @NotEmpty(message = "消息类型不能为空")
  20 + @InEnum(IotDeviceMessageTypeEnum.class)
  21 + private String type;
  22 +
  23 + @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
  24 + @NotEmpty(message = "标识符不能为空")
  25 + private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
  26 +
  27 + @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + private Object data; // 例如说:属性上报的 properties、事件上报的 params
  29 +
  30 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import lombok.Data;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO")
  9 +@Data
  10 +public class IotDeviceLogPageReqVO extends PageParam {
  11 +
  12 + @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
  13 + @NotEmpty(message = "设备标识不能为空")
  14 + private String deviceKey;
  15 +
  16 + @Schema(description = "消息类型", example = "property")
  17 + private String type; // 参见 IotDeviceMessageTypeEnum 枚举,精准匹配
  18 +
  19 + @Schema(description = "标识符", example = "temperature")
  20 + private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举,模糊匹配
  21 +
  22 +}
0 23 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备日志 Response VO")
  9 +@Data
  10 +public class IotDeviceLogRespVO {
  11 +
  12 + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  13 + private String id;
  14 +
  15 + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123")
  16 + private String productKey;
  17 +
  18 + @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
  19 + private String deviceKey;
  20 +
  21 + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
  22 + private String type;
  23 +
  24 + @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
  25 + private String identifier;
  26 +
  27 + @Schema(description = "日志内容", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + private String content;
  29 +
  30 + @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + private LocalDateTime reportTime;
  32 +
  33 + @Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
  34 + private LocalDateTime ts;
  35 +
  36 +}
0 37 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import jakarta.validation.constraints.NotNull;
  7 +import jakarta.validation.constraints.Size;
  8 +import lombok.Data;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.time.LocalDateTime;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@Schema(description = "管理后台 - IoT 设备属性历史分页 Request VO")
  16 +@Data
  17 +public class IotDevicePropertyHistoryPageReqVO extends PageParam {
  18 +
  19 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  20 + @NotNull(message = "设备编号不能为空")
  21 + private Long deviceId;
  22 +
  23 + @Schema(description = "设备 Key", hidden = true)
  24 + private String deviceKey; // 非前端传递,后端自己查询设置
  25 +
  26 + @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
  27 + @NotEmpty(message = "属性标识符不能为空")
  28 + private String identifier;
  29 +
  30 + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + @Size(min = 2, max = 2, message = "请选择时间范围")
  33 + private LocalDateTime[] times;
  34 +
  35 +}
0 36 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
  2 +
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Schema(description = "管理后台 - IoT 设备属性 Response VO")
  8 +@Data
  9 +public class IotDevicePropertyRespVO {
  10 +
  11 + @Schema(description = "属性定义", requiredMode = Schema.RequiredMode.REQUIRED)
  12 + private ThingModelProperty property;
  13 +
  14 + @Schema(description = "最新值", requiredMode = Schema.RequiredMode.REQUIRED)
  15 + private Object value;
  16 +
  17 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  18 + private Long updateTime; // 由于从 TDengine 查询出来的是 Long 类型,所以这里也使用 Long 类型
  19 +
  20 +}
0 21 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelProperty;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import lombok.AllArgsConstructor;
  7 +import lombok.Builder;
  8 +import lombok.Data;
  9 +import lombok.NoArgsConstructor;
  10 +import lombok.experimental.Accessors;
  11 +
  12 +/**
  13 + * 设备 Excel 导入 VO
  14 + */
  15 +@Data
  16 +@Builder
  17 +@AllArgsConstructor
  18 +@NoArgsConstructor
  19 +@Accessors(chain = false) // 设置 chain = false,避免设备导入有问题
  20 +public class IotDeviceImportExcelVO {
  21 +
  22 + @ExcelProperty("设备名称")
  23 + @NotEmpty(message = "设备名称不能为空")
  24 + private String deviceName;
  25 +
  26 + @ExcelProperty("父设备名称")
  27 + @Schema(description = "父设备名称", example = "网关001")
  28 + private String parentDeviceName;
  29 +
  30 + @ExcelProperty("产品标识")
  31 + @NotEmpty(message = "产品标识不能为空")
  32 + private String productKey;
  33 +
  34 + @ExcelProperty("设备分组")
  35 + private String groupNames;
  36 +
  37 +}
0 38 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +@Schema(description = "管理后台 - IoT 设备导入 Response VO")
  11 +@Data
  12 +@Builder
  13 +public class IotDeviceImportRespVO {
  14 +
  15 + @Schema(description = "创建成功的设备名称数组", requiredMode = Schema.RequiredMode.REQUIRED)
  16 + private List<String> createDeviceNames;
  17 +
  18 + @Schema(description = "更新成功的设备名称数组", requiredMode = Schema.RequiredMode.REQUIRED)
  19 + private List<String> updateDeviceNames;
  20 +
  21 + @Schema(description = "导入失败的设备集合,key为设备名称,value为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
  22 + private Map<String, String> failureDeviceNames;
  23 +}
0 24 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  4 +import com.alibaba.excel.annotation.ExcelProperty;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.Data;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备 MQTT 连接参数 Response VO")
  9 +@Data
  10 +@ExcelIgnoreUnannotated
  11 +public class IotDeviceMqttConnectionParamsRespVO {
  12 +
  13 + @Schema(description = "MQTT 客户端 ID", example = "24602")
  14 + @ExcelProperty("MQTT 客户端 ID")
  15 + private String mqttClientId;
  16 +
  17 + @Schema(description = "MQTT 用户名", example = "芋艿")
  18 + @ExcelProperty("MQTT 用户名")
  19 + private String mqttUsername;
  20 +
  21 + @Schema(description = "MQTT 密码")
  22 + @ExcelProperty("MQTT 密码")
  23 + private String mqttPassword;
  24 +
  25 +}
0 26 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
  6 +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - IoT 设备分页 Request VO")
  11 +@Data
  12 +public class IotDevicePageReqVO extends PageParam {
  13 +
  14 + @Schema(description = "设备名称", example = "王五")
  15 + private String deviceName;
  16 +
  17 + @Schema(description = "备注名称", example = "张三")
  18 + private String nickname;
  19 +
  20 + @Schema(description = "产品编号", example = "26202")
  21 + private Long productId;
  22 +
  23 + @Schema(description = "设备类型", example = "1")
  24 + @InEnum(IotProductDeviceTypeEnum.class)
  25 + private Integer deviceType;
  26 +
  27 + @Schema(description = "设备状态", example = "1")
  28 + @InEnum(IotDeviceStateEnum.class)
  29 + private Integer status;
  30 +
  31 + @Schema(description = "设备分组编号", example = "1024")
  32 + private Long groupId;
  33 +
  34 +}
0 35 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java
1   -package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
2 2  
  3 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  4 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
3 5 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
4 6 import com.alibaba.excel.annotation.ExcelProperty;
5 7 import io.swagger.v3.oas.annotations.media.Schema;
6 8 import lombok.Data;
7 9  
8   -import java.math.BigDecimal;
9 10 import java.time.LocalDateTime;
  11 +import java.util.Set;
  12 +
  13 +import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.DEVICE_STATE;
10 14  
11 15 @Schema(description = "管理后台 - IoT 设备 Response VO")
12 16 @Data
... ... @@ -21,9 +25,24 @@ public class IotDeviceRespVO {
21 25 private String deviceKey;
22 26  
23 27 @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
24   - @ExcelProperty("设备名称备")
  28 + @ExcelProperty("设备名称")
25 29 private String deviceName;
26 30  
  31 + @Schema(description = "设备备注名称", example = "张三")
  32 + @ExcelProperty("设备备注名称")
  33 + private String nickname;
  34 +
  35 + @Schema(description = "设备序列号", example = "1024")
  36 + @ExcelProperty("设备序列号")
  37 + private String serialNumber;
  38 +
  39 + @Schema(description = "设备图片", example = "我是一名码农")
  40 + @ExcelProperty("设备图片")
  41 + private String picUrl;
  42 +
  43 + @Schema(description = "设备分组编号数组", example = "1,2")
  44 + private Set<Long> groupIds;
  45 +
27 46 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
28 47 @ExcelProperty("产品编号")
29 48 private Long productId;
... ... @@ -36,28 +55,21 @@ public class IotDeviceRespVO {
36 55 @ExcelProperty("设备类型")
37 56 private Integer deviceType;
38 57  
39   - @Schema(description = "设备备注名称", example = "张三")
40   - @ExcelProperty("设备备注名称")
41   - private String nickname;
42   -
43 58 @Schema(description = "网关设备 ID", example = "16380")
44 59 private Long gatewayId;
45 60  
46 61 @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
47   - @ExcelProperty("设备状态")
48   - private Integer status;
49   -
50   - @Schema(description = "设备状态最后更新时间")
51   - @ExcelProperty("设备状态最后更新时间")
52   - private LocalDateTime statusLastUpdateTime;
  62 + @ExcelProperty(value = "设备状态", converter = DictConvert.class)
  63 + @DictFormat(DEVICE_STATE)
  64 + private Integer state;
53 65  
54 66 @Schema(description = "最后上线时间")
55 67 @ExcelProperty("最后上线时间")
56   - private LocalDateTime lastOnlineTime;
  68 + private LocalDateTime onlineTime;
57 69  
58 70 @Schema(description = "最后离线时间")
59 71 @ExcelProperty("最后离线时间")
60   - private LocalDateTime lastOfflineTime;
  72 + private LocalDateTime offlineTime;
61 73  
62 74 @Schema(description = "设备激活时间")
63 75 @ExcelProperty("设备激活时间")
... ... @@ -67,22 +79,13 @@ public class IotDeviceRespVO {
67 79 @ExcelProperty("设备密钥")
68 80 private String deviceSecret;
69 81  
70   - @Schema(description = "MQTT 客户端 ID", example = "24602")
71   - @ExcelProperty("MQTT 客户端 ID")
72   - private String mqttClientId;
73   -
74   - @Schema(description = "MQTT 用户名", example = "芋艿")
75   - @ExcelProperty("MQTT 用户名")
76   - private String mqttUsername;
77   -
78   - @Schema(description = "MQTT 密码")
79   - @ExcelProperty("MQTT 密码")
80   - private String mqttPassword;
81   -
82 82 @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
83 83 @ExcelProperty("认证类型(如一机一密、动态注册)")
84 84 private String authType;
85 85  
  86 + @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
  87 + private String config;
  88 +
86 89 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
87 90 @ExcelProperty("创建时间")
88 91 private LocalDateTime createTime;
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java
1   -package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.Size;
4 5 import lombok.Data;
5 6  
  7 +import java.util.Set;
  8 +
6 9 @Schema(description = "管理后台 - IoT 设备新增/修改 Request VO")
7 10 @Data
8 11 public class IotDeviceSaveReqVO {
... ... @@ -10,13 +13,32 @@ public class IotDeviceSaveReqVO {
10 13 @Schema(description = "设备编号", example = "177")
11 14 private Long id;
12 15  
13   - @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
  16 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177")
  17 + @Size(max = 50, message = "设备编号长度不能超过 50 个字符")
  18 + private String deviceKey;
  19 +
  20 + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.AUTO, example = "王五")
14 21 private String deviceName;
15 22  
16 23 @Schema(description = "备注名称", example = "张三")
17 24 private String nickname;
18 25  
  26 + @Schema(description = "设备序列号", example = "123456")
  27 + private String serialNumber;
  28 +
  29 + @Schema(description = "设备图片", example = "https://iocoder.cn/1.png")
  30 + private String picUrl;
  31 +
  32 + @Schema(description = "设备分组编号数组", example = "1,2")
  33 + private Set<Long> groupIds;
  34 +
19 35 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
20 36 private Long productId;
21 37  
  38 + @Schema(description = "网关设备 ID", example = "16380")
  39 + private Long gatewayId;
  40 +
  41 + @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
  42 + private String config;
  43 +
22 44 }
23 45 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceUpdateGroupReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotEmpty;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Set;
  8 +
  9 +@Schema(description = "管理后台 - IoT 设备更新分组 Request VO")
  10 +@Data
  11 +public class IotDeviceUpdateGroupReqVO {
  12 +
  13 + @Schema(description = "设备编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
  14 + @NotEmpty(message = "设备编号列表不能为空")
  15 + private Set<Long> ids;
  16 +
  17 + @Schema(description = "分组编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
  18 + @NotEmpty(message = "分组编号列表不能为空")
  19 + private Set<Long> groupIds;
  20 +
  21 +}
0 22 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - IoT 设备分组分页 Request VO")
  15 +@Data
  16 +public class IotDeviceGroupPageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "分组名字", example = "李四")
  19 + private String name;
  20 +
  21 + @Schema(description = "创建时间")
  22 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  23 + private LocalDateTime[] createTime;
  24 +
  25 +}
0 26 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备分组 Response VO")
  9 +@Data
  10 +public class IotDeviceGroupRespVO {
  11 +
  12 + @Schema(description = "分组 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "3583")
  13 + private Long id;
  14 +
  15 + @Schema(description = "分组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  16 + private String name;
  17 +
  18 + @Schema(description = "分组状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Integer status;
  20 +
  21 + @Schema(description = "分组描述", example = "你说的对")
  22 + private String description;
  23 +
  24 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + private LocalDateTime createTime;
  26 +
  27 + @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  28 + private Long deviceCount;
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotEmpty;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备分组新增/修改 Request VO")
  9 +@Data
  10 +public class IotDeviceGroupSaveReqVO {
  11 +
  12 + @Schema(description = "分组 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "3583")
  13 + private Long id;
  14 +
  15 + @Schema(description = "分组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  16 + @NotEmpty(message = "分组名字不能为空")
  17 + private String name;
  18 +
  19 + @Schema(description = "分组状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  20 + @NotNull(message = "分组状态不能为空")
  21 + private Integer status;
  22 +
  23 + @Schema(description = "分组描述", example = "你说的对")
  24 + private String description;
  25 +
  26 +}
0 27 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareRespVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
  11 +import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.security.access.prepost.PreAuthorize;
  17 +import org.springframework.validation.annotation.Validated;
  18 +import org.springframework.web.bind.annotation.*;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +
  22 +@Tag(name = "管理后台 - IoT OTA 固件")
  23 +@RestController
  24 +@RequestMapping("/iot/ota-firmware")
  25 +@Validated
  26 +public class IotOtaFirmwareController {
  27 +
  28 + @Resource
  29 + private IotOtaFirmwareService otaFirmwareService;
  30 +
  31 + @PostMapping("/create")
  32 + @Operation(summary = "创建 OTA 固件")
  33 + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:create')")
  34 + public CommonResult<Long> createOtaFirmware(@Valid @RequestBody IotOtaFirmwareCreateReqVO createReqVO) {
  35 + return success(otaFirmwareService.createOtaFirmware(createReqVO));
  36 + }
  37 +
  38 + @PutMapping("/update")
  39 + @Operation(summary = "更新 OTA 固件")
  40 + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:update')")
  41 + public CommonResult<Boolean> updateOtaFirmware(@Valid @RequestBody IotOtaFirmwareUpdateReqVO updateReqVO) {
  42 + otaFirmwareService.updateOtaFirmware(updateReqVO);
  43 + return success(true);
  44 + }
  45 +
  46 + @GetMapping("/get")
  47 + @Operation(summary = "获得 OTA 固件")
  48 + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')")
  49 + public CommonResult<IotOtaFirmwareRespVO> getOtaFirmware(@RequestParam("id") Long id) {
  50 + IotOtaFirmwareDO otaFirmware = otaFirmwareService.getOtaFirmware(id);
  51 + return success(BeanUtils.toBean(otaFirmware, IotOtaFirmwareRespVO.class));
  52 + }
  53 +
  54 + @GetMapping("/page")
  55 + @Operation(summary = "获得 OTA 固件分页")
  56 + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')")
  57 + public CommonResult<PageResult<IotOtaFirmwareRespVO>> getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO) {
  58 + PageResult<IotOtaFirmwareDO> pageResult = otaFirmwareService.getOtaFirmwarePage(pageReqVO);
  59 + return success(BeanUtils.toBean(pageResult, IotOtaFirmwareRespVO.class));
  60 + }
  61 +
  62 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordRespVO;
  8 +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO;
  9 +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +import io.swagger.v3.oas.annotations.Parameter;
  12 +import io.swagger.v3.oas.annotations.tags.Tag;
  13 +import jakarta.annotation.Resource;
  14 +import jakarta.validation.Valid;
  15 +import org.springframework.security.access.prepost.PreAuthorize;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import java.util.Map;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +@Tag(name = "管理后台 - IoT OTA 升级记录")
  24 +@RestController
  25 +@RequestMapping("/iot/ota-upgrade-record")
  26 +@Validated
  27 +public class IotOtaUpgradeRecordController {
  28 +
  29 + @Resource
  30 + private IotOtaUpgradeRecordService upgradeRecordService;
  31 +
  32 + @GetMapping("/get-statistics")
  33 + @Operation(summary = "固件升级设备统计")
  34 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
  35 + @Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024")
  36 + public CommonResult<Map<Integer, Long>> getOtaUpgradeRecordStatistics(@RequestParam(value = "firmwareId") Long firmwareId) {
  37 + return success(upgradeRecordService.getOtaUpgradeRecordStatistics(firmwareId));
  38 + }
  39 +
  40 + @GetMapping("/get-count")
  41 + @Operation(summary = "获得升级记录分页 tab 数量")
  42 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
  43 + public CommonResult<Map<Integer, Long>> getOtaUpgradeRecordCount(
  44 + @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) {
  45 + return success(upgradeRecordService.getOtaUpgradeRecordCount(pageReqVO));
  46 + }
  47 +
  48 + @GetMapping("/page")
  49 + @Operation(summary = "获得升级记录分页")
  50 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
  51 + public CommonResult<PageResult<IotOtaUpgradeRecordRespVO>> getUpgradeRecordPage(
  52 + @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) {
  53 + PageResult<IotOtaUpgradeRecordDO> pageResult = upgradeRecordService.getUpgradeRecordPage(pageReqVO);
  54 + return success(BeanUtils.toBean(pageResult, IotOtaUpgradeRecordRespVO.class));
  55 + }
  56 +
  57 + @GetMapping("/get")
  58 + @Operation(summary = "获得升级记录")
  59 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
  60 + @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
  61 + public CommonResult<IotOtaUpgradeRecordRespVO> getUpgradeRecord(@RequestParam("id") Long id) {
  62 + IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordService.getUpgradeRecord(id);
  63 + return success(BeanUtils.toBean(upgradeRecord, IotOtaUpgradeRecordRespVO.class));
  64 + }
  65 +
  66 + @PutMapping("/retry")
  67 + @Operation(summary = "重试升级记录")
  68 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:retry')")
  69 + @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
  70 + public CommonResult<Boolean> retryUpgradeRecord(@RequestParam("id") Long id) {
  71 + upgradeRecordService.retryUpgradeRecord(id);
  72 + return success(true);
  73 + }
  74 +
  75 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskRespVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO;
  9 +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO;
  10 +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeTaskService;
  11 +import io.swagger.v3.oas.annotations.Operation;
  12 +import io.swagger.v3.oas.annotations.Parameter;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.security.access.prepost.PreAuthorize;
  17 +import org.springframework.validation.annotation.Validated;
  18 +import org.springframework.web.bind.annotation.*;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +
  22 +@Tag(name = "管理后台 - IoT OTA 升级任务")
  23 +@RestController
  24 +@RequestMapping("/iot/ota-upgrade-task")
  25 +@Validated
  26 +public class IotOtaUpgradeTaskController {
  27 +
  28 + @Resource
  29 + private IotOtaUpgradeTaskService upgradeTaskService;
  30 +
  31 + @PostMapping("/create")
  32 + @Operation(summary = "创建升级任务")
  33 + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:create')")
  34 + public CommonResult<Long> createUpgradeTask(@Valid @RequestBody IotOtaUpgradeTaskSaveReqVO createReqVO) {
  35 + return success(upgradeTaskService.createUpgradeTask(createReqVO));
  36 + }
  37 +
  38 + @PostMapping("/cancel")
  39 + @Operation(summary = "取消升级任务")
  40 + @Parameter(name = "id", description = "升级任务编号", required = true)
  41 + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:cancel')")
  42 + public CommonResult<Boolean> cancelUpgradeTask(@RequestParam("id") Long id) {
  43 + upgradeTaskService.cancelUpgradeTask(id);
  44 + return success(true);
  45 + }
  46 +
  47 + @GetMapping("/page")
  48 + @Operation(summary = "获得升级任务分页")
  49 + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')")
  50 + public CommonResult<PageResult<IotOtaUpgradeTaskRespVO>> getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO) {
  51 + PageResult<IotOtaUpgradeTaskDO> pageResult = upgradeTaskService.getUpgradeTaskPage(pageReqVO);
  52 + return success(BeanUtils.toBean(pageResult, IotOtaUpgradeTaskRespVO.class));
  53 + }
  54 +
  55 + @GetMapping("/get")
  56 + @Operation(summary = "获得升级任务")
  57 + @Parameter(name = "id", description = "升级任务编号", required = true, example = "1024")
  58 + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')")
  59 + public CommonResult<IotOtaUpgradeTaskRespVO> getUpgradeTask(@RequestParam("id") Long id) {
  60 + IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(id);
  61 + return success(BeanUtils.toBean(upgradeTask, IotOtaUpgradeTaskRespVO.class));
  62 + }
  63 +
  64 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotEmpty;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
  9 +
  10 +@Schema(description = "管理后台 - IoT OTA 固件创建 Request VO")
  11 +@Data
  12 +public class IotOtaFirmwareCreateReqVO {
  13 +
  14 + @Schema(description = "固件名称", requiredMode = REQUIRED, example = "智能开关固件")
  15 + @NotEmpty(message = "固件名称不能为空")
  16 + private String name;
  17 +
  18 + @Schema(description = "固件描述", example = "某品牌型号固件,测试用")
  19 + private String description;
  20 +
  21 + @Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0")
  22 + @NotEmpty(message = "版本号不能为空")
  23 + private String version;
  24 +
  25 + @Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024")
  26 + @NotNull(message = "产品编号不能为空")
  27 + private String productId;
  28 +
  29 + @Schema(description = "签名方式", example = "MD5")
  30 + // TODO @li:是不是必传哈
  31 + private String signMethod;
  32 +
  33 + @Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip")
  34 + @NotEmpty(message = "固件文件 URL 不能为空")
  35 + private String fileUrl;
  36 +
  37 + @Schema(description = "自定义信息,建议使用 JSON 格式", example = "{\"key1\":\"value1\",\"key2\":\"value2\"}")
  38 + private String information;
  39 +
  40 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Data
  8 +@Schema(description = "管理后台 - IoT OTA 固件分页 Request VO")
  9 +public class IotOtaFirmwarePageReqVO extends PageParam {
  10 +
  11 + /**
  12 + * 固件名称
  13 + */
  14 + @Schema(description = "固件名称", example = "智能开关固件")
  15 + private String name;
  16 +
  17 + /**
  18 + * 产品标识
  19 + */
  20 + @Schema(description = "产品标识", example = "1024")
  21 + private String productId;
  22 +
  23 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
  2 +
  3 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  4 +import com.fhs.core.trans.anno.Trans;
  5 +import com.fhs.core.trans.constant.TransType;
  6 +import com.fhs.core.trans.vo.VO;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +
  10 +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
  11 +
  12 +@Data
  13 +@Schema(description = "管理后台 - IoT OTA 固件 Response VO")
  14 +public class IotOtaFirmwareRespVO implements VO {
  15 +
  16 + /**
  17 + * 固件编号
  18 + */
  19 + @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024")
  20 + private Long id;
  21 + /**
  22 + * 固件名称
  23 + */
  24 + @Schema(description = "固件名称", requiredMode = REQUIRED, example = "OTA固件")
  25 + private String name;
  26 + /**
  27 + * 固件描述
  28 + */
  29 + @Schema(description = "固件描述")
  30 + private String description;
  31 + /**
  32 + * 版本号
  33 + */
  34 + @Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0")
  35 + private String version;
  36 +
  37 + /**
  38 + * 产品编号
  39 + * <p>
  40 + * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
  41 + */
  42 + @Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024")
  43 + @Trans(type = TransType.SIMPLE, target = IotProductDO.class, fields = {"name"}, refs = {"productName"})
  44 + private String productId;
  45 + /**
  46 + * 产品标识
  47 + * <p>
  48 + * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()}
  49 + */
  50 + @Schema(description = "产品标识", requiredMode = REQUIRED, example = "iot-product-key")
  51 + private String productKey;
  52 + /**
  53 + * 产品名称
  54 + */
  55 + @Schema(description = "产品名称", requiredMode = REQUIRED, example = "OTA产品")
  56 + private String productName;
  57 + /**
  58 + * 签名方式
  59 + * <p>
  60 + * 例如说:MD5、SHA256
  61 + */
  62 + @Schema(description = "签名方式", example = "MD5")
  63 + private String signMethod;
  64 + /**
  65 + * 固件文件签名
  66 + */
  67 + @Schema(description = "固件文件签名", example = "1024")
  68 + private String fileSign;
  69 + /**
  70 + * 固件文件大小
  71 + */
  72 + @Schema(description = "固件文件大小", requiredMode = REQUIRED, example = "1024")
  73 + private Long fileSize;
  74 + /**
  75 + * 固件文件 URL
  76 + */
  77 + @Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn")
  78 + private String fileUrl;
  79 + /**
  80 + * 自定义信息,建议使用 JSON 格式
  81 + */
  82 + @Schema(description = "自定义信息,建议使用 JSON 格式")
  83 + private String information;
  84 +
  85 +}
... ...