feat:【IoT 物联网】新版本同步

This commit is contained in:
YunaiV 2025-08-30 09:34:40 +08:00
parent d8fbd0f6c5
commit a89b6d14a8
500 changed files with 19983 additions and 13090 deletions

View File

@ -16,6 +16,7 @@ import java.util.Arrays;
@AllArgsConstructor
public enum DateIntervalEnum implements ArrayValuable<Integer> {
HOUR(0, "小时"), // 特殊字典里暂时不会有这个枚举因为大多数情况下用不到这个间隔
DAY(1, ""),
WEEK(2, ""),
MONTH(3, ""),

View File

@ -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:

View File

@ -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) 的场景下

View File

@ -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");

View File

@ -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());
});
});

View File

@ -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) {
// 消费消息

View File

@ -9,8 +9,9 @@
</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-server</module>
<module>yudao-module-iot-gateway</module>
</modules>
<modelVersion>4.0.0</modelVersion>

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
/**
* 签名方式
*
* 例如说MD5SHA256
*/
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();
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 {
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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 签名
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1,4 +0,0 @@
/**
* TODO 芋艿占位
*/
package cn.iocoder.yudao.module.iot.api.device.dto;

View File

@ -1,6 +1,4 @@
/**
* 占位
*
* TODO 芋艿后续删除
* iot API 定义暴露给其它模块的 API
*/
package cn.iocoder.yudao.module.iot.api;

View File

@ -7,16 +7,19 @@ package cn.iocoder.yudao.module.iot.enums;
*/
public class DictTypeConstants {
public static final String NET_TYPE = "iot_net_type";
public static final String LOCATION_TYPE = "iot_location_type";
public static final String CODEC_TYPE = "iot_codec_type";
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";
public static final String ALERT_LEVEL = "iot_alert_level";
public static final String OTA_TASK_DEVICE_SCOPE = "iot_ota_task_device_scope";
public static final String OTA_TASK_STATUS = "iot_ota_task_status";
public static final String OTA_TASK_RECORD_STATUS = "iot_ota_task_record_status";
}

View File

@ -14,6 +14,7 @@ public interface ErrorCodeConstants {
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, "产品状是发布状态,不允许操作物模型");
ErrorCode PRODUCT_DELETE_FAIL_HAS_DEVICE = new ErrorCode(1_050_001_004, "产品下存在设备,不允许删除");
// ========== 产品物模型 1-050-002-000 ============
ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
@ -30,7 +31,8 @@ public interface ErrorCodeConstants {
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, "执行失败,原因:{}");
ErrorCode DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL = new ErrorCode(1_050_003_007, "下行设备消息失败,原因:设备未连接网关");
ErrorCode DEVICE_SERIAL_NUMBER_EXISTS = new ErrorCode(1_050_003_008, "设备序列号已存在,序列号必须全局唯一");
// ========== 产品分类 1-050-004-000 ==========
ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在");
@ -39,37 +41,42 @@ public interface ErrorCodeConstants {
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 ==========
// ========== OTA 固件相关 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, "升级任务不能取消");
// ========== OTA 升级任务相关 1-050-008-100 ==========
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, "升级记录不能重试");
ErrorCode OTA_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在");
ErrorCode OTA_TASK_CREATE_FAIL_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "创建 OTA 任务失败,原因:任务名称重复");
ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_FIRMWARE_EXISTS = new ErrorCode(1_050_008_102,
"创建 OTA 任务失败,原因:设备({})已经是该固件版本");
ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_OTA_IN_PROCESS = new ErrorCode(1_050_008_102,
"创建 OTA 任务失败,原因:设备({})已经在升级中...");
ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_EMPTY = new ErrorCode(1_050_008_103, "创建 OTA 任务失败,原因:没有可升级的设备");
ErrorCode OTA_TASK_CANCEL_FAIL_STATUS_END = new ErrorCode(1_050_008_104, "取消 OTA 任务失败,原因:任务状态不是进行中");
// ========== MQTT 通信相关 1-050-009-000 ==========
ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal");
// ========== OTA 升级任务记录相关 1-050-008-200 ==========
// ========== IoT 数据桥梁 1-050-010-000 ==========
ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在");
ErrorCode OTA_TASK_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在");
ErrorCode OTA_TASK_RECORD_CANCEL_FAIL_STATUS_ERROR = new ErrorCode(1_050_008_201, "取消 OTA 升级记录失败,原因:记录状态不是进行中");
ErrorCode OTA_TASK_RECORD_UPDATE_PROGRESS_FAIL_NO_EXISTS = new ErrorCode(1_050_008_202, "更新 OTA 升级记录进度失败,原因:该设备没有进行中的升级记录");
// ========== IoT 数据流转规则 1-050-010-000 ==========
ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在");
// ========== IoT 数据流转目的 1-050-011-000 ==========
ErrorCode DATA_SINK_NOT_EXISTS = new ErrorCode(1_050_011_000, "数据桥梁不存在");
ErrorCode DATA_SINK_DELETE_FAIL_USED_BY_RULE = new ErrorCode(1_050_011_001, "数据流转目的正在被数据流转规则使用,无法删除");
// ========== IoT 场景联动 1-050-012-000 ==========
ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_012_000, "场景联动不存在");
// ========== IoT 告警配置 1-050-013-000 ==========
ErrorCode ALERT_CONFIG_NOT_EXISTS = new ErrorCode(1_050_013_000, "IoT 告警配置不存在");
// ========== IoT 告警记录 1-050-014-000 ==========
ErrorCode ALERT_RECORD_NOT_EXISTS = new ErrorCode(1_050_014_000, "IoT 告警记录不存在");
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.iot.enums.rule;
package cn.iocoder.yudao.module.iot.enums.alert;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.Getter;
@ -7,21 +7,22 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* IoT 告警配置的接收方式枚举
* IoT 告警的接收方式枚举
*
* @author 芋道源码
*/
@RequiredArgsConstructor
@Getter
public enum IotAlertConfigReceiveTypeEnum implements ArrayValuable<Integer> {
public enum IotAlertReceiveTypeEnum implements ArrayValuable<Integer> {
SMS(1), // 短信
MAIL(2), // 邮箱
NOTIFY(3); // 通知
NOTIFY(3); // 站内信
// TODO 待实现欢迎 pull requestwebhook 4
private final Integer type;
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotAlertConfigReceiveTypeEnum::getType).toArray(Integer[]::new);
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotAlertReceiveTypeEnum::getType).toArray(Integer[]::new);
@Override
public Integer[] array() {

View File

@ -7,11 +7,12 @@ import lombok.RequiredArgsConstructor;
/**
* IoT 设备消息标识符枚举
*/
@Deprecated
@Getter
@RequiredArgsConstructor
public enum IotDeviceMessageIdentifierEnum {
PROPERTY_GET("get"), // 下行 TODO 芋艿讨论貌似这个上行更合理device 主动拉取配置 IotDevicePropertyGetReqDTO 一样的配置
PROPERTY_GET("get"), // 下行
PROPERTY_SET("set"), // 下行
PROPERTY_REPORT("report"), // 上行

View File

@ -9,6 +9,7 @@ import java.util.Arrays;
/**
* IoT 设备消息类型枚举
*/
@Deprecated
@Getter
@RequiredArgsConstructor
public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> {

View File

@ -7,18 +7,19 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* IoT OTA 升级任务的范围枚举
* IoT OTA 升级任务的设备范围枚举
*
* @author haohao
*/
@RequiredArgsConstructor
@Getter
public enum IotOtaUpgradeTaskScopeEnum implements ArrayValuable<Integer> {
public enum IotOtaTaskDeviceScopeEnum implements ArrayValuable<Integer> {
ALL(1), // 全部设备只包括当前产品下的设备不包括未来创建的设备
SELECT(2); // 指定设备
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskScopeEnum::getScope).toArray(Integer[]::new);
public static final Integer[] ARRAYS = Arrays.stream(values())
.map(IotOtaTaskDeviceScopeEnum::getScope).toArray(Integer[]::new);
/**
* 范围

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.iot.enums.ota;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* IoT OTA 升级任务记录的状态枚举
*
* @author 芋道源码
*/
@RequiredArgsConstructor
@Getter
public enum IotOtaTaskRecordStatusEnum implements ArrayValuable<Integer> {
PENDING(0), // 待推送
PUSHED(10), // 已推送
UPGRADING(20), // 升级中
SUCCESS(30), // 升级成功
FAILURE(40), // 升级失败
CANCELED(50),; // 升级取消
public static final Integer[] ARRAYS = Arrays.stream(values())
.map(IotOtaTaskRecordStatusEnum::getStatus).toArray(Integer[]::new);
public static final Set<Integer> IN_PROCESS_STATUSES = SetUtils.asSet(
PENDING.getStatus(),
PUSHED.getStatus(),
UPGRADING.getStatus());
public static final List<Integer> PRIORITY_STATUSES = Arrays.asList(
SUCCESS.getStatus(),
PENDING.getStatus(), PUSHED.getStatus(), UPGRADING.getStatus(),
FAILURE.getStatus(), CANCELED.getStatus());
/**
* 状态
*/
private final Integer status;
@Override
public Integer[] array() {
return ARRAYS;
}
public static IotOtaTaskRecordStatusEnum of(Integer status) {
return ArrayUtil.firstMatch(o -> o.getStatus().equals(status), values());
}
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.iot.enums.ota;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@ -8,25 +7,23 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* IoT OTA 升级记录的范围枚举
* IoT OTA 升级任务的状态
*
* @author haohao
* @author 芋道源码
*/
@RequiredArgsConstructor
@Getter
public enum IotOtaUpgradeRecordStatusEnum implements ArrayValuable<Integer> {
public enum IotOtaTaskStatusEnum implements ArrayValuable<Integer> {
PENDING(0), // 待推送
PUSHED(10), // 已推送
UPGRADING(20), // 升级中
SUCCESS(30), // 升级成功
FAILURE(40), // 升级失败
CANCELED(50),; // 已取消
IN_PROGRESS(10), // 进行中升级中
END(20), // 已结束包括全部成功部分成功
CANCELED(30),; // 已取消一般是主动取消任务
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeRecordStatusEnum::getStatus).toArray(Integer[]::new);
public static final Integer[] ARRAYS = Arrays.stream(values())
.map(IotOtaTaskStatusEnum::getStatus).toArray(Integer[]::new);
/**
* 范围
* 状态
*/
private final Integer status;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -7,18 +7,19 @@ import lombok.Getter;
import java.util.Arrays;
/**
* IoT 数据校验级别枚举类
* IoT 定位方式枚举类
*
* @author ahh
* @author alwayssuper
*/
@AllArgsConstructor
@Getter
public enum IotValidateTypeEnum implements ArrayValuable<Integer> {
public enum IotLocationTypeEnum implements ArrayValuable<Integer> {
WEAK(0, "弱校验"),
NONE(1, "免校验");
IP(1, "IP 定位"),
DEVICE(2, "设备上报"),
MANUAL(3, "手动定位");
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotValidateTypeEnum::getType).toArray(Integer[]::new);
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotLocationTypeEnum::getType).toArray(Integer[]::new);
/**
* 类型

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,42 @@
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 IotDataSinkTypeEnum implements ArrayValuable<Integer> {
HTTP(1, "HTTP"),
TCP(2, "TCP"), // TODO @puhui999待实现
WEBSOCKET(3, "WebSocket"), // TODO @puhui999待实现
MQTT(10, "MQTT"), // TODO 待实现
DATABASE(20, "Database"), // TODO @puhui999待实现可以简单点对应的表名是什么字段先固定了
REDIS(21, "Redis"),
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(IotDataSinkTypeEnum::getType).toArray(Integer[]::new);
@Override
public Integer[] array() {
return ARRAYS;
}
}

View File

@ -7,20 +7,26 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* IoT 数据桥接的方向枚举
* IoT Redis 数据结构类型枚举
*
* @author 芋道源码
* @author HUIHUI
*/
@RequiredArgsConstructor
@Getter
public enum IotDataBridgeDirectionEnum implements ArrayValuable<Integer> {
public enum IotRedisDataStructureEnum implements ArrayValuable<Integer> {
INPUT(1), // 输入
OUTPUT(2); // 输出
STREAM(1, "Stream"),
HASH(2, "Hash"),
LIST(3, "List"),
SET(4, "Set"),
ZSET(5, "ZSet"),
STRING(6, "String");
private final Integer type;
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeDirectionEnum::getType).toArray(Integer[]::new);
private final String name;
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRedisDataStructureEnum::getType).toArray(Integer[]::new);
@Override
public Integer[] array() {

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,51 @@
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 IotSceneRuleActionTypeEnum implements ArrayValuable<Integer> {
/**
* 设备属性设置
*
* 对应 {@link IotDeviceMessageMethodEnum#PROPERTY_SET}
*/
DEVICE_PROPERTY_SET(1),
/**
* 设备服务调用
*
* 对应 {@link IotDeviceMessageMethodEnum#SERVICE_INVOKE}
*/
DEVICE_SERVICE_INVOKE(2),
/**
* 告警触发
*/
ALERT_TRIGGER(100),
/**
* 告警恢复
*/
ALERT_RECOVER(101),
;
private final Integer type;
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotSceneRuleActionTypeEnum::getType).toArray(Integer[]::new);
@Override
public Integer[] array() {
return ARRAYS;
}
}

View File

@ -8,13 +8,13 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* IoT 场景触发条件参数的操作符枚举
* IoT 场景触发条件的操作符枚举
*
* @author 芋道源码
*/
@RequiredArgsConstructor
@Getter
public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayValuable<String> {
public enum IotSceneRuleConditionOperatorEnum implements ArrayValuable<String> {
EQUALS("=", "#source == #value"),
NOT_EQUALS("!=", "!(#source == #value)"),
@ -32,12 +32,28 @@ public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayVa
NOT_BETWEEN("not between", "(#source < #values.get(0)) || (#source > #values.get(1))"),
LIKE("like", "#source.contains(#value)"), // 字符串匹配
NOT_NULL("not null", "#source != null && #source.length() > 0"); // 非空
NOT_NULL("not null", "#source != null && #source.length() > 0"), // 非空
// ========== 特殊不放在字典里 ==========
// TODO @puhui999@芋艿需要测试下
DATE_TIME_GREATER_THAN("date_time_>", "#source > #value"), // 在时间之后时间戳
DATE_TIME_LESS_THAN("date_time_<", "#source < #value"), // 在时间之前时间戳
DATE_TIME_BETWEEN("date_time_between", // 在时间之间时间戳
"(#source >= #values.get(0)) && (#source <= #values.get(1))"),
// TODO @puhui999@芋艿需要测试下
TIME_GREATER_THAN("time_>", "#source.isAfter(#value)"), // 在当日时间之后HH:mm:ss
TIME_LESS_THAN("time_<", "#source.isBefore(#value)"), // 在当日时间之前HH:mm:ss
TIME_BETWEEN("time_between", // 在当日时间之间HH:mm:ss
"(#source >= #values.get(0)) && (#source <= #values.get(1))"),
;
private final String operator;
private final String springExpression;
public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerConditionParameterOperatorEnum::getOperator).toArray(String[]::new);
public static final String[] ARRAYS = Arrays.stream(values()).map(IotSceneRuleConditionOperatorEnum::getOperator).toArray(String[]::new);
/**
* Spring 表达式 - 原始值
@ -50,9 +66,9 @@ public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayVa
/**
* Spring 表达式 - 目标值数组
*/
public static final String SPRING_EXPRESSION_VALUE_List = "values";
public static final String SPRING_EXPRESSION_VALUE_LIST = "values";
public static IotRuleSceneTriggerConditionParameterOperatorEnum operatorOf(String operator) {
public static IotSceneRuleConditionOperatorEnum operatorOf(String operator) {
return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values());
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.iot.enums.rule;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* IoT 条件类型枚举
*
* @author 芋道源码
*/
@RequiredArgsConstructor
@Getter
public enum IotSceneRuleConditionTypeEnum implements ArrayValuable<Integer> {
DEVICE_STATE(1, "设备状态"),
DEVICE_PROPERTY(2, "设备属性"),
CURRENT_TIME(100, "当前时间"),
;
private final Integer type;
private final String name;
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotSceneRuleConditionTypeEnum::getType).toArray(Integer[]::new);
@Override
public Integer[] array() {
return ARRAYS;
}
public static IotSceneRuleConditionTypeEnum typeOf(Integer type) {
return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
}
}

View File

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.iot.enums.rule;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* IoT 场景流转的触发类型枚举
*
* 为什么不直接使用 IotDeviceMessageMethodEnum
* 原因是物模型属性上报存在批量上报的情况不只对应一个 method
*
* @author 芋道源码
*/
@RequiredArgsConstructor
@Getter
public enum IotSceneRuleTriggerTypeEnum implements ArrayValuable<Integer> {
// TODO @芋艿后续对应部分 @下等包结构梳理完
/**
* 设备上下线变更
*
* 对应 IotDeviceMessageMethodEnum.STATE_UPDATE
*/
DEVICE_STATE_UPDATE(1),
/**
* 物模型属性上报
*
* 对应 IotDeviceMessageMethodEnum.DEVICE_PROPERTY_POST
*/
DEVICE_PROPERTY_POST(2),
/**
* 设备事件上报
*
* 对应 IotDeviceMessageMethodEnum.DEVICE_EVENT_POST
*/
DEVICE_EVENT_POST(3),
/**
* 设备服务调用
*
* 对应 IotDeviceMessageMethodEnum.DEVICE_SERVICE_INVOKE
*/
DEVICE_SERVICE_INVOKE(4),
/**
* 定时触发
*/
TIMER(100)
;
private final Integer type;
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotSceneRuleTriggerTypeEnum::getType).toArray(Integer[]::new);
@Override
public Integer[] array() {
return ARRAYS;
}
public static IotSceneRuleTriggerTypeEnum typeOf(Integer type) {
return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -1,6 +0,0 @@
/**
* 占位
*
* TODO 芋艿后续删除
*/
package cn.iocoder.yudao.module.iot.api;

View File

@ -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\":\"升级到最新版本\"}"
}
}

View File

@ -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));
}
}

View File

@ -1,95 +0,0 @@
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.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.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.device.data.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;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
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;
@Tag(name = "管理后台 - IoT 设备属性")
@RestController
@RequestMapping("/iot/device/property")
@Validated
public class IotDevicePropertyController {
@Resource
private IotDevicePropertyService devicePropertyService;
@Resource
private IotThingModelService thingModelService;
@Resource
private IotDeviceService deviceService;
@GetMapping("/latest")
@Operation(summary = "获取设备属性最新属性")
@Parameters({
@Parameter(name = "deviceId", description = "设备编号", required = true),
@Parameter(name = "identifier", description = "标识符"),
@Parameter(name = "name", description = "名称")
})
@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);
// 拼接数据
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;
}
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()));
}));
}
@GetMapping("/history-page")
@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));
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 枚举模糊匹配
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1,75 +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 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')")
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")
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);
}
}

View File

@ -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));
}
}

View File

@ -1,40 +0,0 @@
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;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
@Schema(description = "管理后台 - IoT OTA 固件创建 Request VO")
@Data
public class IotOtaFirmwareCreateReqVO {
@Schema(description = "固件名称", requiredMode = REQUIRED, example = "智能开关固件")
@NotEmpty(message = "固件名称不能为空")
private String name;
@Schema(description = "固件描述", example = "某品牌型号固件,测试用")
private String description;
@Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0")
@NotEmpty(message = "版本号不能为空")
private String version;
@Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024")
@NotNull(message = "产品编号不能为空")
private String productId;
@Schema(description = "签名方式", example = "MD5")
// TODO @li是不是必传哈
private String signMethod;
@Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip")
@NotEmpty(message = "固件文件 URL 不能为空")
private String fileUrl;
@Schema(description = "自定义信息,建议使用 JSON 格式", example = "{\"key1\":\"value1\",\"key2\":\"value2\"}")
private String information;
}

View File

@ -1,85 +0,0 @@
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;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
@Data
@Schema(description = "管理后台 - IoT OTA 固件 Response VO")
public class IotOtaFirmwareRespVO implements VO {
/**
* 固件编号
*/
@Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024")
private Long id;
/**
* 固件名称
*/
@Schema(description = "固件名称", requiredMode = REQUIRED, example = "OTA固件")
private String name;
/**
* 固件描述
*/
@Schema(description = "固件描述")
private String description;
/**
* 版本号
*/
@Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0")
private String version;
/**
* 产品编号
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
*/
@Schema(description = "产品编号", 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 = REQUIRED, example = "iot-product-key")
private String productKey;
/**
* 产品名称
*/
@Schema(description = "产品名称", requiredMode = REQUIRED, example = "OTA产品")
private String productName;
/**
* 签名方式
* <p>
* 例如说MD5SHA256
*/
@Schema(description = "签名方式", example = "MD5")
private String signMethod;
/**
* 固件文件签名
*/
@Schema(description = "固件文件签名", example = "1024")
private String fileSign;
/**
* 固件文件大小
*/
@Schema(description = "固件文件大小", requiredMode = REQUIRED, example = "1024")
private Long fileSize;
/**
* 固件文件 URL
*/
@Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn")
private String fileUrl;
/**
* 自定义信息建议使用 JSON 格式
*/
@Schema(description = "自定义信息,建议使用 JSON 格式")
private String information;
}

View File

@ -1,32 +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;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
@Data
@Schema(description = "管理后台 - IoT OTA 升级记录分页 Request VO")
public class IotOtaUpgradeRecordPageReqVO extends PageParam {
// TODO @li已经有注解不用重复注释
/**
* 升级任务编号字段
* <p>
* 该字段用于标识升级任务的唯一编号不能为空
*/
@Schema(description = "升级任务编号", requiredMode = REQUIRED, example = "1024")
@NotNull(message = "升级任务编号不能为空")
private Long taskId;
/**
* 设备标识字段
* <p>
* 该字段用于标识设备的名称通常用于区分不同的设备
*/
@Schema(description = "设备标识", requiredMode = REQUIRED, example = "摄像头A1-1")
private String deviceName;
}

View File

@ -1,109 +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;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
@Data
@Schema(description = "管理后台 - IoT OTA 升级记录 Response VO")
public class IotOtaUpgradeRecordRespVO {
/**
* 升级记录编号
*/
@Schema(description = "升级记录编号", requiredMode = REQUIRED, example = "1024")
private Long id;
/**
* 固件编号
* <p>
* 关联 {@link IotOtaFirmwareDO#getId()}
*/
@Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024")
@Trans(type = TransType.SIMPLE, target = IotOtaFirmwareDO.class, fields = {"version"}, refs = {"firmwareVersion"})
private Long firmwareId;
/**
* 固件版本
*/
@Schema(description = "固件版本", requiredMode = REQUIRED, example = "v1.0.0")
private String firmwareVersion;
/**
* 任务编号
* <p>
* 关联 {@link IotOtaUpgradeTaskDO#getId()}
*/
@Schema(description = "任务编号", requiredMode = REQUIRED, example = "1024")
private Long taskId;
/**
* 产品标识
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
*/
@Schema(description = "产品标识", requiredMode = REQUIRED, example = "iot")
private String productKey;
/**
* 设备名称
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()}
*/
@Schema(description = "设备名称", requiredMode = REQUIRED, example = "iot")
private String deviceName;
/**
* 设备编号
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()}
*/
@Schema(description = "设备编号", requiredMode = REQUIRED, example = "1024")
private String deviceId;
/**
* 来源的固件编号
* <p>
* 关联 {@link IotDeviceDO#getFirmwareId()}
*/
@Schema(description = "来源的固件编号", requiredMode = REQUIRED, example = "1024")
@Trans(type = TransType.SIMPLE, target = IotOtaFirmwareDO.class, fields = {"version"}, refs = {"fromFirmwareVersion"})
private Long fromFirmwareId;
/**
* 来源的固件版本
*/
@Schema(description = "来源的固件版本", requiredMode = REQUIRED, example = "v1.0.0")
private String fromFirmwareVersion;
/**
* 升级状态
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum}
*/
@Schema(description = "升级状态", requiredMode = REQUIRED, allowableValues = {"0", "10", "20", "30", "40", "50"})
private Integer status;
/**
* 升级进度百分比
*/
@Schema(description = "升级进度,百分比", requiredMode = REQUIRED, example = "10")
private Integer progress;
/**
* 升级进度描述
* <p>
* 注意只记录设备最后一次的升级进度描述
* 如果想看历史记录可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志
*/
@Schema(description = "升级进度描述", requiredMode = REQUIRED, example = "10")
private String description;
/**
* 升级开始时间
*/
@Schema(description = "升级开始时间", requiredMode = REQUIRED, example = "2022-07-08 07:30:00")
private LocalDateTime startTime;
/**
* 升级结束时间
*/
@Schema(description = "升级结束时间", requiredMode = REQUIRED, example = "2022-07-08 07:30:00")
private LocalDateTime endTime;
}

View File

@ -1,27 +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;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
@Data
@Schema(description = "管理后台 - IoT OTA 升级任务分页 Request VO")
public class IotOtaUpgradeTaskPageReqVO extends PageParam {
/**
* 任务名称字段用于描述任务的名称
*/
@Schema(description = "任务名称", example = "升级任务")
private String name;
/**
* 固件编号字段用于唯一标识固件不能为空
*/
@NotNull(message = "固件编号不能为空")
@Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024")
private Long firmwareId;
}

View File

@ -1,84 +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;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
@Data
@Schema(description = "管理后台 - IoT OTA 升级任务 Response VO")
public class IotOtaUpgradeTaskRespVO implements VO {
/**
* 任务编号
*/
@Schema(description = "任务编号", requiredMode = REQUIRED, example = "1024")
private Long id;
/**
* 任务名称
*/
@Schema(description = "任务名称", requiredMode = REQUIRED, example = "升级任务")
private String name;
/**
* 任务描述
*/
@Schema(description = "任务描述", example = "升级任务")
private String description;
/**
* 固件编号
* <p>
* 关联 {@link IotOtaFirmwareDO#getId()}
*/
@Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024")
private Long firmwareId;
/**
* 任务状态
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum}
*/
@Schema(description = "任务状态", requiredMode = REQUIRED, allowableValues = {"10", "20", "21", "30"})
private Integer status;
/**
* 任务状态名称
*/
@Schema(description = "任务状态名称", requiredMode = REQUIRED, example = "进行中")
private String statusName;
/**
* 升级范围
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum}
*/
@Schema(description = "升级范围", requiredMode = REQUIRED, allowableValues = {"1", "2"})
private Integer scope;
/**
* 设备数量
*/
@Schema(description = "设备数量", 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 = REQUIRED, example = "2022-07-08 07:30:00")
private LocalDateTime createTime;
}

View File

@ -1,63 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.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 io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
@Data
@Schema(description = "管理后台 - IoT OTA 升级任务创建/修改 Request VO")
public class IotOtaUpgradeTaskSaveReqVO {
// TODO @li已经有注解不用重复注释
// TODO @li @Schema 写在参数校验前面先有定义其他的也检查下
/**
* 任务名称
*/
@NotEmpty(message = "任务名称不能为空")
@Schema(description = "任务名称", requiredMode = REQUIRED, example = "升级任务")
private String name;
/**
* 任务描述
*/
@Schema(description = "任务描述", example = "升级任务")
private String description;
/**
* 固件编号
* <p>
* 关联 {@link IotOtaFirmwareDO#getId()}
*/
@NotNull(message = "固件编号不能为空")
@Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024")
private Long firmwareId;
/**
* 升级范围
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum}
*/
@NotNull(message = "升级范围不能为空")
@InEnum(value = IotOtaUpgradeTaskScopeEnum.class)
@Schema(description = "升级范围", requiredMode = REQUIRED, example = "1")
private Integer scope;
/**
* 选中的设备编号数组
* <p>
* 关联 {@link IotDeviceDO#getId()}
*/
@Schema(description = "选中的设备编号数组", requiredMode = REQUIRED, example = "[1,2,3,4]")
private List<Long> deviceIds;
}

View File

@ -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);
}
}

View File

@ -1,19 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
@Schema(description = "管理后台 - IoT 插件上传 Request VO")
@Data
public class PluginConfigImportReqVO {
@Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
private Long id;
@Schema(description = "插件文件", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "插件文件不能为空")
private MultipartFile file;
}

View File

@ -1,20 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - IoT 插件配置分页 Request VO")
@Data
public class PluginConfigPageReqVO extends PageParam {
@Schema(description = "插件名称", example = "http")
private String name;
@Schema(description = "状态", example = "1")
@InEnum(IotPluginStatusEnum.class)
private Integer status;
}

View File

@ -1,54 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - IoT 插件配置 Response VO")
@Data
public class PluginConfigRespVO {
@Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
private Long id;
@Schema(description = "插件包标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627")
private String pluginKey;
@Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
private String name;
@Schema(description = "描述", example = "你猜")
private String description;
@Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer deployType;
@Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED)
private String fileName;
@Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED)
private String version;
@Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer type;
@Schema(description = "设备插件协议类型")
private String protocol;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer status;
@Schema(description = "插件配置项描述信息")
private String configSchema;
@Schema(description = "插件配置信息")
private String config;
@Schema(description = "插件脚本")
private String script;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -1,56 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - IoT 插件配置新增/修改 Request VO")
@Data
public class PluginConfigSaveReqVO {
// TODO @haohao新增的字段有点多每个都需要哇
// TODO @haohao一些枚举字段需要加枚举校验例如说deployTypestatustype
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
private Long id;
@Schema(description = "插件包标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627")
private String pluginKey;
@Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
private String name;
@Schema(description = "描述", example = "你猜")
private String description;
@Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer deployType;
@Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED)
private String fileName;
@Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED)
private String version;
@Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer type;
@Schema(description = "设备插件协议类型")
private String protocol;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
@InEnum(IotPluginStatusEnum.class)
private Integer status;
@Schema(description = "插件配置项描述信息")
private String configSchema;
@Schema(description = "插件配置信息")
private String config;
@Schema(description = "插件脚本")
private String script;
}

View File

@ -1,19 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - IoT 插件配置状态 Request VO")
@Data
public class PluginConfigStatusReqVO {
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
private Long id;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
@InEnum(IotPluginStatusEnum.class)
private Integer status;
}

View File

@ -1,35 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.instance;
import lombok.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
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;
// TODO @haohao后续需要使用下
@Schema(description = "管理后台 - IoT 插件实例分页 Request VO")
@Data
public class PluginInstancePageReqVO extends PageParam {
@Schema(description = "插件主程序编号", example = "23738")
private String mainId;
@Schema(description = "插件id", example = "26498")
private Long pluginId;
@Schema(description = "插件主程序所在ip")
private String ip;
@Schema(description = "插件主程序端口")
private Integer port;
@Schema(description = "心跳时间心路时间超过30秒需要剔除")
private Long heartbeatAt;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -1,34 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.instance;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
// TODO @haohao后续需要使用下
@Schema(description = "管理后台 - IoT 插件实例 Response VO")
@Data
public class PluginInstanceRespVO {
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23864")
private Long id;
@Schema(description = "插件主程序id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23738")
private String mainId;
@Schema(description = "插件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26498")
private Long pluginId;
@Schema(description = "插件主程序所在ip", requiredMode = Schema.RequiredMode.REQUIRED)
private String ip;
@Schema(description = "插件主程序端口", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer port;
@Schema(description = "心跳时间心路时间超过30秒需要剔除", requiredMode = Schema.RequiredMode.REQUIRED)
private Long heartbeatAt;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -1,72 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule;
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.rule.vo.databridge.IotDataBridgePageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService;
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/data-bridge")
@Validated
public class IotDataBridgeController {
@Resource
private IotDataBridgeService dataBridgeService;
@PostMapping("/create")
@Operation(summary = "创建数据桥梁")
@PreAuthorize("@ss.hasPermission('iot:data-bridge:create')")
public CommonResult<Long> createDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO createReqVO) {
return success(dataBridgeService.createDataBridge(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新数据桥梁")
@PreAuthorize("@ss.hasPermission('iot:data-bridge:update')")
public CommonResult<Boolean> updateDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO updateReqVO) {
dataBridgeService.updateDataBridge(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除数据桥梁")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:data-bridge:delete')")
public CommonResult<Boolean> deleteDataBridge(@RequestParam("id") Long id) {
dataBridgeService.deleteDataBridge(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得数据桥梁")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:data-bridge:query')")
public CommonResult<IotDataBridgeRespVO> getDataBridge(@RequestParam("id") Long id) {
IotDataBridgeDO dataBridge = dataBridgeService.getDataBridge(id);
return success(BeanUtils.toBean(dataBridge, IotDataBridgeRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得数据桥梁分页")
@PreAuthorize("@ss.hasPermission('iot:data-bridge:query')")
public CommonResult<PageResult<IotDataBridgeRespVO>> getDataBridgePage(@Valid IotDataBridgePageReqVO pageReqVO) {
PageResult<IotDataBridgeDO> pageResult = dataBridgeService.getDataBridgePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, IotDataBridgeRespVO.class));
}
}

View File

@ -1,27 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule;
import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
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;
@Tag(name = "管理后台 - IoT 规则场景")
@RestController
@RequestMapping("/iot/rule-scene")
@Validated
public class IotRuleSceneController {
@Resource
private IotRuleSceneService ruleSceneService;
@GetMapping("/test")
@PermitAll
public void test() {
ruleSceneService.test();
}
}

View File

@ -1,37 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - IoT 数据桥梁 Response VO")
@Data
public class IotDataBridgeRespVO {
@Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564")
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 status;
@Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer direction;
@Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer type;
@Schema(description = "桥梁配置")
private IotDataBridgeAbstractConfig config;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -1,46 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig;
import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum;
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 IotDataBridgeSaveReqVO {
@Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564")
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 = "2")
@NotNull(message = "桥梁状态不能为空")
@InEnum(CommonStatusEnum.class)
private Integer status;
@Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "桥梁方向不能为空")
@InEnum(IotDataBridgeDirectionEnum.class)
private Integer direction;
@Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "桥梁类型不能为空")
@InEnum(IotDataBridgeTypeEnum.class)
private Integer type;
@Schema(description = "桥梁配置")
@NotNull(message = "桥梁配置不能为空")
private IotDataBridgeAbstractConfig config;
}

View File

@ -1,35 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config;
import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;
/**
* IoT IotDataBridgeConfig 抽象类
*
* 用于表示数据桥梁配置数据的通用类型根据具体的 "type" 字段动态映射到对应的子类
* 提供多态支持适用于不同类型的数据结构序列化和反序列化场景
*
* @author HUIHUI
*/
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = IotDataBridgeHttpConfig.class, name = "1"),
@JsonSubTypes.Type(value = IotDataBridgeMqttConfig.class, name = "10"),
@JsonSubTypes.Type(value = IotDataBridgeRedisStreamMQConfig.class, name = "21"),
@JsonSubTypes.Type(value = IotDataBridgeRocketMQConfig.class, name = "30"),
@JsonSubTypes.Type(value = IotDataBridgeRabbitMQConfig.class, name = "31"),
@JsonSubTypes.Type(value = IotDataBridgeKafkaMQConfig.class, name = "32"),
})
public abstract class IotDataBridgeAbstractConfig {
/**
* 配置类型
*
* 枚举 {@link IotDataBridgeTypeEnum#getType()}
*/
private String type;
}

View File

@ -1,35 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config;
import lombok.Data;
// TODO @puhui999MQ 可以去掉哈stream 更精准
/**
* IoT Redis Stream 配置 {@link IotDataBridgeAbstractConfig} 实现类
*
* @author HUIHUI
*/
@Data
public class IotDataBridgeRedisStreamMQConfig extends IotDataBridgeAbstractConfig {
/**
* Redis 服务器地址
*/
private String host;
/**
* 端口
*/
private Integer port;
/**
* 密码
*/
private String password;
/**
* 数据库索引
*/
private Integer database;
/**
* 主题
*/
private String topic;
}

View File

@ -1,2 +0,0 @@
// TODO @芋艿占位
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo;

View File

@ -1,19 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Schema(description = "管理后台 - IoT 设备上下行消息数量统计 Response VO")
@Data
public class IotStatisticsDeviceMessageSummaryRespVO {
@Schema(description = "每小时上行数据数量统计")
private List<Map<Long, Integer>> upstreamCounts;
@Schema(description = "每小时下行数据数量统计")
private List<Map<Long, Integer>> downstreamCounts;
}

View File

@ -1,21 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - IoT 统计 Request VO")
@Data
public class IotStatisticsReqVO {
// TODO @super前端传递的时候还是通过 startTime endTime 传递后端转成 Long
@Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1658486600000")
@NotNull(message = "查询起始时间不能为空")
private Long startTime;
@Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1758486600000")
@NotNull(message = "查询结束时间不能为空")
private Long endTime;
}

View File

@ -1,31 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* IoT 物模型数据类型为布尔型或枚举型的 DataSpec 定义
*
* 数据类型取值为 bool enum
*
* @author HUIHUI
*/
@Data
@EqualsAndHashCode(callSuper = true)
@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段从而避免重复
public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs {
// TODO @puhui999要不写下参数校验这样注释可以简洁一点
/**
* 枚举项的名称
* 可包含中文大小写英文字母数字下划线_和短划线-
* 必须以中文英文字母或数字开头长度不超过 20 个字符
*/
private String name;
/**
* 枚举值
*/
private Integer value;
}

View File

@ -1,112 +0,0 @@
### 请求 /iot/think-model-function/create 接口 => 成功
POST {{baseUrl}}/iot/think-model-function/create
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
{
"productId": 1001,
"productKey": "smart-sensor-001",
"identifier": "Temperature",
"name": "温度",
"description": "当前温度值",
"type": 1,
"property": {
"identifier": "Temperature",
"name": "温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": -10.0,
"max": 100.0,
"step": 0.1,
"unit": "℃"
}
},
"description": "当前温度值"
}
}
### 请求 /iot/think-model-function/create 接口 => 成功
POST {{baseUrl}}/iot/think-model-function/create
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
{
"productId": 1001,
"productKey": "smart-sensor-001",
"identifier": "Humidity",
"name": "湿度",
"description": "当前湿度值",
"type": 1,
"property": {
"identifier": "Humidity",
"name": "湿度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": 0.0,
"max": 100.0,
"step": 0.1,
"unit": "%"
}
},
"description": "当前湿度值"
}
}
### 请求 /iot/think-model-function/update 接口 => 成功
PUT {{baseUrl}}/iot/think-model-function/update
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
{
"id": 11,
"productId": 1001,
"productKey": "smart-sensor-001",
"identifier": "Temperature",
"name": "温度",
"description": "当前温度值",
"type": 1,
"property": {
"identifier": "Temperature",
"name": "温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": -111.0,
"max": 222.0,
"step": 0.1,
"unit": "℃"
}
},
"description": "当前温度值"
}
}
### 请求 /iot/think-model-function/delete 接口 => 成功
DELETE {{baseUrl}}/iot/think-model-function/delete?id=7
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
### 请求 /iot/think-model-function/get 接口 => 成功
GET {{baseUrl}}/iot/think-model-function/get?id=10
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
### 请求 /iot/think-model-function/list-by-product-id 接口 => 成功
GET {{baseUrl}}/iot/think-model-function/list-by-product-id?productId=1001
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}

View File

@ -1,95 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.device;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* IoT 设备日志数据 DO
*
* 目前使用 TDengine 存储
*
* @author alwayssuper
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotDeviceLogDO {
/**
* 日志编号
*
* 通过 {@link IdUtil#fastSimpleUUID()} 生成
*/
private String id;
/**
* 请求编号
*
* 对应 {@link IotDeviceMessage#getRequestId()} 字段
*/
private String requestId;
/**
* 产品标识
* <p>
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
* 设备名称
*
* 关联 {@link IotDeviceDO#getDeviceName()}
*/
private String deviceName;
/**
* 设备标识
* <p>
* 关联 {@link IotDeviceDO#getDeviceKey()}}
*/
private String deviceKey; // 非存储字段用于 TDengine TAG
/**
* 日志类型
*
* 枚举 {@link IotDeviceMessageTypeEnum}
*/
private String type;
/**
* 标识符
*
* 枚举 {@link IotDeviceMessageIdentifierEnum}
*/
private String identifier;
/**
* 数据内容
*
* 存储具体的消息数据内容通常是 JSON 格式
*/
private String content;
/**
* 响应码
*
* 目前只有 server 下行消息给 device 设备时才会有响应码
*/
private Integer code;
/**
* 上报时间戳
*/
private Long reportTime;
/**
* 时序时间
*/
private Long ts;
}

View File

@ -1,92 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.ota;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* IoT OTA 升级记录 DO
*
* @author 芋道源码
*/
@TableName(value = "iot_ota_upgrade_record", autoResultMap = true)
@KeySequence("iot_ota_upgrade_record_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotOtaUpgradeRecordDO extends BaseDO {
@TableId
private Long id;
/**
* 固件编号
*
* 关联 {@link IotOtaFirmwareDO#getId()}
*/
private Long firmwareId;
/**
* 任务编号
*
* 关联 {@link IotOtaUpgradeTaskDO#getId()}
*/
private Long taskId;
/**
* 产品标识
*
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
*/
private String productKey;
/**
* 设备名称
*
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()}
*/
private String deviceName;
/**
* 设备编号
*
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()}
*/
private String deviceId;
/**
* 来源的固件编号
*
* 关联 {@link IotDeviceDO#getFirmwareId()}
*/
private Long fromFirmwareId;
/**
* 升级状态
*
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum}
*/
private Integer status;
/**
* 升级进度百分比
*/
private Integer progress;
/**
* 升级进度描述
*
* 注意只记录设备最后一次的升级进度描述
* 如果想看历史记录可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志
*/
private String description;
/**
* 升级开始时间
*/
private LocalDateTime startTime;
/**
* 升级结束时间
*/
private LocalDateTime endTime;
}

View File

@ -1,72 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.ota;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import java.util.List;
/**
* IoT OTA 升级任务 DO
*
* @author 芋道源码
*/
@TableName(value = "iot_ota_upgrade_task", autoResultMap = true)
@KeySequence("iot_ota_upgrade_task_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotOtaUpgradeTaskDO extends BaseDO {
/**
* 任务编号
*/
@TableField
private Long id;
/**
* 任务名称
*/
private String name;
/**
* 任务描述
*/
private String description;
/**
* 固件编号
* <p>
* 关联 {@link IotOtaFirmwareDO#getId()}
*/
private Long firmwareId;
/**
* 任务状态
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum}
*/
private Integer status;
/**
* 升级范围
* <p>
* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum}
*/
private Integer scope;
/**
* 设备数量
*/
private Long deviceCount;
/**
* 选中的设备编号数组
* <p>
* 关联 {@link IotDeviceDO#getId()}
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<Long> deviceIds;
}

View File

@ -1,93 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.plugin;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum;
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* IoT 插件配置 DO
*
* @author 芋道源码
*/
@TableName("iot_plugin_config")
@KeySequence("iot_plugin_config_seq")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotPluginConfigDO extends TenantBaseDO {
/**
* 主键 ID
*/
@TableId
private Long id;
/**
* 插件包标识符
*/
private String pluginKey;
/**
* 插件名称
*/
private String name;
/**
* 插件描述
*/
private String description;
/**
* 部署方式
* <p>
* 枚举 {@link IotPluginDeployTypeEnum}
*/
private Integer deployType;
// TODO @芋艿如果是外置的插件fileName version 的选择~
/**
* 插件包文件名
*/
private String fileName;
/**
* 插件版本
*/
private String version;
// TODO @芋艿type 字典的定义
/**
* 插件类型
* <p>
* 枚举 {@link IotPluginTypeEnum}
*/
private Integer type;
/**
* 设备插件协议类型
*/
// TODO @芋艿枚举字段
private String protocol;
// TODO @haohao这个字段是不是直接用 CommonStatus开启禁用然后插件实例那online 是否在线
/**
* 状态
* <p>
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
// TODO @芋艿configSchemaconfig 示例字段
/**
* 插件配置项描述信息
*/
private String configSchema;
/**
* 插件配置信息
*/
private String config;
// TODO @芋艿script 后续的使用
/**
* 插件脚本
*/
private String script;
}

View File

@ -1,70 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.plugin;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* IoT 插件实例 DO
*
* @author 芋道源码
*/
@TableName("iot_plugin_instance")
@KeySequence("iot_plugin_instance_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotPluginInstanceDO extends TenantBaseDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 插件编号
* <p>
* 关联 {@link IotPluginConfigDO#getId()}
*/
private Long pluginId;
/**
* 插件进程编号
*
* 一般格式是hostIp@processId@${uuid}
*/
private String processId;
/**
* 插件实例所在 IP
*/
private String hostIp;
/**
* 设备下行端口
*/
private Integer downstreamPort;
/**
* 是否在线
*/
private Boolean online;
/**
* 在线时间
*/
private LocalDateTime onlineTime;
/**
* 离线时间
*/
private LocalDateTime offlineTime;
/**
* 心跳时间
*
* 目的心路时间超过一定时间后会被进行下线处理
*/
private LocalDateTime heartbeatTime;
}

View File

@ -1,243 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.rule;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
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.dal.dataobject.thingmodel.IotThingModelDO;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import java.util.List;
import java.util.Map;
/**
* IoT 规则场景场景联动 DO
*
* @author 芋道源码
*/
@TableName("iot_rule_scene")
@KeySequence("iot_rule_scene_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotRuleSceneDO extends TenantBaseDO {
/**
* 场景编号
*/
@TableId
private Long id;
/**
* 场景名称
*/
private String name;
/**
* 场景描述
*/
private String description;
/**
* 场景状态
*
* 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
*/
private Integer status;
/**
* 触发器数组
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<TriggerConfig> triggers;
/**
* 执行器数组
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<ActionConfig> actions;
/**
* 触发器配置
*/
@Data
public static class TriggerConfig {
/**
* 触发类型
*
* 枚举 {@link IotRuleSceneTriggerTypeEnum}
*/
private Integer type;
/**
* 产品标识
*
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
* 设备名称数组
*
* 关联 {@link IotDeviceDO#getDeviceName()}
*/
private List<String> deviceNames;
/**
* 触发条件数组
*
* 必填 {@link #type} {@link IotRuleSceneTriggerTypeEnum#DEVICE}
* 条件与条件之间的关系
*/
private List<TriggerCondition> conditions;
/**
* CRON 表达式
*
* 必填 {@link #type} {@link IotRuleSceneTriggerTypeEnum#TIMER}
*/
private String cronExpression;
}
/**
* 触发条件
*/
@Data
public static class TriggerCondition {
/**
* 消息类型
*
* 枚举 {@link IotDeviceMessageTypeEnum}
*/
private String type;
/**
* 消息标识符
*
* 枚举 {@link IotDeviceMessageIdentifierEnum}
*/
private String identifier;
/**
* 参数数组
*
* 参数与参数之间的关系
*/
private List<TriggerConditionParameter> parameters;
}
/**
* 触发条件参数
*/
@Data
public static class TriggerConditionParameter {
/**
* 标识符属性事件服务
*
* 关联 {@link IotThingModelDO#getIdentifier()}
*/
private String identifier;
/**
* 操作符
*
* 枚举 {@link IotRuleSceneTriggerConditionParameterOperatorEnum}
*/
private String operator;
/**
* 比较值
*
* 如果有多个值则使用 "," 分隔类似 "1,2,3"
* 例如说{@link IotRuleSceneTriggerConditionParameterOperatorEnum#IN}{@link IotRuleSceneTriggerConditionParameterOperatorEnum#BETWEEN}
*/
private String value;
}
/**
* 执行器配置
*/
@Data
public static class ActionConfig {
/**
* 执行类型
*
* 枚举 {@link IotRuleSceneActionTypeEnum}
*/
private Integer type;
/**
* 设备控制
*
* 必填 {@link #type} {@link IotRuleSceneActionTypeEnum#DEVICE_CONTROL}
*/
private ActionDeviceControl deviceControl;
/**
* 数据桥接编号
*
* 必填 {@link #type} {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE}
* 关联{@link IotDataBridgeDO#getId()}
*/
private Long dataBridgeId;
}
/**
* 执行设备控制
*/
@Data
public static class ActionDeviceControl {
/**
* 产品标识
*
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
* 设备名称数组
*
* 关联 {@link IotDeviceDO#getDeviceName()}
*/
private List<String> deviceNames;
/**
* 消息类型
*
* 枚举 {@link IotDeviceMessageTypeEnum#PROPERTY}{@link IotDeviceMessageTypeEnum#SERVICE}
*/
private String type;
/**
* 消息标识符
*
* 枚举 {@link IotDeviceMessageIdentifierEnum}
*
* 1. 属性设置对应 {@link IotDeviceMessageIdentifierEnum#PROPERTY_SET}
* 2. 服务调用对应 {@link IotDeviceMessageIdentifierEnum#SERVICE_INVOKE}
*/
private String identifier;
/**
* 具体数据
*
* 1. 属性设置 {@link #type} {@link IotDeviceMessageTypeEnum#PROPERTY} 对应 properties
* 2. 服务调用 {@link #type} {@link IotDeviceMessageTypeEnum#SERVICE} 对应 params
*/
private Map<String, Object> data;
}
}

View File

@ -1,159 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.mysql.ota;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
@Mapper
public interface IotOtaUpgradeRecordMapper extends BaseMapperX<IotOtaUpgradeRecordDO> {
// TODO @liselectByFirmwareIdAndTaskIdAndDeviceId让方法自解释
/**
* 根据条件查询单个OTA升级记录
*
* @param firmwareId 固件ID可选参数用于筛选固件ID匹配的记录
* @param taskId 任务ID可选参数用于筛选任务ID匹配的记录
* @param deviceId 设备ID可选参数用于筛选设备ID匹配的记录
* @return 返回符合条件的单个OTA升级记录如果不存在则返回null
*/
default IotOtaUpgradeRecordDO selectByConditions(Long firmwareId, Long taskId, String deviceId) {
// 使用LambdaQueryWrapperX构建查询条件根据传入的参数动态添加查询条件
return selectOne(new LambdaQueryWrapperX<IotOtaUpgradeRecordDO>()
.eqIfPresent(IotOtaUpgradeRecordDO::getFirmwareId, firmwareId)
.eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, taskId)
.eqIfPresent(IotOtaUpgradeRecordDO::getDeviceId, deviceId));
}
// TODO @li这个是不是 groupby status ok
/**
* 根据任务ID和设备名称查询OTA升级记录的状态统计信息
* 该函数通过SQL查询统计不同状态0到5的记录数量并返回一个包含统计结果的Map列表
*
* @param taskId 任务ID用于筛选特定任务的OTA升级记录
* @param deviceName 设备名称支持模糊查询用于筛选特定设备的OTA升级记录
* @return 返回一个Map列表每个Map包含不同状态0到5的记录数量
*/
@Select("select count(case when status = 0 then 1 else 0) as `0` " +
"count(case when status = 1 then 1 else 0) as `1` " +
"count(case when status = 2 then 1 else 0) as `2` " +
"count(case when status = 3 then 1 else 0) as `3` " +
"count(case when status = 4 then 1 else 0) as `4` " +
"count(case when status = 5 then 1 else 0) as `5` " +
"from iot_ota_upgrade_record " +
"where task_id = #{taskId} " +
"and device_name like concat('%', #{deviceName}, '%') " +
"and status = #{status}")
List<Map<String, Object>> selectOtaUpgradeRecordCount(@Param("taskId") Long taskId,
@Param("deviceName") String deviceName);
/**
* 根据固件ID查询OTA升级记录的状态统计信息
* 该函数通过SQL查询统计不同状态0到5的记录数量并返回一个包含统计结果的Map列表
*
* @param firmwareId 固件ID用于筛选特定固件的OTA升级记录
* @return 返回一个Map列表每个Map包含不同状态0到5的记录数量
*/
@Select("select count(case when status = 0 then 1 else 0) as `0` " +
"count(case when status = 1 then 1 else 0) as `1` " +
"count(case when status = 2 then 1 else 0) as `2` " +
"count(case when status = 3 then 1 else 0) as `3` " +
"count(case when status = 4 then 1 else 0) as `4` " +
"count(case when status = 5 then 1 else 0) as `5` " +
"from iot_ota_upgrade_record " +
"where firmware_id = #{firmwareId}")
List<Map<String, Object>> selectOtaUpgradeRecordStatistics(Long firmwareId);
// TODO @li这里的注释可以去掉哈
/**
* 根据分页查询条件获取 OTA升级记录的分页结果
*
* @param pageReqVO 分页查询请求参数包含设备名称任务ID等查询条件
* @return 返回分页查询结果包含符合条件的 OTA升级记录列表
*/
// TODO @liselectPage ok
default PageResult<IotOtaUpgradeRecordDO> selectUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) {
// TODO @li这里的注释可以去掉哈然后下面的如果也没必要注释
// 使用LambdaQueryWrapperX构建查询条件并根据请求参数动态添加查询条件
return selectPage(pageReqVO, new LambdaQueryWrapperX<IotOtaUpgradeRecordDO>()
.likeIfPresent(IotOtaUpgradeRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在则添加模糊查询条件
.eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, pageReqVO.getTaskId())); // 如果任务ID存在则添加等值查询条件
}
// TODO @li这里的注释可以去掉哈
/**
* 根据任务ID和状态更新升级记录的状态
* <p>
* 该函数用于将符合指定任务ID和状态的升级记录的状态更新为新的状态
*
* @param setStatus 要设置的新状态值类型为Integer
* @param taskId 要更新的升级记录对应的任务ID类型为Long
* @param whereStatus 用于筛选升级记录的当前状态值类型为Integer
*/
// TODO @li改成 updateByTaskIdAndStatus(taskId, status, IotOtaUpgradeRecordDO) 更通用一些
default void updateUpgradeRecordStatusByTaskIdAndStatus(Integer setStatus, Long taskId, Integer whereStatus) {
// 使用LambdaUpdateWrapper构建更新条件将指定状态的记录更新为指定状态
update(new LambdaUpdateWrapper<IotOtaUpgradeRecordDO>()
.set(IotOtaUpgradeRecordDO::getStatus, setStatus)
.eq(IotOtaUpgradeRecordDO::getTaskId, taskId)
.eq(IotOtaUpgradeRecordDO::getStatus, whereStatus)
);
}
// TODO @li参考上面的建议调整下这个方法
/**
* 根据状态查询符合条件的升级记录列表
* <p>
* 该函数使用LambdaQueryWrapperX构建查询条件查询指定状态的升级记录
*
* @param state 升级记录的状态用于筛选符合条件的记录
* @return 返回符合指定状态的升级记录列表类型为List<IotOtaUpgradeRecordDO>
*/
default List<IotOtaUpgradeRecordDO> selectUpgradeRecordListByState(Integer state) {
// 使用LambdaQueryWrapperX构建查询条件根据状态查询符合条件的升级记录
return selectList(new LambdaQueryWrapperX<IotOtaUpgradeRecordDO>()
.eq(IotOtaUpgradeRecordDO::getStatus, state));
}
// TODO @li参考上面的建议调整下这个方法
/**
* 更新升级记录状态
* <p>
* 该函数用于批量更新指定ID列表中的升级记录状态通过传入的ID列表和状态值使用LambdaUpdateWrapper构建更新条件
* 并执行更新操作
*
* @param ids 需要更新的升级记录ID列表类型为List<Long>传入的ID列表中的记录将被更新
* @param status 要更新的状态值类型为Integer该值将被设置到符合条件的升级记录中
*/
default void updateUpgradeRecordStatus(List<Long> ids, Integer status) {
// 使用LambdaUpdateWrapper构建更新条件设置状态字段并根据ID列表进行筛选
update(new LambdaUpdateWrapper<IotOtaUpgradeRecordDO>()
.set(IotOtaUpgradeRecordDO::getStatus, status)
.in(IotOtaUpgradeRecordDO::getId, ids)
);
}
// TODO @li参考上面的建议调整下这个方法
/**
* 根据任务ID查询升级记录列表
* <p>
* 该函数通过任务ID查询符合条件的升级记录并返回查询结果列表
*
* @param taskId 任务ID用于筛选升级记录
* @return 返回符合条件的升级记录列表若未找到则返回空列表
*/
default List<IotOtaUpgradeRecordDO> selectUpgradeRecordListByTaskId(Long taskId) {
// 使用LambdaQueryWrapperX构建查询条件根据任务ID查询符合条件的升级记录
return selectList(new LambdaQueryWrapperX<IotOtaUpgradeRecordDO>()
.eq(IotOtaUpgradeRecordDO::getTaskId, taskId));
}
}

View File

@ -1,57 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.mysql.ota;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* OTA 升级任务Mapper
*
* @author Shelly
*/
@Mapper
public interface IotOtaUpgradeTaskMapper extends BaseMapperX<IotOtaUpgradeTaskDO> {
/**
* 根据固件ID和任务名称查询升级任务列表
*
* @param firmwareId 固件ID用于筛选升级任务
* @param name 任务名称用于筛选升级任务
* @return 符合条件的升级任务列表
*/
default List<IotOtaUpgradeTaskDO> selectByFirmwareIdAndName(Long firmwareId, String name) {
return selectList(new LambdaQueryWrapperX<IotOtaUpgradeTaskDO>()
.eqIfPresent(IotOtaUpgradeTaskDO::getFirmwareId, firmwareId)
.eqIfPresent(IotOtaUpgradeTaskDO::getName, name));
}
/**
* 分页查询升级任务列表支持根据固件ID和任务名称进行筛选
*
* @param pageReqVO 分页查询请求对象包含分页参数和筛选条件
* @return 分页结果包含符合条件的升级任务列表
*/
default PageResult<IotOtaUpgradeTaskDO> selectUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<IotOtaUpgradeTaskDO>()
.eqIfPresent(IotOtaUpgradeTaskDO::getFirmwareId, pageReqVO.getFirmwareId())
.likeIfPresent(IotOtaUpgradeTaskDO::getName, pageReqVO.getName()));
}
/**
* 根据任务状态查询升级任务列表
* <p>
* 该函数通过传入的任务状态查询数据库中符合条件的升级任务列表
*
* @param status 任务状态用于筛选升级任务的状态值
* @return 返回符合条件的升级任务列表列表中的每个元素为 IotOtaUpgradeTaskDO 对象
*/
default List<IotOtaUpgradeTaskDO> selectUpgradeTaskByState(Integer status) {
return selectList(IotOtaUpgradeTaskDO::getStatus, status);
}
}

View File

@ -1,33 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.mysql.plugin;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface IotPluginConfigMapper extends BaseMapperX<IotPluginConfigDO> {
default PageResult<IotPluginConfigDO> selectPage(PluginConfigPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<IotPluginConfigDO>()
.likeIfPresent(IotPluginConfigDO::getName, reqVO.getName())
.eqIfPresent(IotPluginConfigDO::getStatus, reqVO.getStatus())
.orderByDesc(IotPluginConfigDO::getId));
}
default List<IotPluginConfigDO> selectListByStatusAndDeployType(Integer status, Integer deployType) {
return selectList(new LambdaQueryWrapperX<IotPluginConfigDO>()
.eq(IotPluginConfigDO::getStatus, status)
.eq(IotPluginConfigDO::getDeployType, deployType)
.orderByAsc(IotPluginConfigDO::getId));
}
default IotPluginConfigDO selectByPluginKey(String pluginKey) {
return selectOne(IotPluginConfigDO::getPluginKey, pluginKey);
}
}

View File

@ -1,24 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.mysql.plugin;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime;
import java.util.List;
// TODO @li参考 IotOtaUpgradeRecordMapper 的写法
@Mapper
public interface IotPluginInstanceMapper extends BaseMapperX<IotPluginInstanceDO> {
default IotPluginInstanceDO selectByProcessId(String processId) {
return selectOne(IotPluginInstanceDO::getProcessId, processId);
}
default List<IotPluginInstanceDO> selectListByHeartbeatTimeLt(LocalDateTime heartbeatTime) {
return selectList(new LambdaQueryWrapper<IotPluginInstanceDO>()
.lt(IotPluginInstanceDO::getHeartbeatTime, heartbeatTime));
}
}

Some files were not shown because too many files have changed in this diff Show More