fix:modbus解析失败bug修复
This commit is contained in:
parent
471c3a6a2c
commit
a4583c26a6
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user