fix:modbus解析失败bug修复

This commit is contained in:
zhugongping 2025-12-07 17:13:23 +08:00
parent 471c3a6a2c
commit a4583c26a6
4 changed files with 105 additions and 66 deletions

View File

@ -0,0 +1,36 @@
package com.fastbee.helper;
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
import com.fastbee.common.utils.DateUtils;
import com.fastbee.iot.domain.ModbusConfig;
import java.util.List;
import java.util.function.Function;
/**
* @Date: 2025-12-06
* @Author: zhugongping
**/
public class ModbusProtocolHelper {
/**
* 构建简单数据项
*
* @param simpleItemList
* @param bitOrderFunction
* @param ioConfigs
*/
public static void buildSimpleItem(List<ThingsModelSimpleItem> simpleItemList,
Function<ModbusConfig, String> bitOrderFunction,
List<ModbusConfig> ioConfigs) {
for (ModbusConfig config : ioConfigs) {
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem();
simpleItem.setId(config.getIdentifier());
simpleItem.setValue(bitOrderFunction.apply(config));
simpleItem.setTs(DateUtils.getNowDate());
simpleItemList.add(simpleItem);
}
}
}

View File

@ -18,6 +18,7 @@ import com.fastbee.common.utils.DateUtils;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.gateway.CRC16Utils; import com.fastbee.common.utils.gateway.CRC16Utils;
import com.fastbee.common.utils.modbus.BitUtils; import com.fastbee.common.utils.modbus.BitUtils;
import com.fastbee.helper.ModbusProtocolHelper;
import com.fastbee.iot.cache.IModbusConfigCache; import com.fastbee.iot.cache.IModbusConfigCache;
import com.fastbee.iot.domain.Device; import com.fastbee.iot.domain.Device;
import com.fastbee.iot.domain.ModbusConfig; import com.fastbee.iot.domain.ModbusConfig;
@ -231,7 +232,7 @@ public class ModbusProtocol implements IProtocol {
simpleItemList.add(simpleItem); simpleItemList.add(simpleItem);
} }
} else { } else {
//原数据字符串 // 原数据字符串(保持完整,不截取)
String dataHex = sourceStr.substring(6, sourceStr.length() - 4); String dataHex = sourceStr.substring(6, sourceStr.length() - 4);
//处理多个情况 //处理多个情况
Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByProductId(productId); Map<Integer, List<ModbusConfig>> modbusConfigMap = modbusConfigCache.getModbusConfigCacheByProductId(productId);
@ -239,71 +240,77 @@ public class ModbusProtocol implements IProtocol {
log.warn("寄存器数据不存在"); log.warn("寄存器数据不存在");
return; return;
} }
// 获取起始地址(数据从该地址开始)
int startAddress = Integer.parseInt(address);
int isReadOnly = message.getCode() == 3 ? 1 : 0;
// 获取所有相关的配置
List<ModbusConfig> modbusConfigList = new ArrayList<>(); List<ModbusConfig> modbusConfigList = new ArrayList<>();
for (Map.Entry<Integer, List<ModbusConfig>> entry : modbusConfigMap.entrySet()) { for (Map.Entry<Integer, List<ModbusConfig>> entry : modbusConfigMap.entrySet()) {
modbusConfigList.addAll(entry.getValue()); modbusConfigList.addAll(entry.getValue());
} }
int isReadOnly = message.getCode() == 3 ? 1 : 0;
Map<Integer, ModbusConfig> configMap = modbusConfigList.stream() // 处理IO类型(type == 1):按位处理
Map<Integer, List<ModbusConfig>> ioConfigMap = modbusConfigList.stream()
.filter(config -> config.getType() == 1 && config.getIsReadonly() == isReadOnly)
.collect(Collectors.groupingBy(ModbusConfig::getAddress));
// 遍历数据数组,处理IO类型
for (int i = 0; i < length; i++) {
int currentAddress = startAddress + i;
List<ModbusConfig> ioConfigs = ioConfigMap.get(currentAddress);
if (!CollectionUtils.isEmpty(ioConfigs) && ioConfigs.size() > 1) {
// 处理IO类型,按位取值
int index = i;
Function<ModbusConfig, String> bitOrderFunction = config -> String.valueOf(BitUtils.deter(data[index], config.getBitOrder()));
ModbusProtocolHelper.buildSimpleItem(simpleItemList, bitOrderFunction, ioConfigs);
}
}
// 处理数据寄存器类型(type == 2):根据每个配置的address动态定位数据
List<ModbusConfig> dataConfigList = modbusConfigList.stream()
.filter(config -> config.getType() == 2 && config.getIsReadonly() == isReadOnly) .filter(config -> config.getType() == 2 && config.getIsReadonly() == isReadOnly)
.collect(Collectors.toMap(ModbusConfig::getAddress, Function.identity())); .collect(Collectors.toList());
int registerAd = Integer.parseInt(address);
// 需要根据首地址值以及数据长度动态截取数据 例如数据:0103 0800 3800 4500 5600 7801 e9 for (ModbusConfig modbusConfig : dataConfigList) {
int startIndex = registerAd * 4; // 每个寄存器占4个十六进制字符 int configAddress = modbusConfig.getAddress();
if (startIndex > 0 && startIndex < dataHex.length()) { Integer quantity = modbusConfig.getQuantity();
dataHex = dataHex.substring(startIndex);
log.debug("截取后数据(起始地址{}): {}", registerAd, dataHex); // 计算该配置在dataHex中的位置(相对于起始地址)
} else if (startIndex >= dataHex.length()) { // 每个寄存器占4个十六进制字符
log.error("起始地址{}超出数据范围! 数据长度: {}", registerAd, dataHex.length() / 4); int offset = (configAddress - startAddress) * 4;
return; int hexLength = quantity * 4; // 根据quantity确定需要读取的数据长度
}
for (int i = 0; i < length; ) { // 移除i++,手动控制循环 // 检查数据是否足够
ModbusConfig modbusConfig = configMap.get(registerAd); if (offset < 0 || offset + hexLength > dataHex.length()) {
if (Objects.isNull(modbusConfig)) { log.warn("配置地址{}的数据超出范围,起始地址:{},需要{}个字符,实际可用:{}",
// 处理可能是 03按位运行情况,判断是否有寄存器,而且寄存器对应物模型多个 configAddress, startAddress, hexLength,
List<ModbusConfig> dataToIoList = modbusConfigMap.get(registerAd); offset < 0 ? 0 : dataHex.length() - offset);
if (!CollectionUtils.isEmpty(dataToIoList) && dataToIoList.size() > 1) {
for (ModbusConfig config : dataToIoList) {
int result = BitUtils.deter(data[i], config.getBitOrder());
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem();
simpleItem.setId(config.getIdentifier());
simpleItem.setValue(result + "");
simpleItem.setTs(DateUtils.getNowDate());
simpleItemList.add(simpleItem);
}
} else {
log.warn("寄存器地址:{},不存在", registerAd);
}
registerAd += 1;
i += 1; // 单个寄存器,i增加1
continue; continue;
} }
//个数
Integer quantity = modbusConfig.getQuantity(); // 从dataHex的对应位置提取数据
String handleHex = dataHex.substring(offset, offset + hexLength);
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem(); ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem();
simpleItem.setId(modbusConfig.getIdentifier()); simpleItem.setId(modbusConfig.getIdentifier());
simpleItem.setTs(DateUtils.getNowDate()); simpleItem.setTs(DateUtils.getNowDate());
if (quantity == 1) { if (quantity == 1) {
//将identity与address替换 // 单个寄存器
String handleHex = dataHex.substring(0, 4);
String value = CaculateUtils.handleToUnSign16(Long.parseLong(handleHex, 16) + "", modbusConfig.getDataType()); String value = CaculateUtils.handleToUnSign16(Long.parseLong(handleHex, 16) + "", modbusConfig.getDataType());
simpleItem.setValue(value); simpleItem.setValue(value);
simpleItemList.add(simpleItem);
dataHex = dataHex.substring(4);
i += 1; // 单个寄存器,i增加1
} else if (quantity == 2) { } else if (quantity == 2) {
//这里做数据处理 // 浮点数,2个寄存器
String handleHex = dataHex.substring(0, 8);
String value = CaculateUtils.parseValue(modbusConfig.getDataType(), handleHex); String value = CaculateUtils.parseValue(modbusConfig.getDataType(), handleHex);
simpleItem.setValue(value); simpleItem.setValue(value);
simpleItemList.add(simpleItem); } else {
//处理dataHex log.warn("不支持的quantity值:{},配置地址:{}", quantity, configAddress);
dataHex = dataHex.substring(8); continue;
i += 2; // 浮点数,i增加2
} }
//寄存器地址根据quantity增加 simpleItemList.add(simpleItem);
registerAd += quantity;
} }
} }
} }

View File

@ -18,6 +18,7 @@ import com.fastbee.common.utils.CaculateUtils;
import com.fastbee.common.utils.DateUtils; import com.fastbee.common.utils.DateUtils;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.modbus.BitUtils; import com.fastbee.common.utils.modbus.BitUtils;
import com.fastbee.helper.ModbusProtocolHelper;
import com.fastbee.iot.cache.IModbusConfigCache; import com.fastbee.iot.cache.IModbusConfigCache;
import com.fastbee.iot.domain.ModbusConfig; import com.fastbee.iot.domain.ModbusConfig;
import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem; import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem;
@ -284,14 +285,9 @@ public class ModbusTcpProtocol implements IProtocol {
//处理可能是 03按位运行情况,判断是否有寄存器,而且寄存器对应物模型多个 //处理可能是 03按位运行情况,判断是否有寄存器,而且寄存器对应物模型多个
List<ModbusConfig> dataToIoList = modbusConfigMap.get(registerAd); List<ModbusConfig> dataToIoList = modbusConfigMap.get(registerAd);
if (!CollectionUtils.isEmpty(dataToIoList) && dataToIoList.size() > 1) { if (!CollectionUtils.isEmpty(dataToIoList) && dataToIoList.size() > 1) {
for (ModbusConfig config : dataToIoList) { int index = i;
int result = BitUtils.deter(data[i], config.getBitOrder()); Function<ModbusConfig, String> bitOrderFunction = config -> String.valueOf(BitUtils.deter(data[index], config.getBitOrder()));
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem(); ModbusProtocolHelper.buildSimpleItem(simpleItemList, bitOrderFunction, dataToIoList);
simpleItem.setId(config.getIdentifier());
simpleItem.setValue(result + "");
simpleItem.setTs(DateUtils.getNowDate());
simpleItemList.add(simpleItem);
}
} else { } else {
log.warn("寄存器地址:{},不存在", registerAd); log.warn("寄存器地址:{},不存在", registerAd);
} }

View File

@ -46,16 +46,16 @@ public class ModbusConfigCacheImpl implements IModbusConfigCache {
*/ */
@Override @Override
public Map<Integer, List<ModbusConfig>> getModbusConfigCacheByProductId(Long productId){ public Map<Integer, List<ModbusConfig>> getModbusConfigCacheByProductId(Long productId){
Map<Integer, List<ModbusConfig>> resultMap = new HashMap<>(); // Map<Integer, List<ModbusConfig>> resultMap = new HashMap<>();
String modbusKey = RedisKeyBuilder.buildModbusKey(productId); // String modbusKey = RedisKeyBuilder.buildModbusKey(productId);
Map<String,String> map = redisCache.hashEntity(modbusKey); // Map<String,String> map = redisCache.hashEntity(modbusKey);
if (!CollectionUtils.isEmpty(map)){ // if (!CollectionUtils.isEmpty(map)){
for (Map.Entry<String, String> entry : map.entrySet()) { // for (Map.Entry<String, String> entry : map.entrySet()) {
List<ModbusConfig> modbusConfigList = JSON.parseArray(entry.getValue(), ModbusConfig.class); // List<ModbusConfig> modbusConfigList = JSON.parseArray(entry.getValue(), ModbusConfig.class);
resultMap.put(Integer.parseInt(entry.getKey()), modbusConfigList); // resultMap.put(Integer.parseInt(entry.getKey()), modbusConfigList);
} // }
return resultMap; // return resultMap;
} // }
return setModbusConfigCacheByProductId(productId); return setModbusConfigCacheByProductId(productId);
} }