mirror of
https://gitee.com/zhijiantianya/ruoyi-vue-pro.git
synced 2025-12-26 08:26:44 +08:00
Merge branch 'feature/iot' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17
This commit is contained in:
commit
c4c451320d
2
pom.xml
2
pom.xml
@ -24,7 +24,7 @@
|
||||
<!-- <module>yudao-module-crm</module>-->
|
||||
<!-- <module>yudao-module-erp</module>-->
|
||||
<!-- <module>yudao-module-ai</module>-->
|
||||
<!-- <module>yudao-module-iot</module>-->
|
||||
<module>yudao-module-iot</module>
|
||||
</modules>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
@ -16,6 +16,7 @@ import java.util.Arrays;
|
||||
@AllArgsConstructor
|
||||
public enum DateIntervalEnum implements ArrayValuable<Integer> {
|
||||
|
||||
HOUR(0, "小时"), // 特殊:字典里,暂时不会有这个枚举!!!因为大多数情况下,用不到这个间隔
|
||||
DAY(1, "天"),
|
||||
WEEK(2, "周"),
|
||||
MONTH(3, "月"),
|
||||
|
||||
@ -8,6 +8,7 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
@ -16,8 +17,7 @@ import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.hutool.core.date.DatePattern.UTC_MS_WITH_XXX_OFFSET_PATTERN;
|
||||
import static cn.hutool.core.date.DatePattern.createFormatter;
|
||||
import static cn.hutool.core.date.DatePattern.*;
|
||||
|
||||
/**
|
||||
* 时间工具类,用于 {@link LocalDateTime}
|
||||
@ -82,6 +82,21 @@ public class LocalDateTimeUtils {
|
||||
return new LocalDateTime[]{buildTime(year1, month1, day1), buildTime(year2, month2, day2)};
|
||||
}
|
||||
|
||||
/**
|
||||
* 判指定断时间,是否在该时间范围内
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @param time 指定时间
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime, Timestamp time) {
|
||||
if (startTime == null || endTime == null || time == null) {
|
||||
return false;
|
||||
}
|
||||
return LocalDateTimeUtil.isIn(LocalDateTimeUtil.of(time), startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判指定断时间,是否在该时间范围内
|
||||
*
|
||||
@ -234,6 +249,11 @@ public class LocalDateTimeUtils {
|
||||
// 2. 循环,生成时间范围
|
||||
List<LocalDateTime[]> timeRanges = new ArrayList<>();
|
||||
switch (intervalEnum) {
|
||||
case HOUR:
|
||||
while (startTime.isBefore(endTime)) {
|
||||
timeRanges.add(new LocalDateTime[]{startTime, startTime.plusHours(1).minusNanos(1)});
|
||||
startTime = startTime.plusHours(1);
|
||||
}
|
||||
case DAY:
|
||||
while (startTime.isBefore(endTime)) {
|
||||
timeRanges.add(new LocalDateTime[]{startTime, startTime.plusDays(1).minusNanos(1)});
|
||||
@ -297,6 +317,8 @@ public class LocalDateTimeUtils {
|
||||
|
||||
// 2. 循环,生成时间范围
|
||||
switch (intervalEnum) {
|
||||
case HOUR:
|
||||
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATETIME_MINUTE_PATTERN);
|
||||
case DAY:
|
||||
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN);
|
||||
case WEEK:
|
||||
|
||||
@ -3,18 +3,22 @@ package cn.iocoder.yudao.framework.common.util.json;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
|
||||
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -32,7 +36,11 @@ public class JsonUtils {
|
||||
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值
|
||||
objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化
|
||||
// 解决 LocalDateTime 的序列化
|
||||
SimpleModule simpleModule = new JavaTimeModule()
|
||||
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
|
||||
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
|
||||
objectMapper.registerModules(simpleModule);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,6 +107,18 @@ public class JsonUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T parseObject(byte[] text, Type type) {
|
||||
if (ArrayUtil.isEmpty(text)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));
|
||||
} catch (IOException e) {
|
||||
log.error("json parse err,json:{}", text, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串解析成指定类型的对象
|
||||
* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下,
|
||||
|
||||
@ -60,4 +60,8 @@ public class ObjectUtils {
|
||||
return Arrays.asList(array).contains(obj);
|
||||
}
|
||||
|
||||
public static boolean isNotAllEmpty(Object... objs) {
|
||||
return !ObjectUtil.isAllEmpty(objs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -69,9 +69,8 @@ public class YudaoRedisMQConsumerAutoConfiguration {
|
||||
@ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
|
||||
public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractRedisStreamMessageListener<?>> listeners,
|
||||
RedisMQTemplate redisTemplate,
|
||||
@Value("${spring.application.name}") String groupName,
|
||||
RedissonClient redissonClient) {
|
||||
return new RedisPendingMessageResendJob(listeners, redisTemplate, groupName, redissonClient);
|
||||
return new RedisPendingMessageResendJob(listeners, redisTemplate, redissonClient);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,14 +140,14 @@ public class YudaoRedisMQConsumerAutoConfiguration {
|
||||
*
|
||||
* @return 消费者名字
|
||||
*/
|
||||
private static String buildConsumerName() {
|
||||
public static String buildConsumerName() {
|
||||
return String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID());
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 Redis 版本号,是否满足最低的版本号要求!
|
||||
*/
|
||||
private static void checkRedisVersion(RedisTemplate<String, ?> redisTemplate) {
|
||||
public static void checkRedisVersion(RedisTemplate<String, ?> redisTemplate) {
|
||||
// 获得 Redis 版本
|
||||
Properties info = redisTemplate.execute((RedisCallback<Properties>) RedisServerCommands::info);
|
||||
String version = MapUtil.getStr(info, "redis_version");
|
||||
|
||||
@ -35,7 +35,6 @@ public class RedisPendingMessageResendJob {
|
||||
|
||||
private final List<AbstractRedisStreamMessageListener<?>> listeners;
|
||||
private final RedisMQTemplate redisTemplate;
|
||||
private final String groupName;
|
||||
private final RedissonClient redissonClient;
|
||||
|
||||
/**
|
||||
@ -64,13 +63,13 @@ public class RedisPendingMessageResendJob {
|
||||
private void execute() {
|
||||
StreamOperations<String, Object, Object> ops = redisTemplate.getRedisTemplate().opsForStream();
|
||||
listeners.forEach(listener -> {
|
||||
PendingMessagesSummary pendingMessagesSummary = Objects.requireNonNull(ops.pending(listener.getStreamKey(), groupName));
|
||||
PendingMessagesSummary pendingMessagesSummary = Objects.requireNonNull(ops.pending(listener.getStreamKey(), listener.getGroup()));
|
||||
// 每个消费者的 pending 队列消息数量
|
||||
Map<String, Long> pendingMessagesPerConsumer = pendingMessagesSummary.getPendingMessagesPerConsumer();
|
||||
pendingMessagesPerConsumer.forEach((consumerName, pendingMessageCount) -> {
|
||||
log.info("[processPendingMessage][消费者({}) 消息数量({})]", consumerName, pendingMessageCount);
|
||||
// 每个消费者的 pending消息的详情信息
|
||||
PendingMessages pendingMessages = ops.pending(listener.getStreamKey(), Consumer.from(groupName, consumerName), Range.unbounded(), pendingMessageCount);
|
||||
PendingMessages pendingMessages = ops.pending(listener.getStreamKey(), Consumer.from(listener.getGroup(), consumerName), Range.unbounded(), pendingMessageCount);
|
||||
if (pendingMessages.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -91,7 +90,7 @@ public class RedisPendingMessageResendJob {
|
||||
.ofObject(records.get(0).getValue()) // 设置内容
|
||||
.withStreamKey(listener.getStreamKey()));
|
||||
// ack 消息消费完成
|
||||
redisTemplate.getRedisTemplate().opsForStream().acknowledge(groupName, records.get(0));
|
||||
redisTemplate.getRedisTemplate().opsForStream().acknowledge(listener.getGroup(), records.get(0));
|
||||
log.info("[processPendingMessage][消息({})重新投递成功]", records.get(0).getId());
|
||||
});
|
||||
});
|
||||
|
||||
@ -53,6 +53,12 @@ public abstract class AbstractRedisStreamMessageListener<T extends AbstractRedis
|
||||
this.streamKey = messageType.getDeclaredConstructor().newInstance().getStreamKey();
|
||||
}
|
||||
|
||||
protected AbstractRedisStreamMessageListener(String streamKey, String group) {
|
||||
this.messageType = null;
|
||||
this.streamKey = streamKey;
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ObjectRecord<String, String> message) {
|
||||
// 消费消息
|
||||
|
||||
@ -1,16 +1,19 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.config;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.baomidou.mybatisplus.extension.incrementer.*;
|
||||
import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
|
||||
import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
@ -18,6 +21,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -75,4 +79,11 @@ public class YudaoMybatisAutoConfiguration {
|
||||
throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JacksonTypeHandler jacksonTypeHandler(List<ObjectMapper> objectMappers) {
|
||||
// 特殊:设置 JacksonTypeHandler 的 ObjectMapper!
|
||||
JacksonTypeHandler.setObjectMapper(CollUtil.getFirst(objectMappers));
|
||||
return new JacksonTypeHandler(Object.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ public class RateLimiterAspect {
|
||||
|
||||
@Before("@annotation(rateLimiter)")
|
||||
public void beforePointCut(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||
// 获得 IdempotentKeyResolver 对象
|
||||
// 获得 RateLimiterKeyResolver 对象
|
||||
RateLimiterKeyResolver keyResolver = keyResolvers.get(rateLimiter.keyResolver());
|
||||
Assert.notNull(keyResolver, "找不到对应的 RateLimiterKeyResolver");
|
||||
// 解析 Key
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>yudao</artifactId>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modules>
|
||||
<module>yudao-module-iot-api</module>
|
||||
<module>yudao-module-iot-biz</module>
|
||||
<module>yudao-module-iot-plugins</module>
|
||||
<module>yudao-module-iot-core</module>
|
||||
<module>yudao-module-iot-gateway</module>
|
||||
</modules>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -20,7 +19,7 @@
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
物联网模块
|
||||
<!-- TODO 芋艿:需要补充下说明! -->
|
||||
<!-- TODO 芋艿:需要补充下说明! -->
|
||||
</description>
|
||||
|
||||
</project>
|
||||
@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>yudao-module-iot</artifactId>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>yudao-module-iot-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<!-- TODO 芋艿:需要在整理下,特别是 PF4J -->
|
||||
<description>
|
||||
物联网 模块 API,暴露给其它模块调用
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.pf4j</groupId> <!-- PF4J:内置插件机制 -->
|
||||
<artifactId>pf4j-spring</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -1,93 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
|
||||
import cn.iocoder.yudao.module.iot.enums.ApiConstants;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
/**
|
||||
* 设备数据 Upstream 上行 API
|
||||
*
|
||||
* 目的:设备 -> 插件 -> 服务端
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
public interface IotDeviceUpstreamApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/device/upstream";
|
||||
|
||||
// ========== 设备相关 ==========
|
||||
|
||||
/**
|
||||
* 更新设备状态
|
||||
*
|
||||
* @param updateReqDTO 更新设备状态 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/update-state")
|
||||
CommonResult<Boolean> updateDeviceState(@Valid @RequestBody IotDeviceStateUpdateReqDTO updateReqDTO);
|
||||
|
||||
/**
|
||||
* 上报设备属性数据
|
||||
*
|
||||
* @param reportReqDTO 上报设备属性数据 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/report-property")
|
||||
CommonResult<Boolean> reportDeviceProperty(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO);
|
||||
|
||||
/**
|
||||
* 上报设备事件数据
|
||||
*
|
||||
* @param reportReqDTO 设备事件
|
||||
*/
|
||||
@PostMapping(PREFIX + "/report-event")
|
||||
CommonResult<Boolean> reportDeviceEvent(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO);
|
||||
|
||||
// TODO @芋艿:这个需要 plugins 接入下
|
||||
/**
|
||||
* 注册设备
|
||||
*
|
||||
* @param registerReqDTO 注册设备 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/register")
|
||||
CommonResult<Boolean> registerDevice(@Valid @RequestBody IotDeviceRegisterReqDTO registerReqDTO);
|
||||
|
||||
// TODO @芋艿:这个需要 plugins 接入下
|
||||
/**
|
||||
* 注册子设备
|
||||
*
|
||||
* @param registerReqDTO 注册子设备 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/register-sub")
|
||||
CommonResult<Boolean> registerSubDevice(@Valid @RequestBody IotDeviceRegisterSubReqDTO registerReqDTO);
|
||||
|
||||
// TODO @芋艿:这个需要 plugins 接入下
|
||||
/**
|
||||
* 注册设备拓扑
|
||||
*
|
||||
* @param addReqDTO 注册设备拓扑 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/add-topology")
|
||||
CommonResult<Boolean> addDeviceTopology(@Valid @RequestBody IotDeviceTopologyAddReqDTO addReqDTO);
|
||||
|
||||
// TODO @芋艿:考虑 http 认证
|
||||
/**
|
||||
* 认证 Emqx 连接
|
||||
*
|
||||
* @param authReqDTO 认证 Emqx 连接 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/authenticate-emqx-connection")
|
||||
CommonResult<Boolean> authenticateEmqxConnection(@Valid @RequestBody IotDeviceEmqxAuthReqDTO authReqDTO);
|
||||
|
||||
// ========== 插件相关 ==========
|
||||
|
||||
/**
|
||||
* 心跳插件实例
|
||||
*
|
||||
* @param heartbeatReqDTO 心跳插件实例 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/heartbeat-plugin-instance")
|
||||
CommonResult<Boolean> heartbeatPluginInstance(@Valid @RequestBody IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO);
|
||||
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【配置】设置 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceConfigSetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 配置
|
||||
*/
|
||||
@NotNull(message = "配置不能为空")
|
||||
private Map<String, Object> config;
|
||||
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 设备下行的抽象 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public abstract class IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 请求编号
|
||||
*/
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【OTA】升级下发 Request DTO(更新固件消息)
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceOtaUpgradeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
private Long firmwareId;
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 签名方式
|
||||
*
|
||||
* 例如说:MD5、SHA256
|
||||
*/
|
||||
private String signMethod;
|
||||
/**
|
||||
* 固件文件签名
|
||||
*/
|
||||
private String fileSign;
|
||||
/**
|
||||
* 固件文件大小
|
||||
*/
|
||||
private Long fileSize;
|
||||
/**
|
||||
* 固件文件 URL
|
||||
*/
|
||||
private String fileUrl;
|
||||
|
||||
/**
|
||||
* 自定义信息,建议使用 JSON 格式
|
||||
*/
|
||||
private String information;
|
||||
|
||||
public static IotDeviceOtaUpgradeReqDTO build(Map<?, ?> map) {
|
||||
return new IotDeviceOtaUpgradeReqDTO()
|
||||
.setFirmwareId(MapUtil.getLong(map, "firmwareId")).setVersion((String) map.get("version"))
|
||||
.setSignMethod((String) map.get("signMethod")).setFileSign((String) map.get("fileSign"))
|
||||
.setFileSize(MapUtil.getLong(map, "fileSize")).setFileUrl((String) map.get("fileUrl"))
|
||||
.setInformation((String) map.get("information"));
|
||||
}
|
||||
|
||||
public static Map<?, ?> build(IotDeviceOtaUpgradeReqDTO dto) {
|
||||
return MapUtil.builder()
|
||||
.put("firmwareId", dto.getFirmwareId()).put("version", dto.getVersion())
|
||||
.put("signMethod", dto.getSignMethod()).put("fileSign", dto.getFileSign())
|
||||
.put("fileSize", dto.getFileSize()).put("fileUrl", dto.getFileUrl())
|
||||
.put("information", dto.getInformation())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// TODO @芋艿:从 server => plugin => device 是否有必要?从阿里云 iot 来看,没有这个功能?!
|
||||
// TODO @芋艿:是不是改成 read 更好?在看看阿里云的 topic 设计
|
||||
/**
|
||||
* IoT 设备【属性】获取 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDevicePropertyGetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 属性标识数组
|
||||
*/
|
||||
@NotEmpty(message = "属性标识数组不能为空")
|
||||
private List<String> identifiers;
|
||||
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【属性】设置 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDevicePropertySetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 属性参数
|
||||
*/
|
||||
@NotEmpty(message = "属性参数不能为空")
|
||||
private Map<String, Object> properties;
|
||||
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【服务】调用 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceServiceInvokeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 服务标识
|
||||
*/
|
||||
@NotEmpty(message = "服务标识不能为空")
|
||||
private String identifier;
|
||||
/**
|
||||
* 调用参数
|
||||
*/
|
||||
private Map<String, Object> params;
|
||||
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【事件】上报 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 事件标识
|
||||
*/
|
||||
@NotEmpty(message = "事件标识不能为空")
|
||||
private String identifier;
|
||||
/**
|
||||
* 事件参数
|
||||
*/
|
||||
private Map<String, Object> params;
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/progress
|
||||
/**
|
||||
* IoT 设备【OTA】升级进度 Request DTO(上报更新固件进度)
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceOtaProgressReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
private Long firmwareId;
|
||||
|
||||
/**
|
||||
* 升级状态
|
||||
*
|
||||
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 升级进度,百分比
|
||||
*/
|
||||
private Integer progress;
|
||||
|
||||
/**
|
||||
* 升级进度描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/pull
|
||||
/**
|
||||
* IoT 设备【OTA】升级下拉 Request DTO(拉取固件更新)
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class IotDeviceOtaPullReqDTO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
private Long firmwareId;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/report
|
||||
/**
|
||||
* IoT 设备【OTA】上报 Request DTO(上报固件版本)
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class IotDeviceOtaReportReqDTO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
private Long firmwareId;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【属性】上报 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 属性参数
|
||||
*/
|
||||
@NotEmpty(message = "属性参数不能为空")
|
||||
private Map<String, Object> properties;
|
||||
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 设备【注册】自己 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceRegisterReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IoT 设备【注册】子设备 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceRegisterSubReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
// TODO @芋艿:看看要不要优化命名
|
||||
/**
|
||||
* 子设备数组
|
||||
*/
|
||||
@NotEmpty(message = "子设备不能为空")
|
||||
private List<Device> params;
|
||||
|
||||
/**
|
||||
* 设备信息
|
||||
*/
|
||||
@Data
|
||||
public static class Device {
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 设备【状态】更新 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceStateUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
*/
|
||||
@NotNull(message = "设备状态不能为空")
|
||||
@InEnum(IotDeviceStateEnum.class) // 只使用:在线、离线
|
||||
private Integer state;
|
||||
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// TODO @芋艿:要写清楚,是来自设备网关,还是设备。
|
||||
/**
|
||||
* IoT 设备【拓扑】添加 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceTopologyAddReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
// TODO @芋艿:看看要不要优化命名
|
||||
/**
|
||||
* 子设备数组
|
||||
*/
|
||||
@NotEmpty(message = "子设备不能为空")
|
||||
private List<IotDeviceRegisterSubReqDTO.Device> params;
|
||||
|
||||
/**
|
||||
* 设备信息
|
||||
*/
|
||||
@Data
|
||||
public static class Device {
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
// TODO @芋艿:阿里云还有 sign 签名
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* IoT 设备上行的抽象 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public abstract class IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 请求编号
|
||||
*/
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 插件实例的进程编号
|
||||
*/
|
||||
private String processId;
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 上报时间
|
||||
*/
|
||||
@JsonSerialize(using = TimestampLocalDateTimeSerializer.class) // 解决 iot plugins 序列化 LocalDateTime 是数组,导致无法解析的问题
|
||||
private LocalDateTime reportTime;
|
||||
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 插件实例心跳 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotPluginInstanceHeartbeatReqDTO {
|
||||
|
||||
/**
|
||||
* 请求编号
|
||||
*/
|
||||
@NotEmpty(message = "请求编号不能为空")
|
||||
private String processId;
|
||||
|
||||
/**
|
||||
* 插件包标识符
|
||||
*/
|
||||
@NotEmpty(message = "插件包标识符不能为空")
|
||||
private String pluginKey;
|
||||
|
||||
/**
|
||||
* 插件实例所在 IP
|
||||
*/
|
||||
@NotEmpty(message = "插件实例所在 IP 不能为空")
|
||||
private String hostIp;
|
||||
/**
|
||||
* 插件实例的进程编号
|
||||
*/
|
||||
@NotNull(message = "插件实例的进程编号不能为空")
|
||||
private Integer downstreamPort;
|
||||
|
||||
/**
|
||||
* 是否在线
|
||||
*/
|
||||
@NotNull(message = "是否在线不能为空")
|
||||
private Boolean online;
|
||||
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
/**
|
||||
* TODO 芋艿:占位
|
||||
*/
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto;
|
||||
@ -1,6 +0,0 @@
|
||||
/**
|
||||
* 占位
|
||||
*
|
||||
* TODO 芋艿:后续删除
|
||||
*/
|
||||
package cn.iocoder.yudao.module.iot.api;
|
||||
@ -1,16 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
|
||||
|
||||
/**
|
||||
* API 相关的枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ApiConstants {
|
||||
|
||||
public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/iot";
|
||||
|
||||
public static final String VERSION = "1.0.0";
|
||||
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums;
|
||||
|
||||
/**
|
||||
* IoT 字典类型的枚举类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class DictTypeConstants {
|
||||
|
||||
public static final String PRODUCT_STATUS = "iot_product_status";
|
||||
public static final String PRODUCT_DEVICE_TYPE = "iot_product_device_type";
|
||||
public static final String NET_TYPE = "iot_net_type";
|
||||
public static final String PROTOCOL_TYPE = "iot_protocol_type";
|
||||
public static final String DATA_FORMAT = "iot_data_format";
|
||||
public static final String VALIDATE_TYPE = "iot_validate_type";
|
||||
|
||||
public static final String DEVICE_STATE = "iot_device_state";
|
||||
|
||||
public static final String IOT_DATA_BRIDGE_DIRECTION_ENUM = "iot_data_bridge_direction_enum";
|
||||
public static final String IOT_DATA_BRIDGE_TYPE_ENUM = "iot_data_bridge_type_enum";
|
||||
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* iot 错误码枚举类
|
||||
* <p>
|
||||
* iot 系统,使用 1-050-000-000 段
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 产品相关 1-050-001-000 ============
|
||||
ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在");
|
||||
ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在");
|
||||
ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除");
|
||||
ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型");
|
||||
|
||||
// ========== 产品物模型 1-050-002-000 ============
|
||||
ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
|
||||
ErrorCode THING_MODEL_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
|
||||
ErrorCode THING_MODEL_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。");
|
||||
ErrorCode THING_MODEL_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。");
|
||||
ErrorCode THING_MODEL_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效");
|
||||
|
||||
// ========== 设备 1-050-003-000 ============
|
||||
ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在");
|
||||
ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一");
|
||||
ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除");
|
||||
ErrorCode DEVICE_KEY_EXISTS = new ErrorCode(1_050_003_003, "设备标识已经存在");
|
||||
ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在");
|
||||
ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备");
|
||||
ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!");
|
||||
ErrorCode DEVICE_DOWNSTREAM_FAILED = new ErrorCode(1_050_003_007, "执行失败,原因:{}");
|
||||
|
||||
// ========== 产品分类 1-050-004-000 ==========
|
||||
ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在");
|
||||
|
||||
// ========== 设备分组 1-050-005-000 ==========
|
||||
ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在");
|
||||
ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除");
|
||||
|
||||
// ========== 插件配置 1-050-006-000 ==========
|
||||
ErrorCode PLUGIN_CONFIG_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件配置不存在");
|
||||
ErrorCode PLUGIN_INSTALL_FAILED = new ErrorCode(1_050_006_001, "插件安装失败");
|
||||
ErrorCode PLUGIN_INSTALL_FAILED_FILE_NAME_NOT_MATCH = new ErrorCode(1_050_006_002, "插件安装失败,文件名与原插件id不匹配");
|
||||
ErrorCode PLUGIN_CONFIG_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件");
|
||||
ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效");
|
||||
ErrorCode PLUGIN_CONFIG_KEY_DUPLICATE = new ErrorCode(1_050_006_005, "插件标识已存在");
|
||||
ErrorCode PLUGIN_START_FAILED = new ErrorCode(1_050_006_006, "插件启动失败");
|
||||
ErrorCode PLUGIN_STOP_FAILED = new ErrorCode(1_050_006_007, "插件停止失败");
|
||||
|
||||
// ========== 插件实例 1-050-007-000 ==========
|
||||
|
||||
// ========== 固件相关 1-050-008-000 ==========
|
||||
|
||||
ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在");
|
||||
ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复");
|
||||
|
||||
ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在");
|
||||
ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "升级任务名称重复");
|
||||
ErrorCode OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY = new ErrorCode(1_050_008_102, "设备编号列表不能为空");
|
||||
ErrorCode OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY = new ErrorCode(1_050_008_103, "设备列表不能为空");
|
||||
ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_104, "升级任务不能取消");
|
||||
|
||||
ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在");
|
||||
ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复");
|
||||
ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试");
|
||||
|
||||
// ========== MQTT 通信相关 1-050-009-000 ==========
|
||||
ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal");
|
||||
|
||||
// ========== IoT 数据桥梁 1-050-010-000 ==========
|
||||
ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在");
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.ota;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT OTA 升级任务的范围枚举
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum IotOtaUpgradeTaskStatusEnum implements ArrayValuable<Integer> {
|
||||
|
||||
IN_PROGRESS(10), // 进行中:升级中
|
||||
COMPLETED(20), // 已完成:已结束,全部升级完成
|
||||
INCOMPLETE(21), // 未完成:已结束,部分升级完成
|
||||
CANCELED(30),; // 已取消:一般是主动取消任务
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskStatusEnum::getStatus).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 范围
|
||||
*/
|
||||
private final Integer status;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 部署方式枚举
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum IotPluginDeployTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
JAR(0, "JAR 部署"),
|
||||
STANDALONE(1, "独立部署");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginDeployTypeEnum::getDeployType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 部署方式
|
||||
*/
|
||||
private final Integer deployType;
|
||||
/**
|
||||
* 部署方式名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 插件状态枚举
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum IotPluginStatusEnum implements ArrayValuable<Integer> {
|
||||
|
||||
STOPPED(0, "停止"),
|
||||
RUNNING(1, "运行");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginStatusEnum::getStatus).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private final Integer status;
|
||||
/**
|
||||
* 状态名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 插件类型枚举
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum IotPluginTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
NORMAL(0, "普通插件"),
|
||||
DEVICE(1, "设备插件");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 类型名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.product;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 产品数据格式枚举类
|
||||
*
|
||||
* @author ahh
|
||||
* @see <a href="https://help.aliyun.com/zh/iot/user-guide/message-parsing">阿里云 - 什么是消息解析</a>
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum IotDataFormatEnum implements ArrayValuable<Integer> {
|
||||
|
||||
JSON(0, "标准数据格式(JSON)"),
|
||||
CUSTOMIZE(1, "透传/自定义");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataFormatEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.product;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 接入网关协议枚举类
|
||||
*
|
||||
* @author ahh
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum IotProtocolTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
CUSTOM(0, "自定义"),
|
||||
MODBUS(1, "Modbus"),
|
||||
OPC_UA(2, "OPC UA"),
|
||||
ZIGBEE(3, "ZigBee"),
|
||||
BLE(4, "BLE");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProtocolTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.rule;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 数据桥接的类型枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum IotDataBridgeTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
HTTP(1, "HTTP"),
|
||||
TCP(2, "TCP"),
|
||||
WEBSOCKET(3, "WEBSOCKET"),
|
||||
|
||||
MQTT(10, "MQTT"),
|
||||
|
||||
DATABASE(20, "DATABASE"),
|
||||
REDIS_STREAM(21, "REDIS_STREAM"),
|
||||
|
||||
ROCKETMQ(30, "ROCKETMQ"),
|
||||
RABBITMQ(31, "RABBITMQ"),
|
||||
KAFKA(32, "KAFKA");
|
||||
|
||||
private final Integer type;
|
||||
|
||||
private final String name;
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.rule;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 规则场景的触发类型枚举
|
||||
*
|
||||
* 设备触发,定时触发
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum IotRuleSceneActionTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
DEVICE_CONTROL(1), // 设备执行
|
||||
ALERT(2), // 告警执行
|
||||
DATA_BRIDGE(3); // 桥接执行
|
||||
|
||||
private final Integer type;
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneActionTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.enums.rule;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 场景流转的触发类型枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum IotRuleSceneTriggerTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
DEVICE(1), // 设备触发
|
||||
TIMER(2); // 定时触发
|
||||
|
||||
private final Integer type;
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>yudao-module-iot</artifactId>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
@ -15,7 +14,7 @@
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
物联网 模块,主要实现 产品管理、设备管理、协议管理等功能。
|
||||
<!-- TODO 芋艿:后续补充下 -->
|
||||
<!-- TODO 芋艿:后续补充下 -->
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
@ -26,7 +25,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-iot-api</artifactId>
|
||||
<artifactId>yudao-module-iot-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
@ -75,10 +74,11 @@
|
||||
</dependency>
|
||||
|
||||
<!-- 消息队列相关 -->
|
||||
<!-- TODO @芋艿:临时打开 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
<!-- <optional>true</optional>-->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.kafka</groupId>
|
||||
@ -91,47 +91,17 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.pf4j</groupId> <!-- PF4J:内置插件机制 -->
|
||||
<artifactId>pf4j-spring</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO @芋艿:bom 管理 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<version>4.0.25</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO @芋艿:bom 管理 -->
|
||||
<dependency>
|
||||
<groupId>org.graalvm.js</groupId>
|
||||
<artifactId>js</artifactId>
|
||||
<version>24.1.2</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.graalvm.js</groupId>
|
||||
<artifactId>js-scriptengine</artifactId>
|
||||
<version>24.1.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO @芋艿:合理注释 -->
|
||||
<!-- IoT 数据桥梁的执行器所需消息队列。如果您只需要使用 rocketmq 那么则注释掉其它消息队列即可 -->
|
||||
<!-- IoT 网络组件:接收来自设备的上行数据 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.apache.rocketmq</groupId>-->
|
||||
<!-- <artifactId>rocketmq-spring-boot-starter</artifactId>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-iot-net-component-http</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.kafka</groupId>-->
|
||||
<!-- <artifactId>spring-kafka</artifactId>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-iot-net-component-emqx</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-amqp</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot;
|
||||
|
||||
import cn.hutool.script.ScriptUtil;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* TODO 芋艿:测试脚本的接入
|
||||
*/
|
||||
public class ScriptTest {
|
||||
|
||||
public static void main2(String[] args) {
|
||||
// 创建一个 Groovy 脚本引擎
|
||||
ScriptEngine engine = ScriptUtil.createGroovyEngine();
|
||||
|
||||
// 创建绑定参数
|
||||
Bindings bindings = engine.createBindings();
|
||||
bindings.put("name", "Alice");
|
||||
bindings.put("age", 30);
|
||||
|
||||
// 定义一个稍微复杂的 Groovy 脚本
|
||||
String script = "def greeting = 'Hello, ' + name + '!';\n" +
|
||||
"def ageInFiveYears = age + 5;\n" +
|
||||
"def message = greeting + ' In five years, you will be ' + ageInFiveYears + ' years old.';\n" +
|
||||
"return message.toUpperCase();\n";
|
||||
|
||||
try {
|
||||
// 执行脚本并获取结果
|
||||
Object result = engine.eval(script, bindings);
|
||||
System.out.println(result); // 输出: HELLO, ALICE! IN FIVE YEARS, YOU WILL BE 35 YEARS OLD.
|
||||
} catch (ScriptException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 创建一个 JavaScript 脚本引擎
|
||||
ScriptEngine jsEngine = ScriptUtil.createJsEngine();
|
||||
|
||||
// 创建绑定参数
|
||||
Bindings jsBindings = jsEngine.createBindings();
|
||||
jsBindings.put("name", "Bob");
|
||||
jsBindings.put("age", 25);
|
||||
|
||||
// 定义一个简单的 JavaScript 脚本
|
||||
String jsScript = "var greeting = 'Hello, ' + name + '!';\n" +
|
||||
"var ageInTenYears = age + 10;\n" +
|
||||
"var message = greeting + ' In ten years, you will be ' + ageInTenYears + ' years old.';\n" +
|
||||
"message.toUpperCase();\n";
|
||||
|
||||
try {
|
||||
// 执行脚本并获取结果
|
||||
Object jsResult = jsEngine.eval(jsScript, jsBindings);
|
||||
System.out.println(jsResult); // 输出: HELLO, BOB! IN TEN YEARS, YOU WILL BE 35 YEARS OLD.
|
||||
} catch (ScriptException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceGetReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* IoT 设备 API 实现类
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
@Primary // 保证优先匹配,因为 yudao-iot-gateway 也有 IotDeviceCommonApi 的实现,并且也可能会被 biz 引入
|
||||
public class IoTDeviceApiImpl implements IotDeviceCommonApi {
|
||||
|
||||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
@Resource
|
||||
private IotProductService productService;
|
||||
|
||||
@Override
|
||||
@PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/auth")
|
||||
@PermitAll
|
||||
public CommonResult<Boolean> authDevice(@RequestBody IotDeviceAuthReqDTO authReqDTO) {
|
||||
return success(deviceService.authDevice(authReqDTO));
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/get") // 特殊:方便调用,暂时使用 POST,实际更推荐 GET
|
||||
@PermitAll
|
||||
public CommonResult<IotDeviceRespDTO> getDevice(@RequestBody IotDeviceGetReqDTO getReqDTO) {
|
||||
IotDeviceDO device = getReqDTO.getId() != null ? deviceService.getDeviceFromCache(getReqDTO.getId())
|
||||
: deviceService.getDeviceFromCache(getReqDTO.getProductKey(), getReqDTO.getDeviceName());
|
||||
return success(BeanUtils.toBean(device, IotDeviceRespDTO.class, deviceDTO -> {
|
||||
IotProductDO product = productService.getProductFromCache(deviceDTO.getProductId());
|
||||
if (product != null) {
|
||||
deviceDTO.setCodecType(product.getCodecType());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.api.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
|
||||
import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
|
||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* * 设备数据 Upstream 上行 API 实现类
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
|
||||
|
||||
@Resource
|
||||
private IotDeviceUpstreamService deviceUpstreamService;
|
||||
@Resource
|
||||
private IotPluginInstanceService pluginInstanceService;
|
||||
|
||||
// ========== 设备相关 ==========
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
|
||||
deviceUpstreamService.updateDeviceState(updateReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) {
|
||||
deviceUpstreamService.reportDeviceProperty(reportReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) {
|
||||
deviceUpstreamService.reportDeviceEvent(reportReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> registerDevice(IotDeviceRegisterReqDTO registerReqDTO) {
|
||||
deviceUpstreamService.registerDevice(registerReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) {
|
||||
deviceUpstreamService.registerSubDevice(registerReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) {
|
||||
deviceUpstreamService.addDeviceTopology(addReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
|
||||
boolean result = deviceUpstreamService.authenticateEmqxConnection(authReqDTO);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
// ========== 插件相关 ==========
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) {
|
||||
pluginInstanceService.heartbeatPluginInstance(heartbeatReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,4 @@
|
||||
/**
|
||||
* 占位
|
||||
*
|
||||
* TODO 芋艿:后续删除
|
||||
* iot API 包,定义并实现提供给其它模块的 API
|
||||
*/
|
||||
package cn.iocoder.yudao.module.iot.api;
|
||||
@ -0,0 +1,105 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO;
|
||||
import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 告警配置")
|
||||
@RestController
|
||||
@RequestMapping("/iot/alert-config")
|
||||
@Validated
|
||||
public class IotAlertConfigController {
|
||||
|
||||
@Resource
|
||||
private IotAlertConfigService alertConfigService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建告警配置")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-config:create')")
|
||||
public CommonResult<Long> createAlertConfig(@Valid @RequestBody IotAlertConfigSaveReqVO createReqVO) {
|
||||
return success(alertConfigService.createAlertConfig(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新告警配置")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-config:update')")
|
||||
public CommonResult<Boolean> updateAlertConfig(@Valid @RequestBody IotAlertConfigSaveReqVO updateReqVO) {
|
||||
alertConfigService.updateAlertConfig(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除告警配置")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-config:delete')")
|
||||
public CommonResult<Boolean> deleteAlertConfig(@RequestParam("id") Long id) {
|
||||
alertConfigService.deleteAlertConfig(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得告警配置")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-config:query')")
|
||||
public CommonResult<IotAlertConfigRespVO> getAlertConfig(@RequestParam("id") Long id) {
|
||||
IotAlertConfigDO alertConfig = alertConfigService.getAlertConfig(id);
|
||||
return success(BeanUtils.toBean(alertConfig, IotAlertConfigRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得告警配置分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-config:query')")
|
||||
public CommonResult<PageResult<IotAlertConfigRespVO>> getAlertConfigPage(@Valid IotAlertConfigPageReqVO pageReqVO) {
|
||||
PageResult<IotAlertConfigDO> pageResult = alertConfigService.getAlertConfigPage(pageReqVO);
|
||||
|
||||
// 转换返回
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
convertSetByFlatMap(pageResult.getList(), config -> config.getReceiveUserIds().stream()));
|
||||
return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class, vo -> {
|
||||
vo.setReceiveUserNames(vo.getReceiveUserIds().stream()
|
||||
.map(userMap::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(AdminUserRespDTO::getNickname)
|
||||
.collect(Collectors.toList()));
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得告警配置简单列表", description = "只包含被开启的告警配置,主要用于前端的下拉选项")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-config:query')")
|
||||
public CommonResult<List<IotAlertConfigRespVO>> getAlertConfigSimpleList() {
|
||||
List<IotAlertConfigDO> list = alertConfigService.getAlertConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return success(convertList(list, config -> // 只返回 id、name 字段
|
||||
new IotAlertConfigRespVO().setId(config.getId()).setName(config.getName())));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordRespVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO;
|
||||
import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static java.util.Collections.singleton;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 告警记录")
|
||||
@RestController
|
||||
@RequestMapping("/iot/alert-record")
|
||||
@Validated
|
||||
public class IotAlertRecordController {
|
||||
|
||||
@Resource
|
||||
private IotAlertRecordService alertRecordService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得告警记录")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-record:query')")
|
||||
public CommonResult<IotAlertRecordRespVO> getAlertRecord(@RequestParam("id") Long id) {
|
||||
IotAlertRecordDO alertRecord = alertRecordService.getAlertRecord(id);
|
||||
return success(BeanUtils.toBean(alertRecord, IotAlertRecordRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得告警记录分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-record:query')")
|
||||
public CommonResult<PageResult<IotAlertRecordRespVO>> getAlertRecordPage(@Valid IotAlertRecordPageReqVO pageReqVO) {
|
||||
PageResult<IotAlertRecordDO> pageResult = alertRecordService.getAlertRecordPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotAlertRecordRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/process")
|
||||
@Operation(summary = "处理告警记录")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-record:process')")
|
||||
public CommonResult<Boolean> processAlertRecord(@Valid @RequestBody IotAlertRecordProcessReqVO processReqVO) {
|
||||
alertRecordService.processAlertRecordList(singleton(processReqVO.getId()), processReqVO.getProcessRemark());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警配置分页 Request VO")
|
||||
@Data
|
||||
public class IotAlertConfigPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "配置名称", example = "赵六")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "配置状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警配置 Response VO")
|
||||
@Data
|
||||
public class IotAlertConfigRespVO {
|
||||
|
||||
@Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3566")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "配置名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "配置描述", example = "你猜")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer level;
|
||||
|
||||
@Schema(description = "配置状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "关联的场景联动规则编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
|
||||
private List<Long> sceneRuleIds;
|
||||
|
||||
@Schema(description = "接收的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "100,200")
|
||||
private List<Long> receiveUserIds;
|
||||
|
||||
@Schema(description = "接收的用户名称数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三,李四")
|
||||
private List<String> receiveUserNames;
|
||||
|
||||
@Schema(description = "接收的类型数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
|
||||
private List<Integer> receiveTypes;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警配置新增/修改 Request VO")
|
||||
@Data
|
||||
public class IotAlertConfigSaveReqVO {
|
||||
|
||||
@Schema(description = "配置编号", example = "3566")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "配置名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
|
||||
@NotEmpty(message = "配置名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "配置描述", example = "你猜")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "告警级别不能为空")
|
||||
private Integer level;
|
||||
|
||||
@Schema(description = "配置状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "配置状态不能为空")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "关联的场景联动规则编号数组")
|
||||
@NotEmpty(message = "关联的场景联动规则编号数组不能为空")
|
||||
private List<Long> sceneRuleIds;
|
||||
|
||||
@Schema(description = "接收的用户编号数组")
|
||||
@NotEmpty(message = "接收的用户编号数组不能为空")
|
||||
private List<Long> receiveUserIds;
|
||||
|
||||
@Schema(description = "接收的类型数组")
|
||||
@NotEmpty(message = "接收的类型数组不能为空")
|
||||
private List<Integer> receiveTypes;
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警记录分页 Request VO")
|
||||
@Data
|
||||
public class IotAlertRecordPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "告警配置编号", example = "29320")
|
||||
private Long configId;
|
||||
|
||||
@Schema(description = "告警级别", example = "1")
|
||||
private Integer level;
|
||||
|
||||
@Schema(description = "产品编号", example = "2050")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "设备编号", example = "21727")
|
||||
private String deviceId;
|
||||
|
||||
@Schema(description = "是否处理", example = "true")
|
||||
private Boolean processStatus;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警记录处理 Request VO")
|
||||
@Data
|
||||
public class IotAlertRecordProcessReqVO {
|
||||
|
||||
@Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "记录编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "处理结果(备注)", requiredMode = Schema.RequiredMode.REQUIRED, example = "已处理告警,问题已解决")
|
||||
private String processRemark;
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警记录 Response VO")
|
||||
@Data
|
||||
public class IotAlertRecordRespVO {
|
||||
|
||||
@Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19904")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "告警配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29320")
|
||||
private Long configId;
|
||||
|
||||
@Schema(description = "告警名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
|
||||
private String configName;
|
||||
|
||||
@Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer configLevel;
|
||||
|
||||
@Schema(description = "产品编号", example = "2050")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "设备编号", example = "21727")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "触发的设备消息")
|
||||
private IotDeviceMessage deviceMessage;
|
||||
|
||||
@Schema(description = "是否处理", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Boolean processStatus;
|
||||
|
||||
@Schema(description = "处理结果(备注)", example = "你说的对")
|
||||
private String processRemark;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
### 请求 /iot/device/downstream 接口(服务调用) => 成功
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "service",
|
||||
"identifier": "temperature",
|
||||
"data": {
|
||||
"xx": "yy"
|
||||
}
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(属性设置) => 成功
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "property",
|
||||
"identifier": "set",
|
||||
"data": {
|
||||
"xx": "yy"
|
||||
}
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(属性获取) => 成功
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "property",
|
||||
"identifier": "get",
|
||||
"data": ["xx", "yy"]
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(配置设置) => 成功
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "config",
|
||||
"identifier": "set"
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(OTA 升级) => 成功
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "ota",
|
||||
"identifier": "upgrade",
|
||||
"data": {
|
||||
"firmwareId": 1,
|
||||
"version": "1.0.0",
|
||||
"signMethod": "MD5",
|
||||
"fileSign": "d41d8cd98f00b204e9800998ecf8427e",
|
||||
"fileSize": 1024,
|
||||
"fileUrl": "http://example.com/firmware.bin",
|
||||
"information": "{\"desc\":\"升级到最新版本\"}"
|
||||
}
|
||||
}
|
||||
@ -6,15 +6,13 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotLocationTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@ -41,10 +39,6 @@ public class IotDeviceController {
|
||||
|
||||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
@Resource
|
||||
private IotDeviceUpstreamService deviceUpstreamService;
|
||||
@Resource
|
||||
private IotDeviceDownstreamService deviceDownstreamService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建设备")
|
||||
@ -111,7 +105,7 @@ public class IotDeviceController {
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportDeviceExcel(@Valid IotDevicePageReqVO exportReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
HttpServletResponse response) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
CommonResult<PageResult<IotDeviceRespVO>> result = getDevicePage(exportReqVO);
|
||||
// 导出 Excel
|
||||
@ -129,12 +123,17 @@ public class IotDeviceController {
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项")
|
||||
@Parameter(name = "deviceType", description = "设备类型", example = "1")
|
||||
public CommonResult<List<IotDeviceRespVO>> getSimpleDeviceList(
|
||||
@RequestParam(value = "deviceType", required = false) Integer deviceType) {
|
||||
List<IotDeviceDO> list = deviceService.getDeviceListByDeviceType(deviceType);
|
||||
return success(convertList(list, device -> // 只返回 id、name 字段
|
||||
new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName())));
|
||||
@Parameters({
|
||||
@Parameter(name = "deviceType", description = "设备类型", example = "1"),
|
||||
@Parameter(name = "productId", description = "产品编号", example = "1024")
|
||||
})
|
||||
public CommonResult<List<IotDeviceRespVO>> getDeviceSimpleList(
|
||||
@RequestParam(value = "deviceType", required = false) Integer deviceType,
|
||||
@RequestParam(value = "productId", required = false) Long productId) {
|
||||
List<IotDeviceDO> list = deviceService.getDeviceListByCondition(deviceType, productId);
|
||||
return success(convertList(list, device -> // 只返回 id、name、productId 字段
|
||||
new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName())
|
||||
.setProductId(device.getProductId()).setState(device.getState())));
|
||||
}
|
||||
|
||||
@PostMapping("/import")
|
||||
@ -154,35 +153,28 @@ public class IotDeviceController {
|
||||
// 手动创建导出 demo
|
||||
List<IotDeviceImportExcelVO> list = Arrays.asList(
|
||||
IotDeviceImportExcelVO.builder().deviceName("温度传感器001").parentDeviceName("gateway110")
|
||||
.productKey("1de24640dfe").groupNames("灰度分组,生产分组").build(),
|
||||
IotDeviceImportExcelVO.builder().deviceName("biubiu")
|
||||
.productKey("YzvHxd4r67sT4s2B").groupNames("").build());
|
||||
.productKey("1de24640dfe").groupNames("灰度分组,生产分组")
|
||||
.locationType(IotLocationTypeEnum.IP.getType()).build(),
|
||||
IotDeviceImportExcelVO.builder().deviceName("biubiu").productKey("YzvHxd4r67sT4s2B")
|
||||
.groupNames("").locationType(IotLocationTypeEnum.MANUAL.getType()).build());
|
||||
// 输出
|
||||
ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list);
|
||||
}
|
||||
|
||||
@PostMapping("/upstream")
|
||||
@Operation(summary = "设备上行", description = "可用于设备模拟")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:upstream')")
|
||||
public CommonResult<Boolean> upstreamDevice(@Valid @RequestBody IotDeviceUpstreamReqVO upstreamReqVO) {
|
||||
deviceUpstreamService.upstreamDevice(upstreamReqVO);
|
||||
return success(true);
|
||||
@GetMapping("/get-auth-info")
|
||||
@Operation(summary = "获得设备连接信息")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:auth-info')")
|
||||
public CommonResult<IotDeviceAuthInfoRespVO> getDeviceAuthInfo(@RequestParam("id") Long id) {
|
||||
return success(deviceService.getDeviceAuthInfo(id));
|
||||
}
|
||||
|
||||
@PostMapping("/downstream")
|
||||
@Operation(summary = "设备下行", description = "可用于设备模拟")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:downstream')")
|
||||
public CommonResult<Boolean> downstreamDevice(@Valid @RequestBody IotDeviceDownstreamReqVO downstreamReqVO) {
|
||||
deviceDownstreamService.downstreamDevice(downstreamReqVO);
|
||||
return success(true);
|
||||
// TODO @haohao:可以使用 @RequestParam("productKey") String productKey, @RequestParam("deviceNames") List<String> deviceNames 来接收哇?
|
||||
@GetMapping("/list-by-product-key-and-names")
|
||||
@Operation(summary = "通过产品标识和设备名称列表获取设备")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:query')")
|
||||
public CommonResult<List<IotDeviceRespVO>> getDevicesByProductKeyAndNames(@Valid IotDeviceByProductKeyAndNamesReqVO reqVO) {
|
||||
List<IotDeviceDO> devices = deviceService.getDeviceListByProductKeyAndNames(reqVO.getProductKey(), reqVO.getDeviceNames());
|
||||
return success(BeanUtils.toBean(devices, IotDeviceRespVO.class));
|
||||
}
|
||||
|
||||
// TODO @haohao:是不是默认详情接口,不返回 secret,然后这个接口,用于统一返回。然后接口名可以更通用一点。
|
||||
@GetMapping("/mqtt-connection-params")
|
||||
@Operation(summary = "获取 MQTT 连接参数")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:mqtt-connection-params')")
|
||||
public CommonResult<IotDeviceMqttConnectionParamsRespVO> getMqttConnectionParams(@RequestParam("deviceId") Long deviceId) {
|
||||
return success(deviceService.getMqttConnectionParams(deviceId));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogRespVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
|
||||
import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 设备日志")
|
||||
@RestController
|
||||
@RequestMapping("/iot/device/log")
|
||||
@Validated
|
||||
public class IotDeviceLogController {
|
||||
|
||||
@Resource
|
||||
private IotDeviceLogService deviceLogService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得设备日志分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:log-query')")
|
||||
public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) {
|
||||
PageResult<IotDeviceLogDO> pageResult = deviceLogService.getDeviceLogPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
### 请求 /iot/device/message/send 接口(属性上报)=> 成功
|
||||
POST {{baseUrl}}/iot/device/message/send
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"deviceId": 25,
|
||||
"method": "thing.property.post",
|
||||
"params": {
|
||||
"width": 1,
|
||||
"height": "2",
|
||||
"oneThree": "3"
|
||||
}
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(服务调用)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "service",
|
||||
"identifier": "temperature",
|
||||
"data": {
|
||||
"xx": "yy"
|
||||
}
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(属性设置)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "property",
|
||||
"identifier": "set",
|
||||
"data": {
|
||||
"xx": "yy"
|
||||
}
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(属性获取)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "property",
|
||||
"identifier": "get",
|
||||
"data": ["xx", "yy"]
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(配置设置)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "config",
|
||||
"identifier": "set"
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(OTA 升级)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 25,
|
||||
"type": "ota",
|
||||
"identifier": "upgrade",
|
||||
"data": {
|
||||
"firmwareId": 1,
|
||||
"version": "1.0.0",
|
||||
"signMethod": "MD5",
|
||||
"fileSign": "d41d8cd98f00b204e9800998ecf8427e",
|
||||
"fileSize": 1024,
|
||||
"fileUrl": "http://example.com/firmware.bin",
|
||||
"information": "{\"desc\":\"升级到最新版本\"}"
|
||||
}
|
||||
}
|
||||
|
||||
### 查询设备消息对分页 - 基础查询(设备编号25)
|
||||
GET {{baseUrl}}/iot/device/message/pair-page?deviceId=25&pageNo=1&pageSize=10
|
||||
Authorization: Bearer {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
### 查询设备消息对分页 - 按标识符过滤(identifier=eat)
|
||||
GET {{baseUrl}}/iot/device/message/pair-page?deviceId=25&identifier=eat&pageNo=1&pageSize=10
|
||||
Authorization: Bearer {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
@ -0,0 +1,92 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessagePageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageRespPairVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageSendReqVO;
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceMessageMapper;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService;
|
||||
import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 设备消息")
|
||||
@RestController
|
||||
@RequestMapping("/iot/device/message")
|
||||
@Validated
|
||||
public class IotDeviceMessageController {
|
||||
|
||||
@Resource
|
||||
private IotDeviceMessageService deviceMessageService;
|
||||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
@Resource
|
||||
private IotThingModelService thingModelService;
|
||||
@Resource
|
||||
private IotDeviceMessageMapper deviceMessageMapper;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得设备消息分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:message-query')")
|
||||
public CommonResult<PageResult<IotDeviceMessageRespVO>> getDeviceMessagePage(
|
||||
@Valid IotDeviceMessagePageReqVO pageReqVO) {
|
||||
PageResult<IotDeviceMessageDO> pageResult = deviceMessageService.getDeviceMessagePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotDeviceMessageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/pair-page")
|
||||
@Operation(summary = "获得设备消息对分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:message-query')")
|
||||
public CommonResult<PageResult<IotDeviceMessageRespPairVO>> getDeviceMessagePairPage(
|
||||
@Valid IotDeviceMessagePageReqVO pageReqVO) {
|
||||
// 1.1 先按照条件,查询 request 的消息(非 reply)
|
||||
pageReqVO.setReply(false);
|
||||
PageResult<IotDeviceMessageDO> requestMessagePageResult = deviceMessageService.getDeviceMessagePage(pageReqVO);
|
||||
if (CollUtil.isEmpty(requestMessagePageResult.getList())) {
|
||||
return success(PageResult.empty());
|
||||
}
|
||||
// 1.2 接着按照 requestIds,批量查询 reply 消息
|
||||
List<String> requestIds = convertList(requestMessagePageResult.getList(), IotDeviceMessageDO::getRequestId);
|
||||
List<IotDeviceMessageDO> replyMessageList = deviceMessageService.getDeviceMessageListByRequestIdsAndReply(
|
||||
pageReqVO.getDeviceId(), requestIds, true);
|
||||
Map<String, IotDeviceMessageDO> replyMessages = convertMap(replyMessageList, IotDeviceMessageDO::getRequestId);
|
||||
|
||||
// 2. 组装结果
|
||||
List<IotDeviceMessageRespPairVO> pairMessages = convertList(requestMessagePageResult.getList(),
|
||||
requestMessage -> {
|
||||
IotDeviceMessageDO replyMessage = replyMessages.get(requestMessage.getRequestId());
|
||||
return new IotDeviceMessageRespPairVO()
|
||||
.setRequest(BeanUtils.toBean(requestMessage, IotDeviceMessageRespVO.class))
|
||||
.setReply(BeanUtils.toBean(replyMessage, IotDeviceMessageRespVO.class));
|
||||
});
|
||||
return success(new PageResult<>(pairMessages, requestMessagePageResult.getTotal()));
|
||||
}
|
||||
|
||||
@PostMapping("/send")
|
||||
@Operation(summary = "发送消息", description = "可用于设备模拟")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:message-end')")
|
||||
public CommonResult<Boolean> sendDeviceMessage(@Valid @RequestBody IotDeviceMessageSendReqVO sendReqVO) {
|
||||
deviceMessageService.sendDeviceMessage(BeanUtils.toBean(sendReqVO, IotDeviceMessage.class));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,22 +1,21 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyDetailRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyHistoryListReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
|
||||
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService;
|
||||
import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
@ -46,50 +45,45 @@ public class IotDevicePropertyController {
|
||||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
|
||||
@GetMapping("/latest")
|
||||
@GetMapping("/get-latest")
|
||||
@Operation(summary = "获取设备属性最新属性")
|
||||
@Parameters({
|
||||
@Parameter(name = "deviceId", description = "设备编号", required = true),
|
||||
@Parameter(name = "identifier", description = "标识符"),
|
||||
@Parameter(name = "name", description = "名称")
|
||||
})
|
||||
@Parameter(name = "deviceId", description = "设备编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:property-query')")
|
||||
public CommonResult<List<IotDevicePropertyRespVO>> getLatestDeviceProperties(
|
||||
@RequestParam("deviceId") Long deviceId,
|
||||
@RequestParam(value = "identifier", required = false) String identifier,
|
||||
@RequestParam(value = "name", required = false) String name) {
|
||||
Map<String, IotDevicePropertyDO> properties = devicePropertyService.getLatestDeviceProperties(deviceId);
|
||||
|
||||
// 拼接数据
|
||||
public CommonResult<List<IotDevicePropertyDetailRespVO>> getLatestDeviceProperties(
|
||||
@RequestParam("deviceId") Long deviceId) {
|
||||
// 1.1 获取设备信息
|
||||
IotDeviceDO device = deviceService.getDevice(deviceId);
|
||||
Assert.notNull(device, "设备不存在");
|
||||
List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductId(device.getProductId());
|
||||
return success(convertList(properties.entrySet(), entry -> {
|
||||
IotThingModelDO thingModel = CollUtil.findOne(thingModels,
|
||||
item -> item.getIdentifier().equals(entry.getKey()));
|
||||
if (thingModel == null || thingModel.getProperty() == null) {
|
||||
return null;
|
||||
// 1.2 获取设备最新属性
|
||||
Map<String, IotDevicePropertyDO> properties = devicePropertyService.getLatestDeviceProperties(deviceId);
|
||||
// 1.3 根据 productId + type 查询属性类型的物模型
|
||||
List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductIdAndType(
|
||||
device.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
|
||||
|
||||
// 2. 基于 thingModels 遍历,拼接 properties
|
||||
return success(convertList(thingModels, thingModel -> {
|
||||
ThingModelProperty thingModelProperty = thingModel.getProperty();
|
||||
Assert.notNull(thingModelProperty, "属性不能为空");
|
||||
IotDevicePropertyDetailRespVO result = new IotDevicePropertyDetailRespVO()
|
||||
.setName(thingModel.getName()).setDataType(thingModelProperty.getDataType())
|
||||
.setDataSpecs(thingModelProperty.getDataSpecs())
|
||||
.setDataSpecsList(thingModelProperty.getDataSpecsList());
|
||||
result.setIdentifier(thingModel.getIdentifier());
|
||||
IotDevicePropertyDO property = properties.get(thingModel.getIdentifier());
|
||||
if (property != null) {
|
||||
result.setValue(property.getValue())
|
||||
.setUpdateTime(LocalDateTimeUtil.toEpochMilli(property.getUpdateTime()));
|
||||
}
|
||||
if (StrUtil.isNotEmpty(identifier) && !StrUtil.contains(thingModel.getIdentifier(), identifier)) {
|
||||
return null;
|
||||
}
|
||||
if (StrUtil.isNotEmpty(name) && !StrUtil.contains(thingModel.getName(), name)) {
|
||||
return null;
|
||||
}
|
||||
// 构建对象
|
||||
IotDevicePropertyDO property = entry.getValue();
|
||||
return new IotDevicePropertyRespVO().setProperty(thingModel.getProperty())
|
||||
.setValue(property.getValue()).setUpdateTime(LocalDateTimeUtil.toEpochMilli(property.getUpdateTime()));
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/history-page")
|
||||
@Operation(summary = "获取设备属性历史数据")
|
||||
@GetMapping("/history-list")
|
||||
@Operation(summary = "获取设备属性历史数据列表")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:property-query')")
|
||||
public CommonResult<PageResult<IotDevicePropertyRespVO>> getHistoryDevicePropertyPage(
|
||||
@Valid IotDevicePropertyHistoryPageReqVO pageReqVO) {
|
||||
Assert.notEmpty(pageReqVO.getIdentifier(), "标识符不能为空");
|
||||
return success(devicePropertyService.getHistoryDevicePropertyPage(pageReqVO));
|
||||
public CommonResult<List<IotDevicePropertyRespVO>> getHistoryDevicePropertyList(
|
||||
@Valid IotDevicePropertyHistoryListReqVO listReqVO) {
|
||||
return success(devicePropertyService.getHistoryDevicePropertyList(listReqVO));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备下行 Request VO") // 服务调用、属性设置、属性获取等
|
||||
@Data
|
||||
public class IotDeviceDownstreamReqVO {
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
|
||||
@NotEmpty(message = "消息类型不能为空")
|
||||
@InEnum(IotDeviceMessageTypeEnum.class)
|
||||
private String type;
|
||||
|
||||
@Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
|
||||
@NotEmpty(message = "标识符不能为空")
|
||||
private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
|
||||
|
||||
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Object data; // 例如说:服务调用的 params、属性设置的 properties
|
||||
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备上行 Request VO") // 属性上报、事件上报、状态变更等
|
||||
@Data
|
||||
public class IotDeviceUpstreamReqVO {
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
|
||||
@NotEmpty(message = "消息类型不能为空")
|
||||
@InEnum(IotDeviceMessageTypeEnum.class)
|
||||
private String type;
|
||||
|
||||
@Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
|
||||
@NotEmpty(message = "标识符不能为空")
|
||||
private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
|
||||
|
||||
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Object data; // 例如说:属性上报的 properties、事件上报的 params
|
||||
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO")
|
||||
@Data
|
||||
public class IotDeviceLogPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
|
||||
@NotEmpty(message = "设备标识不能为空")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "消息类型", example = "property")
|
||||
private String type; // 参见 IotDeviceMessageTypeEnum 枚举,精准匹配
|
||||
|
||||
@Schema(description = "标识符", example = "temperature")
|
||||
private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举,模糊匹配
|
||||
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备日志 Response VO")
|
||||
@Data
|
||||
public class IotDeviceLogRespVO {
|
||||
|
||||
@Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123")
|
||||
private String productKey;
|
||||
|
||||
@Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
|
||||
private String identifier;
|
||||
|
||||
@Schema(description = "日志内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
|
||||
@Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime reportTime;
|
||||
|
||||
@Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime ts;
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备认证信息 Response VO")
|
||||
@Data
|
||||
public class IotDeviceAuthInfoRespVO {
|
||||
|
||||
@Schema(description = "客户端 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123.device001")
|
||||
@NotBlank(message = "客户端 ID 不能为空")
|
||||
private String clientId;
|
||||
|
||||
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "device001&product123")
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1a2b3c4d5e6f7890abcdef1234567890")
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 通过产品标识和设备名称列表获取设备 Request VO")
|
||||
@Data
|
||||
public class IotDeviceByProductKeyAndNamesReqVO {
|
||||
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1de24640dfe")
|
||||
@NotBlank(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
|
||||
@Schema(description = "设备名称列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "device001,device002")
|
||||
@NotEmpty(message = "设备名称列表不能为空")
|
||||
private List<String> deviceNames;
|
||||
|
||||
}
|
||||
@ -1,8 +1,11 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotLocationTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -34,4 +37,9 @@ public class IotDeviceImportExcelVO {
|
||||
@ExcelProperty("设备分组")
|
||||
private String groupNames;
|
||||
|
||||
@ExcelProperty("上报方式(1:IP 定位, 2:设备上报,3:手动定位)")
|
||||
@NotNull(message = "上报方式不能为空")
|
||||
@InEnum(IotLocationTypeEnum.class)
|
||||
private Integer locationType;
|
||||
|
||||
}
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备 MQTT 连接参数 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class IotDeviceMqttConnectionParamsRespVO {
|
||||
|
||||
@Schema(description = "MQTT 客户端 ID", example = "24602")
|
||||
@ExcelProperty("MQTT 客户端 ID")
|
||||
private String mqttClientId;
|
||||
|
||||
@Schema(description = "MQTT 用户名", example = "芋艿")
|
||||
@ExcelProperty("MQTT 用户名")
|
||||
private String mqttUsername;
|
||||
|
||||
@Schema(description = "MQTT 密码")
|
||||
@ExcelProperty("MQTT 密码")
|
||||
private String mqttPassword;
|
||||
|
||||
}
|
||||
@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||
import cn.iocoder.yudao.module.iot.enums.DictTypeConstants;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
@ -20,10 +22,6 @@ public class IotDeviceRespVO {
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "设备唯一标识符", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("设备唯一标识符")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
|
||||
@ExcelProperty("设备名称")
|
||||
private String deviceName;
|
||||
@ -86,8 +84,19 @@ public class IotDeviceRespVO {
|
||||
@Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
|
||||
private String config;
|
||||
|
||||
@Schema(description = "定位方式", example = "2")
|
||||
@ExcelProperty(value = "定位方式", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.LOCATION_TYPE)
|
||||
private Integer locationType;
|
||||
|
||||
@Schema(description = "设备位置的纬度", example = "45.000000")
|
||||
private BigDecimal latitude;
|
||||
|
||||
@Schema(description = "设备位置的经度", example = "45.000000")
|
||||
private BigDecimal longitude;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,11 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotLocationTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备新增/修改 Request VO")
|
||||
@ -13,10 +15,6 @@ public class IotDeviceSaveReqVO {
|
||||
@Schema(description = "设备编号", example = "177")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177")
|
||||
@Size(max = 50, message = "设备编号长度不能超过 50 个字符")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.AUTO, example = "王五")
|
||||
private String deviceName;
|
||||
|
||||
@ -41,4 +39,14 @@ public class IotDeviceSaveReqVO {
|
||||
@Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
|
||||
private String config;
|
||||
|
||||
@Schema(description = "定位类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@InEnum(value = IotLocationTypeEnum.class, message = "定位方式必须是 {value}")
|
||||
private Integer locationType;
|
||||
|
||||
@Schema(description = "设备位置的纬度", example = "16380")
|
||||
private BigDecimal latitude;
|
||||
|
||||
@Schema(description = "设备位置的经度", example = "16380")
|
||||
private BigDecimal longitude;
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备消息分页查询 Request VO")
|
||||
@Data
|
||||
public class IotDeviceMessagePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "消息类型", example = "property")
|
||||
@InEnum(IotDeviceMessageMethodEnum.class)
|
||||
private String method;
|
||||
|
||||
@Schema(description = "是否上行", example = "true")
|
||||
private Boolean upstream;
|
||||
|
||||
@Schema(description = "是否回复", example = "true")
|
||||
private Boolean reply;
|
||||
|
||||
@Schema(description = "标识符", example = "temperature")
|
||||
private String identifier;
|
||||
|
||||
@Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Size(min = 2, max = 2, message = "请选择时间范围")
|
||||
private LocalDateTime[] times;
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备消息对 Response VO")
|
||||
@Data
|
||||
public class IotDeviceMessageRespPairVO {
|
||||
|
||||
@Schema(description = "请求消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private IotDeviceMessageRespVO request;
|
||||
|
||||
@Schema(description = "响应消息")
|
||||
private IotDeviceMessageRespVO reply; // 通过 requestId 配对
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备消息 Response VO")
|
||||
@Data
|
||||
public class IotDeviceMessageRespVO {
|
||||
|
||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime reportTime;
|
||||
|
||||
@Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime ts;
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "服务编号", example = "server_123")
|
||||
private String serverId;
|
||||
|
||||
@Schema(description = "是否上行消息", example = "true", examples = "false")
|
||||
private Boolean upstream;
|
||||
|
||||
@Schema(description = "是否回复消息", example = "false", examples = "true")
|
||||
private Boolean reply;
|
||||
|
||||
@Schema(description = "标识符", example = "temperature")
|
||||
private String identifier;
|
||||
|
||||
// ========== codec(编解码)字段 ==========
|
||||
|
||||
@Schema(description = "请求编号", example = "req_123")
|
||||
private String requestId;
|
||||
|
||||
@Schema(description = "请求方法", requiredMode = Schema.RequiredMode.REQUIRED, example = "thing.property.report")
|
||||
private String method;
|
||||
|
||||
@Schema(description = "请求参数")
|
||||
private Object params;
|
||||
|
||||
@Schema(description = "响应结果")
|
||||
private Object data;
|
||||
|
||||
@Schema(description = "响应错误码", example = "200")
|
||||
private Integer code;
|
||||
|
||||
@Schema(description = "响应提示", example = "操作成功")
|
||||
private String msg;
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备消息发送 Request VO") // 属性上报、事件上报、状态变更等
|
||||
@Data
|
||||
public class IotDeviceMessageSendReqVO {
|
||||
|
||||
@Schema(description = "请求方法", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
|
||||
@NotEmpty(message = "请求方法不能为空")
|
||||
@InEnum(IotDeviceMessageMethodEnum.class)
|
||||
private String method;
|
||||
|
||||
@Schema(description = "请求参数")
|
||||
private Object params; // 例如说:属性上报的 properties、事件上报的 params
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long deviceId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.property;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDataSpecs;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备属性详细 Response VO") // 额外增加 来自 ThingModelProperty 的变量 属性
|
||||
@Data
|
||||
public class IotDevicePropertyDetailRespVO extends IotDevicePropertyRespVO {
|
||||
|
||||
@Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String name;
|
||||
|
||||
@Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int")
|
||||
private String dataType;
|
||||
|
||||
@Schema(description = "数据定义")
|
||||
private ThingModelDataSpecs dataSpecs;
|
||||
|
||||
@Schema(description = "数据定义列表")
|
||||
private List<ThingModelDataSpecs> dataSpecsList;
|
||||
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.property;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
@ -12,17 +11,14 @@ import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备属性历史分页 Request VO")
|
||||
@Schema(description = "管理后台 - IoT 设备属性历史列表 Request VO")
|
||||
@Data
|
||||
public class IotDevicePropertyHistoryPageReqVO extends PageParam {
|
||||
public class IotDevicePropertyHistoryListReqVO {
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "设备 Key", hidden = true)
|
||||
private String deviceKey; // 非前端传递,后端自己查询设置
|
||||
|
||||
@Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "属性标识符不能为空")
|
||||
private String identifier;
|
||||
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.property;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@ -8,10 +7,10 @@ import lombok.Data;
|
||||
@Data
|
||||
public class IotDevicePropertyRespVO {
|
||||
|
||||
@Schema(description = "属性定义", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private ThingModelProperty property;
|
||||
@Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String identifier;
|
||||
|
||||
@Schema(description = "最新值", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Schema(description = "属性值", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Object value;
|
||||
|
||||
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ -3,13 +3,14 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService;
|
||||
import com.fhs.core.trans.anno.TransMethodResult;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
@ -22,12 +23,14 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT OTA 固件")
|
||||
@RestController
|
||||
@RequestMapping("/iot/ota-firmware")
|
||||
@RequestMapping("/iot/ota/firmware")
|
||||
@Validated
|
||||
public class IotOtaFirmwareController {
|
||||
|
||||
@Resource
|
||||
private IotOtaFirmwareService otaFirmwareService;
|
||||
@Resource
|
||||
private IotProductService productService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建 OTA 固件")
|
||||
@ -47,10 +50,17 @@ public class IotOtaFirmwareController {
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 OTA 固件")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')")
|
||||
@TransMethodResult
|
||||
public CommonResult<IotOtaFirmwareRespVO> getOtaFirmware(@RequestParam("id") Long id) {
|
||||
IotOtaFirmwareDO otaFirmware = otaFirmwareService.getOtaFirmware(id);
|
||||
return success(BeanUtils.toBean(otaFirmware, IotOtaFirmwareRespVO.class));
|
||||
IotOtaFirmwareDO firmware = otaFirmwareService.getOtaFirmware(id);
|
||||
if (firmware == null) {
|
||||
return success(null);
|
||||
}
|
||||
return success(BeanUtils.toBean(firmware, IotOtaFirmwareRespVO.class, o -> {
|
||||
IotProductDO product = productService.getProduct(firmware.getProductId());
|
||||
if (product != null) {
|
||||
o.setProductName(product.getName());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskCreateReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO;
|
||||
import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT OTA 升级任务")
|
||||
@RestController
|
||||
@RequestMapping("/iot/ota/task")
|
||||
@Validated
|
||||
public class IotOtaTaskController {
|
||||
|
||||
@Resource
|
||||
private IotOtaTaskService otaTaskService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建 OTA 升级任务")
|
||||
@PreAuthorize(value = "@ss.hasPermission('iot:ota-task:create')")
|
||||
public CommonResult<Long> createOtaTask(@Valid @RequestBody IotOtaTaskCreateReqVO createReqVO) {
|
||||
return success(otaTaskService.createOtaTask(createReqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/cancel")
|
||||
@Operation(summary = "取消 OTA 升级任务")
|
||||
@Parameter(name = "id", description = "升级任务编号", required = true)
|
||||
@PreAuthorize(value = "@ss.hasPermission('iot:ota-task:cancel')")
|
||||
public CommonResult<Boolean> cancelOtaTask(@RequestParam("id") Long id) {
|
||||
otaTaskService.cancelOtaTask(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得 OTA 升级任务分页")
|
||||
@PreAuthorize(value = "@ss.hasPermission('iot:ota-task:query')")
|
||||
public CommonResult<PageResult<IotOtaTaskRespVO>> getOtaTaskPage(@Valid IotOtaTaskPageReqVO pageReqVO) {
|
||||
PageResult<IotOtaTaskDO> pageResult = otaTaskService.getOtaTaskPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotOtaTaskRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 OTA 升级任务")
|
||||
@Parameter(name = "id", description = "升级任务编号", required = true, example = "1024")
|
||||
@PreAuthorize(value = "@ss.hasPermission('iot:ota-task:query')")
|
||||
public CommonResult<IotOtaTaskRespVO> getOtaTask(@RequestParam("id") Long id) {
|
||||
IotOtaTaskDO upgradeTask = otaTaskService.getOtaTask(id);
|
||||
return success(BeanUtils.toBean(upgradeTask, IotOtaTaskRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordRespVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService;
|
||||
import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskRecordService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - IoT OTA 升级任务记录")
|
||||
@RestController
|
||||
@RequestMapping("/iot/ota/task/record")
|
||||
@Validated
|
||||
public class IotOtaTaskRecordController {
|
||||
|
||||
@Resource
|
||||
private IotOtaTaskRecordService otaTaskRecordService;
|
||||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
@Resource
|
||||
private IotOtaFirmwareService otaFirmwareService;
|
||||
|
||||
@GetMapping("/get-status-statistics")
|
||||
@Operation(summary = "获得 OTA 升级记录状态统计")
|
||||
@Parameters({
|
||||
@Parameter(name = "firmwareId", description = "固件编号", example = "1024"),
|
||||
@Parameter(name = "taskId", description = "升级任务编号", example = "2048")
|
||||
})
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')")
|
||||
public CommonResult<Map<Integer, Long>> getOtaTaskRecordStatusStatistics(
|
||||
@RequestParam(value = "firmwareId", required = false) Long firmwareId,
|
||||
@RequestParam(value = "taskId", required = false) Long taskId) {
|
||||
return success(otaTaskRecordService.getOtaTaskRecordStatusStatistics(firmwareId, taskId));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得 OTA 升级记录分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')")
|
||||
public CommonResult<PageResult<IotOtaTaskRecordRespVO>> getOtaTaskRecordPage(
|
||||
@Valid IotOtaTaskRecordPageReqVO pageReqVO) {
|
||||
PageResult<IotOtaTaskRecordDO> pageResult = otaTaskRecordService.getOtaTaskRecordPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty());
|
||||
}
|
||||
|
||||
// 批量查询固件信息
|
||||
Map<Long, IotOtaFirmwareDO> firmwareMap = otaFirmwareService.getOtaFirmwareMap(
|
||||
convertSet(pageResult.getList(), IotOtaTaskRecordDO::getFromFirmwareId));
|
||||
Map<Long, IotDeviceDO> deviceMap = deviceService.getDeviceMap(
|
||||
convertSet(pageResult.getList(), IotOtaTaskRecordDO::getDeviceId));
|
||||
// 转换为响应 VO
|
||||
return success(BeanUtils.toBean(pageResult, IotOtaTaskRecordRespVO.class, (vo) -> {
|
||||
MapUtils.findAndThen(firmwareMap, vo.getFromFirmwareId(), firmware ->
|
||||
vo.setFromFirmwareVersion(firmware.getVersion()));
|
||||
MapUtils.findAndThen(deviceMap, vo.getDeviceId(), device ->
|
||||
vo.setDeviceName(device.getDeviceName()));
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 OTA 升级记录")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')")
|
||||
@Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
|
||||
public CommonResult<IotOtaTaskRecordRespVO> getOtaTaskRecord(@RequestParam("id") Long id) {
|
||||
IotOtaTaskRecordDO upgradeRecord = otaTaskRecordService.getOtaTaskRecord(id);
|
||||
return success(BeanUtils.toBean(upgradeRecord, IotOtaTaskRecordRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/cancel")
|
||||
@Operation(summary = "取消 OTA 升级记录")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-task-record:cancel')")
|
||||
@Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
|
||||
public CommonResult<Boolean> cancelOtaTaskRecord(@RequestParam("id") Long id) {
|
||||
otaTaskRecordService.cancelOtaTaskRecord(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordRespVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO;
|
||||
import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService;
|
||||
import com.fhs.core.trans.anno.TransMethodResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT OTA 升级记录")
|
||||
@RestController
|
||||
@RequestMapping("/iot/ota-upgrade-record")
|
||||
@Validated
|
||||
public class IotOtaUpgradeRecordController {
|
||||
|
||||
@Resource
|
||||
private IotOtaUpgradeRecordService upgradeRecordService;
|
||||
|
||||
@GetMapping("/get-statistics")
|
||||
@Operation(summary = "固件升级设备统计")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
|
||||
@Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024")
|
||||
public CommonResult<Map<Integer, Long>> getOtaUpgradeRecordStatistics(@RequestParam(value = "firmwareId") Long firmwareId) {
|
||||
return success(upgradeRecordService.getOtaUpgradeRecordStatistics(firmwareId));
|
||||
}
|
||||
|
||||
@GetMapping("/get-count")
|
||||
@Operation(summary = "获得升级记录分页 tab 数量")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
|
||||
public CommonResult<Map<Integer, Long>> getOtaUpgradeRecordCount(
|
||||
@Valid IotOtaUpgradeRecordPageReqVO pageReqVO) {
|
||||
return success(upgradeRecordService.getOtaUpgradeRecordCount(pageReqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得升级记录分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
|
||||
@TransMethodResult
|
||||
public CommonResult<PageResult<IotOtaUpgradeRecordRespVO>> getUpgradeRecordPage(
|
||||
@Valid IotOtaUpgradeRecordPageReqVO pageReqVO) {
|
||||
PageResult<IotOtaUpgradeRecordDO> pageResult = upgradeRecordService.getUpgradeRecordPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotOtaUpgradeRecordRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得升级记录")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
|
||||
@Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
|
||||
@TransMethodResult
|
||||
public CommonResult<IotOtaUpgradeRecordRespVO> getUpgradeRecord(@RequestParam("id") Long id) {
|
||||
IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordService.getUpgradeRecord(id);
|
||||
return success(BeanUtils.toBean(upgradeRecord, IotOtaUpgradeRecordRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/retry")
|
||||
@Operation(summary = "重试升级记录")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:retry')")
|
||||
@Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
|
||||
public CommonResult<Boolean> retryUpgradeRecord(@RequestParam("id") Long id) {
|
||||
upgradeRecordService.retryUpgradeRecord(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO;
|
||||
import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeTaskService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT OTA 升级任务")
|
||||
@RestController
|
||||
@RequestMapping("/iot/ota-upgrade-task")
|
||||
@Validated
|
||||
public class IotOtaUpgradeTaskController {
|
||||
|
||||
@Resource
|
||||
private IotOtaUpgradeTaskService upgradeTaskService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建升级任务")
|
||||
@PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:create')")
|
||||
public CommonResult<Long> createUpgradeTask(@Valid @RequestBody IotOtaUpgradeTaskSaveReqVO createReqVO) {
|
||||
return success(upgradeTaskService.createUpgradeTask(createReqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/cancel")
|
||||
@Operation(summary = "取消升级任务")
|
||||
@Parameter(name = "id", description = "升级任务编号", required = true)
|
||||
@PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:cancel')")
|
||||
public CommonResult<Boolean> cancelUpgradeTask(@RequestParam("id") Long id) {
|
||||
upgradeTaskService.cancelUpgradeTask(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得升级任务分页")
|
||||
@PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')")
|
||||
public CommonResult<PageResult<IotOtaUpgradeTaskRespVO>> getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO) {
|
||||
PageResult<IotOtaUpgradeTaskDO> pageResult = upgradeTaskService.getUpgradeTaskPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotOtaUpgradeTaskRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得升级任务")
|
||||
@Parameter(name = "id", description = "升级任务编号", required = true, example = "1024")
|
||||
@PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')")
|
||||
public CommonResult<IotOtaUpgradeTaskRespVO> getUpgradeTask(@RequestParam("id") Long id) {
|
||||
IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(id);
|
||||
return success(BeanUtils.toBean(upgradeTask, IotOtaUpgradeTaskRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
@Schema(description = "管理后台 - IoT OTA 固件创建 Request VO")
|
||||
@Data
|
||||
@ -22,17 +23,11 @@ public class IotOtaFirmwareCreateReqVO {
|
||||
|
||||
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "产品编号不能为空")
|
||||
private String productId;
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "签名方式", example = "MD5")
|
||||
// TODO @li:是不是必传哈
|
||||
private String signMethod;
|
||||
|
||||
@Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip")
|
||||
@Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.zip")
|
||||
@NotEmpty(message = "固件文件 URL 不能为空")
|
||||
@URL(message = "固件文件 URL 格式错误")
|
||||
private String fileUrl;
|
||||
|
||||
@Schema(description = "自定义信息,建议使用 JSON 格式", example = "{\"key1\":\"value1\",\"key2\":\"value2\"}")
|
||||
private String information;
|
||||
|
||||
}
|
||||
|
||||
@ -3,21 +3,24 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - IoT OTA 固件分页 Request VO")
|
||||
@Data
|
||||
public class IotOtaFirmwarePageReqVO extends PageParam {
|
||||
|
||||
/**
|
||||
* 固件名称
|
||||
*/
|
||||
@Schema(description = "固件名称", example = "智能开关固件")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@Schema(description = "产品标识", example = "1024")
|
||||
private String productId;
|
||||
|
||||
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
|
||||
@ -1,83 +1,49 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT OTA 固件 Response VO")
|
||||
@Data
|
||||
public class IotOtaFirmwareRespVO implements VO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
@Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
/**
|
||||
* 固件名称
|
||||
*/
|
||||
@Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA固件")
|
||||
|
||||
@Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA 固件")
|
||||
private String name;
|
||||
/**
|
||||
* 固件描述
|
||||
*/
|
||||
|
||||
@Schema(description = "固件描述")
|
||||
private String description;
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
|
||||
@Schema(description = "版本号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0.0")
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 产品编号
|
||||
* <p>
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
|
||||
*/
|
||||
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@Trans(type = TransType.SIMPLE, target = IotProductDO.class, fields = {"name"}, refs = {"productName"})
|
||||
private String productId;
|
||||
/**
|
||||
* 产品标识
|
||||
* <p>
|
||||
* 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()}
|
||||
*/
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot-product-key")
|
||||
private String productKey;
|
||||
/**
|
||||
* 产品名称
|
||||
*/
|
||||
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA产品")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能设备")
|
||||
private String productName;
|
||||
/**
|
||||
* 签名方式
|
||||
* <p>
|
||||
* 例如说:MD5、SHA256
|
||||
*/
|
||||
@Schema(description = "签名方式", example = "MD5")
|
||||
private String signMethod;
|
||||
/**
|
||||
* 固件文件签名
|
||||
*/
|
||||
@Schema(description = "固件文件签名", example = "1024")
|
||||
private String fileSign;
|
||||
/**
|
||||
* 固件文件大小
|
||||
*/
|
||||
|
||||
@Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/firmware.bin")
|
||||
private String fileUrl;
|
||||
|
||||
@Schema(description = "固件文件大小", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long fileSize;
|
||||
/**
|
||||
* 固件文件 URL
|
||||
*/
|
||||
@Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
|
||||
private String fileUrl;
|
||||
/**
|
||||
* 自定义信息,建议使用 JSON 格式
|
||||
*/
|
||||
@Schema(description = "自定义信息,建议使用 JSON 格式")
|
||||
private String information;
|
||||
|
||||
@Schema(description = "固件文件签名算法", example = "MD5")
|
||||
private String fileDigestAlgorithm;
|
||||
|
||||
@Schema(description = "固件文件签名结果", example = "d41d8cd98f00b204e9800998ecf8427e")
|
||||
private String fileDigestValue;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@ -13,9 +12,7 @@ public class IotOtaFirmwareUpdateReqVO {
|
||||
@NotNull(message = "固件编号不能为空")
|
||||
private Long id;
|
||||
|
||||
// TODO @li:name 是不是可以飞必传哈
|
||||
@Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能开关固件")
|
||||
@NotEmpty(message = "固件名称不能为空")
|
||||
@Schema(description = "固件名称", example = "智能开关固件")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "固件描述", example = "某品牌型号固件,测试用")
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task;
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
|
||||
import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
@ -11,51 +9,29 @@ import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT OTA 升级任务创建 Request VO")
|
||||
@Data
|
||||
@Schema(description = "管理后台 - IoT OTA 升级任务创建/修改 Request VO")
|
||||
public class IotOtaUpgradeTaskSaveReqVO {
|
||||
public class IotOtaTaskCreateReqVO {
|
||||
|
||||
// TODO @li:已经有注解,不用重复注释
|
||||
// TODO @li: @Schema 写在参数校验前面。先有定义;其他的,也检查下;
|
||||
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
@NotEmpty(message = "任务名称不能为空")
|
||||
@Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "升级任务")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 任务描述
|
||||
*/
|
||||
@Schema(description = "任务描述", example = "升级任务")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
* <p>
|
||||
* 关联 {@link IotOtaFirmwareDO#getId()}
|
||||
*/
|
||||
@NotNull(message = "固件编号不能为空")
|
||||
@Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "固件编号不能为空")
|
||||
private Long firmwareId;
|
||||
|
||||
/**
|
||||
* 升级范围
|
||||
* <p>
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum}
|
||||
*/
|
||||
@NotNull(message = "升级范围不能为空")
|
||||
@InEnum(value = IotOtaUpgradeTaskScopeEnum.class)
|
||||
@Schema(description = "升级范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer scope;
|
||||
@NotNull(message = "升级范围不能为空")
|
||||
@InEnum(value = IotOtaTaskDeviceScopeEnum.class)
|
||||
private Integer deviceScope;
|
||||
|
||||
/**
|
||||
* 选中的设备编号数组
|
||||
* <p>
|
||||
* 关联 {@link IotDeviceDO#getId()}
|
||||
*/
|
||||
@Schema(description = "选中的设备编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3,4]")
|
||||
@Schema(description = "选中的设备编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
|
||||
private List<Long> deviceIds;
|
||||
|
||||
// TODO @li:如果 deviceScope 等于 2 时,deviceIds 校验非空;
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT OTA 升级任务分页 Request VO")
|
||||
@Data
|
||||
public class IotOtaTaskPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "任务名称", example = "升级任务")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "固件编号", example = "1024")
|
||||
private Long firmwareId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task;
|
||||
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT OTA 升级任务 Response VO")
|
||||
@Data
|
||||
public class IotOtaTaskRespVO implements VO {
|
||||
|
||||
@Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "升级任务")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "任务描述", example = "升级任务")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long firmwareId;
|
||||
|
||||
@Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "升级范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer deviceScope;
|
||||
|
||||
@Schema(description = "设备总共数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer deviceTotalCount;
|
||||
|
||||
@Schema(description = "设备成功数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "66")
|
||||
private Integer deviceSuccessCount;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-08 07:30:00")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT OTA 升级记录分页 Request VO")
|
||||
@Data
|
||||
public class IotOtaTaskRecordPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "升级任务编号", example = "1024")
|
||||
private Long taskId;
|
||||
|
||||
@Schema(description = "升级记录状态", example = "5")
|
||||
@InEnum(IotOtaTaskRecordStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT OTA 升级任务记录 Response VO")
|
||||
@Data
|
||||
public class IotOtaTaskRecordRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long firmwareId;
|
||||
|
||||
@Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long taskId;
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "设备名称", example = "智能开关")
|
||||
private String deviceName;
|
||||
|
||||
@Schema(description = "来源的固件编号", example = "1023")
|
||||
private Long fromFirmwareId;
|
||||
|
||||
@Schema(description = "来源固件版本", example = "1.0.0")
|
||||
private String fromFirmwareVersion;
|
||||
|
||||
@Schema(description = "升级状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "升级进度,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "50")
|
||||
private Integer progress;
|
||||
|
||||
@Schema(description = "升级进度描述", example = "正在下载固件...")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - IoT OTA 升级记录分页 Request VO")
|
||||
public class IotOtaUpgradeRecordPageReqVO extends PageParam {
|
||||
|
||||
// TODO @li:已经有注解,不用重复注释
|
||||
/**
|
||||
* 升级任务编号字段。
|
||||
* <p>
|
||||
* 该字段用于标识升级任务的唯一编号,不能为空。
|
||||
*/
|
||||
@Schema(description = "升级任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "升级任务编号不能为空")
|
||||
private Long taskId;
|
||||
|
||||
/**
|
||||
* 设备标识字段。
|
||||
* <p>
|
||||
* 该字段用于标识设备的名称,通常用于区分不同的设备。
|
||||
*/
|
||||
@Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "摄像头A1-1")
|
||||
private String deviceName;
|
||||
|
||||
}
|
||||
@ -1,107 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - IoT OTA 升级记录 Response VO")
|
||||
public class IotOtaUpgradeRecordRespVO {
|
||||
|
||||
/**
|
||||
* 升级记录编号
|
||||
*/
|
||||
@Schema(description = "升级记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
/**
|
||||
* 固件编号
|
||||
* <p>
|
||||
* 关联 {@link IotOtaFirmwareDO#getId()}
|
||||
*/
|
||||
@Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@Trans(type = TransType.SIMPLE, target = IotOtaFirmwareDO.class, fields = {"version"}, refs = {"firmwareVersion"})
|
||||
private Long firmwareId;
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
@Schema(description = "固件版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0")
|
||||
private String firmwareVersion;
|
||||
/**
|
||||
* 任务编号
|
||||
* <p>
|
||||
* 关联 {@link IotOtaUpgradeTaskDO#getId()}
|
||||
*/
|
||||
@Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long taskId;
|
||||
/**
|
||||
* 产品标识
|
||||
* <p>
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
|
||||
*/
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot")
|
||||
private String productKey;
|
||||
/**
|
||||
* 设备名称
|
||||
* <p>
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()}
|
||||
*/
|
||||
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot")
|
||||
private String deviceName;
|
||||
/**
|
||||
* 设备编号
|
||||
* <p>
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()}
|
||||
*/
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private String deviceId;
|
||||
/**
|
||||
* 来源的固件编号
|
||||
* <p>
|
||||
* 关联 {@link IotDeviceDO#getFirmwareId()}
|
||||
*/
|
||||
@Schema(description = "来源的固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@Trans(type = TransType.SIMPLE, target = IotOtaFirmwareDO.class, fields = {"version"}, refs = {"fromFirmwareVersion"})
|
||||
private Long fromFirmwareId;
|
||||
/**
|
||||
* 来源的固件版本
|
||||
*/
|
||||
@Schema(description = "来源的固件版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0")
|
||||
private String fromFirmwareVersion;
|
||||
/**
|
||||
* 升级状态
|
||||
* <p>
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum}
|
||||
*/
|
||||
@Schema(description = "升级状态", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"0", "10", "20", "30", "40", "50"})
|
||||
private Integer status;
|
||||
/**
|
||||
* 升级进度,百分比
|
||||
*/
|
||||
@Schema(description = "升级进度,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer progress;
|
||||
/**
|
||||
* 升级进度描述
|
||||
* <p>
|
||||
* 注意,只记录设备最后一次的升级进度描述
|
||||
* 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志
|
||||
*/
|
||||
@Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private String description;
|
||||
/**
|
||||
* 升级开始时间
|
||||
*/
|
||||
@Schema(description = "升级开始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-08 07:30:00")
|
||||
private LocalDateTime startTime;
|
||||
/**
|
||||
* 升级结束时间
|
||||
*/
|
||||
@Schema(description = "升级结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-08 07:30:00")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - IoT OTA 升级任务分页 Request VO")
|
||||
public class IotOtaUpgradeTaskPageReqVO extends PageParam {
|
||||
|
||||
/**
|
||||
* 任务名称字段,用于描述任务的名称
|
||||
*/
|
||||
@Schema(description = "任务名称", example = "升级任务")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 固件编号字段,用于唯一标识固件,不能为空
|
||||
*/
|
||||
@NotNull(message = "固件编号不能为空")
|
||||
@Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long firmwareId;
|
||||
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "管理后台 - IoT OTA 升级任务 Response VO")
|
||||
public class IotOtaUpgradeTaskRespVO implements VO {
|
||||
|
||||
/**
|
||||
* 任务编号
|
||||
*/
|
||||
@Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
@Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "升级任务")
|
||||
private String name;
|
||||
/**
|
||||
* 任务描述
|
||||
*/
|
||||
@Schema(description = "任务描述", example = "升级任务")
|
||||
private String description;
|
||||
/**
|
||||
* 固件编号
|
||||
* <p>
|
||||
* 关联 {@link IotOtaFirmwareDO#getId()}
|
||||
*/
|
||||
@Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long firmwareId;
|
||||
/**
|
||||
* 任务状态
|
||||
* <p>
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum}
|
||||
*/
|
||||
@Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"10", "20", "21", "30"})
|
||||
private Integer status;
|
||||
/**
|
||||
* 任务状态名称
|
||||
*/
|
||||
@Schema(description = "任务状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中")
|
||||
private String statusName;
|
||||
/**
|
||||
* 升级范围
|
||||
* <p>
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum}
|
||||
*/
|
||||
@Schema(description = "升级范围", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"1", "2"})
|
||||
private Integer scope;
|
||||
/**
|
||||
* 设备数量
|
||||
*/
|
||||
@Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long deviceCount;
|
||||
/**
|
||||
* 选中的设备编号数组
|
||||
* <p>
|
||||
* 关联 {@link IotDeviceDO#getId()}
|
||||
*/
|
||||
@Schema(description = "选中的设备编号数组", example = "1024")
|
||||
private List<Long> deviceIds;
|
||||
/**
|
||||
* 选中的设备名字数组
|
||||
* <p>
|
||||
* 关联 {@link IotDeviceDO#getDeviceName()}
|
||||
*/
|
||||
@Schema(description = "选中的设备名字数组", example = "1024")
|
||||
private List<String> deviceNames;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-08 07:30:00")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigImportReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigStatusReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
|
||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 插件配置")
|
||||
@RestController
|
||||
@RequestMapping("/iot/plugin-config")
|
||||
@Validated
|
||||
public class PluginConfigController {
|
||||
|
||||
@Resource
|
||||
private IotPluginConfigService pluginConfigService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建插件配置")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:create')")
|
||||
public CommonResult<Long> createPluginConfig(@Valid @RequestBody PluginConfigSaveReqVO createReqVO) {
|
||||
return success(pluginConfigService.createPluginConfig(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新插件配置")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
||||
public CommonResult<Boolean> updatePluginConfig(@Valid @RequestBody PluginConfigSaveReqVO updateReqVO) {
|
||||
pluginConfigService.updatePluginConfig(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除插件配置")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:delete')")
|
||||
public CommonResult<Boolean> deletePluginConfig(@RequestParam("id") Long id) {
|
||||
pluginConfigService.deletePluginConfig(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得插件配置")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:query')")
|
||||
public CommonResult<PluginConfigRespVO> getPluginConfig(@RequestParam("id") Long id) {
|
||||
IotPluginConfigDO pluginConfig = pluginConfigService.getPluginConfig(id);
|
||||
return success(BeanUtils.toBean(pluginConfig, PluginConfigRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得插件配置分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:query')")
|
||||
public CommonResult<PageResult<PluginConfigRespVO>> getPluginConfigPage(@Valid PluginConfigPageReqVO pageReqVO) {
|
||||
PageResult<IotPluginConfigDO> pageResult = pluginConfigService.getPluginConfigPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, PluginConfigRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/upload-file")
|
||||
@Operation(summary = "上传插件文件")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
||||
public CommonResult<Boolean> uploadFile(@Valid PluginConfigImportReqVO reqVO) {
|
||||
pluginConfigService.uploadFile(reqVO.getId(), reqVO.getFile());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "修改插件状态")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
||||
public CommonResult<Boolean> updatePluginConfigStatus(@Valid @RequestBody PluginConfigStatusReqVO reqVO) {
|
||||
pluginConfigService.updatePluginStatus(reqVO.getId(), reqVO.getStatus());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user