【新增功能】 设备数据存储和展示
This commit is contained in:
parent
3dafd31da6
commit
624f5283b3
|
@ -30,7 +30,7 @@ public enum IotProductFunctionTypeEnum implements IntArrayValuable {
|
||||||
*/
|
*/
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|
||||||
public static IotProductFunctionTypeEnum valueOf(Integer type) {
|
public static IotProductFunctionTypeEnum valueOfType(Integer type) {
|
||||||
for (IotProductFunctionTypeEnum value : values()) {
|
for (IotProductFunctionTypeEnum value : values()) {
|
||||||
if (value.getType().equals(type)) {
|
if (value.getType().equals(type)) {
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -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.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
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.device.IotDevicePageReqVO;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO;
|
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceRespVO;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
|
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO;
|
||||||
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.IotDeviceDO;
|
||||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
|
|
@ -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<List<IotDeviceDataRespVO>> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) {
|
||||||
|
List<IotDeviceDataDO> list = deviceDataService.getDevicePropertiesLatestData(deviceDataReqVO);
|
||||||
|
return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
|
@ -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.ExcelIgnoreUnannotated;
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
|
@ -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 io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -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.framework.common.validation.InEnum;
|
||||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
|
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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<IotDeviceDataRespVO> convert(Map<String, Object> deviceData, IotDeviceDO device){
|
||||||
|
// List<IotDeviceDataRespVO> 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;
|
||||||
|
// }
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
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 cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package cn.iocoder.yudao.module.iot.dal.redis;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iot Redis Key 枚举类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface RedisKeyConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备属性数据缓存
|
||||||
|
* <p>
|
||||||
|
* KEY 格式:device_property_data:{deviceId}
|
||||||
|
* VALUE 数据类型:String 设备属性数据
|
||||||
|
*/
|
||||||
|
String DEVICE_PROPERTY_DATA = "device_property_data:%s_%s_%s";
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.device;
|
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.deviceData.IotDeviceDataReqVO;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
|
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
|
||||||
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 jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IoT 设备数据 Service 接口
|
* IoT 设备数据 Service 接口
|
||||||
*
|
*
|
||||||
|
@ -23,4 +22,12 @@ public interface IotDeviceDataService {
|
||||||
* @param message 消息
|
* @param message 消息
|
||||||
*/
|
*/
|
||||||
void saveDeviceData(String productKey, String deviceName, String message);
|
void saveDeviceData(String productKey, String deviceName, String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得设备属性最新数据
|
||||||
|
*
|
||||||
|
* @param deviceId 设备编号
|
||||||
|
* @return 设备属性最新数据
|
||||||
|
*/
|
||||||
|
List<IotDeviceDataDO> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceId);
|
||||||
}
|
}
|
|
@ -1,13 +1,23 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.device;
|
package cn.iocoder.yudao.module.iot.service.device;
|
||||||
|
|
||||||
import cn.hutool.json.JSONObject;
|
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.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.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.tdengine.IotThingModelMessageService;
|
||||||
|
import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class IotDeviceDataServiceImpl implements IotDeviceDataService {
|
public class IotDeviceDataServiceImpl implements IotDeviceDataService {
|
||||||
|
@ -16,6 +26,11 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService {
|
||||||
private IotDeviceService deviceService;
|
private IotDeviceService deviceService;
|
||||||
@Resource
|
@Resource
|
||||||
private IotThingModelMessageService thingModelMessageService;
|
private IotThingModelMessageService thingModelMessageService;
|
||||||
|
@Resource
|
||||||
|
private IotThinkModelFunctionService thinkModelFunctionService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceDataRedisDAO deviceDataRedisDAO;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveDeviceData(String productKey, String deviceName, String message) {
|
public void saveDeviceData(String productKey, String deviceName, String message) {
|
||||||
|
@ -36,4 +51,44 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService {
|
||||||
.build();
|
.build();
|
||||||
thingModelMessageService.saveThingModelMessage(device, thingModelMessage);
|
thingModelMessageService.saveThingModelMessage(device, thingModelMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IotDeviceDataDO> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) {
|
||||||
|
List<IotDeviceDataDO> list = new ArrayList<>();
|
||||||
|
// 1. 获取设备信息
|
||||||
|
IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId());
|
||||||
|
// 2. 获取设备属性最新数据
|
||||||
|
List<IotThinkModelFunctionDO> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.device;
|
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 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.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
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.device.IotDevicePageReqVO;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
|
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO;
|
||||||
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.IotDeviceDO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
|
import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.tdengine;
|
package cn.iocoder.yudao.module.iot.service.tdengine;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
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.ThingModelProperty;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO;
|
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.product.IotProductDO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser;
|
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.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.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
|
||||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
|
import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -14,10 +14,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -27,9 +24,6 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
@Resource
|
@Resource
|
||||||
private IotTdEngineService iotTdEngineService;
|
private IotTdEngineService iotTdEngineService;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private TdRestApi tdRestApi;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.dynamic.datasource.tdengine.url}")
|
@Value("${spring.datasource.dynamic.datasource.tdengine.url}")
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
|
@ -37,39 +31,25 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) {
|
public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) {
|
||||||
// 1. 解析物模型,获得字段列表
|
// 1. 解析物模型,获得字段列表
|
||||||
List<TdFieldDO> schemaFields = new ArrayList<>();
|
List<TdFieldDO> schemaFields = new ArrayList<>();
|
||||||
schemaFields.add(TdFieldDO.builder().
|
schemaFields.add(TdFieldDO.builder()
|
||||||
fieldName("time").
|
.fieldName("time")
|
||||||
dataType("TIMESTAMP").
|
.dataType("TIMESTAMP")
|
||||||
build());
|
.build());
|
||||||
schemaFields.addAll(FieldParser.parse(thingModel));
|
schemaFields.addAll(FieldParser.parse(thingModel));
|
||||||
|
|
||||||
// 3. 设置超级表的标签
|
// 3. 设置超级表的标签
|
||||||
List<TdFieldDO> tagsFields = new ArrayList<>();
|
List<TdFieldDO> tagsFields = Arrays.asList(
|
||||||
tagsFields.add(TdFieldDO.builder().
|
TdFieldDO.builder().fieldName("product_key").dataType("NCHAR").dataLength(64).build(),
|
||||||
fieldName("product_key").
|
TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build(),
|
||||||
dataType("NCHAR").
|
TdFieldDO.builder().fieldName("device_name").dataType("NCHAR").dataLength(64).build(),
|
||||||
dataLength(64).
|
TdFieldDO.builder().fieldName("device_type").dataType("INT").build()
|
||||||
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());
|
|
||||||
|
|
||||||
// 4. 获取超级表的名称
|
// 4. 获取超级表的名称
|
||||||
String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey());
|
String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey());
|
||||||
|
|
||||||
// 5. 创建超级表
|
// 5. 创建超级表
|
||||||
String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
|
String dataBaseName = getDatabaseName();
|
||||||
iotTdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
|
iotTdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +61,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
List<TdFieldDO> newFields = FieldParser.parse(thingModel);
|
List<TdFieldDO> newFields = FieldParser.parse(thingModel);
|
||||||
|
|
||||||
updateTableFields(tbName, oldFields, newFields);
|
updateTableFields(tbName, oldFields, newFields);
|
||||||
} catch (Throwable e) {
|
} catch (Exception e) {
|
||||||
log.error("更新物模型超级表失败", e);
|
log.error("更新物模型超级表失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,14 +70,15 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
private List<TdFieldDO> getTableFields(String tableName) {
|
private List<TdFieldDO> getTableFields(String tableName) {
|
||||||
List<TdFieldDO> fields = new ArrayList<>();
|
List<TdFieldDO> fields = new ArrayList<>();
|
||||||
// 获取超级表的描述信息
|
// 获取超级表的描述信息
|
||||||
List<Map<String, Object>> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName);
|
List<Map<String, Object>> maps = iotTdEngineService.describeSuperTable(getDatabaseName(), tableName);
|
||||||
if (maps != null) {
|
if (maps != null) {
|
||||||
// 过滤掉 note 字段为 TAG 的记录
|
// 过滤掉 note 字段为 TAG 的记录和 time 字段
|
||||||
maps = maps.stream().filter(map -> !"TAG".equals(map.get("note"))).toList();
|
List<Map<String, Object>> filteredMaps = maps.stream()
|
||||||
// 过滤掉 time 字段
|
.filter(map -> !"TAG".equals(map.get("note")))
|
||||||
maps = maps.stream().filter(map -> !"time".equals(map.get("field"))).toList();
|
.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")))
|
.map(map -> List.of(map.get("field"), map.get("type"), map.get("length")))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
@ -113,7 +94,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
// 获取删除字段
|
// 获取删除字段
|
||||||
List<TdFieldDO> dropFields = getDropFields(oldFields, newFields);
|
List<TdFieldDO> dropFields = getDropFields(oldFields, newFields);
|
||||||
|
|
||||||
String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
|
String dataBaseName = getDatabaseName();
|
||||||
// 添加新增字段
|
// 添加新增字段
|
||||||
if (CollUtil.isNotEmpty(addFields)) {
|
if (CollUtil.isNotEmpty(addFields)) {
|
||||||
iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, addFields);
|
iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, addFields);
|
||||||
|
@ -131,25 +112,37 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
|
|
||||||
// 获取新增字段
|
// 获取新增字段
|
||||||
private List<TdFieldDO> getAddFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
private List<TdFieldDO> getAddFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
||||||
|
Set<String> oldFieldNames = oldFields.stream()
|
||||||
|
.map(TdFieldDO::getFieldName)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
return newFields.stream()
|
return newFields.stream()
|
||||||
.filter(f -> oldFields.stream().noneMatch(old -> old.getFieldName().equals(f.getFieldName())))
|
.filter(f -> !oldFieldNames.contains(f.getFieldName()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取修改字段
|
// 获取修改字段
|
||||||
private List<TdFieldDO> getModifyFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
private List<TdFieldDO> getModifyFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
||||||
|
Map<String, TdFieldDO> oldFieldMap = oldFields.stream()
|
||||||
|
.collect(Collectors.toMap(TdFieldDO::getFieldName, f -> f));
|
||||||
|
|
||||||
return newFields.stream()
|
return newFields.stream()
|
||||||
.filter(f -> oldFields.stream().anyMatch(old ->
|
.filter(f -> {
|
||||||
old.getFieldName().equals(f.getFieldName()) &&
|
TdFieldDO oldField = oldFieldMap.get(f.getFieldName());
|
||||||
(!old.getDataType().equals(f.getDataType()) || !Objects.equals(old.getDataLength(), f.getDataLength()))))
|
return oldField != null &&
|
||||||
|
(!oldField.getDataType().equals(f.getDataType()) ||
|
||||||
|
!Objects.equals(oldField.getDataLength(), f.getDataLength()));
|
||||||
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取删除字段
|
// 获取删除字段
|
||||||
private List<TdFieldDO> getDropFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
private List<TdFieldDO> getDropFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
||||||
|
Set<String> newFieldNames = newFields.stream()
|
||||||
|
.map(TdFieldDO::getFieldName)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
return oldFields.stream()
|
return oldFields.stream()
|
||||||
.filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()) &&
|
.filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()))
|
||||||
newFields.stream().noneMatch(n -> n.getFieldName().equals(f.getFieldName())))
|
.filter(f -> !newFieldNames.contains(f.getFieldName()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,13 +150,13 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) {
|
public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) {
|
||||||
ThingModelRespVO thingModel = buildThingModel(product, functionList);
|
ThingModelRespVO thingModel = buildThingModel(product, functionList);
|
||||||
|
|
||||||
if (thingModel.getModel().getProperties().isEmpty()) {
|
if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) {
|
||||||
log.warn("物模型属性列表为空,不创建超级表");
|
log.warn("物模型属性列表为空,不创建超级表");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey());
|
String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey());
|
||||||
String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
|
String dataBaseName = getDatabaseName();
|
||||||
Integer tableExists = iotTdEngineService.checkSuperTableExists(dataBaseName, superTableName);
|
Integer tableExists = iotTdEngineService.checkSuperTableExists(dataBaseName, superTableName);
|
||||||
|
|
||||||
if (tableExists != null && tableExists > 0) {
|
if (tableExists != null && tableExists > 0) {
|
||||||
|
@ -180,7 +173,8 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
|
|
||||||
ThingModelRespVO.Model model = new ThingModelRespVO.Model();
|
ThingModelRespVO.Model model = new ThingModelRespVO.Model();
|
||||||
List<ThingModelProperty> properties = functionList.stream()
|
List<ThingModelProperty> properties = functionList.stream()
|
||||||
.filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(IotProductFunctionTypeEnum.valueOf(function.getType())))
|
.filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(
|
||||||
|
IotProductFunctionTypeEnum.valueOfType(function.getType())))
|
||||||
.map(this::buildThingModelProperty)
|
.map(this::buildThingModelProperty)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
@ -191,14 +185,15 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
||||||
}
|
}
|
||||||
|
|
||||||
private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) {
|
private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) {
|
||||||
ThingModelProperty property = new ThingModelProperty();
|
ThingModelProperty property = BeanUtil.copyProperties(function, ThingModelProperty.class);
|
||||||
property.setIdentifier(function.getIdentifier());
|
|
||||||
property.setName(function.getName());
|
|
||||||
property.setDescription(function.getDescription());
|
|
||||||
property.setDataType(function.getProperty().getDataType());
|
property.setDataType(function.getProperty().getDataType());
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getDatabaseName() {
|
||||||
|
return url.substring(url.lastIndexOf("/") + 1);
|
||||||
|
}
|
||||||
|
|
||||||
static String getProductPropertySTableName(Integer deviceType, String productKey) {
|
static String getProductPropertySTableName(Integer deviceType, String productKey) {
|
||||||
return switch (deviceType) {
|
return switch (deviceType) {
|
||||||
case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase();
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,13 +1,16 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.tdengine;
|
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.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.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.FieldParser;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO;
|
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.TdFieldDO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
|
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.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.device.IotDeviceStatusEnum;
|
||||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
|
import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
|
||||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
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.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -36,11 +37,14 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
||||||
@Resource
|
@Resource
|
||||||
private IotTdEngineService iotTdEngineService;
|
private IotTdEngineService iotTdEngineService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DeviceDataRedisDAO deviceDataRedisDAO;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@TenantIgnore
|
@TenantIgnore
|
||||||
public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) {
|
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());
|
createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
|
||||||
// 更新设备状态
|
// 更新设备状态
|
||||||
|
@ -50,53 +54,99 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
||||||
iotDeviceService.updateDeviceStatus(updateReqVO);
|
iotDeviceService.updateDeviceStatus(updateReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 获取设备属性
|
// 获取设备属性
|
||||||
Map<String, Object> params = thingModelMessage.dataToMap();
|
Map<String, Object> params = thingModelMessage.dataToMap();
|
||||||
|
|
||||||
// 2. 物模型校验,过滤非物模型属性
|
// 物模型校验,过滤非物模型属性
|
||||||
List<IotThinkModelFunctionDO> thinkModelFunctionListByProductKey = iotThinkModelFunctionService.getThinkModelFunctionListByProductKey(thingModelMessage.getProductKey());
|
List<IotThinkModelFunctionDO> functionList = iotThinkModelFunctionService
|
||||||
|
.getThinkModelFunctionListByProductKey(thingModelMessage.getProductKey())
|
||||||
|
.stream()
|
||||||
|
.filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
// 2.1 筛选是属性 IotProductFunctionTypeEnum
|
if (functionList.isEmpty()) {
|
||||||
thinkModelFunctionListByProductKey.removeIf(iotThinkModelFunctionDO -> !iotThinkModelFunctionDO.getType().equals(IotProductFunctionTypeEnum.PROPERTY.getType()));
|
|
||||||
if (thinkModelFunctionListByProductKey.isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 2.2 获取属性名称
|
|
||||||
Map<String, String> thingModelProperties = thinkModelFunctionListByProductKey.stream().collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, IotThinkModelFunctionDO::getName));
|
|
||||||
|
|
||||||
// 4. 保存属性记录
|
// 获取属性标识符集合
|
||||||
|
Set<String> propertyIdentifiers = functionList.stream()
|
||||||
|
.map(IotThinkModelFunctionDO::getIdentifier)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
Map<String, IotThinkModelFunctionDO> functionMap = functionList.stream()
|
||||||
|
.collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, function -> function));
|
||||||
|
|
||||||
|
// 过滤并收集有效的属性字段
|
||||||
List<TdFieldDO> schemaFieldValues = new ArrayList<>();
|
List<TdFieldDO> schemaFieldValues = new ArrayList<>();
|
||||||
|
|
||||||
// 1. 设置字段名
|
|
||||||
schemaFieldValues.add(new TdFieldDO("time", thingModelMessage.getTime()));
|
schemaFieldValues.add(new TdFieldDO("time", thingModelMessage.getTime()));
|
||||||
|
|
||||||
// 2. 遍历新属性
|
|
||||||
params.forEach((key, val) -> {
|
params.forEach((key, val) -> {
|
||||||
if (thingModelProperties.containsKey(key)) {
|
if (propertyIdentifiers.contains(key)) {
|
||||||
schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val));
|
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();
|
TableDO tableData = new TableDO();
|
||||||
tableData.setDataBaseName(url.substring(url.lastIndexOf("/") + 1));
|
tableData.setDataBaseName(getDatabaseName());
|
||||||
tableData.setSuperTableName(getProductPropertySTableName(device.getDeviceType(), device.getProductKey()));
|
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);
|
tableData.setSchemaFieldValues(schemaFieldValues);
|
||||||
|
|
||||||
// 4. 保存数据
|
|
||||||
iotTdEngineService.insertData(tableData);
|
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) {
|
private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) {
|
||||||
|
String superTableName = getProductPropertySTableName(deviceType, productKey);
|
||||||
|
String dataBaseName = getDatabaseName();
|
||||||
|
|
||||||
|
List<Map<String, Object>> maps = iotTdEngineService.describeSuperTable(dataBaseName, superTableName);
|
||||||
List<TdFieldDO> tagsFieldValues = new ArrayList<>();
|
List<TdFieldDO> tagsFieldValues = new ArrayList<>();
|
||||||
String SuperTableName = getProductPropertySTableName(deviceType, productKey);
|
|
||||||
List<Map<String, Object>> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), SuperTableName);
|
|
||||||
if (maps != null) {
|
if (maps != null) {
|
||||||
List<Map<String, Object>> taggedNotesList = maps.stream().filter(map -> "TAG".equals(map.get("note"))).toList();
|
List<Map<String, Object>> taggedNotesList = maps.stream()
|
||||||
|
.filter(map -> "TAG".equals(map.get("note")))
|
||||||
|
.toList();
|
||||||
|
|
||||||
tagsFieldValues = FieldParser.parse(taggedNotesList.stream()
|
tagsFieldValues = FieldParser.parse(taggedNotesList.stream()
|
||||||
.map(map -> List.of(map.get("field"), map.get("type"), map.get("length")))
|
.map(map -> List.of(map.get("field"), map.get("type"), map.get("length")))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
for (TdFieldDO tagsFieldValue : tagsFieldValues) {
|
for (TdFieldDO tagsFieldValue : tagsFieldValues) {
|
||||||
switch (tagsFieldValue.getFieldName()) {
|
switch (tagsFieldValue.getFieldName()) {
|
||||||
case "product_key" -> tagsFieldValue.setFieldValue(productKey);
|
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();
|
TableDO tableDto = new TableDO();
|
||||||
tableDto.setDataBaseName(url.substring(url.lastIndexOf("/") + 1));
|
tableDto.setDataBaseName(dataBaseName);
|
||||||
tableDto.setSuperTableName(SuperTableName);
|
tableDto.setSuperTableName(superTableName);
|
||||||
tableDto.setTableName(tableName);
|
tableDto.setTableName(tableName);
|
||||||
tableDto.setTagsFieldValues(tagsFieldValues);
|
tableDto.setTagsFieldValues(tagsFieldValues);
|
||||||
|
|
||||||
iotTdEngineService.createTable(tableDto);
|
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) {
|
return switch (deviceType) {
|
||||||
case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase();
|
case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase();
|
||||||
case 2 -> String.format("gateway_%s", productKey).toLowerCase();
|
case 2 -> String.format("gateway_%s", productKey).toLowerCase();
|
||||||
default -> String.format("device_%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());
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue