Compare commits
79 Commits
master
...
feature/io
Author | SHA1 | Date |
---|---|---|
|
6a06f520fb | |
|
d346a8d2ae | |
|
72245b5b0d | |
|
7b114e1986 | |
|
7e49c90156 | |
|
f1368d9e79 | |
|
2737ffa116 | |
|
569eef4a74 | |
|
b06556da2d | |
|
6488d5bcaa | |
|
d1b2fb41ae | |
|
7b10b59541 | |
|
a4e80d45fe | |
|
c658ac69c0 | |
|
af0ff1ce26 | |
|
74db72c9c0 | |
|
b37814ec9c | |
|
21472e8dfa | |
|
c3499af524 | |
|
33fed79820 | |
|
66b42367cb | |
|
4ea6e08f99 | |
|
800a85f7bc | |
|
479e0356ad | |
|
120029bb17 | |
|
f58cf282dd | |
|
d7c57f5023 | |
|
40a9242691 | |
|
a0a26c3d64 | |
|
643cc4cfd2 | |
|
1498389d26 | |
|
0bb01eaeeb | |
|
ac624b7495 | |
|
c3485a3f3d | |
|
81cbc61f3c | |
|
cf52a16f6c | |
|
02c3aa748b | |
|
b4035cb036 | |
|
1b59aa9ccb | |
|
385cea8d90 | |
|
6cf2eb07d7 | |
|
70a0df54e4 | |
|
39fb31d400 | |
|
af37176d50 | |
|
fbb664026d | |
|
ab4b148df3 | |
|
f124584d06 | |
|
d83af87f9f | |
|
44b835bd4a | |
|
2954445d34 | |
|
ae96ff4a25 | |
|
72d8511d6b | |
|
b5ce269fef | |
|
516e3a2387 | |
|
2585c4753a | |
|
80239e7f26 | |
|
08c0461a3e | |
|
5a66037725 | |
|
b3dcd7b133 | |
|
e5a74193ba | |
|
37fdd6247d | |
|
eeb1dc4a07 | |
|
0ae893272b | |
|
6e48154fb8 | |
|
d155876f09 | |
|
343353b8f8 | |
|
a9dc654b36 | |
|
e3e3a00fba | |
|
3266bf0f98 | |
|
cd656fad4b | |
|
9b2389356f | |
|
e26903b06b | |
|
87a43b8354 | |
|
2f9d760327 | |
|
35dd91d6c9 | |
|
2073ecb2f3 | |
|
38e8c85276 | |
|
f118d66006 | |
|
6d6547be39 |
2
pom.xml
2
pom.xml
|
@ -24,7 +24,7 @@
|
|||
<!-- <module>yudao-module-crm</module>-->
|
||||
<!-- <module>yudao-module-erp</module>-->
|
||||
<!-- <module>yudao-module-ai</module>-->
|
||||
<!-- <module>yudao-module-iot</module>-->
|
||||
<module>yudao-module-iot</module>
|
||||
</modules>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
|
|
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.date;
|
|||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.date.TemporalAccessorUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
|
||||
|
@ -312,4 +313,16 @@ public class LocalDateTimeUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将给定的 {@link LocalDateTime} 转换为自 Unix 纪元时间(1970-01-01T00:00:00Z)以来的秒数。
|
||||
*
|
||||
* @param sourceDateTime 需要转换的本地日期时间,不能为空
|
||||
* @return 自 1970-01-01T00:00:00Z 起的秒数(epoch second)
|
||||
* @throws NullPointerException 如果 {@code sourceDateTime} 为 {@code null}
|
||||
* @throws DateTimeException 如果转换过程中发生时间超出范围或其他时间处理异常
|
||||
*/
|
||||
public static Long toEpochSecond(LocalDateTime sourceDateTime) {
|
||||
return TemporalAccessorUtil.toInstant(sourceDateTime).getEpochSecond();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,18 +3,22 @@ package cn.iocoder.yudao.framework.common.util.json;
|
|||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
|
||||
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -32,7 +36,11 @@ public class JsonUtils {
|
|||
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值
|
||||
objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化
|
||||
// 解决 LocalDateTime 的序列化
|
||||
SimpleModule simpleModule = new JavaTimeModule()
|
||||
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
|
||||
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
|
||||
objectMapper.registerModules(simpleModule);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,6 +107,18 @@ public class JsonUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static <T> T parseObject(byte[] text, Type type) {
|
||||
if (ArrayUtil.isEmpty(text)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));
|
||||
} catch (IOException e) {
|
||||
log.error("json parse err,json:{}", text, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串解析成指定类型的对象
|
||||
* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下,
|
||||
|
|
|
@ -60,4 +60,8 @@ public class ObjectUtils {
|
|||
return Arrays.asList(array).contains(obj);
|
||||
}
|
||||
|
||||
public static boolean isNotAllEmpty(Object... objs) {
|
||||
return !ObjectUtil.isAllEmpty(objs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ public class GlobalExceptionHandler {
|
|||
if(ex.getCause() instanceof InvalidFormatException) {
|
||||
InvalidFormatException invalidFormatException = (InvalidFormatException) ex.getCause();
|
||||
return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", invalidFormatException.getValue()));
|
||||
}else {
|
||||
} else {
|
||||
return defaultExceptionHandler(ServletUtils.getRequest(), ex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>yudao</artifactId>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
|
@ -10,7 +9,8 @@
|
|||
<modules>
|
||||
<module>yudao-module-iot-api</module>
|
||||
<module>yudao-module-iot-biz</module>
|
||||
<module>yudao-module-iot-plugins</module>
|
||||
<module>yudao-module-iot-core</module>
|
||||
<module>yudao-module-iot-gateway</module>
|
||||
</modules>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
|||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
物联网模块
|
||||
<!-- TODO 芋艿:需要补充下说明! -->
|
||||
<!-- TODO 芋艿:需要补充下说明! -->
|
||||
</description>
|
||||
|
||||
</project>
|
|
@ -37,10 +37,10 @@
|
|||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.pf4j</groupId> <!-- PF4J:内置插件机制 -->
|
||||
<artifactId>pf4j-spring</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.pf4j</groupId> <!– PF4J:内置插件机制 –>-->
|
||||
<!-- <artifactId>pf4j-spring</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
|
||||
import cn.iocoder.yudao.module.iot.enums.ApiConstants;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
/**
|
||||
* 设备数据 Upstream 上行 API
|
||||
*
|
||||
* 目的:设备 -> 插件 -> 服务端
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
public interface IotDeviceUpstreamApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/device/upstream";
|
||||
|
||||
// ========== 设备相关 ==========
|
||||
|
||||
/**
|
||||
* 更新设备状态
|
||||
*
|
||||
* @param updateReqDTO 更新设备状态 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/update-state")
|
||||
CommonResult<Boolean> updateDeviceState(@Valid @RequestBody IotDeviceStateUpdateReqDTO updateReqDTO);
|
||||
|
||||
/**
|
||||
* 上报设备属性数据
|
||||
*
|
||||
* @param reportReqDTO 上报设备属性数据 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/report-property")
|
||||
CommonResult<Boolean> reportDeviceProperty(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO);
|
||||
|
||||
/**
|
||||
* 上报设备事件数据
|
||||
*
|
||||
* @param reportReqDTO 设备事件
|
||||
*/
|
||||
@PostMapping(PREFIX + "/report-event")
|
||||
CommonResult<Boolean> reportDeviceEvent(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO);
|
||||
|
||||
// TODO @芋艿:这个需要 plugins 接入下
|
||||
/**
|
||||
* 注册设备
|
||||
*
|
||||
* @param registerReqDTO 注册设备 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/register")
|
||||
CommonResult<Boolean> registerDevice(@Valid @RequestBody IotDeviceRegisterReqDTO registerReqDTO);
|
||||
|
||||
// TODO @芋艿:这个需要 plugins 接入下
|
||||
/**
|
||||
* 注册子设备
|
||||
*
|
||||
* @param registerReqDTO 注册子设备 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/register-sub")
|
||||
CommonResult<Boolean> registerSubDevice(@Valid @RequestBody IotDeviceRegisterSubReqDTO registerReqDTO);
|
||||
|
||||
// TODO @芋艿:这个需要 plugins 接入下
|
||||
/**
|
||||
* 注册设备拓扑
|
||||
*
|
||||
* @param addReqDTO 注册设备拓扑 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/add-topology")
|
||||
CommonResult<Boolean> addDeviceTopology(@Valid @RequestBody IotDeviceTopologyAddReqDTO addReqDTO);
|
||||
|
||||
// TODO @芋艿:考虑 http 认证
|
||||
/**
|
||||
* 认证 Emqx 连接
|
||||
*
|
||||
* @param authReqDTO 认证 Emqx 连接 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/authenticate-emqx-connection")
|
||||
CommonResult<Boolean> authenticateEmqxConnection(@Valid @RequestBody IotDeviceEmqxAuthReqDTO authReqDTO);
|
||||
|
||||
// ========== 插件相关 ==========
|
||||
|
||||
/**
|
||||
* 心跳插件实例
|
||||
*
|
||||
* @param heartbeatReqDTO 心跳插件实例 DTO
|
||||
*/
|
||||
@PostMapping(PREFIX + "/heartbeat-plugin-instance")
|
||||
CommonResult<Boolean> heartbeatPluginInstance(@Valid @RequestBody IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO);
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【配置】设置 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceConfigSetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 配置
|
||||
*/
|
||||
@NotNull(message = "配置不能为空")
|
||||
private Map<String, Object> config;
|
||||
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 设备下行的抽象 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public abstract class IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 请求编号
|
||||
*/
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【OTA】升级下发 Request DTO(更新固件消息)
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceOtaUpgradeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
private Long firmwareId;
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 签名方式
|
||||
*
|
||||
* 例如说:MD5、SHA256
|
||||
*/
|
||||
private String signMethod;
|
||||
/**
|
||||
* 固件文件签名
|
||||
*/
|
||||
private String fileSign;
|
||||
/**
|
||||
* 固件文件大小
|
||||
*/
|
||||
private Long fileSize;
|
||||
/**
|
||||
* 固件文件 URL
|
||||
*/
|
||||
private String fileUrl;
|
||||
|
||||
/**
|
||||
* 自定义信息,建议使用 JSON 格式
|
||||
*/
|
||||
private String information;
|
||||
|
||||
public static IotDeviceOtaUpgradeReqDTO build(Map<?, ?> map) {
|
||||
return new IotDeviceOtaUpgradeReqDTO()
|
||||
.setFirmwareId(MapUtil.getLong(map, "firmwareId")).setVersion((String) map.get("version"))
|
||||
.setSignMethod((String) map.get("signMethod")).setFileSign((String) map.get("fileSign"))
|
||||
.setFileSize(MapUtil.getLong(map, "fileSize")).setFileUrl((String) map.get("fileUrl"))
|
||||
.setInformation((String) map.get("information"));
|
||||
}
|
||||
|
||||
public static Map<?, ?> build(IotDeviceOtaUpgradeReqDTO dto) {
|
||||
return MapUtil.builder()
|
||||
.put("firmwareId", dto.getFirmwareId()).put("version", dto.getVersion())
|
||||
.put("signMethod", dto.getSignMethod()).put("fileSign", dto.getFileSign())
|
||||
.put("fileSize", dto.getFileSize()).put("fileUrl", dto.getFileUrl())
|
||||
.put("information", dto.getInformation())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// TODO @芋艿:从 server => plugin => device 是否有必要?从阿里云 iot 来看,没有这个功能?!
|
||||
// TODO @芋艿:是不是改成 read 更好?在看看阿里云的 topic 设计
|
||||
/**
|
||||
* IoT 设备【属性】获取 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDevicePropertyGetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 属性标识数组
|
||||
*/
|
||||
@NotEmpty(message = "属性标识数组不能为空")
|
||||
private List<String> identifiers;
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【属性】设置 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDevicePropertySetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 属性参数
|
||||
*/
|
||||
@NotEmpty(message = "属性参数不能为空")
|
||||
private Map<String, Object> properties;
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 设备【服务】调用 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceServiceInvokeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 服务标识
|
||||
*/
|
||||
@NotEmpty(message = "服务标识不能为空")
|
||||
private String identifier;
|
||||
/**
|
||||
* 调用参数
|
||||
*/
|
||||
private Map<String, Object> params;
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/progress
|
||||
/**
|
||||
* IoT 设备【OTA】升级进度 Request DTO(上报更新固件进度)
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceOtaProgressReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
private Long firmwareId;
|
||||
|
||||
/**
|
||||
* 升级状态
|
||||
*
|
||||
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 升级进度,百分比
|
||||
*/
|
||||
private Integer progress;
|
||||
|
||||
/**
|
||||
* 升级进度描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/pull
|
||||
/**
|
||||
* IoT 设备【OTA】升级下拉 Request DTO(拉取固件更新)
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class IotDeviceOtaPullReqDTO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
private Long firmwareId;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/report
|
||||
/**
|
||||
* IoT 设备【OTA】上报 Request DTO(上报固件版本)
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class IotDeviceOtaReportReqDTO {
|
||||
|
||||
/**
|
||||
* 固件编号
|
||||
*/
|
||||
private Long firmwareId;
|
||||
|
||||
/**
|
||||
* 固件版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 设备【注册】自己 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceRegisterReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IoT 设备【注册】子设备 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceRegisterSubReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
// TODO @芋艿:看看要不要优化命名
|
||||
/**
|
||||
* 子设备数组
|
||||
*/
|
||||
@NotEmpty(message = "子设备不能为空")
|
||||
private List<Device> params;
|
||||
|
||||
/**
|
||||
* 设备信息
|
||||
*/
|
||||
@Data
|
||||
public static class Device {
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 设备【状态】更新 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceStateUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
*/
|
||||
@NotNull(message = "设备状态不能为空")
|
||||
@InEnum(IotDeviceStateEnum.class) // 只使用:在线、离线
|
||||
private Integer state;
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// TODO @芋艿:要写清楚,是来自设备网关,还是设备。
|
||||
/**
|
||||
* IoT 设备【拓扑】添加 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceTopologyAddReqDTO extends IotDeviceUpstreamAbstractReqDTO {
|
||||
|
||||
// TODO @芋艿:看看要不要优化命名
|
||||
/**
|
||||
* 子设备数组
|
||||
*/
|
||||
@NotEmpty(message = "子设备不能为空")
|
||||
private List<IotDeviceRegisterSubReqDTO.Device> params;
|
||||
|
||||
/**
|
||||
* 设备信息
|
||||
*/
|
||||
@Data
|
||||
public static class Device {
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
// TODO @芋艿:阿里云还有 sign 签名
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 插件实例心跳 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotPluginInstanceHeartbeatReqDTO {
|
||||
|
||||
/**
|
||||
* 请求编号
|
||||
*/
|
||||
@NotEmpty(message = "请求编号不能为空")
|
||||
private String processId;
|
||||
|
||||
/**
|
||||
* 插件包标识符
|
||||
*/
|
||||
@NotEmpty(message = "插件包标识符不能为空")
|
||||
private String pluginKey;
|
||||
|
||||
/**
|
||||
* 插件实例所在 IP
|
||||
*/
|
||||
@NotEmpty(message = "插件实例所在 IP 不能为空")
|
||||
private String hostIp;
|
||||
/**
|
||||
* 插件实例的进程编号
|
||||
*/
|
||||
@NotNull(message = "插件实例的进程编号不能为空")
|
||||
private Integer downstreamPort;
|
||||
|
||||
/**
|
||||
* 是否在线
|
||||
*/
|
||||
@NotNull(message = "是否在线不能为空")
|
||||
private Boolean online;
|
||||
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
/**
|
||||
* TODO 芋艿:占位
|
||||
*/
|
||||
package cn.iocoder.yudao.module.iot.api.device.dto;
|
|
@ -1,6 +0,0 @@
|
|||
/**
|
||||
* 占位
|
||||
*
|
||||
* TODO 芋艿:后续删除
|
||||
*/
|
||||
package cn.iocoder.yudao.module.iot.api;
|
|
@ -1,16 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
|
||||
|
||||
/**
|
||||
* API 相关的枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ApiConstants {
|
||||
|
||||
public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/iot";
|
||||
|
||||
public static final String VERSION = "1.0.0";
|
||||
|
||||
}
|
|
@ -10,13 +10,9 @@ public class DictTypeConstants {
|
|||
public static final String PRODUCT_STATUS = "iot_product_status";
|
||||
public static final String PRODUCT_DEVICE_TYPE = "iot_product_device_type";
|
||||
public static final String NET_TYPE = "iot_net_type";
|
||||
public static final String PROTOCOL_TYPE = "iot_protocol_type";
|
||||
public static final String DATA_FORMAT = "iot_data_format";
|
||||
public static final String VALIDATE_TYPE = "iot_validate_type";
|
||||
public static final String CODEC_TYPE = "iot_codec_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";
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ 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, "下行设备消息失败,原因:设备未连接网关");
|
||||
|
||||
// ========== 产品分类 1-050-004-000 ==========
|
||||
ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在");
|
||||
|
@ -39,18 +39,6 @@ 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 ==========
|
||||
|
||||
ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在");
|
||||
|
@ -66,10 +54,10 @@ public interface ErrorCodeConstants {
|
|||
ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复");
|
||||
ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试");
|
||||
|
||||
// ========== MQTT 通信相关 1-050-009-000 ==========
|
||||
ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal");
|
||||
|
||||
// ========== IoT 数据桥梁 1-050-010-000 ==========
|
||||
ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在");
|
||||
|
||||
// ========== IoT 场景联动 1-050-011-000 ==========
|
||||
ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_011_000, "IoT 场景联动不存在");
|
||||
|
||||
}
|
|
@ -11,7 +11,7 @@ import lombok.RequiredArgsConstructor;
|
|||
@RequiredArgsConstructor
|
||||
public enum IotDeviceMessageIdentifierEnum {
|
||||
|
||||
PROPERTY_GET("get"), // 下行 TODO 芋艿:【讨论】貌似这个“上行”更合理?device 主动拉取配置。和 IotDevicePropertyGetReqDTO 一样的配置
|
||||
PROPERTY_GET("get"), // 下行
|
||||
PROPERTY_SET("set"), // 下行
|
||||
PROPERTY_REPORT("report"), // 上行
|
||||
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.enums.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 部署方式枚举
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum IotPluginDeployTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
JAR(0, "JAR 部署"),
|
||||
STANDALONE(1, "独立部署");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginDeployTypeEnum::getDeployType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 部署方式
|
||||
*/
|
||||
private final Integer deployType;
|
||||
/**
|
||||
* 部署方式名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.enums.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 插件状态枚举
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum IotPluginStatusEnum implements ArrayValuable<Integer> {
|
||||
|
||||
STOPPED(0, "停止"),
|
||||
RUNNING(1, "运行");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginStatusEnum::getStatus).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private final Integer status;
|
||||
/**
|
||||
* 状态名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.enums.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 插件类型枚举
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum IotPluginTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
NORMAL(0, "普通插件"),
|
||||
DEVICE(1, "设备插件");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 类型名
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.enums.product;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 产品数据格式枚举类
|
||||
*
|
||||
* @author ahh
|
||||
* @see <a href="https://help.aliyun.com/zh/iot/user-guide/message-parsing">阿里云 - 什么是消息解析</a>
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum IotDataFormatEnum implements ArrayValuable<Integer> {
|
||||
|
||||
JSON(0, "标准数据格式(JSON)"),
|
||||
CUSTOMIZE(1, "透传/自定义");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataFormatEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.enums.product;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* IoT 接入网关协议枚举类
|
||||
*
|
||||
* @author ahh
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum IotProtocolTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
CUSTOM(0, "自定义"),
|
||||
MODBUS(1, "Modbus"),
|
||||
OPC_UA(2, "OPC UA"),
|
||||
ZIGBEE(3, "ZigBee"),
|
||||
BLE(4, "BLE");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProtocolTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +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 IotValidateTypeEnum implements ArrayValuable<Integer> {
|
||||
|
||||
WEAK(0, "弱校验"),
|
||||
NONE(1, "免校验");
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotValidateTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
@Override
|
||||
public Integer[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
|
@ -50,7 +50,7 @@ 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) {
|
||||
return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values());
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>yudao-module-iot</artifactId>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
|
@ -15,7 +14,7 @@
|
|||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
物联网 模块,主要实现 产品管理、设备管理、协议管理等功能。
|
||||
<!-- TODO 芋艿:后续补充下 -->
|
||||
<!-- TODO 芋艿:后续补充下 -->
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
@ -29,6 +28,11 @@
|
|||
<artifactId>yudao-module-iot-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-iot-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
|
@ -75,10 +79,11 @@
|
|||
</dependency>
|
||||
|
||||
<!-- 消息队列相关 -->
|
||||
<!-- TODO @芋艿:临时打开 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
<!-- <optional>true</optional>-->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.kafka</groupId>
|
||||
|
@ -91,47 +96,17 @@
|
|||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.pf4j</groupId> <!-- PF4J:内置插件机制 -->
|
||||
<artifactId>pf4j-spring</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO @芋艿:bom 管理 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<version>4.0.25</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO @芋艿:bom 管理 -->
|
||||
<dependency>
|
||||
<groupId>org.graalvm.js</groupId>
|
||||
<artifactId>js</artifactId>
|
||||
<version>24.1.2</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.graalvm.js</groupId>
|
||||
<artifactId>js-scriptengine</artifactId>
|
||||
<version>24.1.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO @芋艿:合理注释 -->
|
||||
<!-- IoT 数据桥梁的执行器所需消息队列。如果您只需要使用 rocketmq 那么则注释掉其它消息队列即可 -->
|
||||
<!-- IoT 网络组件:接收来自设备的上行数据 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.apache.rocketmq</groupId>-->
|
||||
<!-- <artifactId>rocketmq-spring-boot-starter</artifactId>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-iot-net-component-http</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.kafka</groupId>-->
|
||||
<!-- <artifactId>spring-kafka</artifactId>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-iot-net-component-emqx</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-amqp</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot;
|
||||
|
||||
import cn.hutool.script.ScriptUtil;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* TODO 芋艿:测试脚本的接入
|
||||
*/
|
||||
public class ScriptTest {
|
||||
|
||||
public static void main2(String[] args) {
|
||||
// 创建一个 Groovy 脚本引擎
|
||||
ScriptEngine engine = ScriptUtil.createGroovyEngine();
|
||||
|
||||
// 创建绑定参数
|
||||
Bindings bindings = engine.createBindings();
|
||||
bindings.put("name", "Alice");
|
||||
bindings.put("age", 30);
|
||||
|
||||
// 定义一个稍微复杂的 Groovy 脚本
|
||||
String script = "def greeting = 'Hello, ' + name + '!';\n" +
|
||||
"def ageInFiveYears = age + 5;\n" +
|
||||
"def message = greeting + ' In five years, you will be ' + ageInFiveYears + ' years old.';\n" +
|
||||
"return message.toUpperCase();\n";
|
||||
|
||||
try {
|
||||
// 执行脚本并获取结果
|
||||
Object result = engine.eval(script, bindings);
|
||||
System.out.println(result); // 输出: HELLO, ALICE! IN FIVE YEARS, YOU WILL BE 35 YEARS OLD.
|
||||
} catch (ScriptException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 创建一个 JavaScript 脚本引擎
|
||||
ScriptEngine jsEngine = ScriptUtil.createJsEngine();
|
||||
|
||||
// 创建绑定参数
|
||||
Bindings jsBindings = jsEngine.createBindings();
|
||||
jsBindings.put("name", "Bob");
|
||||
jsBindings.put("age", 25);
|
||||
|
||||
// 定义一个简单的 JavaScript 脚本
|
||||
String jsScript = "var greeting = 'Hello, ' + name + '!';\n" +
|
||||
"var ageInTenYears = age + 10;\n" +
|
||||
"var message = greeting + ' In ten years, you will be ' + ageInTenYears + ' years old.';\n" +
|
||||
"message.toUpperCase();\n";
|
||||
|
||||
try {
|
||||
// 执行脚本并获取结果
|
||||
Object jsResult = jsEngine.eval(jsScript, jsBindings);
|
||||
System.out.println(jsResult); // 输出: HELLO, BOB! IN TEN YEARS, YOU WILL BE 35 YEARS OLD.
|
||||
} catch (ScriptException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceGetReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* IoT 设备 API 实现类
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
@Primary // 保证优先匹配,因为 yudao-iot-gateway 也有 IotDeviceCommonApi 的实现,并且也可能会被 biz 引入
|
||||
public class IoTDeviceApiImpl implements IotDeviceCommonApi {
|
||||
|
||||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
@Resource
|
||||
private IotProductService productService;
|
||||
|
||||
@Override
|
||||
@PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/auth")
|
||||
@PermitAll
|
||||
public CommonResult<Boolean> authDevice(@RequestBody IotDeviceAuthReqDTO authReqDTO) {
|
||||
return success(deviceService.authDevice(authReqDTO));
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/get") // 特殊:方便调用,暂时使用 POST,实际更推荐 GET
|
||||
@PermitAll
|
||||
public CommonResult<IotDeviceRespDTO> getDevice(@RequestBody IotDeviceGetReqDTO getReqDTO) {
|
||||
IotDeviceDO device = getReqDTO.getId() != null ? deviceService.getDeviceFromCache(getReqDTO.getId())
|
||||
: deviceService.getDeviceFromCache(getReqDTO.getProductKey(), getReqDTO.getDeviceName());
|
||||
return success(BeanUtils.toBean(device, IotDeviceRespDTO.class, deviceDTO -> {
|
||||
IotProductDO product = productService.getProductFromCache(deviceDTO.getProductId());
|
||||
if (product != null) {
|
||||
deviceDTO.setCodecType(product.getCodecType());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.api.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
|
||||
import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
|
||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* * 设备数据 Upstream 上行 API 实现类
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
|
||||
|
||||
@Resource
|
||||
private IotDeviceUpstreamService deviceUpstreamService;
|
||||
@Resource
|
||||
private IotPluginInstanceService pluginInstanceService;
|
||||
|
||||
// ========== 设备相关 ==========
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
|
||||
deviceUpstreamService.updateDeviceState(updateReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) {
|
||||
deviceUpstreamService.reportDeviceProperty(reportReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) {
|
||||
deviceUpstreamService.reportDeviceEvent(reportReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> registerDevice(IotDeviceRegisterReqDTO registerReqDTO) {
|
||||
deviceUpstreamService.registerDevice(registerReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) {
|
||||
deviceUpstreamService.registerSubDevice(registerReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) {
|
||||
deviceUpstreamService.addDeviceTopology(addReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
|
||||
boolean result = deviceUpstreamService.authenticateEmqxConnection(authReqDTO);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
// ========== 插件相关 ==========
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) {
|
||||
pluginInstanceService.heartbeatPluginInstance(heartbeatReqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
/**
|
||||
* 占位
|
||||
*
|
||||
* TODO 芋艿:后续删除
|
||||
* iot API 包,定义并实现提供给其它模块的 API
|
||||
*/
|
||||
package cn.iocoder.yudao.module.iot.api;
|
|
@ -6,13 +6,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
@ -42,9 +39,7 @@ public class IotDeviceController {
|
|||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
@Resource
|
||||
private IotDeviceUpstreamService deviceUpstreamService;
|
||||
@Resource
|
||||
private IotDeviceDownstreamService deviceDownstreamService;
|
||||
private IotDeviceMessageService deviceMessageService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建设备")
|
||||
|
@ -161,28 +156,20 @@ public class IotDeviceController {
|
|||
ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list);
|
||||
}
|
||||
|
||||
@PostMapping("/upstream")
|
||||
@Operation(summary = "设备上行", description = "可用于设备模拟")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:upstream')")
|
||||
public CommonResult<Boolean> upstreamDevice(@Valid @RequestBody IotDeviceUpstreamReqVO upstreamReqVO) {
|
||||
deviceUpstreamService.upstreamDevice(upstreamReqVO);
|
||||
return success(true);
|
||||
@GetMapping("/get-auth-info")
|
||||
@Operation(summary = "获得设备连接信息")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:auth-info')")
|
||||
public CommonResult<IotDeviceAuthInfoRespVO> getDeviceAuthInfo(@RequestParam("id") Long id) {
|
||||
return success(deviceService.getDeviceAuthInfo(id));
|
||||
}
|
||||
|
||||
@PostMapping("/downstream")
|
||||
@Operation(summary = "设备下行", description = "可用于设备模拟")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:downstream')")
|
||||
public CommonResult<Boolean> downstreamDevice(@Valid @RequestBody IotDeviceDownstreamReqVO downstreamReqVO) {
|
||||
deviceDownstreamService.downstreamDevice(downstreamReqVO);
|
||||
return success(true);
|
||||
// TODO @haohao:可以使用 @RequestParam("productKey") String productKey, @RequestParam("deviceNames") List<String> deviceNames 来接收哇?
|
||||
@GetMapping("/list-by-product-key-and-names")
|
||||
@Operation(summary = "通过产品标识和设备名称列表获取设备")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:query')")
|
||||
public CommonResult<List<IotDeviceRespVO>> getDevicesByProductKeyAndNames(@Valid IotDeviceByProductKeyAndNamesReqVO reqVO) {
|
||||
List<IotDeviceDO> devices = deviceService.getDeviceListByProductKeyAndNames(reqVO.getProductKey(), reqVO.getDeviceNames());
|
||||
return success(BeanUtils.toBean(devices, IotDeviceRespVO.class));
|
||||
}
|
||||
|
||||
// TODO @haohao:是不是默认详情接口,不返回 secret,然后这个接口,用于统一返回。然后接口名可以更通用一点。
|
||||
@GetMapping("/mqtt-connection-params")
|
||||
@Operation(summary = "获取 MQTT 连接参数")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:mqtt-connection-params')")
|
||||
public CommonResult<IotDeviceMqttConnectionParamsRespVO> getMqttConnectionParams(@RequestParam("deviceId") Long deviceId) {
|
||||
return success(deviceService.getMqttConnectionParams(deviceId));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogRespVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
|
||||
import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 设备日志")
|
||||
@RestController
|
||||
@RequestMapping("/iot/device/log")
|
||||
@Validated
|
||||
public class IotDeviceLogController {
|
||||
|
||||
@Resource
|
||||
private IotDeviceLogService deviceLogService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得设备日志分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:log-query')")
|
||||
public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) {
|
||||
PageResult<IotDeviceLogDO> pageResult = deviceLogService.getDeviceLogPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,23 @@
|
|||
### 请求 /iot/device/downstream 接口(服务调用) => 成功
|
||||
### 请求 /iot/device/message/send 接口(属性上报)=> 成功
|
||||
POST {{baseUrl}}/iot/device/message/send
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"deviceId": 25,
|
||||
"method": "thing.property.post",
|
||||
"params": {
|
||||
"width": 1,
|
||||
"height": "2",
|
||||
"oneThree": "3"
|
||||
}
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(服务调用)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
|
@ -13,10 +29,10 @@ Authorization: Bearer {{token}}
|
|||
}
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(属性设置) => 成功
|
||||
### 请求 /iot/device/downstream 接口(属性设置)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
|
@ -28,10 +44,10 @@ Authorization: Bearer {{token}}
|
|||
}
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(属性获取) => 成功
|
||||
### 请求 /iot/device/downstream 接口(属性获取)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
|
@ -41,10 +57,10 @@ Authorization: Bearer {{token}}
|
|||
"data": ["xx", "yy"]
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(配置设置) => 成功
|
||||
### 请求 /iot/device/downstream 接口(配置设置)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
|
@ -53,10 +69,10 @@ Authorization: Bearer {{token}}
|
|||
"identifier": "set"
|
||||
}
|
||||
|
||||
### 请求 /iot/device/downstream 接口(OTA 升级) => 成功
|
||||
### 请求 /iot/device/downstream 接口(OTA 升级)=> 成功 TODO 芋艿:未更新为最新
|
||||
POST {{baseUrl}}/iot/device/downstream
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenentId}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
|
@ -0,0 +1,47 @@
|
|||
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.message.IotDeviceMessageRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessagePageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageSendReqVO;
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO;
|
||||
import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 设备消息")
|
||||
@RestController
|
||||
@RequestMapping("/iot/device/message")
|
||||
@Validated
|
||||
public class IotDeviceMessageController {
|
||||
|
||||
@Resource
|
||||
private IotDeviceMessageService deviceMessageService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得设备消息分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:message-query')")
|
||||
public CommonResult<PageResult<IotDeviceMessageRespVO>> getDeviceLogPage(@Valid IotDeviceMessagePageReqVO pageReqVO) {
|
||||
PageResult<IotDeviceMessageDO> pageResult = deviceMessageService.getDeviceMessagePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotDeviceMessageRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/send")
|
||||
@Operation(summary = "发送消息", description = "可用于设备模拟")
|
||||
@PreAuthorize("@ss.hasPermission('iot:device:message-end')")
|
||||
public CommonResult<Boolean> upstreamDevice(@Valid @RequestBody IotDeviceMessageSendReqVO sendReqVO) {
|
||||
deviceMessageService.sendDeviceMessage(BeanUtils.toBean(sendReqVO, IotDeviceMessage.class));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@ 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.device.property.IotDevicePropertyService;
|
||||
import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备下行 Request VO") // 服务调用、属性设置、属性获取等
|
||||
@Data
|
||||
public class IotDeviceDownstreamReqVO {
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
|
||||
@NotEmpty(message = "消息类型不能为空")
|
||||
@InEnum(IotDeviceMessageTypeEnum.class)
|
||||
private String type;
|
||||
|
||||
@Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
|
||||
@NotEmpty(message = "标识符不能为空")
|
||||
private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
|
||||
|
||||
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Object data; // 例如说:服务调用的 params、属性设置的 properties
|
||||
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备上行 Request VO") // 属性上报、事件上报、状态变更等
|
||||
@Data
|
||||
public class IotDeviceUpstreamReqVO {
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
|
||||
@NotEmpty(message = "消息类型不能为空")
|
||||
@InEnum(IotDeviceMessageTypeEnum.class)
|
||||
private String type;
|
||||
|
||||
@Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
|
||||
@NotEmpty(message = "标识符不能为空")
|
||||
private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
|
||||
|
||||
@Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Object data; // 例如说:属性上报的 properties、事件上报的 params
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO")
|
||||
@Data
|
||||
public class IotDeviceLogPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
|
||||
@NotEmpty(message = "设备标识不能为空")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "消息类型", example = "property")
|
||||
private String type; // 参见 IotDeviceMessageTypeEnum 枚举,精准匹配
|
||||
|
||||
@Schema(description = "标识符", example = "temperature")
|
||||
private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举,模糊匹配
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备日志 Response VO")
|
||||
@Data
|
||||
public class IotDeviceLogRespVO {
|
||||
|
||||
@Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123")
|
||||
private String productKey;
|
||||
|
||||
@Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
|
||||
private String identifier;
|
||||
|
||||
@Schema(description = "日志内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
|
||||
@Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime reportTime;
|
||||
|
||||
@Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime ts;
|
||||
|
||||
}
|
|
@ -20,9 +20,6 @@ public class IotDevicePropertyHistoryPageReqVO extends PageParam {
|
|||
@NotNull(message = "设备编号不能为空")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "设备 Key", hidden = true)
|
||||
private String deviceKey; // 非前端传递,后端自己查询设置
|
||||
|
||||
@Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "属性标识符不能为空")
|
||||
private String identifier;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备认证信息 Response VO")
|
||||
@Data
|
||||
public class IotDeviceAuthInfoRespVO {
|
||||
|
||||
@Schema(description = "客户端 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123.device001")
|
||||
@NotBlank(message = "客户端 ID 不能为空")
|
||||
private String clientId;
|
||||
|
||||
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "device001&product123")
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1a2b3c4d5e6f7890abcdef1234567890")
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 通过产品标识和设备名称列表获取设备 Request VO")
|
||||
@Data
|
||||
public class IotDeviceByProductKeyAndNamesReqVO {
|
||||
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1de24640dfe")
|
||||
@NotBlank(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
|
||||
@Schema(description = "设备名称列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "device001,device002")
|
||||
@NotEmpty(message = "设备名称列表不能为空")
|
||||
private List<String> deviceNames;
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备 MQTT 连接参数 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class IotDeviceMqttConnectionParamsRespVO {
|
||||
|
||||
@Schema(description = "MQTT 客户端 ID", example = "24602")
|
||||
@ExcelProperty("MQTT 客户端 ID")
|
||||
private String mqttClientId;
|
||||
|
||||
@Schema(description = "MQTT 用户名", example = "芋艿")
|
||||
@ExcelProperty("MQTT 用户名")
|
||||
private String mqttUsername;
|
||||
|
||||
@Schema(description = "MQTT 密码")
|
||||
@ExcelProperty("MQTT 密码")
|
||||
private String mqttPassword;
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
|||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
|
|
@ -20,10 +20,6 @@ public class IotDeviceRespVO {
|
|||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "设备唯一标识符", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("设备唯一标识符")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
|
||||
@ExcelProperty("设备名称")
|
||||
private String deviceName;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Set;
|
||||
|
@ -13,10 +12,6 @@ public class IotDeviceSaveReqVO {
|
|||
@Schema(description = "设备编号", example = "177")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177")
|
||||
@Size(max = 50, message = "设备编号长度不能超过 50 个字符")
|
||||
private String deviceKey;
|
||||
|
||||
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.AUTO, example = "王五")
|
||||
private String deviceName;
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备消息分页查询 Request VO")
|
||||
@Data
|
||||
public class IotDeviceMessagePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "消息类型", example = "property")
|
||||
@InEnum(IotDeviceMessageMethodEnum.class)
|
||||
private String method;
|
||||
|
||||
@Schema(description = "是否上行", example = "true")
|
||||
private Boolean upstream;
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备消息 Response VO")
|
||||
@Data
|
||||
public class IotDeviceMessageRespVO {
|
||||
|
||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime reportTime;
|
||||
|
||||
@Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime ts;
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "服务编号", example = "server_123")
|
||||
private String serverId;
|
||||
|
||||
@Schema(description = "是否上行消息", example = "true", examples = "false")
|
||||
private Boolean upstream;
|
||||
|
||||
@Schema(description = "是否回复消息", example = "false", examples = "true")
|
||||
private Boolean reply;
|
||||
|
||||
// ========== codec(编解码)字段 ==========
|
||||
|
||||
@Schema(description = "请求编号", example = "req_123")
|
||||
private String requestId;
|
||||
|
||||
@Schema(description = "请求方法", requiredMode = Schema.RequiredMode.REQUIRED, example = "thing.property.report")
|
||||
private String method;
|
||||
|
||||
@Schema(description = "请求参数")
|
||||
private Object params;
|
||||
|
||||
@Schema(description = "响应结果")
|
||||
private Object data;
|
||||
|
||||
@Schema(description = "响应错误码", example = "200")
|
||||
private Integer code;
|
||||
|
||||
@Schema(description = "响应提示", example = "操作成功")
|
||||
private String msg;
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 设备消息发送 Request VO") // 属性上报、事件上报、状态变更等
|
||||
@Data
|
||||
public class IotDeviceMessageSendReqVO {
|
||||
|
||||
@Schema(description = "请求方法", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
|
||||
@NotEmpty(message = "请求方法不能为空")
|
||||
@InEnum(IotDeviceMessageMethodEnum.class)
|
||||
private String method;
|
||||
|
||||
@Schema(description = "请求参数")
|
||||
private Object params; // 例如说:属性上报的 properties、事件上报的 params
|
||||
|
||||
@Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
|
||||
@NotNull(message = "设备编号不能为空")
|
||||
private Long deviceId;
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
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.device.IotDeviceMessageDO;
|
||||
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;
|
||||
|
@ -89,7 +90,7 @@ public class IotOtaUpgradeRecordRespVO {
|
|||
* 升级进度描述
|
||||
* <p>
|
||||
* 注意,只记录设备最后一次的升级进度描述
|
||||
* 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志
|
||||
* 如果想看历史记录,可以查看 {@link IotDeviceMessageDO} 设备日志
|
||||
*/
|
||||
@Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private String description;
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigImportReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigSaveReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigStatusReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
|
||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 插件配置")
|
||||
@RestController
|
||||
@RequestMapping("/iot/plugin-config")
|
||||
@Validated
|
||||
public class PluginConfigController {
|
||||
|
||||
@Resource
|
||||
private IotPluginConfigService pluginConfigService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建插件配置")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:create')")
|
||||
public CommonResult<Long> createPluginConfig(@Valid @RequestBody PluginConfigSaveReqVO createReqVO) {
|
||||
return success(pluginConfigService.createPluginConfig(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新插件配置")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
||||
public CommonResult<Boolean> updatePluginConfig(@Valid @RequestBody PluginConfigSaveReqVO updateReqVO) {
|
||||
pluginConfigService.updatePluginConfig(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除插件配置")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:delete')")
|
||||
public CommonResult<Boolean> deletePluginConfig(@RequestParam("id") Long id) {
|
||||
pluginConfigService.deletePluginConfig(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得插件配置")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:query')")
|
||||
public CommonResult<PluginConfigRespVO> getPluginConfig(@RequestParam("id") Long id) {
|
||||
IotPluginConfigDO pluginConfig = pluginConfigService.getPluginConfig(id);
|
||||
return success(BeanUtils.toBean(pluginConfig, PluginConfigRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得插件配置分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:query')")
|
||||
public CommonResult<PageResult<PluginConfigRespVO>> getPluginConfigPage(@Valid PluginConfigPageReqVO pageReqVO) {
|
||||
PageResult<IotPluginConfigDO> pageResult = pluginConfigService.getPluginConfigPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, PluginConfigRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/upload-file")
|
||||
@Operation(summary = "上传插件文件")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
||||
public CommonResult<Boolean> uploadFile(@Valid PluginConfigImportReqVO reqVO) {
|
||||
pluginConfigService.uploadFile(reqVO.getId(), reqVO.getFile());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "修改插件状态")
|
||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
||||
public CommonResult<Boolean> updatePluginConfigStatus(@Valid @RequestBody PluginConfigStatusReqVO reqVO) {
|
||||
pluginConfigService.updatePluginStatus(reqVO.getId(), reqVO.getStatus());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 插件上传 Request VO")
|
||||
@Data
|
||||
public class PluginConfigImportReqVO {
|
||||
|
||||
@Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "插件文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "插件文件不能为空")
|
||||
private MultipartFile file;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -84,6 +84,27 @@ public class IotProductController {
|
|||
@PreAuthorize("@ss.hasPermission('iot:product:query')")
|
||||
public CommonResult<IotProductRespVO> getProduct(@RequestParam("id") Long id) {
|
||||
IotProductDO product = productService.getProduct(id);
|
||||
if (product == null) {
|
||||
return success(null);
|
||||
}
|
||||
// 拼接数据
|
||||
IotProductCategoryDO category = categoryService.getProductCategory(product.getCategoryId());
|
||||
return success(BeanUtils.toBean(product, IotProductRespVO.class, bean -> {
|
||||
if (category != null) {
|
||||
bean.setCategoryName(category.getName());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/get-by-key")
|
||||
@Operation(summary = "通过 ProductKey 获得产品")
|
||||
@Parameter(name = "productKey", description = "产品Key", required = true, example = "abc123")
|
||||
@PreAuthorize("@ss.hasPermission('iot:product:query')")
|
||||
public CommonResult<IotProductRespVO> getProductByKey(@RequestParam("productKey") String productKey) {
|
||||
IotProductDO product = productService.getProductByProductKey(productKey);
|
||||
if (product == null) {
|
||||
return success(null);
|
||||
}
|
||||
// 拼接数据
|
||||
IotProductCategoryDO category = categoryService.getProductCategory(product.getCategoryId());
|
||||
return success(BeanUtils.toBean(product, IotProductRespVO.class, bean -> {
|
||||
|
|
|
@ -61,24 +61,10 @@ public class IotProductRespVO {
|
|||
@DictFormat(DictTypeConstants.NET_TYPE)
|
||||
private Integer netType;
|
||||
|
||||
@Schema(description = "接入网关协议", example = "2")
|
||||
@ExcelProperty(value = "接入网关协议", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.PROTOCOL_TYPE)
|
||||
private Integer protocolType;
|
||||
|
||||
@Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177")
|
||||
@ExcelProperty("协议编号(脚本解析 id)")
|
||||
private Long protocolId;
|
||||
|
||||
@Schema(description = "数据格式")
|
||||
@Schema(description = "数据格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@ExcelProperty(value = "数据格式", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.DATA_FORMAT)
|
||||
private Integer dataFormat;
|
||||
|
||||
@Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "数据校验级别", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.VALIDATE_TYPE)
|
||||
private Integer validateType;
|
||||
@DictFormat(DictTypeConstants.CODEC_TYPE)
|
||||
private String codecType;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.product.vo.product;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.*;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotNetTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
@ -43,18 +44,8 @@ public class IotProductSaveReqVO {
|
|||
@InEnum(value = IotNetTypeEnum.class, message = "联网方式必须是 {value}")
|
||||
private Integer netType;
|
||||
|
||||
@Schema(description = "接入网关协议", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@InEnum(value = IotProtocolTypeEnum.class, message = "接入网关协议必须是 {value}")
|
||||
private Integer protocolType;
|
||||
|
||||
@Schema(description = "数据格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@InEnum(value = IotDataFormatEnum.class, message = "数据格式必须是 {value}")
|
||||
@NotNull(message = "数据格式不能为空")
|
||||
private Integer dataFormat;
|
||||
|
||||
@Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@InEnum(value = IotValidateTypeEnum.class, message = "数据校验级别必须是 {value}")
|
||||
@NotNull(message = "数据校验级别不能为空")
|
||||
private Integer validateType;
|
||||
@Schema(description = "数据格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@NotEmpty(message = "数据格式不能为空")
|
||||
private String codecType;
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.rule;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
|
@ -17,7 +18,10 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
|||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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
|
||||
|
@ -69,4 +73,12 @@ public class IotDataBridgeController {
|
|||
return success(BeanUtils.toBean(pageResult, IotDataBridgeRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获取数据桥梁的精简信息列表", description = "主要用于前端的下拉选项")
|
||||
public CommonResult<List<IotDataBridgeRespVO>> getSimpleDataBridgeList() {
|
||||
List<IotDataBridgeDO> list = dataBridgeService.getDataBridgeList(CommonStatusEnum.ENABLE.getStatus());
|
||||
return success(convertList(list, dataBridge -> // 只返回 id、name 字段
|
||||
new IotDataBridgeRespVO().setId(dataBridge.getId()).setName(dataBridge.getName())));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
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.scene.IotRuleScenePageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
|
||||
import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 规则场景")
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 场景联动")
|
||||
@RestController
|
||||
@RequestMapping("/iot/rule-scene")
|
||||
@Validated
|
||||
|
@ -18,6 +29,47 @@ public class IotRuleSceneController {
|
|||
@Resource
|
||||
private IotRuleSceneService ruleSceneService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建场景联动")
|
||||
@PreAuthorize("@ss.hasPermission('iot:rule-scene:create')")
|
||||
public CommonResult<Long> createRuleScene(@Valid @RequestBody IotRuleSceneSaveReqVO createReqVO) {
|
||||
return success(ruleSceneService.createRuleScene(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新场景联动")
|
||||
@PreAuthorize("@ss.hasPermission('iot:rule-scene:update')")
|
||||
public CommonResult<Boolean> updateRuleScene(@Valid @RequestBody IotRuleSceneSaveReqVO updateReqVO) {
|
||||
ruleSceneService.updateRuleScene(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除场景联动")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('iot:rule-scene:delete')")
|
||||
public CommonResult<Boolean> deleteRuleScene(@RequestParam("id") Long id) {
|
||||
ruleSceneService.deleteRuleScene(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得场景联动")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('iot:rule-scene:query')")
|
||||
public CommonResult<IotRuleSceneRespVO> getRuleScene(@RequestParam("id") Long id) {
|
||||
IotRuleSceneDO ruleScene = ruleSceneService.getRuleScene(id);
|
||||
return success(BeanUtils.toBean(ruleScene, IotRuleSceneRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得场景联动分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:rule-scene:query')")
|
||||
public CommonResult<PageResult<IotRuleSceneRespVO>> getRuleScenePage(@Valid IotRuleScenePageReqVO pageReqVO) {
|
||||
PageResult<IotRuleSceneDO> pageResult = ruleSceneService.getRuleScenePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotRuleSceneRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/test")
|
||||
@PermitAll
|
||||
public void test() {
|
||||
|
|
|
@ -18,7 +18,7 @@ import lombok.Data;
|
|||
@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 = IotDataBridgeRedisStreamConfig.class, name = "21"),
|
||||
@JsonSubTypes.Type(value = IotDataBridgeRocketMQConfig.class, name = "30"),
|
||||
@JsonSubTypes.Type(value = IotDataBridgeRabbitMQConfig.class, name = "31"),
|
||||
@JsonSubTypes.Type(value = IotDataBridgeKafkaMQConfig.class, name = "32"),
|
||||
|
|
|
@ -2,14 +2,13 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config;
|
|||
|
||||
import lombok.Data;
|
||||
|
||||
// TODO @puhui999:MQ 可以去掉哈。stream 更精准
|
||||
/**
|
||||
* IoT Redis Stream 配置 {@link IotDataBridgeAbstractConfig} 实现类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
public class IotDataBridgeRedisStreamMQConfig extends IotDataBridgeAbstractConfig {
|
||||
public class IotDataBridgeRedisStreamConfig extends IotDataBridgeAbstractConfig {
|
||||
|
||||
/**
|
||||
* Redis 服务器地址
|
|
@ -1,2 +0,0 @@
|
|||
// TODO @芋艿:占位
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo;
|
|
@ -0,0 +1,36 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 场景联动分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class IotRuleScenePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "场景名称", example = "赵六")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "场景描述", example = "你猜")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "场景状态", example = "1")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 场景联动 Response VO")
|
||||
@Data
|
||||
public class IotRuleSceneRespVO {
|
||||
|
||||
@Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15865")
|
||||
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 List<IotRuleSceneDO.TriggerConfig> triggers;
|
||||
|
||||
@Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<IotRuleSceneDO.ActionConfig> actions;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 场景联动新增/修改 Request VO")
|
||||
@Data
|
||||
public class IotRuleSceneSaveReqVO {
|
||||
|
||||
@Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15865")
|
||||
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)
|
||||
@NotEmpty(message = "触发器数组不能为空")
|
||||
private List<IotRuleSceneDO.TriggerConfig> triggers;
|
||||
|
||||
@Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "执行器数组不能为空")
|
||||
private List<IotRuleSceneDO.ActionConfig> actions;
|
||||
|
||||
}
|
|
@ -4,9 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|||
import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsSummaryRespVO;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
|
||||
import cn.iocoder.yudao.module.iot.service.device.property.IotDeviceLogService;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -174,8 +174,7 @@ GET {{baseUrl}}/iot/product-thing-model/get?id=67
|
|||
tenant-id: {{adminTenentId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
|
||||
### 请求 /iot/product-thing-model/list-by-product-id 接口 => 成功
|
||||
GET {{baseUrl}}/iot/product-thing-model/list-by-product-id?productId=1001
|
||||
### 请求 /iot/product-thing-model/get-tsl 接口 => 成功
|
||||
GET {{baseUrl}}/iot/product-thing-model/get-tsl?productId=1001
|
||||
tenant-id: {{adminTenentId}}
|
||||
Authorization: Bearer {{token}}
|
|
@ -1,13 +1,13 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
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.thingmodel.vo.IotThingModelListReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.*;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
|
||||
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
|
@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.*;
|
|||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 产品物模型")
|
||||
@RestController
|
||||
|
@ -64,16 +66,31 @@ public class IotThingModelController {
|
|||
return success(BeanUtils.toBean(thingModel, IotThingModelRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-product-id")
|
||||
@Operation(summary = "获得产品物模型")
|
||||
@Parameter(name = "productId", description = "产品ID", required = true, example = "1024")
|
||||
@GetMapping("/get-tsl")
|
||||
@Operation(summary = "获得产品物模型 TSL")
|
||||
@Parameter(name = "productId", description = "产品 ID", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('iot:thing-model:query')")
|
||||
public CommonResult<List<IotThingModelRespVO>> getThingModelListByProductId(@RequestParam("productId") Long productId) {
|
||||
List<IotThingModelDO> list = thingModelService.getThingModelListByProductId(productId);
|
||||
return success(BeanUtils.toBean(list, IotThingModelRespVO.class));
|
||||
public CommonResult<IotThingModelTSLRespVO> getThingModelTsl(@RequestParam("productId") Long productId) {
|
||||
IotThingModelTSLRespVO tslRespVO = new IotThingModelTSLRespVO();
|
||||
// TODO @puhui999:是不是要先查询产品哈?原因是,万一没配置物模型,但是产品已经有了!
|
||||
// 1. 获得产品所有物模型定义
|
||||
List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductId(productId);
|
||||
if (CollUtil.isEmpty(thingModels)) {
|
||||
return success(tslRespVO);
|
||||
}
|
||||
|
||||
// 2. 设置公共部分参数
|
||||
IotThingModelDO thingModel = thingModels.get(0);
|
||||
tslRespVO.setProductId(thingModel.getProductId()).setProductKey(thingModel.getProductKey());
|
||||
tslRespVO.setProperties(convertList(filterList(thingModels, item ->
|
||||
ObjUtil.equal(IotThingModelTypeEnum.PROPERTY.getType(), item.getType())), IotThingModelDO::getProperty));
|
||||
tslRespVO.setServices(convertList(filterList(thingModels, item ->
|
||||
ObjUtil.equal(IotThingModelTypeEnum.SERVICE.getType(), item.getType())), IotThingModelDO::getService));
|
||||
tslRespVO.setEvents(convertList(filterList(thingModels, item ->
|
||||
ObjUtil.equal(IotThingModelTypeEnum.EVENT.getType(), item.getType())), IotThingModelDO::getEvent));
|
||||
return success(tslRespVO);
|
||||
}
|
||||
|
||||
// TODO @puhui @super:getThingModelListByProductId 和 getThingModelListByProductId 可以融合么?
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得产品物模型列表")
|
||||
@PreAuthorize("@ss.hasPermission('iot:thing-model:query')")
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
@ -16,18 +20,17 @@ import java.util.List;
|
|||
@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复
|
||||
public class ThingModelArrayDataSpecs extends ThingModelDataSpecs {
|
||||
|
||||
/**
|
||||
* 数组中的元素个数
|
||||
*/
|
||||
@NotNull(message = "数组元素个数不能为空")
|
||||
private Integer size;
|
||||
/**
|
||||
* 数组中的元素的数据类型。可选值:struct、int、float、double 或 text
|
||||
*/
|
||||
|
||||
@NotEmpty(message = "数组元素的数据类型不能为空")
|
||||
@Pattern(regexp = "^(struct|int|float|double|text)$", message = "数组元素的数据类型必须为:struct、int、float、double 或 text")
|
||||
private String childDataType;
|
||||
/**
|
||||
* 数据类型(childDataType)为列表型 struct 的数据规范存储在 dataSpecsList 中
|
||||
* 此时 struct 取值范围为:int、float、double、text、date、enum、bool
|
||||
*/
|
||||
@Valid
|
||||
private List<ThingModelDataSpecs> dataSpecsList;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
@ -16,16 +19,12 @@ import lombok.EqualsAndHashCode;
|
|||
@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复
|
||||
public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs {
|
||||
|
||||
// TODO @puhui999:要不写下参数校验?这样,注释可以简洁一点
|
||||
/**
|
||||
* 枚举项的名称。
|
||||
* 可包含中文、大小写英文字母、数字、下划线(_)和短划线(-)
|
||||
* 必须以中文、英文字母或数字开头,长度不超过 20 个字符
|
||||
*/
|
||||
@NotEmpty(message = "枚举项的名称不能为空")
|
||||
@Pattern(regexp = "^[\\u4e00-\\u9fa5a-zA-Z0-9][\\u4e00-\\u9fa5a-zA-Z0-9_-]{0,19}$",
|
||||
message = "枚举项的名称只能包含中文、大小写英文字母、数字、下划线和短划线,必须以中文、英文字母或数字开头,长度不超过 20 个字符")
|
||||
private String name;
|
||||
/**
|
||||
* 枚举值。
|
||||
*/
|
||||
|
||||
@NotNull(message = "枚举值不能为空")
|
||||
private Integer value;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
@ -20,6 +21,7 @@ public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs {
|
|||
* 数据长度,单位为字节。取值不能超过 2048。
|
||||
* 当 dataType 为 text 时,需传入该参数。
|
||||
*/
|
||||
@Max(value = 2048, message = "数据长度不能超过 2048")
|
||||
private Integer length;
|
||||
/**
|
||||
* 默认值,可选参数,用于存储默认值。
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
@ -18,18 +20,21 @@ public class ThingModelNumericDataSpec extends ThingModelDataSpecs {
|
|||
|
||||
/**
|
||||
* 最大值,需转为字符串类型。值必须与 dataType 类型一致。
|
||||
* 例如,当 dataType 为 int 时,取值为 "200",而不是 200。
|
||||
*/
|
||||
@NotEmpty(message = "最大值不能为空")
|
||||
@Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "最大值必须为数值类型")
|
||||
private String max;
|
||||
/**
|
||||
* 最小值,需转为字符串类型。值必须与 dataType 类型一致。
|
||||
* 例如,当 dataType 为 int 时,取值为 "0",而不是 0。
|
||||
*/
|
||||
@NotEmpty(message = "最小值不能为空")
|
||||
@Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "最小值必须为数值类型")
|
||||
private String min;
|
||||
/**
|
||||
* 步长,需转为字符串类型。值必须与 dataType 类型一致。
|
||||
* 例如,当 dataType 为 int 时,取值为 "10",而不是 10。
|
||||
*/
|
||||
@NotEmpty(message = "步长不能为空")
|
||||
@Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "步长必须为数值类型")
|
||||
private String step;
|
||||
/**
|
||||
* 精度。当 dataType 为 float 或 double 时可选传入。
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
@ -17,35 +21,36 @@ import java.util.List;
|
|||
@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复
|
||||
public class ThingModelStructDataSpecs extends ThingModelDataSpecs {
|
||||
|
||||
/**
|
||||
* 属性标识符
|
||||
*/
|
||||
@NotEmpty(message = "属性标识符不能为空")
|
||||
@Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符")
|
||||
private String identifier;
|
||||
/**
|
||||
* 属性名称
|
||||
*/
|
||||
|
||||
@NotEmpty(message = "属性名称不能为空")
|
||||
private String name;
|
||||
/**
|
||||
* 云端可以对该属性进行的操作类型
|
||||
*
|
||||
* 枚举 {@link IotThingModelAccessModeEnum}
|
||||
*/
|
||||
|
||||
@NotEmpty(message = "操作类型不能为空")
|
||||
@InEnum(IotThingModelAccessModeEnum.class)
|
||||
private String accessMode;
|
||||
|
||||
/**
|
||||
* 是否是标准品类的必选服务
|
||||
*/
|
||||
private Boolean required;
|
||||
/**
|
||||
* struct 数据的数据类型
|
||||
*/
|
||||
|
||||
@NotEmpty(message = "数据类型不能为空")
|
||||
@Pattern(regexp = "^(int|float|double|text|date|enum|bool)$", message = "数据类型必须为:int、float、double、text、date、enum、bool")
|
||||
private String childDataType;
|
||||
|
||||
/**
|
||||
* 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中
|
||||
*/
|
||||
@Valid
|
||||
private ThingModelDataSpecs dataSpecs;
|
||||
|
||||
/**
|
||||
* 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中
|
||||
*/
|
||||
@Valid
|
||||
private List<ThingModelDataSpecs> dataSpecsList;
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo;
|
|||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
|
@ -12,18 +10,15 @@ import java.time.LocalDateTime;
|
|||
|
||||
@Schema(description = "管理后台 - IoT 产品物模型 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class IotThingModelRespVO {
|
||||
|
||||
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816")
|
||||
@ExcelProperty("产品ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_sensor")
|
||||
@ExcelProperty("产品标识")
|
||||
private String productKey;
|
||||
|
||||
@Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
|
||||
|
@ -48,7 +43,6 @@ public class IotThingModelRespVO {
|
|||
private ThingModelService service;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 产品物模型 TSL Response VO")
|
||||
@Data
|
||||
public class IotThingModelTSLRespVO {
|
||||
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_sensor")
|
||||
private String productKey;
|
||||
|
||||
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<ThingModelProperty> properties;
|
||||
|
||||
@Schema(description = "服务列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<ThingModelEvent> events;
|
||||
|
||||
@Schema(description = "事件列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<ThingModelService> services;
|
||||
|
||||
}
|
|
@ -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}}
|
|
@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.type.LongSetTypeHandler;
|
|||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
|
@ -33,12 +33,6 @@ public class IotDeviceDO extends TenantBaseDO {
|
|||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 设备唯一标识符,全局唯一,用于识别设备
|
||||
*
|
||||
* 类似阿里云 <a href="https://help.aliyun.com/zh/iot/developer-reference/api-querydeviceinfo">QueryDeviceInfo</a> 的 IotInstanceId
|
||||
*/
|
||||
private String deviceKey;
|
||||
/**
|
||||
* 设备名称,在产品内唯一,用于标识设备
|
||||
*/
|
||||
|
@ -120,23 +114,10 @@ public class IotDeviceDO extends TenantBaseDO {
|
|||
*/
|
||||
private String firmwareId;
|
||||
|
||||
// TODO @芋艿:【待定 003】:要不要增加 username?目前 tl 有,阿里云之类的没有
|
||||
/**
|
||||
* 设备密钥,用于设备认证,需安全存储
|
||||
* 设备密钥,用于设备认证
|
||||
*/
|
||||
private String deviceSecret;
|
||||
/**
|
||||
* MQTT 客户端 ID
|
||||
*/
|
||||
private String mqttClientId;
|
||||
/**
|
||||
* MQTT 用户名
|
||||
*/
|
||||
private String mqttUsername;
|
||||
/**
|
||||
* MQTT 密码
|
||||
*/
|
||||
private String mqttPassword;
|
||||
/**
|
||||
* 认证类型(如一机一密、动态注册)
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package cn.iocoder.yudao.module.iot.dal.dataobject.device;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.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 IotDeviceMessageDO {
|
||||
|
||||
/**
|
||||
* 消息编号
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 上报时间戳
|
||||
*/
|
||||
private Long reportTime;
|
||||
/**
|
||||
* 存储时间戳
|
||||
*/
|
||||
private Long ts;
|
||||
|
||||
/**
|
||||
* 设备编号
|
||||
*
|
||||
* 关联 {@link IotDeviceDO#getId()}
|
||||
*/
|
||||
private Long deviceId;
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 服务编号,该消息由哪个 server 发送
|
||||
*/
|
||||
private String serverId;
|
||||
|
||||
/**
|
||||
* 是否上行消息
|
||||
*
|
||||
* 由 {@link cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils#isUpstreamMessage(IotDeviceMessage)} 计算。
|
||||
* 计算并存储的目的:方便计算多少条上行、多少条下行
|
||||
*/
|
||||
private Boolean upstream;
|
||||
/**
|
||||
* 是否回复消息
|
||||
*
|
||||
* 由 {@link cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils#isReplyMessage(IotDeviceMessage)} 计算。
|
||||
* 计算并存储的目的:方便计算多少条请求、多少条回复
|
||||
*/
|
||||
private Boolean reply;
|
||||
|
||||
// ========== codec(编解码)字段 ==========
|
||||
|
||||
/**
|
||||
* 请求编号
|
||||
*
|
||||
* 由设备生成,对应阿里云 IoT 的 Alink 协议中的 id、华为云 IoTDA 协议的 request_id
|
||||
*/
|
||||
private String requestId;
|
||||
/**
|
||||
* 请求方法
|
||||
*
|
||||
* 枚举 {@link IotDeviceMessageMethodEnum}
|
||||
* 例如说:thing.property.report 属性上报
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* 请求参数
|
||||
*
|
||||
* 例如说:属性上报的 properties、事件上报的 params
|
||||
*/
|
||||
private Object params;
|
||||
/**
|
||||
* 响应结果
|
||||
*/
|
||||
private Object data;
|
||||
/**
|
||||
* 响应错误码
|
||||
*/
|
||||
private Integer code;
|
||||
/**
|
||||
* 响应提示
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.ota;
|
|||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
@ -77,7 +78,7 @@ public class IotOtaUpgradeRecordDO extends BaseDO {
|
|||
* 升级进度描述
|
||||
*
|
||||
* 注意,只记录设备最后一次的升级进度描述
|
||||
* 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志
|
||||
* 如果想看历史记录,可以查看 {@link IotDeviceMessageDO} 设备日志
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.dal.dataobject.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* IoT 插件配置 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("iot_plugin_config")
|
||||
@KeySequence("iot_plugin_config_seq")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IotPluginConfigDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 插件包标识符
|
||||
*/
|
||||
private String pluginKey;
|
||||
/**
|
||||
* 插件名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 插件描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 部署方式
|
||||
* <p>
|
||||
* 枚举 {@link IotPluginDeployTypeEnum}
|
||||
*/
|
||||
private Integer deployType;
|
||||
// TODO @芋艿:如果是外置的插件,fileName 和 version 的选择~
|
||||
/**
|
||||
* 插件包文件名
|
||||
*/
|
||||
private String fileName;
|
||||
/**
|
||||
* 插件版本
|
||||
*/
|
||||
private String version;
|
||||
// TODO @芋艿:type 字典的定义
|
||||
/**
|
||||
* 插件类型
|
||||
* <p>
|
||||
* 枚举 {@link IotPluginTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 设备插件协议类型
|
||||
*/
|
||||
// TODO @芋艿:枚举字段
|
||||
private String protocol;
|
||||
// TODO @haohao:这个字段,是不是直接用 CommonStatus,开启、禁用;然后插件实例那,online 是否在线
|
||||
/**
|
||||
* 状态
|
||||
* <p>
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
// TODO @芋艿:configSchema、config 示例字段
|
||||
/**
|
||||
* 插件配置项描述信息
|
||||
*/
|
||||
private String configSchema;
|
||||
/**
|
||||
* 插件配置信息
|
||||
*/
|
||||
private String config;
|
||||
|
||||
// TODO @芋艿:script 后续的使用
|
||||
/**
|
||||
* 插件脚本
|
||||
*/
|
||||
private String script;
|
||||
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package cn.iocoder.yudao.module.iot.dal.dataobject.plugin;
|
||||
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* IoT 插件实例 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("iot_plugin_instance")
|
||||
@KeySequence("iot_plugin_instance_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IotPluginInstanceDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 插件编号
|
||||
* <p>
|
||||
* 关联 {@link IotPluginConfigDO#getId()}
|
||||
*/
|
||||
private Long pluginId;
|
||||
/**
|
||||
* 插件进程编号
|
||||
*
|
||||
* 一般格式是:hostIp@processId@${uuid}
|
||||
*/
|
||||
private String processId;
|
||||
|
||||
/**
|
||||
* 插件实例所在 IP
|
||||
*/
|
||||
private String hostIp;
|
||||
/**
|
||||
* 设备下行端口
|
||||
*/
|
||||
private Integer downstreamPort;
|
||||
|
||||
/**
|
||||
* 是否在线
|
||||
*/
|
||||
private Boolean online;
|
||||
/**
|
||||
* 在线时间
|
||||
*/
|
||||
private LocalDateTime onlineTime;
|
||||
/**
|
||||
* 离线时间
|
||||
*/
|
||||
private LocalDateTime offlineTime;
|
||||
/**
|
||||
* 心跳时间
|
||||
*
|
||||
* 目的:心路时间超过一定时间后,会被进行下线处理
|
||||
*/
|
||||
private LocalDateTime heartbeatTime;
|
||||
|
||||
}
|
|
@ -71,28 +71,12 @@ public class IotProductDO extends TenantBaseDO {
|
|||
private Integer netType;
|
||||
|
||||
/**
|
||||
* 接入网关协议
|
||||
* 数据格式(编解码器类型)
|
||||
* <p>
|
||||
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProtocolTypeEnum}
|
||||
* 字典 {@link cn.iocoder.yudao.module.iot.enums.DictTypeConstants#CODEC_TYPE}
|
||||
*
|
||||
* 目的:用于 gateway-server 解析消息格式
|
||||
*/
|
||||
private Integer protocolType;
|
||||
/**
|
||||
* 协议编号
|
||||
* <p>
|
||||
* TODO 外键:后续加
|
||||
*/
|
||||
private Long protocolId;
|
||||
/**
|
||||
* 数据格式
|
||||
* <p>
|
||||
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotDataFormatEnum}
|
||||
*/
|
||||
private Integer dataFormat;
|
||||
/**
|
||||
* 数据校验级别
|
||||
* <p>
|
||||
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotValidateTypeEnum}
|
||||
*/
|
||||
private Integer validateType;
|
||||
private String codecType;
|
||||
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
package cn.iocoder.yudao.module.iot.dal.dataobject.rule;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* IoT 告警记录 DO
|
||||
|
|
|
@ -14,17 +14,20 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
|||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT 规则场景(场景联动) DO
|
||||
* IoT 场景联动 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("iot_rule_scene")
|
||||
@TableName(value = "iot_rule_scene", autoResultMap = true)
|
||||
@KeySequence("iot_rule_scene_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
|
@ -141,8 +144,17 @@ public class IotRuleSceneDO extends TenantBaseDO {
|
|||
@Data
|
||||
public static class TriggerConditionParameter {
|
||||
|
||||
// TODO @芋艿: identifier0 存事件和服务的 identifier 属性的情况 identifier0 就为 null 解决前端回显问题
|
||||
// TODO @puhui999:可以根据 TriggerCondition.type 判断,是服务、还是事件、还是属性么?
|
||||
/**
|
||||
* 标识符(属性、事件、服务)
|
||||
* 标识符(事件、服务)
|
||||
*
|
||||
* 关联 {@link IotThingModelDO#getIdentifier()}
|
||||
*/
|
||||
private String identifier0;
|
||||
|
||||
/**
|
||||
* 标识符(属性)
|
||||
*
|
||||
* 关联 {@link IotThingModelDO#getIdentifier()}
|
||||
*/
|
||||
|
|
|
@ -6,11 +6,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -50,11 +50,6 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
|
|||
return selectCount(IotDeviceDO::getProductId, productId);
|
||||
}
|
||||
|
||||
default IotDeviceDO selectByDeviceKey(String deviceKey) {
|
||||
return selectOne(new LambdaQueryWrapper<IotDeviceDO>()
|
||||
.apply("LOWER(device_key) = {0}", deviceKey.toLowerCase()));
|
||||
}
|
||||
|
||||
default List<IotDeviceDO> selectListByDeviceType(Integer deviceType) {
|
||||
return selectList(IotDeviceDO::getDeviceType, deviceType);
|
||||
}
|
||||
|
@ -77,6 +72,12 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
|
|||
.geIfPresent(IotDeviceDO::getCreateTime, createTime));
|
||||
}
|
||||
|
||||
default List<IotDeviceDO> selectByProductKeyAndDeviceNames(String productKey, Collection<String> deviceNames) {
|
||||
return selectList(new LambdaQueryWrapperX<IotDeviceDO>()
|
||||
.eq(IotDeviceDO::getProductKey, productKey)
|
||||
.in(IotDeviceDO::getDeviceName, deviceNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定产品下各状态的设备数量
|
||||
*
|
||||
|
@ -93,4 +94,4 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
|
|||
*/
|
||||
List<Map<String, Object>> selectDeviceCountGroupByState();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue