# Conflicts:
#	yudao-dependencies/pom.xml
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceConfigSetReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceDownstreamAbstractReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertySetReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceServiceInvokeReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceStateUpdateReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotPluginInstanceHeartbeatReqDTO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogPageReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginConfigController.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigImportReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/plugin/DevicePluginProcessIdRedisDAO.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceOnlineMessageConsumer.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java
#	yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/biz/dto/IotDeviceAuthReqDTO.java
#	yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java
#	yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java
#	yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java
#	yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java
#	yudao-module-iot/yudao-module-iot-server/pom.xml
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java
#	yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java
pull/208/head
YunaiV 2025-08-30 11:18:33 +08:00
commit 78dea8a9cc
512 changed files with 20091 additions and 13354 deletions

View File

@ -82,8 +82,8 @@
<awssdk.version>2.30.14</awssdk.version>
<justauth.version>1.16.7</justauth.version>
<justauth-starter.version>1.4.0</justauth-starter.version>
<jimureport.version>2.1.0</jimureport.version>
<jimubi.version>1.9.5</jimubi.version>
<jimureport.version>2.1.1</jimureport.version>
<jimubi.version>2.1.0</jimubi.version>
<weixin-java.version>4.7.7-20250808.182223</weixin-java.version>
<!-- 专属于 JDK8 安全漏洞升级 -->
<logback.version>1.2.13</logback.version> <!-- 无法使用 1.3.X 版本,启动会报错 -->
@ -675,6 +675,10 @@
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</exclusion>
</exclusions>
</dependency>

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,23 @@ 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.Getter;
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;
@ -26,13 +31,18 @@ import java.util.List;
@Slf4j
public class JsonUtils {
@Getter
private static ObjectMapper objectMapper = new ObjectMapper();
static {
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 +109,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

@ -60,4 +60,8 @@ public class ObjectUtils {
return Arrays.asList(array).contains(obj);
}
public static boolean isNotAllEmpty(Object... objs) {
return !ObjectUtil.isAllEmpty(objs);
}
}

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

@ -1,16 +1,20 @@
package cn.iocoder.yudao.framework.mybatis.config;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.baomidou.mybatisplus.extension.incrementer.*;
import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@ -18,6 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@ -75,4 +80,15 @@ public class YudaoMybatisAutoConfiguration {
throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType));
}
@Bean
public JacksonTypeHandler jacksonTypeHandler(List<ObjectMapper> objectMappers) {
// 特殊:设置 JacksonTypeHandler 的 ObjectMapper
ObjectMapper objectMapper = CollUtil.getFirst(objectMappers);
if (objectMapper == null) {
objectMapper = JsonUtils.getObjectMapper();
}
JacksonTypeHandler.setObjectMapper(objectMapper);
return new JacksonTypeHandler(Object.class);
}
}

View File

@ -39,7 +39,7 @@ public class RateLimiterAspect {
@Before("@annotation(rateLimiter)")
public void beforePointCut(JoinPoint joinPoint, RateLimiter rateLimiter) {
// 获得 IdempotentKeyResolver 对象
// 获得 RateLimiterKeyResolver 对象
RateLimiterKeyResolver keyResolver = keyResolvers.get(rateLimiter.keyResolver());
Assert.notNull(keyResolver, "找不到对应的 RateLimiterKeyResolver");
// 解析 Key

View File

@ -1,174 +0,0 @@
# AiBoChaWebSearchClient 使用指南
## 概述
`AiBoChaWebSearchClient` 是基于博查AI开放平台提供的网页搜索服务的Java客户端实现了符合项目架构风格的HTTP客户端封装。
## 特性
- **统一的API调用风格**:参考 SunoApi 和 XunFeiPptApi 的实现方式
- **Record 类型数据结构**:使用 Record 类型定义请求和响应数据
- **简洁的响应数据模型**:包含网页搜索结果
- **灵活的搜索配置**:支持时间范围、域名过滤、结果数量等参数
- **错误处理机制**:统一的异常处理和日志记录
## 快速开始
### 1. 创建客户端实例
```java
// 使用默认base URL
AiBoChaWebSearchClient client = new AiBoChaWebSearchClient("your-api-key");
// 使用自定义base URL
AiBoChaWebSearchClient client = new AiBoChaWebSearchClient("https://custom.api.com", "your-api-key");
```
### 2. 基本搜索
```java
// 基本搜索
WebSearchRequest request = new WebSearchRequest(
"Spring Boot 教程",
null, null, null, null, null
);
AiWebSearchResponse result = client.search(request);
```
### 3. 高级搜索
```java
// 构建详细的搜索请求
WebSearchRequest request = new WebSearchRequest(
"人工智能最新进展",
FreshnessType.ONE_WEEK.getValue(), // 搜索一周内的内容
true, // 显示摘要
"zhihu.com|csdn.net", // 只搜索指定域名
"spam.com", // 排除指定域名
20 // 返回20条结果
);
AiWebSearchResponse result = client.search(request);
```
## API参数说明
### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| query | String | 是 | 用户的搜索词 |
| freshness | String | 否 | 搜索时间范围,默认为 noLimit |
| summary | Boolean | 否 | 是否显示文本摘要,默认为 false |
| include | String | 否 | 指定搜索的网站范围,多个域名使用\|或,分隔 |
| exclude | String | 否 | 排除搜索的网站范围,多个域名使用\|或,分隔 |
| count | Integer | 否 | 返回结果条数范围1-50默认为10 |
### 时间范围选项
使用 `FreshnessType` 枚举:
```java
FreshnessType.NO_LIMIT // 不限(默认)
FreshnessType.ONE_DAY // 一天内
FreshnessType.ONE_WEEK // 一周内
FreshnessType.ONE_MONTH // 一个月内
FreshnessType.ONE_YEAR // 一年内
```
也可以使用自定义日期范围:
- 日期范围:`"2025-01-01..2025-04-06"`
- 指定日期:`"2025-04-06"`
### 响应数据结构
```java
// 主要响应数据
AiWebSearchResponse result = client.search(request);
// 网页搜索结果
List<AiWebSearchResponse.WebPage> webPages = result.webPages();
for (AiWebSearchResponse.WebPage page : webPages) {
String title = page.title(); // 网页标题
String url = page.url(); // 网页URL
String snippet = page.snippet(); // 内容描述
String summary = page.summary(); // 文本摘要如果请求了summary
String siteName = page.siteName(); // 网站名称
}
```
## 使用示例
### 示例1搜索技术文档
```java
WebSearchRequest request = new WebSearchRequest(
"Spring Boot 3.x 新特性",
FreshnessType.ONE_MONTH.getValue(),
true,
"spring.io|baeldung.com|github.com",
null,
15
);
AiWebSearchResponse result = client.search(request);
```
### 示例2搜索新闻资讯
```java
WebSearchRequest request = new WebSearchRequest(
"AI大模型发展趋势",
FreshnessType.ONE_WEEK.getValue(),
null,
null,
"advertisement.com|spam.net",
30
);
AiWebSearchResponse result = client.search(request);
```
## 注意事项
1. **API密钥**需要先到博查AI开放平台https://open.bochaai.com获取API KEY
2. **请求频率**注意遵守平台的API调用频率限制
3. **时间范围**:建议使用 `noLimit` 以获得更好的搜索效果
4. **域名过滤**include和exclude参数最多支持20个域名
5. **结果数量**单次搜索最多返回50条结果
## 集成建议
在Spring Boot项目中建议将客户端配置为Bean
```java
@Configuration
public class AiConfiguration {
@Value("${ai.bocha.api-key}")
private String apiKey;
@Value("${ai.bocha.base-url:https://open.bochaai.com}")
private String baseUrl;
@Bean
public AiBoChaWebSearchClient boChaWebSearchClient() {
return new AiBoChaWebSearchClient(baseUrl, apiKey);
}
}
```
## 故障排查
1. **网络连接问题**:检查网络连接和防火墙设置
2. **API密钥错误**确认API KEY正确且有效
3. **请求参数错误**:检查必填参数是否正确填写
4. **服务器响应错误**:查看日志中的详细错误信息
## 更新日志
- v2.0.0:重大重构,统一 Record 类型,简化 API 调用,支持新的响应结构
- v1.3.0:统一使用 Record 类型,移除 Lombok 注解,保持代码风格一致性
- v1.2.0:进一步简化,移除视频搜索功能,专注于网页搜索
- v1.1.0:使用 Lombok 简化代码,移除图片搜索功能
- v1.0.0:初始版本,实现基本的网页搜索功能

View File

@ -155,13 +155,13 @@ spring:
rerank: false # 是否开启“通义千问”的 Rerank 模型,填写 dashscope 开启
mcp:
server:
enabled: true
enabled: false
name: yudao-mcp-server
version: 1.0.0
instructions: 一个 MCP 示例服务
sse-endpoint: /sse
client:
enabled: true
enabled: false
name: mcp
sse:
connections:

View File

@ -19,6 +19,7 @@ public enum BpmReasonEnum {
CANCEL_PROCESS_INSTANCE_BY_START_USER("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程
CANCEL_PROCESS_INSTANCE_BY_ADMIN("管理员【{}】取消流程,原因:{}"), // 场景:管理员取消流程
CANCEL_CHILD_PROCESS_INSTANCE_BY_MAIN_PROCESS("子流程自动取消,原因:主流程已取消"),
REJECT_CHILD_PROCESS("子流程审批不通过"),
// ========== 流程任务的独有原因 ==========

View File

@ -50,6 +50,7 @@ import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
import org.flowable.task.api.Task;
@ -949,6 +950,29 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
status);
}
// 1.3 如果子流程拒绝,设置其父流程也为拒绝状态,且结束父流程
// 相关问题链接https://t.zsxq.com/kZhyb
if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())
&& StrUtil.isNotBlank(instance.getSuperExecutionId())) {
// 1.3.1 获取父流程实例 并标记为不通过
Execution execution = runtimeService.createExecutionQuery().executionId(instance.getSuperExecutionId()).singleResult();
ProcessInstance parentProcessInstance = getProcessInstance(execution.getProcessInstanceId());
updateProcessInstanceReject(parentProcessInstance, BpmReasonEnum.REJECT_CHILD_PROCESS.getReason());
// 1.3.2 结束父流程。需要在子流程结束事务提交后执行
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCompletion(int transactionStatus) {
// 回滚情况,直接返回
if (ObjectUtil.equal(transactionStatus, TransactionSynchronization.STATUS_ROLLED_BACK)) {
return;
}
taskService.moveTaskToEnd(parentProcessInstance.getId(), BpmReasonEnum.REJECT_CHILD_PROCESS.getReason());
}
});
}
// 2. 发送对应的消息通知
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
messageService.sendMessageWhenProcessInstanceApprove(
@ -996,17 +1020,18 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
if (ObjUtil.notEqual(instance.getName(), name)) {
runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), name);
}
// 流程前置通知:需要在流程启动后(事务提交后),保证 variables 已设置
// 相关问题链接https://t.zsxq.com/DF7Kq
if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
return;
}
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
}
});
// 流程前置通知
if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
return;
}
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
}
}

View File

@ -804,7 +804,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
.setTargetTaskDefinitionKey(returnTaskId).setReason(reqVO.getReason()));
return;
}
// 3.2 情况二:直接结束,审批不通过
// 3.2 情况二: 标记流程为不通过并结束流程
processInstanceService.updateProcessInstanceReject(instance, reqVO.getReason()); // 标记不通过
moveTaskToEnd(task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); // 结束流程
}
@ -986,6 +987,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public void moveTaskToEnd(String processInstanceId, String reason) {
List<Task> taskList = getRunningTaskListByProcessInstanceId(processInstanceId, null, null);
if (CollUtil.isEmpty(taskList)) {

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,94 +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 org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.validation.Valid;
/**
* 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 lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Map;
/**
* IoT Request DTO
*
* @author
*/
@Data
public class IotDeviceConfigSetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
/**
*
*/
@NotNull(message = "配置不能为空")
private Map<String, Object> config;
}

View File

@ -1,31 +0,0 @@
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* 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 lombok.Data;
import javax.validation.constraints.NotEmpty;
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 lombok.Data;
import javax.validation.constraints.NotEmpty;
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 lombok.Data;
import javax.validation.constraints.NotEmpty;
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 lombok.Data;
import javax.validation.constraints.NotEmpty;
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 lombok.Data;
import javax.validation.constraints.NotEmpty;
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 lombok.Data;
import javax.validation.constraints.NotEmpty;
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,24 +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 lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 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 lombok.Data;
import javax.validation.constraints.NotEmpty;
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 lombok.Data;
import javax.validation.constraints.NotEmpty;
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,45 +0,0 @@
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 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,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 IotDataBridgeDirectionEnum implements ArrayValuable<Integer> {
INPUT(1), // 输入
OUTPUT(2); // 输出
private final Integer type;
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeDirectionEnum::getType).toArray(Integer[]::new);
@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,21 +7,26 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays;
/**
* IoT
* IoT Redis
*
*
* @author HUIHUI
*/
@RequiredArgsConstructor
@Getter
public enum IotRuleSceneActionTypeEnum implements ArrayValuable<Integer> {
public enum IotRedisDataStructureEnum implements ArrayValuable<Integer> {
DEVICE_CONTROL(1), // 设备执行
ALERT(2), // 告警执行
DATA_BRIDGE(3); // 桥接执行
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(IotRuleSceneActionTypeEnum::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,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,78 +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 org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
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,40 +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 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 javax.annotation.Resource;
import javax.validation.Valid;
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 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 javax.annotation.Resource;
import javax.validation.Valid;
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,31 +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 lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@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,31 +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 lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@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,23 +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 lombok.Data;
import javax.validation.constraints.NotEmpty;
@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 org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
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,65 +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 org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
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,41 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
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,33 +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 lombok.Data;
import javax.validation.constraints.NotNull;
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,28 +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 lombok.Data;
import javax.validation.constraints.NotNull;
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 lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
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,91 +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 org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
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,20 +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 org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotNull;
@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一些枚举字段需要加枚举校验。例如说deployType、status、type 等
@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,73 +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 org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
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,28 +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 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 javax.annotation.Resource;
import javax.annotation.security.PermitAll;
@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,47 +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 lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@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,22 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
@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;
}

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