#update
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package com.maibu.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.maibu.core.business.DeviceModel;
|
||||
import com.maibu.mybatis.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
@@ -11,7 +11,7 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
* @Entity com.maibu.core.business.DeviceModel;
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysDeviceModelMapper extends BaseMapper<DeviceModel> {
|
||||
public interface SysDeviceModelMapper extends BaseMapperX<DeviceModel> {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
package com.maibu.mapper;
|
||||
package com.maibu.mapper;
|
||||
@@ -2,25 +2,37 @@ package com.maibu.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.maibu.constant.Constant;
|
||||
import com.maibu.core.business.DeviceModelPropertyMapping;
|
||||
import com.maibu.core.business.DevicePlanTask;
|
||||
import com.maibu.core.business.IoTCommonDevice;
|
||||
import com.maibu.core.business.Product;
|
||||
import com.maibu.core.business.device.NettyDevice;
|
||||
import com.maibu.core.business.dto.DeviceConfigDTO;
|
||||
import com.maibu.core.enums.ConnectType;
|
||||
import com.maibu.mapper.IotDeviceCommonMapper;
|
||||
import com.maibu.mapper.SysDeviceModelPropertyMappingMapper;
|
||||
import com.maibu.memory.GlobalMemory;
|
||||
import com.maibu.memory.SiteMemory;
|
||||
import com.maibu.mqtt.*;
|
||||
import com.maibu.utils.SecurityUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -38,6 +50,17 @@ public class IotDeviceCommonService {
|
||||
@Autowired
|
||||
private IotDeviceCommonMapper iotDeviceCommonMapper;
|
||||
|
||||
@Autowired
|
||||
private SysDeviceModelPropertyMappingMapper sysDeviceModelPropertyMappingMapper;
|
||||
|
||||
public void save(IoTCommonDevice ioTCommonDevice) throws Exception {
|
||||
iotDeviceCommonMapper.saveOrUpdate(ioTCommonDevice);
|
||||
SiteMemory siteMemory = GlobalMemory.getSiteMemory(ioTCommonDevice.getOrgId(), ioTCommonDevice.getSiteId());
|
||||
if (siteMemory != null) {
|
||||
siteMemory.saveCommonDevice(ioTCommonDevice);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeviceToUnRegisterCache(DeviceConfigDTO deviceDTO) throws Exception {
|
||||
// 1. 检查 SN 是否已存在(缓存 + 数据库)
|
||||
if (GlobalMemory.unRegisterCommonDeviceMap.containsKey(deviceDTO.getSn())) {
|
||||
@@ -68,8 +91,7 @@ public class IotDeviceCommonService {
|
||||
device.setDelFlag(false);
|
||||
device.setCreateTime(LocalDateTime.now());
|
||||
|
||||
// 存入未注册缓存(key 用 SN)
|
||||
GlobalMemory.unRegisterCommonDeviceMap.put(deviceDTO.getSn(), device);
|
||||
|
||||
log.info("设备 {} 已加入未注册缓存", deviceDTO.getSn());
|
||||
}
|
||||
|
||||
@@ -109,10 +131,16 @@ public class IotDeviceCommonService {
|
||||
}
|
||||
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void registerDevice(Long deviceId, Long orgId, Long siteId) {
|
||||
// TODO: 从未注册缓存取出设备,绑定组织/场站,落库
|
||||
// 根据具体业务实现
|
||||
public void registerDevice(IoTCommonDevice device) {
|
||||
device.setHasRegister(true);
|
||||
device.setUpdateTime(LocalDateTime.now());
|
||||
device.setUpdateBy(SecurityUtils.getUsername());
|
||||
iotDeviceCommonMapper.saveOrUpdate(device);
|
||||
SiteMemory siteMemory = GlobalMemory.getSiteMemory(device.getOrgId(), device.getSiteId());
|
||||
if (siteMemory != null) {
|
||||
siteMemory.saveCommonDevice(device);
|
||||
}
|
||||
GlobalMemory.unRegisterCommonDeviceMap.remove(device.getSn());
|
||||
}
|
||||
|
||||
|
||||
@@ -237,23 +265,77 @@ public class IotDeviceCommonService {
|
||||
}
|
||||
|
||||
|
||||
// 3. 按 productId 分组,缓存映射配置避免重复查询
|
||||
public static Map<Long, List<DeviceModelPropertyMapping>> mappingCache = new ConcurrentHashMap<>();
|
||||
|
||||
public void commonDeviceMonitor() {
|
||||
|
||||
//prepare 进执行execute的逻辑
|
||||
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||
executor.scheduleWithFixedDelay(() -> {
|
||||
try {
|
||||
//先初始化 外部设备连接
|
||||
GlobalMemory.getAllSiteMemory().forEach(x -> {
|
||||
List<IoTCommonDevice> list = x.getAllCommonDevice();
|
||||
if (!CollectionUtils.isEmpty(list)) {
|
||||
list.forEach(y -> {
|
||||
if (ConnectType.MQTT.equals(y.getConnectType())) {
|
||||
String ip = y.getNetworkIp();
|
||||
Integer port = y.getPort();
|
||||
}
|
||||
});
|
||||
GlobalMemory.getAllSiteMemory().forEach(siteMemory -> {
|
||||
|
||||
|
||||
CustomMqttDeviceMonitor monitor = siteMemory.getCustomMqttDeviceMonitor();
|
||||
if (monitor == null) {
|
||||
// 1. 创建 MQTT 监控器和消息处理器
|
||||
monitor = new CustomMqttDeviceMonitor();
|
||||
monitor.registerHandler(new GenericPropertyMessageHandler());
|
||||
monitor.registerHandler(new ActionMessageHandler());
|
||||
|
||||
siteMemory.setCustomMqttDeviceMonitor(monitor);
|
||||
}
|
||||
// 2. 查询所有外部设备
|
||||
List<IoTCommonDevice> deviceList = siteMemory.getAllCommonDevice();
|
||||
if (CollectionUtils.isEmpty(deviceList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (IoTCommonDevice device : deviceList) {
|
||||
if (!ConnectType.MQTT.equals(device.getConnectType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Long productId = device.getProductId();
|
||||
|
||||
// 查询产品属性映射(缓存避免同一产品多次查询)
|
||||
List<DeviceModelPropertyMapping> mappings = mappingCache.computeIfAbsent(productId, pid -> {
|
||||
LambdaQueryWrapper<DeviceModelPropertyMapping> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(DeviceModelPropertyMapping::getProductId, pid);
|
||||
return sysDeviceModelPropertyMappingMapper.selectList(wrapper);
|
||||
});
|
||||
|
||||
// 构建映射配置
|
||||
PropertyMappingConfig mappingConfig = buildMappingConfig(mappings);
|
||||
|
||||
// 注册到处理器,用 productId 区分不同产品的映射
|
||||
String handlerType = "property-" + productId;
|
||||
GenericPropertyMessageHandler handler = (GenericPropertyMessageHandler) monitor.getMessageHandler(handlerType);
|
||||
handler.registerMappingConfig(handlerType, mappingConfig);
|
||||
|
||||
// 获取产品信息
|
||||
Product product = siteMemory.getProduct(productId);
|
||||
if (product == null || !StringUtils.hasText(product.getSubscribeTopic())) {
|
||||
log.warn("设备 {} 的产品 {} 未配置订阅主题,跳过", device.getSn(), productId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 注册设备到 MQTT 监控器
|
||||
CustomMqttDeviceConfig deviceConfig = new CustomMqttDeviceConfig();
|
||||
deviceConfig.setDeviceKey(device.getSn());
|
||||
deviceConfig.setBrokerUrl(device.getNetworkIp());
|
||||
deviceConfig.setClientId(Constant.mqttClientPrefix + device.getSn());
|
||||
deviceConfig.setUsername(device.getUsername());
|
||||
deviceConfig.setPassword(device.getPassword());
|
||||
deviceConfig.setSubscribeTopics(Arrays.asList(product.getSubscribeTopic()));
|
||||
deviceConfig.setHandlerType(handlerType);
|
||||
|
||||
monitor.registerDevice(deviceConfig);
|
||||
}
|
||||
|
||||
siteMemory.setCustomMqttDeviceMonitor(monitor);
|
||||
monitor.start();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("执行任务execute线程错误", e);
|
||||
@@ -262,4 +344,63 @@ public class IotDeviceCommonService {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据库映射列表构建 PropertyMappingConfig
|
||||
*
|
||||
* <p>将 {@link DeviceModelPropertyMapping} 转换为 {@link PropertyMappingConfig.FieldMapping}:</p>
|
||||
* <ul>
|
||||
* <li>sourceKey → FieldMapping.source(外部 JSON 中的字段名)</li>
|
||||
* <li>standardKey → FieldMapping.target(统一后的内部属性名)</li>
|
||||
* <li>dataType → FieldMapping.valueType(自动类型转换)</li>
|
||||
* </ul>
|
||||
*/
|
||||
private PropertyMappingConfig buildMappingConfig(List<DeviceModelPropertyMapping> mappings) {
|
||||
PropertyMappingConfig config = new PropertyMappingConfig();
|
||||
config.setParserType(PropertyMappingConfig.ParserType.FLAT);
|
||||
|
||||
if (CollectionUtils.isEmpty(mappings)) {
|
||||
return config;
|
||||
}
|
||||
|
||||
List<PropertyMappingConfig.FieldMapping> fieldMappings = new ArrayList<>();
|
||||
for (DeviceModelPropertyMapping mapping : mappings) {
|
||||
if (!StringUtils.hasText(mapping.getSourceKey()) || !StringUtils.hasText(mapping.getStandardKey())) {
|
||||
continue;
|
||||
}
|
||||
PropertyMappingConfig.FieldMapping fieldMapping = PropertyMappingConfig.FieldMapping
|
||||
.of(mapping.getSourceKey(), mapping.getStandardKey(), convertValueType(mapping.getDataType()));
|
||||
fieldMappings.add(fieldMapping);
|
||||
}
|
||||
config.setMappings(fieldMappings);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据库 dataType 转换为 ValueType
|
||||
*/
|
||||
private PropertyMappingConfig.ValueType convertValueType(String dataType) {
|
||||
if (!StringUtils.hasText(dataType)) {
|
||||
return PropertyMappingConfig.ValueType.AUTO;
|
||||
}
|
||||
switch (dataType.toLowerCase()) {
|
||||
case "string":
|
||||
case "varchar":
|
||||
case "text":
|
||||
return PropertyMappingConfig.ValueType.STRING;
|
||||
case "int":
|
||||
case "integer":
|
||||
case "long":
|
||||
case "float":
|
||||
case "double":
|
||||
case "number":
|
||||
case "decimal":
|
||||
return PropertyMappingConfig.ValueType.NUMBER;
|
||||
case "boolean":
|
||||
case "bool":
|
||||
return PropertyMappingConfig.ValueType.BOOLEAN;
|
||||
default:
|
||||
return PropertyMappingConfig.ValueType.AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user