Commit 8e80a53a8bb37fe40f9a1d1ee5f243ce0f7b1ed5

Authored by YunaiV
1 parent b319485c

【功能优化】IoT:部分实现 IotDevicePropertyMessageConsumer,支持缓存的记录(差设备属性的日志记录)

Showing 15 changed files with 245 additions and 215 deletions
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; @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; 6 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*;
7 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; 7 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; 8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
9 import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; 9 import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
10 import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; 10 import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
@@ -28,18 +28,14 @@ public class IotDeviceDataController { @@ -28,18 +28,14 @@ public class IotDeviceDataController {
28 28
29 @Resource 29 @Resource
30 private IotDevicePropertyService deviceDataService; 30 private IotDevicePropertyService deviceDataService;
31 -  
32 @Resource 31 @Resource
33 - private IotDeviceLogService iotDeviceLogDataService;  
34 -  
35 - @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性  
36 private IotDeviceLogService deviceLogDataService; 32 private IotDeviceLogService deviceLogDataService;
37 33
38 // TODO @浩浩:这里的 /latest-list,包括方法名。 34 // TODO @浩浩:这里的 /latest-list,包括方法名。
39 @GetMapping("/latest") 35 @GetMapping("/latest")
40 @Operation(summary = "获取设备属性最新数据") 36 @Operation(summary = "获取设备属性最新数据")
41 public CommonResult<List<IotDeviceDataRespVO>> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { 37 public CommonResult<List<IotDeviceDataRespVO>> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) {
42 - List<IotDeviceDataDO> list = deviceDataService.getLatestDeviceProperties(deviceDataReqVO); 38 + List<IotDevicePropertyDO> list = deviceDataService.getLatestDeviceProperties(deviceDataReqVO);
43 return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); 39 return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class));
44 } 40 }
45 41
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java deleted
1 -package cn.iocoder.yudao.module.iot.dal.dataobject.device;  
2 -  
3 -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;  
4 -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;  
5 -import lombok.AllArgsConstructor;  
6 -import lombok.Builder;  
7 -import lombok.Data;  
8 -import lombok.NoArgsConstructor;  
9 -  
10 -import java.time.LocalDateTime;  
11 -  
12 -/**  
13 - * IoT 设备数据 DO  
14 - *  
15 - * @author haohao  
16 - */  
17 -@Data  
18 -@Builder  
19 -@NoArgsConstructor  
20 -@AllArgsConstructor  
21 -public class IotDeviceDataDO {  
22 -  
23 - /**  
24 - * 设备编号  
25 - * <p>  
26 - * 关联 {@link IotDeviceDO#getId()}  
27 - */  
28 - private Long deviceId;  
29 -  
30 - /**  
31 - * 物模型编号  
32 - * <p>  
33 - * 关联 {@link IotThingModelDO#getId()}  
34 - */  
35 - private Long thingModelId;  
36 -  
37 - /**  
38 - * 产品标识  
39 - * <p>  
40 - * 关联 {@link IotProductDO#getProductKey()}  
41 - */  
42 - private String productKey;  
43 -  
44 - /**  
45 - * 设备名称  
46 - * <p>  
47 - * 冗余 {@link IotDeviceDO#getDeviceName()}  
48 - */  
49 - private String deviceName;  
50 -  
51 - /**  
52 - * 属性标识符  
53 - * <p>  
54 - * 关联 {@link IotThingModelDO#getIdentifier()}  
55 - */  
56 - private String identifier;  
57 -  
58 - /**  
59 - * 属性名称  
60 - * <p>  
61 - * 关联 {@link IotThingModelDO#getName()}  
62 - */  
63 - private String name;  
64 -  
65 - /**  
66 - * 数据类型  
67 - * <p>  
68 - * 关联 {@link IotThingModelDO#getProperty()#getDataType()}  
69 - */  
70 - private String dataType;  
71 -  
72 - /**  
73 - * 更新时间  
74 - */  
75 - private LocalDateTime updateTime;  
76 -  
77 - /**  
78 - * 最新值  
79 - */  
80 - private String value;  
81 -  
82 -}  
83 \ No newline at end of file 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDevicePropertyDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.dataobject.device;
  2 +
  3 +import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Builder;
  6 +import lombok.Data;
  7 +import lombok.NoArgsConstructor;
  8 +
  9 +import java.time.LocalDateTime;
  10 +
  11 +/**
  12 + * IoT 设备属性项 Redis DO
  13 + *
  14 + * @see cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants#DEVICE_PROPERTY
  15 + * @see DevicePropertyRedisDAO
  16 + *
  17 + * @author haohao
  18 + */
  19 +@Data
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class IotDevicePropertyDO {
  24 +
  25 + /**
  26 + * 属性值(最新)
  27 + */
  28 + private Object value;
  29 +
  30 + /**
  31 + * 更新时间
  32 + */
  33 + private LocalDateTime updateTime;
  34 +
  35 +}
0 \ No newline at end of file 36 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java
1 package cn.iocoder.yudao.module.iot.dal.redis; 1 package cn.iocoder.yudao.module.iot.dal.redis;
2 2
3 - 3 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
4 4
5 /** 5 /**
6 * Iot Redis Key 枚举类 6 * Iot Redis Key 枚举类
@@ -10,11 +10,20 @@ package cn.iocoder.yudao.module.iot.dal.redis; @@ -10,11 +10,20 @@ package cn.iocoder.yudao.module.iot.dal.redis;
10 public interface RedisKeyConstants { 10 public interface RedisKeyConstants {
11 11
12 /** 12 /**
13 - * 设备属性数据缓存 13 + * 设备属性数据缓存,采用 HASH 结构
14 * <p> 14 * <p>
15 - * KEY 格式:device_property_data:{deviceId}  
16 - * VALUE 数据类型:String 设备属性数据 15 + * KEY 格式:device_property:{deviceKey}
  16 + * HASH KEY:identifier 属性标识
  17 + * VALUE 数据类型:String(JSON) {@link IotDevicePropertyDO}
  18 + */
  19 + String DEVICE_PROPERTY = "device_property:%s";
  20 +
  21 + /**
  22 + * 设备的最后上报时间,采用 ZSET 结构
  23 + *
  24 + * KEY 格式:{deviceKey}
  25 + * SCORE:上报时间
17 */ 26 */
18 - String DEVICE_PROPERTY_DATA = "device_property_data:%s_%s_%s"; 27 + String DEVICE_REPORT_TIME = "device_report_time";
19 28
20 } 29 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.redis.device;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  5 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
  6 +import jakarta.annotation.Resource;
  7 +import org.springframework.data.redis.core.StringRedisTemplate;
  8 +import org.springframework.stereotype.Repository;
  9 +
  10 +import java.util.Collections;
  11 +import java.util.Map;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  14 +import static cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants.DEVICE_PROPERTY;
  15 +
  16 +/**
  17 + * {@link IotDevicePropertyDO} 的 Redis DAO
  18 + */
  19 +@Repository
  20 +public class DevicePropertyRedisDAO {
  21 +
  22 + @Resource
  23 + private StringRedisTemplate stringRedisTemplate;
  24 +
  25 + public Map<String, IotDevicePropertyDO> get(String deviceKey) {
  26 + String redisKey = formatKey(deviceKey);
  27 + Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(redisKey);
  28 + if (CollUtil.isEmpty(entries)) {
  29 + return Collections.emptyMap();
  30 + }
  31 + return convertMap(entries.values(), key -> (String) key,
  32 + value -> JsonUtils.parseObject((String) value, IotDevicePropertyDO.class));
  33 + }
  34 +
  35 + public void set(String deviceKey, Map<String, IotDevicePropertyDO> properties) {
  36 + if (CollUtil.isEmpty(properties)) {
  37 + return;
  38 + }
  39 + String redisKey = formatKey(deviceKey);
  40 + stringRedisTemplate.opsForHash().putAll(redisKey, convertMap(properties.entrySet(),
  41 + Map.Entry::getKey,
  42 + entry -> JsonUtils.toJsonString(entry.getValue())));
  43 + }
  44 +
  45 + public void delete(String deviceKey) {
  46 + String redisKey = formatKey(deviceKey);
  47 + stringRedisTemplate.delete(redisKey);
  48 + }
  49 +
  50 + private static String formatKey(String deviceKey) {
  51 + return String.format(DEVICE_PROPERTY, deviceKey);
  52 + }
  53 +
  54 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.redis.device;
  2 +
  3 +import cn.hutool.core.date.LocalDateTimeUtil;
  4 +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.data.redis.core.StringRedisTemplate;
  7 +import org.springframework.stereotype.Repository;
  8 +
  9 +import java.time.LocalDateTime;
  10 +
  11 +/**
  12 + * 设备的最后上报时间的 Redis DAO
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Repository
  17 +public class DeviceReportTimeRedisDAO {
  18 +
  19 + @Resource
  20 + private StringRedisTemplate stringRedisTemplate;
  21 +
  22 + public void update(String deviceKey, LocalDateTime reportTime) {
  23 + stringRedisTemplate.opsForZSet().add(RedisKeyConstants.DEVICE_REPORT_TIME, deviceKey,
  24 + LocalDateTimeUtil.toEpochMilli(reportTime));
  25 + }
  26 +
  27 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java deleted
1 -package cn.iocoder.yudao.module.iot.dal.redis.deviceData;  
2 -  
3 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
4 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
5 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;  
6 -import jakarta.annotation.Resource;  
7 -import org.springframework.data.redis.core.StringRedisTemplate;  
8 -import org.springframework.stereotype.Repository;  
9 -  
10 -import java.util.Collection;  
11 -import java.util.List;  
12 -import java.util.concurrent.TimeUnit;  
13 -  
14 -import static cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants.DEVICE_PROPERTY_DATA;  
15 -  
16 -/**  
17 - * {@link IotDeviceDataDO} 的 Redis DAO  
18 - */  
19 -@Repository  
20 -public class DeviceDataRedisDAO {  
21 -  
22 - @Resource  
23 - private StringRedisTemplate stringRedisTemplate;  
24 -  
25 - public IotDeviceDataDO get(String productKey, String deviceName, String identifier) {  
26 - String redisKey = formatKey(productKey, deviceName, identifier);  
27 - return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), IotDeviceDataDO.class);  
28 - }  
29 -  
30 - public void set(IotDeviceDataDO deviceData) {  
31 - String redisKey = formatKey(deviceData.getProductKey(), deviceData.getDeviceName(), deviceData.getIdentifier());  
32 - stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(deviceData));  
33 - }  
34 -  
35 - public void delete(String productKey, String deviceName, String identifier) {  
36 - String redisKey = formatKey(productKey, deviceName, identifier);  
37 - stringRedisTemplate.delete(redisKey);  
38 - }  
39 -  
40 - private static String formatKey(String productKey, String deviceName, String identifier) {  
41 - return String.format(DEVICE_PROPERTY_DATA, productKey, deviceName, identifier);  
42 - }  
43 -}  
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 { @@ -77,6 +77,7 @@ public interface IotDevicePropertyDataMapper {
77 void alterProductPropertySTableDropField(@Param("productKey") String productKey, 77 void alterProductPropertySTableDropField(@Param("productKey") String productKey,
78 @Param("field") TDengineTableField field); 78 @Param("field") TDengineTableField field);
79 79
  80 + // TODO @芋艿:待实现
80 /** 81 /**
81 * 获取历史数据列表 82 * 获取历史数据列表
82 * 83 *
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 { @@ -39,7 +39,7 @@ public class EmqxServiceImpl implements EmqxService {
39 // .deviceName(deviceName) 39 // .deviceName(deviceName)
40 // .properties(message) // TODO 芋艿:临时去掉,看看 40 // .properties(message) // TODO 芋艿:临时去掉,看看
41 .build(); 41 .build();
42 - iotDeviceDataService.saveDeviceData(createDTO); 42 +// iotDeviceDataService.saveDeviceProperty(createDTO);
43 } 43 }
44 } 44 }
45 45
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java
1 package cn.iocoder.yudao.module.iot.mq.consumer.device; 1 package cn.iocoder.yudao.module.iot.mq.consumer.device;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
  5 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
3 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; 6 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
4 import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; 7 import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
5 import lombok.extern.slf4j.Slf4j; 8 import lombok.extern.slf4j.Slf4j;
@@ -24,11 +27,14 @@ public class IotDevicePropertyMessageConsumer { @@ -24,11 +27,14 @@ public class IotDevicePropertyMessageConsumer {
24 @EventListener 27 @EventListener
25 @Async 28 @Async
26 public void onMessage(IotDeviceMessage message) { 29 public void onMessage(IotDeviceMessage message) {
  30 + if (ObjectUtil.notEqual(message.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())
  31 + || ObjectUtil.notEqual(message.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())) {
  32 + return;
  33 + }
27 log.info("[onMessage][消息内容({})]", message); 34 log.info("[onMessage][消息内容({})]", message);
28 35
29 - // 设备日志记录  
30 - // TODO @芋艿:重新写下  
31 -// deviceLogDataService.createDeviceLog(message); 36 + // 保存设备属性
  37 + deviceDataService.saveDeviceProperty(message);
32 } 38 }
33 39
34 } 40 }
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 { @@ -113,6 +113,7 @@ public interface IotDeviceService {
113 */ 113 */
114 Long getDeviceCountByGroupId(Long groupId); 114 Long getDeviceCountByGroupId(Long groupId);
115 115
  116 + // TODO @芋艿:增加缓存
116 /** 117 /**
117 * 根据产品 key 和设备名称,获得设备信息 118 * 根据产品 key 和设备名称,获得设备信息
118 * 119 *
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; @@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException;
8 import cn.iocoder.yudao.framework.common.pojo.PageResult; 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
10 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; 10 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
11 -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;  
12 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 11 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
13 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; 12 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
14 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 13 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
@@ -247,7 +246,6 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -247,7 +246,6 @@ public class IotDeviceServiceImpl implements IotDeviceService {
247 } 246 }
248 247
249 @Override 248 @Override
250 - @TenantIgnore  
251 public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) { 249 public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) {
252 return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); 250 return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName);
253 } 251 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java
1 package cn.iocoder.yudao.module.iot.service.device.data; 1 package cn.iocoder.yudao.module.iot.service.device.data;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;  
5 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; 4 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO;
6 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; 5 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO;
7 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; 6 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
  7 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
8 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
9 9
10 import java.util.List; 10 import java.util.List;
@@ -27,9 +27,9 @@ public interface IotDevicePropertyService { @@ -27,9 +27,9 @@ public interface IotDevicePropertyService {
27 /** 27 /**
28 * 保存设备数据 28 * 保存设备数据
29 * 29 *
30 - * @param createDTO 设备数据 30 + * @param message 设备消息
31 */ 31 */
32 - void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); 32 + void saveDeviceProperty(IotDeviceMessage message);
33 33
34 /** 34 /**
35 * 模拟设备 35 * 模拟设备
@@ -44,7 +44,7 @@ public interface IotDevicePropertyService { @@ -44,7 +44,7 @@ public interface IotDevicePropertyService {
44 * @param deviceId 设备编号 44 * @param deviceId 设备编号
45 * @return 设备属性最新数据 45 * @return 设备属性最新数据
46 */ 46 */
47 - List<IotDeviceDataDO> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceId); 47 + List<IotDevicePropertyDO> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceId);
48 48
49 /** 49 /**
50 * 获得设备属性历史数据 50 * 获得设备属性历史数据
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java
1 package cn.iocoder.yudao.module.iot.service.device.data; 1 package cn.iocoder.yudao.module.iot.service.device.data;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.hutool.core.date.DateUtil;  
5 import cn.hutool.core.map.MapUtil; 4 import cn.hutool.core.map.MapUtil;
6 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
7 import cn.hutool.json.JSONObject; 6 import cn.hutool.json.JSONObject;
8 import cn.hutool.json.JSONUtil; 7 import cn.hutool.json.JSONUtil;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; 9 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
11 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; 10 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO;
12 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; 11 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO;
13 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; 12 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs;
14 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 13 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
15 -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; 14 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
16 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; 15 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
17 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO;  
18 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; 16 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
19 -import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; 17 +import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO;
20 import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; 18 import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper;
21 import cn.iocoder.yudao.module.iot.enums.IotConstants; 19 import cn.iocoder.yudao.module.iot.enums.IotConstants;
22 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; 20 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
23 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; 21 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
24 import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; 22 import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField;
  23 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
25 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; 24 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
26 import cn.iocoder.yudao.module.iot.service.product.IotProductService; 25 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
27 import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; 26 import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
@@ -31,15 +30,13 @@ import lombok.extern.slf4j.Slf4j; @@ -31,15 +30,13 @@ import lombok.extern.slf4j.Slf4j;
31 import org.springframework.beans.factory.annotation.Value; 30 import org.springframework.beans.factory.annotation.Value;
32 import org.springframework.stereotype.Service; 31 import org.springframework.stereotype.Service;
33 32
34 -import java.time.ZoneId;  
35 import java.util.ArrayList; 33 import java.util.ArrayList;
36 import java.util.HashMap; 34 import java.util.HashMap;
37 import java.util.List; 35 import java.util.List;
38 import java.util.Map; 36 import java.util.Map;
39 37
40 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 38 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
41 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;  
42 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; 39 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
43 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_CONTENT_JSON_PARSE_ERROR; 40 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_CONTENT_JSON_PARSE_ERROR;
44 41
45 /** 42 /**
@@ -77,7 +74,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { @@ -77,7 +74,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
77 private IotProductService productService; 74 private IotProductService productService;
78 75
79 @Resource 76 @Resource
80 - private DeviceDataRedisDAO deviceDataRedisDAO; 77 + private DevicePropertyRedisDAO deviceDataRedisDAO;
81 78
82 @Resource 79 @Resource
83 private IotDevicePropertyDataMapper devicePropertyDataMapper; 80 private IotDevicePropertyDataMapper devicePropertyDataMapper;
@@ -126,13 +123,41 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { @@ -126,13 +123,41 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
126 } 123 }
127 124
128 @Override 125 @Override
129 - public void saveDeviceData(IotDevicePropertyReportReqDTO createDTO) {  
130 - // TODO 芋艿:这块需要实现  
131 - // 1. 根据产品 key 和设备名称,获得设备信息  
132 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName());  
133 - // 2. 解析消息,保存数据  
134 - JSONObject jsonObject = new JSONObject(createDTO.getProperties());  
135 - log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); 126 + public void saveDeviceProperty(IotDeviceMessage message) {
  127 + if (!(message.getData() instanceof Map)) {
  128 + log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message);
  129 + return;
  130 + }
  131 + // 1. 获得设备信息
  132 + IotDeviceDO device = TenantUtils.executeIgnore(() ->
  133 + deviceService.getDeviceByProductKeyAndDeviceName(message.getProductKey(), message.getDeviceName()));
  134 + if (device == null) {
  135 + log.error("[saveDeviceProperty][消息({}) 对应的设备不存在]", message);
  136 + return;
  137 + }
  138 +
  139 + // 2. 根据物模型,拼接合法的属性
  140 + List<IotThingModelDO> thingModels = TenantUtils.executeIgnore(() ->
  141 + thingModelService.getThingModelListByProductId(device.getProductId()));
  142 + Map<String, Object> properties = new HashMap<>();
  143 + ((Map<?, ?>) message.getData()).forEach((key, value) -> {
  144 + if (CollUtil.findOne(thingModels, thingModel -> thingModel.getIdentifier().equals(key)) == null) {
  145 + log.error("[saveDeviceProperty][消息({}) 的属性({}) 不存在]", message, key);
  146 + return;
  147 + }
  148 + properties.put((String) key, value);
  149 + });
  150 + if (CollUtil.isEmpty(properties)) {
  151 + log.error("[saveDeviceProperty][消息({}) 没有合法的属性]", message);
  152 + return;
  153 + }
  154 +
  155 + // 3.1 保存属性【数据】
  156 + // TODO 芋艿,未实现
  157 +
  158 + // 3.2 保存属性【日志】
  159 + deviceDataRedisDAO.set(message.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey,
  160 + entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build()));
136 } 161 }
137 162
138 //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 163 //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化
@@ -163,62 +188,64 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { @@ -163,62 +188,64 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
163 } 188 }
164 189
165 @Override 190 @Override
166 - public List<IotDeviceDataDO> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) {  
167 - List<IotDeviceDataDO> list = new ArrayList<>();  
168 - // 1. 获取设备信息  
169 - IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId());  
170 - // 2. 获取设备属性最新数据  
171 - List<IotThingModelDO> thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey());  
172 - thingModelList = filterList(thingModelList, thingModel -> IotThingModelTypeEnum.PROPERTY.getType()  
173 - .equals(thingModel.getType()));  
174 -  
175 - // 3. 过滤标识符和属性名称  
176 - if (deviceDataReqVO.getIdentifier() != null) {  
177 - thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier()  
178 - .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase()));  
179 - }  
180 - if (deviceDataReqVO.getName() != null) {  
181 - thingModelList = filterList(thingModelList, thingModel -> thingModel.getName()  
182 - .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase()));  
183 - }  
184 - // 4. 获取设备属性最新数据  
185 - thingModelList.forEach(thingModel -> {  
186 - IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier());  
187 - if (deviceData == null) {  
188 - deviceData = new IotDeviceDataDO();  
189 - deviceData.setProductKey(device.getProductKey());  
190 - deviceData.setDeviceName(device.getDeviceName());  
191 - deviceData.setIdentifier(thingModel.getIdentifier());  
192 - deviceData.setDeviceId(deviceDataReqVO.getDeviceId());  
193 - deviceData.setThingModelId(thingModel.getId());  
194 - deviceData.setName(thingModel.getName());  
195 - deviceData.setDataType(thingModel.getProperty().getDataType());  
196 - }  
197 - list.add(deviceData);  
198 - });  
199 - return list; 191 + public List<IotDevicePropertyDO> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) {
  192 +// List<IotDevicePropertyDO> list = new ArrayList<>();
  193 +// // 1. 获取设备信息
  194 +// IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId());
  195 +// // 2. 获取设备属性最新数据
  196 +// List<IotThingModelDO> thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey());
  197 +// thingModelList = filterList(thingModelList, thingModel -> IotThingModelTypeEnum.PROPERTY.getType()
  198 +// .equals(thingModel.getType()));
  199 +//
  200 +// // 3. 过滤标识符和属性名称
  201 +// if (deviceDataReqVO.getIdentifier() != null) {
  202 +// thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier()
  203 +// .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase()));
  204 +// }
  205 +// if (deviceDataReqVO.getName() != null) {
  206 +// thingModelList = filterList(thingModelList, thingModel -> thingModel.getName()
  207 +// .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase()));
  208 +// }
  209 +// // 4. 获取设备属性最新数据
  210 +// thingModelList.forEach(thingModel -> {
  211 +// IotDevicePropertyDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier());
  212 +// if (deviceData == null) {
  213 +// deviceData = new IotDevicePropertyDO();
  214 +// deviceData.setProductKey(device.getProductKey());
  215 +// deviceData.setDeviceName(device.getDeviceName());
  216 +// deviceData.setIdentifier(thingModel.getIdentifier());
  217 +// deviceData.setDeviceId(deviceDataReqVO.getDeviceId());
  218 +// deviceData.setThingModelId(thingModel.getId());
  219 +// deviceData.setName(thingModel.getName());
  220 +// deviceData.setDataType(thingModel.getProperty().getDataType());
  221 +// }
  222 +// list.add(deviceData);
  223 +// });
  224 +// return list;
  225 + return null; // TODO 芋艿:晚点实现
200 } 226 }
201 227
202 @Override 228 @Override
203 public PageResult<Map<String, Object>> getHistoryDeviceProperties(IotDeviceDataPageReqVO deviceDataReqVO) { 229 public PageResult<Map<String, Object>> getHistoryDeviceProperties(IotDeviceDataPageReqVO deviceDataReqVO) {
204 - PageResult<Map<String, Object>> pageResult = new PageResult<>();  
205 - // 1. 获取设备信息  
206 - IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId());  
207 - // 2. 获取设备属性历史数据  
208 - SelectVisualDO selectVisualDO = new SelectVisualDO();  
209 - selectVisualDO.setDataBaseName(getDatabaseName());  
210 - selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()));  
211 - selectVisualDO.setDeviceKey(device.getDeviceKey());  
212 - selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier());  
213 - selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());  
214 - selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());  
215 - Map<String, Object> params = new HashMap<>();  
216 - params.put("rows", deviceDataReqVO.getPageSize());  
217 - params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize());  
218 - selectVisualDO.setParams(params);  
219 - pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO));  
220 - pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO));  
221 - return pageResult; 230 +// PageResult<Map<String, Object>> pageResult = new PageResult<>();
  231 +// // 1. 获取设备信息
  232 +// IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId());
  233 +// // 2. 获取设备属性历史数据
  234 +// SelectVisualDO selectVisualDO = new SelectVisualDO();
  235 +// selectVisualDO.setDataBaseName(getDatabaseName());
  236 +// selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()));
  237 +// selectVisualDO.setDeviceKey(device.getDeviceKey());
  238 +// selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier());
  239 +// selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());
  240 +// selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());
  241 +// Map<String, Object> params = new HashMap<>();
  242 +// params.put("rows", deviceDataReqVO.getPageSize());
  243 +// params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize());
  244 +// selectVisualDO.setParams(params);
  245 +// pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO));
  246 +// pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO));
  247 +// return pageResult;
  248 + return null; // TODO 芋艿:晚点实现
222 } 249 }
223 250
224 private String getDatabaseName() { 251 private String getDatabaseName() {
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 { @@ -46,6 +46,7 @@ public interface IotThingModelService {
46 */ 46 */
47 IotThingModelDO getThingModel(Long id); 47 IotThingModelDO getThingModel(Long id);
48 48
  49 + // TODO @芋艿:增加缓存
49 /** 50 /**
50 * 获得产品物模型列表 51 * 获得产品物模型列表
51 * 52 *