fix:修复iot采集设备问题

main
HuangHuiKang 7 days ago
parent 41c7102969
commit 0758f2de3a

@ -47,7 +47,7 @@ public interface DeviceModelAttributeMapper extends BaseMapperX<DeviceModelAttri
.eqIfPresent(DeviceModelAttributeDO::getDataUnit, reqVO.getDataUnit()) .eqIfPresent(DeviceModelAttributeDO::getDataUnit, reqVO.getDataUnit())
.eqIfPresent(DeviceModelAttributeDO::getRatio, reqVO.getRatio()) .eqIfPresent(DeviceModelAttributeDO::getRatio, reqVO.getRatio())
.eqIfPresent(DeviceModelAttributeDO::getRemark, reqVO.getRemark()) .eqIfPresent(DeviceModelAttributeDO::getRemark, reqVO.getRemark())
.eqIfPresent(DeviceModelAttributeDO::getDeviceModelId, reqVO.getId()) .eqIfPresent(DeviceModelAttributeDO::getDeviceModelId, reqVO.getDeviceModelId())
.betweenIfPresent(DeviceModelAttributeDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(DeviceModelAttributeDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DeviceModelAttributeDO::getId); .orderByDesc(DeviceModelAttributeDO::getId);

@ -47,6 +47,7 @@ import cn.iocoder.yudao.module.iot.dal.mysql.mqttdatarecord.MqttDataRecordMapper
import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceAttributeDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceAttributeDO;
import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceAttributeMapper; import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceAttributeMapper;
import cn.iocoder.yudao.module.iot.framework.mqtt.config.DefaultBizTopicSet;
import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IMqttservice; import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IMqttservice;
import cn.iocoder.yudao.module.iot.util.MapListStatsCalculator; import cn.iocoder.yudao.module.iot.util.MapListStatsCalculator;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@ -139,6 +140,9 @@ public class DeviceServiceImpl implements DeviceService {
@Resource @Resource
private IMqttservice mqttService; private IMqttservice mqttService;
@Resource
private DefaultBizTopicSet defaultBizTopicSet;
@Resource @Resource
private ErpProductUnitMapper productUnitMapper; private ErpProductUnitMapper productUnitMapper;
@ -273,24 +277,59 @@ public class DeviceServiceImpl implements DeviceService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateDevice(DeviceSaveReqVO updateReqVO) { public void updateDevice(DeviceSaveReqVO updateReqVO) {
// 校验存在 // 校验存在
validateDeviceExists(updateReqVO.getId()); validateDeviceExists(updateReqVO.getId());
//校驗topic是否唯一 //校驗topic是否唯一
validTopicExists(updateReqVO.getTopic()); validTopicExists(updateReqVO.getTopic(), updateReqVO.getId());
// 更新 // 更新
DeviceDO updateObj = BeanUtils.toBean(updateReqVO, DeviceDO.class); DeviceDO updateObj = BeanUtils.toBean(updateReqVO, DeviceDO.class);
deviceMapper.updateById(updateObj); deviceMapper.updateById(updateObj);
} }
private void validTopicExists(String topic) { private void validTopicExists(String topic, Long currentDeviceId) {
boolean exists = deviceMapper.exists(Wrappers.<DeviceDO>lambdaQuery().eq(DeviceDO::getTopic, topic)); if (StringUtils.isBlank(topic)) {
return;
}
boolean exists = deviceMapper.exists(Wrappers.<DeviceDO>lambdaQuery()
.eq(DeviceDO::getTopic, topic)
.ne(currentDeviceId != null, DeviceDO::getId, currentDeviceId));
if (exists){ if (exists){
throw exception(DEVICE_MQTT_TOPIC_ALREADY_EXIST); throw exception(DEVICE_MQTT_TOPIC_ALREADY_EXIST);
} }
} }
private void disableGatewayByDevice(DeviceDO device) {
if (device == null) {
return;
}
LambdaUpdateWrapper<GatewayDO> updateWrapper = new LambdaUpdateWrapper<GatewayDO>()
.set(GatewayDO::getIsEnable, false)
.set(GatewayDO::getUpdateTime, LocalDateTime.now());
if (StringUtils.isNotBlank(device.getTopic())) {
updateWrapper.eq(GatewayDO::getTopic, device.getTopic());
} else if (StringUtils.isNotBlank(device.getDeviceCode())) {
updateWrapper.eq(GatewayDO::getGatewayCode, device.getDeviceCode());
} else {
return;
}
if (StringUtils.isNotBlank(device.getDeviceCode())) {
updateWrapper.or().eq(GatewayDO::getGatewayCode, device.getDeviceCode());
}
gatewayMapper.update(null, updateWrapper);
}
private void removeRuntimeTopic(String topic) {
if (StringUtils.isBlank(topic) || defaultBizTopicSet == null || defaultBizTopicSet.getTopicMap() == null) {
return;
}
synchronized (defaultBizTopicSet.getTopicMap()) {
defaultBizTopicSet.getTopicMap().removeIf(item -> topic.equals(item.getSubTopic()));
}
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deleteDevice(List<Long> ids) { public void deleteDevice(List<Long> ids) {
@ -323,10 +362,12 @@ public class DeviceServiceImpl implements DeviceService {
deviceContactModelMapper.delete(deviceContactModelDOLambdaQueryWrapper); deviceContactModelMapper.delete(deviceContactModelDOLambdaQueryWrapper);
} }
private void validateDeviceExists(Long id) { private DeviceDO validateDeviceExists(Long id) {
if (deviceMapper.selectById(id) == null) { DeviceDO device = deviceMapper.selectById(id);
if (device == null) {
throw exception(DEVICE_NOT_EXISTS); throw exception(DEVICE_NOT_EXISTS);
} }
return device;
} }
@Override @Override
@ -795,6 +836,7 @@ public class DeviceServiceImpl implements DeviceService {
} }
@Override @Override
// @Transactional(rollbackFor = Exception.class)
public Long copyDevice(Long id) { public Long copyDevice(Long id) {
if (id == null){ if (id == null){
throw exception(DEVICE_ID_MODEL_NOT_EXISTS); throw exception(DEVICE_ID_MODEL_NOT_EXISTS);
@ -811,6 +853,7 @@ public class DeviceServiceImpl implements DeviceService {
int randomNumber = random.nextInt(9000) + 1000; int randomNumber = random.nextInt(9000) + 1000;
newDevice.setDeviceCode(deviceDO.getDeviceCode()+ "-" + randomNumber); newDevice.setDeviceCode(deviceDO.getDeviceCode()+ "-" + randomNumber);
newDevice.setDeviceName(deviceDO.getDeviceName() + "-副本"); newDevice.setDeviceName(deviceDO.getDeviceName() + "-副本");
newDevice.setTopic(null);
deviceMapper.insert(newDevice); deviceMapper.insert(newDevice);
//复制关联表 //复制关联表
@ -818,14 +861,20 @@ public class DeviceServiceImpl implements DeviceService {
lambdaQueryWrapper.eq(DeviceContactModelDO::getDeviceId,deviceDO.getId()); lambdaQueryWrapper.eq(DeviceContactModelDO::getDeviceId,deviceDO.getId());
List<DeviceContactModelDO> deviceContactModelDOS = deviceContactModelMapper.selectList(lambdaQueryWrapper); List<DeviceContactModelDO> deviceContactModelDOS = deviceContactModelMapper.selectList(lambdaQueryWrapper);
List<DeviceContactModelDO> newContactModelList = new ArrayList<>();
if (deviceContactModelDOS != null && !deviceContactModelDOS.isEmpty()){ if (deviceContactModelDOS != null && !deviceContactModelDOS.isEmpty()){
for (DeviceContactModelDO deviceModelAttributeDOS : deviceContactModelDOS) { for (DeviceContactModelDO deviceContactModelDO : deviceContactModelDOS) {
deviceModelAttributeDOS.setId(null); DeviceContactModelDO newContactModel = new DeviceContactModelDO();
deviceModelAttributeDOS.setDeviceId(newDevice.getId()); BeanUtils.copyProperties(deviceContactModelDO, newContactModel);
newContactModel.setId(null);
newContactModel.setDeviceId(newDevice.getId());
newContactModel.setCreateTime(LocalDateTime.now());
newContactModel.setUpdateTime(LocalDateTime.now());
newContactModelList.add(newContactModel);
} }
deviceContactModelMapper.insertBatch(deviceContactModelDOS); deviceContactModelMapper.insertBatch(newContactModelList);
} }
tdengineService.createTdengineTable(newDevice.getId(), newContactModelList);
return newDevice.getId(); return newDevice.getId();
@ -2032,12 +2081,7 @@ public class DeviceServiceImpl implements DeviceService {
throw exception(DEVICE_MQTT_TOPIC_EXIST); throw exception(DEVICE_MQTT_TOPIC_EXIST);
} }
// 2. 如果状态没有变化,直接返回 // 2. 执行状态同步操作:重复启停也要同步 MQTT 与 gateway保证幂等
if (Objects.equals(deviceDO.getIsEnable(), updateEnabledReqVO.getEnabled())) {
return;
}
// 3. 执行状态更新操作
executeEnableUpdate(deviceDO, updateEnabledReqVO.getEnabled()); executeEnableUpdate(deviceDO, updateEnabledReqVO.getEnabled());
@ -2051,6 +2095,8 @@ public class DeviceServiceImpl implements DeviceService {
private void executeEnableUpdate(DeviceDO deviceDO, Boolean enabled) { private void executeEnableUpdate(DeviceDO deviceDO, Boolean enabled) {
MqttException syncException = null;
try { try {
// 1. 更新设备启用状态 // 1. 更新设备启用状态
deviceDO.setIsEnable(enabled); deviceDO.setIsEnable(enabled);
@ -2066,6 +2112,7 @@ public class DeviceServiceImpl implements DeviceService {
mqttService.subscribeTopic(topic); mqttService.subscribeTopic(topic);
log.info("MQTT订阅成功: {}", topic); log.info("MQTT订阅成功: {}", topic);
} catch (MqttException e) { } catch (MqttException e) {
syncException = e;
log.error("MQTT订阅失败: {}", topic, e); log.error("MQTT订阅失败: {}", topic, e);
} }
@ -2091,6 +2138,8 @@ public class DeviceServiceImpl implements DeviceService {
} else { } else {
//更新gateway状态 //更新gateway状态
gateway.setGatewayName(deviceDO.getDeviceName());
gateway.setGatewayCode(deviceDO.getDeviceCode());
gateway.setIsEnable(true); gateway.setIsEnable(true);
gateway.setUpdateTime(LocalDateTime.now()); gateway.setUpdateTime(LocalDateTime.now());
@ -2109,17 +2158,14 @@ public class DeviceServiceImpl implements DeviceService {
mqttService.unsubscribeTopic(topic); mqttService.unsubscribeTopic(topic);
log.info("MQTT取消订阅成功: {}", topic); log.info("MQTT取消订阅成功: {}", topic);
} catch (MqttException e) { } catch (MqttException e) {
syncException = e;
log.error("MQTT取消订阅失败: {}", topic, e); log.error("MQTT取消订阅失败: {}", topic, e);
} finally {
removeRuntimeTopic(topic);
} }
// 3.2 更新gateway状态为禁用 // 3.2 更新gateway状态为禁用
gatewayMapper.update( disableGatewayByDevice(deviceDO);
null,
new LambdaUpdateWrapper<GatewayDO>()
.eq(GatewayDO::getTopic, topic)
.set(GatewayDO::getIsEnable, false)
.set(GatewayDO::getUpdateTime, LocalDateTime.now())
);
log.info("gateway订阅记录已禁用 topic={}", topic); log.info("gateway订阅记录已禁用 topic={}", topic);
@ -2130,9 +2176,14 @@ public class DeviceServiceImpl implements DeviceService {
} }
if (syncException != null) {
throw new RuntimeException("MQTT订阅状态同步失败", syncException);
}
} catch (Exception e) { } catch (Exception e) {
log.error("更新设备状态失败 deviceCode={}", deviceDO.getDeviceCode(), e); log.error("更新设备状态失败 deviceCode={}", deviceDO.getDeviceCode(), e);
throw new RuntimeException("更新设备状态失败", e);
} }
} }

@ -779,6 +779,8 @@ public class TDengineService {
continue; continue;
} }
validateColumnName(attributeCode);
String tdType = JavaToTdengineTypeEnum.getTdTypeByJavaType(dataType); String tdType = JavaToTdengineTypeEnum.getTdTypeByJavaType(dataType);
if (tdType == null) { if (tdType == null) {
tdType = "DOUBLE"; tdType = "DOUBLE";
@ -1292,7 +1294,7 @@ public class TDengineService {
Set<String> reservedWords = new HashSet<>(Arrays.asList( Set<String> reservedWords = new HashSet<>(Arrays.asList(
"value", "timestamp", "current", "database", "table", "value", "timestamp", "current", "database", "table",
"user", "password", "select", "insert", "update", "delete", "user", "password", "select", "insert", "update", "delete",
"create", "drop", "alter", "show", "describe", "use", "ts" "create", "drop", "alter", "show", "describe", "use", "ts", "state"
)); ));
return reservedWords.contains(columnName.toLowerCase()); return reservedWords.contains(columnName.toLowerCase());
@ -1312,7 +1314,7 @@ public class TDengineService {
Set<String> reservedKeywords = new HashSet<>(Arrays.asList( Set<String> reservedKeywords = new HashSet<>(Arrays.asList(
"value", "timestamp", "current", "database", "table", "user", "password", "value", "timestamp", "current", "database", "table", "user", "password",
"select", "insert", "update", "delete", "create", "drop", "alter", "select", "insert", "update", "delete", "create", "drop", "alter",
"show", "describe", "use", "ts", "now", "current_timestamp" "show", "describe", "use", "ts", "now", "current_timestamp", "state"
)); ));
if (reservedKeywords.contains(columnName.toLowerCase())) { if (reservedKeywords.contains(columnName.toLowerCase())) {
@ -1359,7 +1361,7 @@ public class TDengineService {
Set<String> reservedKeywords = new HashSet<>(Arrays.asList( Set<String> reservedKeywords = new HashSet<>(Arrays.asList(
"value", "timestamp", "current", "database", "table", "user", "password", "value", "timestamp", "current", "database", "table", "user", "password",
"select", "insert", "update", "delete", "create", "drop", "alter", "select", "insert", "update", "delete", "create", "drop", "alter",
"show", "describe", "use", "ts", "now", "current_timestamp" "show", "describe", "use", "ts", "now", "current_timestamp", "state"
)); ));
if (reservedKeywords.contains(tableName.toLowerCase())) { if (reservedKeywords.contains(tableName.toLowerCase())) {

Loading…
Cancel
Save