From 8e80a53a8bb37fe40f9a1d1ee5f243ce0f7b1ed5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 27 Jan 2025 16:50:10 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E3=80=91IoT=EF=BC=9A=E9=83=A8=E5=88=86=E5=AE=9E=E7=8E=B0=20Iot?= =?UTF-8?q?DevicePropertyMessageConsumer=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E7=9A=84=E8=AE=B0=E5=BD=95=EF=BC=88=E5=B7=AE?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E5=B1=9E=E6=80=A7=E7=9A=84=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceDataController.java | 8 +- .../dataobject/device/IotDeviceDataDO.java | 82 --------- .../device/IotDevicePropertyDO.java | 35 ++++ .../iot/dal/redis/RedisKeyConstants.java | 19 +- .../redis/device/DevicePropertyRedisDAO.java | 54 ++++++ .../device/DeviceReportTimeRedisDAO.java | 27 +++ .../redis/deviceData/DeviceDataRedisDAO.java | 43 ----- .../tdengine/IotDevicePropertyDataMapper.java | 1 + .../iot/emq/service/EmqxServiceImpl.java | 2 +- .../IotDevicePropertyMessageConsumer.java | 12 +- .../iot/service/device/IotDeviceService.java | 1 + .../service/device/IotDeviceServiceImpl.java | 2 - .../device/data/IotDevicePropertyService.java | 10 +- .../data/IotDevicePropertyServiceImpl.java | 163 ++++++++++-------- .../thingmodel/IotThingModelService.java | 1 + 15 files changed, 245 insertions(+), 215 deletions(-) delete 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/dataobject/device/IotDevicePropertyDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java delete 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-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 index 15366cf9c3..8012ec2ec4 100644 --- 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 @@ -4,7 +4,7 @@ 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.deviceData.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; @@ -28,18 +28,14 @@ public class IotDeviceDataController { @Resource private IotDevicePropertyService deviceDataService; - @Resource - private IotDeviceLogService iotDeviceLogDataService; - - @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性 private IotDeviceLogService deviceLogDataService; // TODO @浩浩:这里的 /latest-list,包括方法名。 @GetMapping("/latest") @Operation(summary = "获取设备属性最新数据") public CommonResult> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { - List list = deviceDataService.getLatestDeviceProperties(deviceDataReqVO); + List list = deviceDataService.getLatestDeviceProperties(deviceDataReqVO); return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); } 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 deleted file mode 100644 index 63b732d20f..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ /dev/null @@ -1,82 +0,0 @@ -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.dal.dataobject.thingmodel.IotThingModelDO; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; - -/** - * IoT 设备数据 DO - * - * @author haohao - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class IotDeviceDataDO { - - /** - * 设备编号 - *

- * 关联 {@link IotDeviceDO#getId()} - */ - private Long deviceId; - - /** - * 物模型编号 - *

- * 关联 {@link IotThingModelDO#getId()} - */ - private Long thingModelId; - - /** - * 产品标识 - *

- * 关联 {@link IotProductDO#getProductKey()} - */ - private String productKey; - - /** - * 设备名称 - *

- * 冗余 {@link IotDeviceDO#getDeviceName()} - */ - private String deviceName; - - /** - * 属性标识符 - *

- * 关联 {@link IotThingModelDO#getIdentifier()} - */ - private String identifier; - - /** - * 属性名称 - *

- * 关联 {@link IotThingModelDO#getName()} - */ - private String name; - - /** - * 数据类型 - *

- * 关联 {@link IotThingModelDO#getProperty()#getDataType()} - */ - 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/dataobject/device/IotDevicePropertyDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDevicePropertyDO.java new file mode 100644 index 0000000000..afb3288941 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDevicePropertyDO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.device; + +import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * IoT 设备属性项 Redis DO + * + * @see cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants#DEVICE_PROPERTY + * @see DevicePropertyRedisDAO + * + * @author haohao + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDevicePropertyDO { + + /** + * 属性值(最新) + */ + private Object value; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + +} \ 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/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index 25ea7a2926..04858248fa 100644 --- 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 @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.redis; - +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; /** * Iot Redis Key 枚举类 @@ -10,11 +10,20 @@ package cn.iocoder.yudao.module.iot.dal.redis; public interface RedisKeyConstants { /** - * 设备属性数据缓存 + * 设备属性数据缓存,采用 HASH 结构 *

- * KEY 格式:device_property_data:{deviceId} - * VALUE 数据类型:String 设备属性数据 + * KEY 格式:device_property:{deviceKey} + * HASH KEY:identifier 属性标识 + * VALUE 数据类型:String(JSON) {@link IotDevicePropertyDO} */ - String DEVICE_PROPERTY_DATA = "device_property_data:%s_%s_%s"; + String DEVICE_PROPERTY = "device_property:%s"; + + /** + * 设备的最后上报时间,采用 ZSET 结构 + * + * KEY 格式:{deviceKey} + * SCORE:上报时间 + */ + String DEVICE_REPORT_TIME = "device_report_time"; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java new file mode 100644 index 0000000000..fa25b84720 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.dal.redis.device; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.util.Collections; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants.DEVICE_PROPERTY; + +/** + * {@link IotDevicePropertyDO} 的 Redis DAO + */ +@Repository +public class DevicePropertyRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public Map get(String deviceKey) { + String redisKey = formatKey(deviceKey); + Map entries = stringRedisTemplate.opsForHash().entries(redisKey); + if (CollUtil.isEmpty(entries)) { + return Collections.emptyMap(); + } + return convertMap(entries.values(), key -> (String) key, + value -> JsonUtils.parseObject((String) value, IotDevicePropertyDO.class)); + } + + public void set(String deviceKey, Map properties) { + if (CollUtil.isEmpty(properties)) { + return; + } + String redisKey = formatKey(deviceKey); + stringRedisTemplate.opsForHash().putAll(redisKey, convertMap(properties.entrySet(), + Map.Entry::getKey, + entry -> JsonUtils.toJsonString(entry.getValue()))); + } + + public void delete(String deviceKey) { + String redisKey = formatKey(deviceKey); + stringRedisTemplate.delete(redisKey); + } + + private static String formatKey(String deviceKey) { + return String.format(DEVICE_PROPERTY, deviceKey); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java new file mode 100644 index 0000000000..35c99a06e0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.dal.redis.device; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.time.LocalDateTime; + +/** + * 设备的最后上报时间的 Redis DAO + * + * @author 芋道源码 + */ +@Repository +public class DeviceReportTimeRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public void update(String deviceKey, LocalDateTime reportTime) { + stringRedisTemplate.opsForZSet().add(RedisKeyConstants.DEVICE_REPORT_TIME, deviceKey, + LocalDateTimeUtil.toEpochMilli(reportTime)); + } + +} 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 deleted file mode 100644 index b1b69f8dce..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java +++ /dev/null @@ -1,43 +0,0 @@ -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/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java index 42b5e01eb8..e8df639c29 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java @@ -77,6 +77,7 @@ public interface IotDevicePropertyDataMapper { void alterProductPropertySTableDropField(@Param("productKey") String productKey, @Param("field") TDengineTableField field); + // TODO @芋艿:待实现 /** * 获取历史数据列表 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index ca9a6bac7b..6d45b9be9a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -39,7 +39,7 @@ public class EmqxServiceImpl implements EmqxService { // .deviceName(deviceName) // .properties(message) // TODO 芋艿:临时去掉,看看 .build(); - iotDeviceDataService.saveDeviceData(createDTO); +// iotDeviceDataService.saveDeviceProperty(createDTO); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java index 63b4c9a5e0..3f7fe10890 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.iot.mq.consumer.device; +import cn.hutool.core.util.ObjectUtil; +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 cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import lombok.extern.slf4j.Slf4j; @@ -24,11 +27,14 @@ public class IotDevicePropertyMessageConsumer { @EventListener @Async public void onMessage(IotDeviceMessage message) { + if (ObjectUtil.notEqual(message.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType()) + || ObjectUtil.notEqual(message.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())) { + return; + } log.info("[onMessage][消息内容({})]", message); - // 设备日志记录 - // TODO @芋艿:重新写下 -// deviceLogDataService.createDeviceLog(message); + // 保存设备属性 + deviceDataService.saveDeviceProperty(message); } } 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 adf3304d02..f01460a1b5 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 @@ -113,6 +113,7 @@ public interface IotDeviceService { */ Long getDeviceCountByGroupId(Long groupId); + // TODO @芋艿:增加缓存 /** * 根据产品 key 和设备名称,获得设备信息 * 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 6a28b27f34..683570916f 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 @@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -247,7 +246,6 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @Override - @TenantIgnore public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) { return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java index 828f2fef5e..b5fce2bc17 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import jakarta.validation.Valid; import java.util.List; @@ -27,9 +27,9 @@ public interface IotDevicePropertyService { /** * 保存设备数据 * - * @param createDTO 设备数据 + * @param message 设备消息 */ - void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); + void saveDeviceProperty(IotDeviceMessage message); /** * 模拟设备 @@ -44,7 +44,7 @@ public interface IotDevicePropertyService { * @param deviceId 设备编号 * @return 设备属性最新数据 */ - List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceId); + List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceId); /** * 获得设备属性历史数据 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index 741ba70cb3..61355e02df 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -1,27 +1,26 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.DateUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; 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.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; -import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; @@ -31,15 +30,13 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.time.ZoneId; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_CONTENT_JSON_PARSE_ERROR; /** @@ -77,7 +74,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { private IotProductService productService; @Resource - private DeviceDataRedisDAO deviceDataRedisDAO; + private DevicePropertyRedisDAO deviceDataRedisDAO; @Resource private IotDevicePropertyDataMapper devicePropertyDataMapper; @@ -126,13 +123,41 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } @Override - public void saveDeviceData(IotDevicePropertyReportReqDTO createDTO) { - // TODO 芋艿:这块需要实现 - // 1. 根据产品 key 和设备名称,获得设备信息 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName()); - // 2. 解析消息,保存数据 - JSONObject jsonObject = new JSONObject(createDTO.getProperties()); - log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); + public void saveDeviceProperty(IotDeviceMessage message) { + if (!(message.getData() instanceof Map)) { + log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message); + return; + } + // 1. 获得设备信息 + IotDeviceDO device = TenantUtils.executeIgnore(() -> + deviceService.getDeviceByProductKeyAndDeviceName(message.getProductKey(), message.getDeviceName())); + if (device == null) { + log.error("[saveDeviceProperty][消息({}) 对应的设备不存在]", message); + return; + } + + // 2. 根据物模型,拼接合法的属性 + List thingModels = TenantUtils.executeIgnore(() -> + thingModelService.getThingModelListByProductId(device.getProductId())); + Map properties = new HashMap<>(); + ((Map) message.getData()).forEach((key, value) -> { + if (CollUtil.findOne(thingModels, thingModel -> thingModel.getIdentifier().equals(key)) == null) { + log.error("[saveDeviceProperty][消息({}) 的属性({}) 不存在]", message, key); + return; + } + properties.put((String) key, value); + }); + if (CollUtil.isEmpty(properties)) { + log.error("[saveDeviceProperty][消息({}) 没有合法的属性]", message); + return; + } + + // 3.1 保存属性【数据】 + // TODO 芋艿,未实现 + + // 3.2 保存属性【日志】 + deviceDataRedisDAO.set(message.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey, + entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build())); } //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 @@ -163,62 +188,64 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } @Override - public List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { - List list = new ArrayList<>(); - // 1. 获取设备信息 - IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); - // 2. 获取设备属性最新数据 - List thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); - thingModelList = filterList(thingModelList, thingModel -> IotThingModelTypeEnum.PROPERTY.getType() - .equals(thingModel.getType())); - - // 3. 过滤标识符和属性名称 - if (deviceDataReqVO.getIdentifier() != null) { - thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier() - .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())); - } - if (deviceDataReqVO.getName() != null) { - thingModelList = filterList(thingModelList, thingModel -> thingModel.getName() - .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())); - } - // 4. 获取设备属性最新数据 - thingModelList.forEach(thingModel -> { - IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier()); - if (deviceData == null) { - deviceData = new IotDeviceDataDO(); - deviceData.setProductKey(device.getProductKey()); - deviceData.setDeviceName(device.getDeviceName()); - deviceData.setIdentifier(thingModel.getIdentifier()); - deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); - deviceData.setThingModelId(thingModel.getId()); - deviceData.setName(thingModel.getName()); - deviceData.setDataType(thingModel.getProperty().getDataType()); - } - list.add(deviceData); - }); - return list; + public List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { +// List list = new ArrayList<>(); +// // 1. 获取设备信息 +// IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); +// // 2. 获取设备属性最新数据 +// List thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); +// thingModelList = filterList(thingModelList, thingModel -> IotThingModelTypeEnum.PROPERTY.getType() +// .equals(thingModel.getType())); +// +// // 3. 过滤标识符和属性名称 +// if (deviceDataReqVO.getIdentifier() != null) { +// thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier() +// .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())); +// } +// if (deviceDataReqVO.getName() != null) { +// thingModelList = filterList(thingModelList, thingModel -> thingModel.getName() +// .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())); +// } +// // 4. 获取设备属性最新数据 +// thingModelList.forEach(thingModel -> { +// IotDevicePropertyDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier()); +// if (deviceData == null) { +// deviceData = new IotDevicePropertyDO(); +// deviceData.setProductKey(device.getProductKey()); +// deviceData.setDeviceName(device.getDeviceName()); +// deviceData.setIdentifier(thingModel.getIdentifier()); +// deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); +// deviceData.setThingModelId(thingModel.getId()); +// deviceData.setName(thingModel.getName()); +// deviceData.setDataType(thingModel.getProperty().getDataType()); +// } +// list.add(deviceData); +// }); +// return list; + return null; // TODO 芋艿:晚点实现 } @Override public PageResult> getHistoryDeviceProperties(IotDeviceDataPageReqVO deviceDataReqVO) { - PageResult> pageResult = new PageResult<>(); - // 1. 获取设备信息 - IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); - // 2. 获取设备属性历史数据 - SelectVisualDO selectVisualDO = new SelectVisualDO(); - selectVisualDO.setDataBaseName(getDatabaseName()); - selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); - selectVisualDO.setDeviceKey(device.getDeviceKey()); - selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier()); - selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); - selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); - Map params = new HashMap<>(); - params.put("rows", deviceDataReqVO.getPageSize()); - params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); - selectVisualDO.setParams(params); - pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO)); - pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO)); - return pageResult; +// PageResult> pageResult = new PageResult<>(); +// // 1. 获取设备信息 +// IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); +// // 2. 获取设备属性历史数据 +// SelectVisualDO selectVisualDO = new SelectVisualDO(); +// selectVisualDO.setDataBaseName(getDatabaseName()); +// selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); +// selectVisualDO.setDeviceKey(device.getDeviceKey()); +// selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier()); +// selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); +// selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); +// Map params = new HashMap<>(); +// params.put("rows", deviceDataReqVO.getPageSize()); +// params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); +// selectVisualDO.setParams(params); +// pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO)); +// pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO)); +// return pageResult; + return null; // TODO 芋艿:晚点实现 } private String getDatabaseName() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index d68b3429e4..71d47a53f5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -46,6 +46,7 @@ public interface IotThingModelService { */ IotThingModelDO getThingModel(Long id); + // TODO @芋艿:增加缓存 /** * 获得产品物模型列表 *