From 624f5283b3ec89295f3562a068bd009881b1c487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 3 Nov 2024 00:16:46 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E3=80=91=20=E8=AE=BE=E5=A4=87=E6=95=B0=E6=8D=AE=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E5=92=8C=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/IotProductFunctionTypeEnum.java | 2 +- .../admin/device/IotDeviceController.java | 8 +- .../admin/device/IotDeviceDataController.java | 38 +++++ .../vo/{ => device}/IotDevicePageReqVO.java | 2 +- .../vo/{ => device}/IotDeviceRespVO.java | 2 +- .../vo/{ => device}/IotDeviceSaveReqVO.java | 2 +- .../IotDeviceStatusUpdateReqVO.java | 2 +- .../vo/deviceData/IotDeviceDataReqVO.java | 21 +++ .../vo/deviceData/IotDeviceDataRespVO.java | 42 ++++++ .../convert/device/IotDeviceDataConvert.java | 46 ++++++ .../dataobject/device/IotDeviceDataDO.java | 71 +++++++++ .../iot/dal/mysql/device/IotDeviceMapper.java | 2 +- .../iot/dal/redis/RedisKeyConstants.java | 20 +++ .../redis/deviceData/DeviceDataRedisDAO.java | 43 ++++++ .../service/device/IotDeviceDataService.java | 17 ++- .../device/IotDeviceDataServiceImpl.java | 57 ++++++- .../iot/service/device/IotDeviceService.java | 4 +- .../service/device/IotDeviceServiceImpl.java | 6 +- .../IotDbStructureDataServiceImpl.java | 106 ++++++------- .../IotThingModelMessageServiceImpl.java | 140 ++++++++++++++---- 20 files changed, 523 insertions(+), 108 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/{ => device}/IotDevicePageReqVO.java (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/{ => device}/IotDeviceRespVO.java (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/{ => device}/IotDeviceSaveReqVO.java (89%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/{ => device}/IotDeviceStatusUpdateReqVO.java (91%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java index b99d2b0938..c8a03a4d39 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java @@ -30,7 +30,7 @@ public enum IotProductFunctionTypeEnum implements IntArrayValuable { */ private final String description; - public static IotProductFunctionTypeEnum valueOf(Integer type) { + public static IotProductFunctionTypeEnum valueOfType(Integer type) { for (IotProductFunctionTypeEnum value : values()) { if (value.getType().equals(type)) { return value; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 6d75f1cdd2..ba68e02328 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -3,10 +3,10 @@ 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.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import io.swagger.v3.oas.annotations.Operation; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java new file mode 100644 index 0000000000..93b368bd8d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; +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.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 java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 设备数据") +@RestController +@RequestMapping("/iot/device/data") +@Validated +public class IotDeviceDataController { + + @Resource + private IotDeviceDataService deviceDataService; + + @GetMapping("/latest-data") + @Operation(summary = "获取设备属性最新数据") + public CommonResult> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) { + List list = deviceDataService.getDevicePropertiesLatestData(deviceDataReqVO); + return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java index 1c29f9f810..90ded80898 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; +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; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java index 0b2cf25f56..fd2fbaa686 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java index 620e5310fa..85fde9d3d9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceStatusUpdateReqVO.java similarity index 91% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceStatusUpdateReqVO.java index a91a586906..daa1efde80 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceStatusUpdateReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java new file mode 100644 index 0000000000..b8a95f607e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 设备数据 Request VO") +@Data +public class IotDeviceDataReqVO { + + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + private Long deviceId; + + @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED) + private String identifier; + + @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String name; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java new file mode 100644 index 0000000000..256bf84faa --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 设备数据 Response VO") +@Data +public class IotDeviceDataRespVO { + + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + private Long deviceId; + + @Schema(description = "物模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") + private Long thinkModelFunctionId; + + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + private String productKey; + + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String deviceName; + + @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED) + private String identifier; + + @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String name; + + @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED) + private String dataType; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + + @Schema(description = "最新值", requiredMode = Schema.RequiredMode.REQUIRED) + private String value; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java new file mode 100644 index 0000000000..3bad54ba09 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.iot.convert.device; + +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@Mapper +public interface IotDeviceDataConvert { + + IotDeviceDataConvert INSTANCE = Mappers.getMapper(IotDeviceDataConvert.class); + +// default List convert(Map deviceData, IotDeviceDO device){ +// List list = new ArrayList<>(); +// deviceData.forEach((identifier, value) -> { +//// ThingModelProperty property = ThingModelService.INSTANCE.getProperty(device.getProductId(), identifier); +//// if (Objects.isNull(property)) { +//// return; +//// } +// IotDeviceDataRespVO vo = new IotDeviceDataRespVO(); +// vo.setDeviceId(device.getId()); +// vo.setProductKey(device.getProductKey()); +// vo.setDeviceName(device.getDeviceName()); +// vo.setIdentifier(identifier); +//// vo.setName(property.getName()); +//// vo.setDataType(property.getDataType().getType()); +// vo.setUpdateTime(device.getUpdateTime()); +// vo.setValue(value.toString()); +// list.add(vo); +// }); +// return list; +// } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java new file mode 100644 index 0000000000..5d80511721 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.device; + +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * IoT 设备数据 DO + * + * @author haohao + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDeviceDataDO { + + /** + * 设备编号 + */ + private Long deviceId; + + /** + * 物模型编号 + */ + private Long thinkModelFunctionId; + + /** + * 产品标识 + */ + private String productKey; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 属性标识符 + */ + private String identifier; + + /** + * 属性名称 + */ + private String name; + + /** + * 数据类型 + */ + private String dataType; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 最新值 + */ + private String value; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 0e5552f83b..3129f400c2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.mysql.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import org.apache.ibatis.annotations.Mapper; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java new file mode 100644 index 0000000000..25ea7a2926 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.dal.redis; + + + +/** + * Iot Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 设备属性数据缓存 + *

+ * KEY 格式:device_property_data:{deviceId} + * VALUE 数据类型:String 设备属性数据 + */ + String DEVICE_PROPERTY_DATA = "device_property_data:%s_%s_%s"; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java new file mode 100644 index 0000000000..b1b69f8dce --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.iot.dal.redis.deviceData; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants.DEVICE_PROPERTY_DATA; + +/** + * {@link IotDeviceDataDO} 的 Redis DAO + */ +@Repository +public class DeviceDataRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public IotDeviceDataDO get(String productKey, String deviceName, String identifier) { + String redisKey = formatKey(productKey, deviceName, identifier); + return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), IotDeviceDataDO.class); + } + + public void set(IotDeviceDataDO deviceData) { + String redisKey = formatKey(deviceData.getProductKey(), deviceData.getDeviceName(), deviceData.getIdentifier()); + stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(deviceData)); + } + + public void delete(String productKey, String deviceName, String identifier) { + String redisKey = formatKey(productKey, deviceName, identifier); + stringRedisTemplate.delete(redisKey); + } + + private static String formatKey(String productKey, String deviceName, String identifier) { + return String.format(DEVICE_PROPERTY_DATA, productKey, deviceName, identifier); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 4f3ef37d6c..f67f426855 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -1,12 +1,11 @@ package cn.iocoder.yudao.module.iot.service.device; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import jakarta.validation.Valid; +import java.util.List; + /** * IoT 设备数据 Service 接口 * @@ -23,4 +22,12 @@ public interface IotDeviceDataService { * @param message 消息 */ void saveDeviceData(String productKey, String deviceName, String message); + + /** + * 获得设备属性最新数据 + * + * @param deviceId 设备编号 + * @return 设备属性最新数据 + */ + List getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceId); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 6b7aac21f9..86ac630c6f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -1,13 +1,23 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.hutool.json.JSONObject; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; +import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import jakarta.annotation.Resource; +import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + @Slf4j @Service public class IotDeviceDataServiceImpl implements IotDeviceDataService { @@ -16,6 +26,11 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { private IotDeviceService deviceService; @Resource private IotThingModelMessageService thingModelMessageService; + @Resource + private IotThinkModelFunctionService thinkModelFunctionService; + + @Resource + private DeviceDataRedisDAO deviceDataRedisDAO; @Override public void saveDeviceData(String productKey, String deviceName, String message) { @@ -34,6 +49,46 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { .deviceName(deviceName) .deviceKey(device.getDeviceKey()) .build(); - thingModelMessageService.saveThingModelMessage(device,thingModelMessage); + thingModelMessageService.saveThingModelMessage(device, thingModelMessage); + } + + @Override + public List getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) { + List list = new ArrayList<>(); + // 1. 获取设备信息 + IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); + // 2. 获取设备属性最新数据 + List thinkModelFunctionList = thinkModelFunctionService.getThinkModelFunctionListByProductKey(device.getProductKey()); + thinkModelFunctionList = thinkModelFunctionList.stream() + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType() + .equals(function.getType())).toList(); + + // 3. 过滤标识符和属性名称 + if (deviceDataReqVO.getIdentifier() != null) { + thinkModelFunctionList = thinkModelFunctionList.stream() + .filter(function -> function.getIdentifier().toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())) + .toList(); + } + if (deviceDataReqVO.getName() != null) { + thinkModelFunctionList = thinkModelFunctionList.stream() + .filter(function -> function.getName().toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())) + .toList(); + } + // 4. 获取设备属性最新数据 + thinkModelFunctionList.forEach(function -> { + IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), function.getIdentifier()); + if (deviceData == null) { + deviceData = new IotDeviceDataDO(); + deviceData.setProductKey(device.getProductKey()); + deviceData.setDeviceName(device.getDeviceName()); + deviceData.setIdentifier(function.getIdentifier()); + deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); + deviceData.setThinkModelFunctionId(function.getId()); + deviceData.setName(function.getName()); + deviceData.setDataType(function.getProperty().getDataType().getType()); + } + list.add(deviceData); + }); + return list; } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index c967a957ed..ed4c6a60ce 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import jakarta.validation.*; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index f3243900e7..60743f6713 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -5,9 +5,9 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java index b7de8882a9..9471781027 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.iot.service.tdengine; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdRestApi; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import jakarta.annotation.Resource; @@ -14,10 +14,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; @Service @@ -27,9 +24,6 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService @Resource private IotTdEngineService iotTdEngineService; - @Resource - private TdRestApi tdRestApi; - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") private String url; @@ -37,39 +31,25 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { // 1. 解析物模型,获得字段列表 List schemaFields = new ArrayList<>(); - schemaFields.add(TdFieldDO.builder(). - fieldName("time"). - dataType("TIMESTAMP"). - build()); + schemaFields.add(TdFieldDO.builder() + .fieldName("time") + .dataType("TIMESTAMP") + .build()); schemaFields.addAll(FieldParser.parse(thingModel)); // 3. 设置超级表的标签 - List tagsFields = new ArrayList<>(); - tagsFields.add(TdFieldDO.builder(). - fieldName("product_key"). - dataType("NCHAR"). - dataLength(64). - build()); - tagsFields.add(TdFieldDO.builder(). - fieldName("device_key"). - dataType("NCHAR"). - dataLength(64). - build()); - tagsFields.add(TdFieldDO.builder(). - fieldName("device_name"). - dataType("NCHAR"). - dataLength(64). - build()); - tagsFields.add(TdFieldDO.builder(). - fieldName("device_type"). - dataType("INT"). - build()); + List tagsFields = Arrays.asList( + TdFieldDO.builder().fieldName("product_key").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_name").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_type").dataType("INT").build() + ); // 4. 获取超级表的名称 String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); // 5. 创建超级表 - String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + String dataBaseName = getDatabaseName(); iotTdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); } @@ -81,7 +61,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService List newFields = FieldParser.parse(thingModel); updateTableFields(tbName, oldFields, newFields); - } catch (Throwable e) { + } catch (Exception e) { log.error("更新物模型超级表失败", e); } } @@ -90,14 +70,15 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService private List getTableFields(String tableName) { List fields = new ArrayList<>(); // 获取超级表的描述信息 - List> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName); + List> maps = iotTdEngineService.describeSuperTable(getDatabaseName(), tableName); if (maps != null) { - // 过滤掉 note 字段为 TAG 的记录 - maps = maps.stream().filter(map -> !"TAG".equals(map.get("note"))).toList(); - // 过滤掉 time 字段 - maps = maps.stream().filter(map -> !"time".equals(map.get("field"))).toList(); + // 过滤掉 note 字段为 TAG 的记录和 time 字段 + List> filteredMaps = maps.stream() + .filter(map -> !"TAG".equals(map.get("note"))) + .filter(map -> !"time".equals(map.get("field"))) + .toList(); // 解析字段信息 - fields = FieldParser.parse(maps.stream() + fields = FieldParser.parse(filteredMaps.stream() .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) .collect(Collectors.toList())); } @@ -113,7 +94,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService // 获取删除字段 List dropFields = getDropFields(oldFields, newFields); - String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + String dataBaseName = getDatabaseName(); // 添加新增字段 if (CollUtil.isNotEmpty(addFields)) { iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, addFields); @@ -131,25 +112,37 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService // 获取新增字段 private List getAddFields(List oldFields, List newFields) { + Set oldFieldNames = oldFields.stream() + .map(TdFieldDO::getFieldName) + .collect(Collectors.toSet()); return newFields.stream() - .filter(f -> oldFields.stream().noneMatch(old -> old.getFieldName().equals(f.getFieldName()))) + .filter(f -> !oldFieldNames.contains(f.getFieldName())) .collect(Collectors.toList()); } // 获取修改字段 private List getModifyFields(List oldFields, List newFields) { + Map oldFieldMap = oldFields.stream() + .collect(Collectors.toMap(TdFieldDO::getFieldName, f -> f)); + return newFields.stream() - .filter(f -> oldFields.stream().anyMatch(old -> - old.getFieldName().equals(f.getFieldName()) && - (!old.getDataType().equals(f.getDataType()) || !Objects.equals(old.getDataLength(), f.getDataLength())))) + .filter(f -> { + TdFieldDO oldField = oldFieldMap.get(f.getFieldName()); + return oldField != null && + (!oldField.getDataType().equals(f.getDataType()) || + !Objects.equals(oldField.getDataLength(), f.getDataLength())); + }) .collect(Collectors.toList()); } // 获取删除字段 private List getDropFields(List oldFields, List newFields) { + Set newFieldNames = newFields.stream() + .map(TdFieldDO::getFieldName) + .collect(Collectors.toSet()); return oldFields.stream() - .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()) && - newFields.stream().noneMatch(n -> n.getFieldName().equals(f.getFieldName()))) + .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName())) + .filter(f -> !newFieldNames.contains(f.getFieldName())) .collect(Collectors.toList()); } @@ -157,13 +150,13 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService public void createSuperTableDataModel(IotProductDO product, List functionList) { ThingModelRespVO thingModel = buildThingModel(product, functionList); - if (thingModel.getModel().getProperties().isEmpty()) { + if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) { log.warn("物模型属性列表为空,不创建超级表"); return; } String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); - String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + String dataBaseName = getDatabaseName(); Integer tableExists = iotTdEngineService.checkSuperTableExists(dataBaseName, superTableName); if (tableExists != null && tableExists > 0) { @@ -180,7 +173,8 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService ThingModelRespVO.Model model = new ThingModelRespVO.Model(); List properties = functionList.stream() - .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(IotProductFunctionTypeEnum.valueOf(function.getType()))) + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals( + IotProductFunctionTypeEnum.valueOfType(function.getType()))) .map(this::buildThingModelProperty) .collect(Collectors.toList()); @@ -191,14 +185,15 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService } private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) { - ThingModelProperty property = new ThingModelProperty(); - property.setIdentifier(function.getIdentifier()); - property.setName(function.getName()); - property.setDescription(function.getDescription()); + ThingModelProperty property = BeanUtil.copyProperties(function, ThingModelProperty.class); property.setDataType(function.getProperty().getDataType()); return property; } + private String getDatabaseName() { + return url.substring(url.lastIndexOf("/") + 1); + } + static String getProductPropertySTableName(Integer deviceType, String productKey) { return switch (deviceType) { case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); @@ -207,7 +202,4 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService }; } - static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) { - return String.format("%s_%s_%s", deviceType, productKey, deviceKey).toLowerCase(); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index ae7fa51ee7..9bad7613ed 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -1,13 +1,16 @@ package cn.iocoder.yudao.module.iot.service.tdengine; +import cn.hutool.core.date.DateUtil; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; @@ -17,9 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; @Slf4j @@ -36,11 +37,14 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private IotTdEngineService iotTdEngineService; + @Resource + private DeviceDataRedisDAO deviceDataRedisDAO; + @Override @TenantIgnore public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { // 判断设备状态,如果为未激活状态,创建数据表 - if (device.getStatus().equals(0)) { + if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { // 创建设备数据表 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); // 更新设备状态 @@ -50,53 +54,99 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ iotDeviceService.updateDeviceStatus(updateReqVO); } - // 1. 获取设备属性 + // 获取设备属性 Map params = thingModelMessage.dataToMap(); - // 2. 物模型校验,过滤非物模型属性 - List thinkModelFunctionListByProductKey = iotThinkModelFunctionService.getThinkModelFunctionListByProductKey(thingModelMessage.getProductKey()); + // 物模型校验,过滤非物模型属性 + List functionList = iotThinkModelFunctionService + .getThinkModelFunctionListByProductKey(thingModelMessage.getProductKey()) + .stream() + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType())) + .toList(); - // 2.1 筛选是属性 IotProductFunctionTypeEnum - thinkModelFunctionListByProductKey.removeIf(iotThinkModelFunctionDO -> !iotThinkModelFunctionDO.getType().equals(IotProductFunctionTypeEnum.PROPERTY.getType())); - if (thinkModelFunctionListByProductKey.isEmpty()) { + if (functionList.isEmpty()) { return; } - // 2.2 获取属性名称 - Map thingModelProperties = thinkModelFunctionListByProductKey.stream().collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, IotThinkModelFunctionDO::getName)); - // 4. 保存属性记录 + // 获取属性标识符集合 + Set propertyIdentifiers = functionList.stream() + .map(IotThinkModelFunctionDO::getIdentifier) + .collect(Collectors.toSet()); + + Map functionMap = functionList.stream() + .collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, function -> function)); + + // 过滤并收集有效的属性字段 List schemaFieldValues = new ArrayList<>(); - - // 1. 设置字段名 schemaFieldValues.add(new TdFieldDO("time", thingModelMessage.getTime())); - - // 2. 遍历新属性 params.forEach((key, val) -> { - if (thingModelProperties.containsKey(key)) { + if (propertyIdentifiers.contains(key)) { schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); + // 缓存设备属性 + setDeviceDataCache(device, functionMap.get(key), val, thingModelMessage.getTime()); } }); + if (schemaFieldValues.size() == 1) { + return; + } - // 3. 保存设备属性 + // 构建并保存设备属性 TableDO tableData = new TableDO(); - tableData.setDataBaseName(url.substring(url.lastIndexOf("/") + 1)); + tableData.setDataBaseName(getDatabaseName()); tableData.setSuperTableName(getProductPropertySTableName(device.getDeviceType(), device.getProductKey())); - tableData.setTableName("device_" + device.getProductKey().toLowerCase() + "_" + device.getDeviceName().toLowerCase()); + tableData.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); tableData.setSchemaFieldValues(schemaFieldValues); - // 4. 保存数据 iotTdEngineService.insertData(tableData); } + /** + * 缓存设备属性 + * + * @param device 设备信息 + * @param iotThinkModelFunctionDO 物模型属性 + * @param val 属性值 + * @param time 时间 + */ + private void setDeviceDataCache(IotDeviceDO device, IotThinkModelFunctionDO iotThinkModelFunctionDO, Object val, Long time) { + IotDeviceDataDO deviceData = IotDeviceDataDO.builder() + .productKey(device.getProductKey()) + .deviceName(device.getDeviceName()) + .identifier(iotThinkModelFunctionDO.getIdentifier()) + .value(val != null ? val.toString() : null) + .updateTime(DateUtil.toLocalDateTime(new Date(time))) + .deviceId(device.getId()) + .thinkModelFunctionId(iotThinkModelFunctionDO.getId()) + .name(iotThinkModelFunctionDO.getName()) + .dataType(iotThinkModelFunctionDO.getProperty().getDataType().getType()) + .build(); + deviceDataRedisDAO.set(deviceData); + } + + /** + * 创建设备数据表 + * + * @param deviceType 设备类型 + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @param deviceKey 设备 Key + */ private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) { + String superTableName = getProductPropertySTableName(deviceType, productKey); + String dataBaseName = getDatabaseName(); + + List> maps = iotTdEngineService.describeSuperTable(dataBaseName, superTableName); List tagsFieldValues = new ArrayList<>(); - String SuperTableName = getProductPropertySTableName(deviceType, productKey); - List> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), SuperTableName); + if (maps != null) { - List> taggedNotesList = maps.stream().filter(map -> "TAG".equals(map.get("note"))).toList(); + List> taggedNotesList = maps.stream() + .filter(map -> "TAG".equals(map.get("note"))) + .toList(); + tagsFieldValues = FieldParser.parse(taggedNotesList.stream() .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) .collect(Collectors.toList())); + for (TdFieldDO tagsFieldValue : tagsFieldValues) { switch (tagsFieldValue.getFieldName()) { case "product_key" -> tagsFieldValue.setFieldValue(productKey); @@ -107,21 +157,49 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ } } - // 1. 创建设备数据表 - String tableName = "device_" + productKey.toLowerCase() + "_" + deviceName.toLowerCase(); + // 创建设备数据表 + String tableName = getDeviceTableName(productKey, deviceName); TableDO tableDto = new TableDO(); - tableDto.setDataBaseName(url.substring(url.lastIndexOf("/") + 1)); - tableDto.setSuperTableName(SuperTableName); + tableDto.setDataBaseName(dataBaseName); + tableDto.setSuperTableName(superTableName); tableDto.setTableName(tableName); tableDto.setTagsFieldValues(tagsFieldValues); + iotTdEngineService.createTable(tableDto); } - static String getProductPropertySTableName(Integer deviceType, String productKey) { + /** + * 获取数据库名称 + * + * @return 数据库名称 + */ + private String getDatabaseName() { + return url.substring(url.lastIndexOf("/") + 1); + } + + /** + * 获取产品属性表名 + * + * @param deviceType 设备类型 + * @param productKey 产品 Key + * @return 产品属性表名 + */ + private static String getProductPropertySTableName(Integer deviceType, String productKey) { return switch (deviceType) { case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); case 2 -> String.format("gateway_%s", productKey).toLowerCase(); default -> String.format("device_%s", productKey).toLowerCase(); }; } + + /** + * 获取设备表名 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 设备表名 + */ + private static String getDeviceTableName(String productKey, String deviceName) { + return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase()); + } } \ No newline at end of file