From 471c3a6a2c57f16e24f02e7f8073bbf8eec98f51 Mon Sep 17 00:00:00 2001 From: zhugongping Date: Sat, 6 Dec 2025 17:56:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E5=AF=84=E5=AD=98=E5=99=A8=E9=A6=96?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E5=8F=96=E5=80=BC=E5=85=88=E8=B5=B0DB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 6 +- .../src/main/resources/application.yml | 2 + .../fastbee/common/utils/CaculateUtils.java | 10 +- .../common/utils/gateway/CRC16Utils.java | 2 +- .../common/utils/modbus/ModbusUtils.java | 2 + .../fastbee/modbus/codec/ModbusProtocol.java | 123 ++++++++++++------ .../iot/mapper/ModbusConfigMapper.java | 7 + .../mapper/iot/ModbusConfigMapper.xml | 9 ++ 8 files changed, 109 insertions(+), 52 deletions(-) diff --git a/fastbee-admin/src/main/resources/application-dev.yml b/fastbee-admin/src/main/resources/application-dev.yml index 83890eed..d047888d 100644 --- a/fastbee-admin/src/main/resources/application-dev.yml +++ b/fastbee-admin/src/main/resources/application-dev.yml @@ -41,7 +41,7 @@ spring: # slave: # type: com.alibaba.druid.pool.DruidDataSource # driver-class-name: com.mysql.cj.jdbc.Driver - # url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + # url: jdbc:mysql://1.116.124.85:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # username: root # password: fastbee shardingsphere: @@ -113,7 +113,7 @@ spring: mqtt: username: fastbee # 账号 password: fastbee # 密码 - host-url: tcp://localhost:1883 # mqtt连接tcp地址 + host-url: tcp://1.116.124.85:1883 # mqtt连接tcp地址 client-id: ${random.int} # 客户端Id,不能相同,采用随机数 ${random.value} default-topic: test # 默认主题 timeout: 30 # 超时时间 @@ -121,7 +121,7 @@ spring: clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) # EMQX API配置需要在运行emqx之后去EMQX管理后台手动创建API Key和Secret,并配置到application.yml中 emqx: - host: localhost # EMQX服务器地址 + host: 1.116.124.85 # EMQX服务器地址 port: 18083 ApiKey: emqx.key.123 # EMQX API Key ApiSecret: emqx.api.123 diff --git a/fastbee-admin/src/main/resources/application.yml b/fastbee-admin/src/main/resources/application.yml index 4c9f00c4..0a79cd7b 100644 --- a/fastbee-admin/src/main/resources/application.yml +++ b/fastbee-admin/src/main/resources/application.yml @@ -51,6 +51,8 @@ server: # Spring配置 spring: +# quartz: +# auto-startup: false # 上线前去掉 # 环境配置,dev=开发环境,prod=生产环境 profiles: active: dev # 环境配置,dev=开发环境,prod=生产环境 diff --git a/fastbee-common/src/main/java/com/fastbee/common/utils/CaculateUtils.java b/fastbee-common/src/main/java/com/fastbee/common/utils/CaculateUtils.java index 2c0206b5..95be154a 100644 --- a/fastbee-common/src/main/java/com/fastbee/common/utils/CaculateUtils.java +++ b/fastbee-common/src/main/java/com/fastbee/common/utils/CaculateUtils.java @@ -301,8 +301,8 @@ public class CaculateUtils { * @param bytes * @return */ - public static Float toFloat32_CDAB(byte[] bytes) { - int intValue = ((bytes[2] & 0xFF) << 24) | ((bytes[3] & 0xFF) << 16) | ((bytes[0] & 0xFF) << 8) | ((bytes[1] & 0xFF)) ; + public static Float toFloat32_DCBA(byte[] bytes) { + int intValue = ((bytes[3] & 0xFF) << 24) | ((bytes[2] & 0xFF) << 16) | ((bytes[1] & 0xFF) << 8) | ((bytes[0] & 0xFF)) ; return Float.intBitsToFloat(intValue); } @@ -339,8 +339,8 @@ public class CaculateUtils { case FLOAT_ABCD: value = CaculateUtils.toFloat32_ABCD(bytes) + ""; break; - case FLOAT_CDAB: - value = CaculateUtils.toFloat32_CDAB(bytes) + ""; + case FLOAT_CDAB: // todo:待改枚举页面枚举 + value = CaculateUtils.toFloat32_DCBA(bytes) + ""; break; } } @@ -417,7 +417,7 @@ public class CaculateUtils { System.out.println(i); byte[] bytes1 = ByteBufUtil.decodeHexDump(hexToBytes1); - float v2 = toFloat32_CDAB(bytes1); + float v2 = toFloat32_DCBA(bytes1); System.out.println("转32位浮点型-CDAB序:"+v2); int signedShort = -32627; // 16位有符号整形 diff --git a/fastbee-common/src/main/java/com/fastbee/common/utils/gateway/CRC16Utils.java b/fastbee-common/src/main/java/com/fastbee/common/utils/gateway/CRC16Utils.java index a6a6cce9..75bc241d 100644 --- a/fastbee-common/src/main/java/com/fastbee/common/utils/gateway/CRC16Utils.java +++ b/fastbee-common/src/main/java/com/fastbee/common/utils/gateway/CRC16Utils.java @@ -141,7 +141,7 @@ public class CRC16Utils { byte[] byte8 = ByteUtils.hexToByte(crc8); int b = CRC8(byte8); System.out.println((int) b); - float v = CaculateUtils.toFloat32_CDAB(bytes); + float v = CaculateUtils.toFloat32_DCBA(bytes); System.out.println(v); } diff --git a/fastbee-common/src/main/java/com/fastbee/common/utils/modbus/ModbusUtils.java b/fastbee-common/src/main/java/com/fastbee/common/utils/modbus/ModbusUtils.java index f7605e62..4d292340 100644 --- a/fastbee-common/src/main/java/com/fastbee/common/utils/modbus/ModbusUtils.java +++ b/fastbee-common/src/main/java/com/fastbee/common/utils/modbus/ModbusUtils.java @@ -71,5 +71,7 @@ public class ModbusUtils { public static void main(String[] args) { int modbusAddress = getModbusAddress("0101000A0001FDCA"); System.out.println(modbusAddress); + Mparams modbusParams = getModbusParams("01030001000815cc"); + System.out.println("modbusParams.getAddress() = " + modbusParams.getAddress()); } } diff --git a/fastbee-protocol/fastbee-protocol-collect/src/main/java/com/fastbee/modbus/codec/ModbusProtocol.java b/fastbee-protocol/fastbee-protocol-collect/src/main/java/com/fastbee/modbus/codec/ModbusProtocol.java index 9818b0e4..a0210654 100644 --- a/fastbee-protocol/fastbee-protocol-collect/src/main/java/com/fastbee/modbus/codec/ModbusProtocol.java +++ b/fastbee-protocol/fastbee-protocol-collect/src/main/java/com/fastbee/modbus/codec/ModbusProtocol.java @@ -11,26 +11,20 @@ import com.fastbee.common.core.mq.message.DeviceData; import com.fastbee.common.core.mq.message.FunctionCallBackBo; import com.fastbee.common.core.protocol.modbus.ModbusCode; import com.fastbee.common.core.redis.RedisCache; -import com.fastbee.common.core.redis.RedisKeyBuilder; import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem; import com.fastbee.common.enums.FunctionReplyStatus; -import com.fastbee.common.enums.ModbusDataType; -import com.fastbee.common.exception.ServiceException; import com.fastbee.common.utils.CaculateUtils; import com.fastbee.common.utils.DateUtils; import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.gateway.CRC16Utils; import com.fastbee.common.utils.modbus.BitUtils; -import com.fastbee.common.utils.modbus.ModbusUtils; -import com.fastbee.common.utils.modbus.Mparams; import com.fastbee.iot.cache.IModbusConfigCache; +import com.fastbee.iot.domain.Device; import com.fastbee.iot.domain.ModbusConfig; -import com.fastbee.iot.model.ThingsModelItem.Datatype; +import com.fastbee.iot.mapper.DeviceMapper; +import com.fastbee.iot.mapper.ModbusConfigMapper; import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem; -import com.fastbee.iot.model.gateWay.SubDeviceListVO; -import com.fastbee.iot.service.IDeviceService; import com.fastbee.iot.service.ISubGatewayService; -import com.fastbee.iot.service.IThingsModelService; import com.fastbee.modbus.model.ModbusRtu; import com.fastbee.protocol.base.protocol.IProtocol; import io.netty.buffer.ByteBuf; @@ -41,7 +35,10 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; @@ -64,6 +61,11 @@ public class ModbusProtocol implements IProtocol { private IModbusConfigCache modbusConfigCache; @Resource private ISubGatewayService subGatewayService; + @Resource + private DeviceMapper deviceMapper; + + @Resource + private ModbusConfigMapper modbusConfigMapper; @Override public DeviceReport decode(DeviceData deviceData, String clientId) { @@ -96,14 +98,14 @@ public class ModbusProtocol implements IProtocol { case Read01: case Read02: //起始地址 - String address0102 = getCacheModbusAddress(deviceData.getSerialNumber(),slaveId,code); + String address0102 = getCacheModbusAddress(deviceData.getSerialNumber(), slaveId, code); //读线圈或读离散型寄存器处理 handleRead0102(productId, message, address0102, values); break; case Read03: case Read04: //起始地址 - String address0304 = getCacheModbusAddress(deviceData.getSerialNumber(),slaveId,code); + String address0304 = getCacheModbusAddress(deviceData.getSerialNumber(), slaveId, code); //读输入、保持寄存器 handleRead0304(productId, message, address0304, values, hexDump); break; @@ -117,7 +119,7 @@ public class ModbusProtocol implements IProtocol { report.setSources(hexDump); report.setProtocolCode(FastBeeConstant.PROTOCOL.ModbusRtu); report.setStatus(FunctionReplyStatus.SUCCESS); - this.handleMsgReply(message,report,modbusCode); + this.handleMsgReply(message, report, modbusCode); return report; } @@ -158,8 +160,9 @@ public class ModbusProtocol implements IProtocol { modbusConfigList.addAll(entry.getValue()); } int isReadOnly = message.getCode() == 1 ? 1 : 0; - Map> listMap = modbusConfigList.stream().filter(config -> - { return config.getType() == 1 && config.getIsReadonly() == isReadOnly;}).collect(Collectors.groupingBy(ModbusConfig::getAddress)); + Map> listMap = modbusConfigList.stream() + .filter(config -> config.getType() == 1 && config.getIsReadonly() == isReadOnly) + .collect(Collectors.groupingBy(ModbusConfig::getAddress)); //分割值 List values = StringUtils.splitEvenly(hexDump, 2); int ioAd = Integer.parseInt(address); @@ -204,7 +207,7 @@ public class ModbusProtocol implements IProtocol { List IOConfigList = listMap.get(1); if (!CollectionUtils.isEmpty(IOConfigList)) { if (IOConfigList.size() > 1) { - //03按位运行情况,读寄存器需要将16进制转换为2进制,按位取值 + // 03按位运行情况,读寄存器需要将16进制转换为2进制,按位取值 // 如1-4个继电器开关情况,寄存器值是0x0007 从右到左,1-4 对应 on-on-on-off for (ModbusConfig config : IOConfigList) { int result = BitUtils.deter(data[0], config.getBitOrder()); @@ -241,13 +244,23 @@ public class ModbusProtocol implements IProtocol { modbusConfigList.addAll(entry.getValue()); } int isReadOnly = message.getCode() == 3 ? 1 : 0; - Map configMap = modbusConfigList.stream().filter(config -> - {return config.getType() == 2 && config.getIsReadonly() == isReadOnly;}).collect(Collectors.toMap(ModbusConfig::getAddress, Function.identity())); + Map configMap = modbusConfigList.stream() + .filter(config -> config.getType() == 2 && config.getIsReadonly() == isReadOnly) + .collect(Collectors.toMap(ModbusConfig::getAddress, Function.identity())); int registerAd = Integer.parseInt(address); - for (int i = 0; i < length; i++) { + // 需要根据首地址值以及数据长度动态截取数据 例如数据:0103 0800 3800 4500 5600 7801 e9 + int startIndex = registerAd * 4; // 每个寄存器占4个十六进制字符 + if (startIndex > 0 && startIndex < dataHex.length()) { + dataHex = dataHex.substring(startIndex); + log.debug("截取后数据(起始地址{}): {}", registerAd, dataHex); + } else if (startIndex >= dataHex.length()) { + log.error("起始地址{}超出数据范围! 数据长度: {}", registerAd, dataHex.length() / 4); + return; + } + for (int i = 0; i < length; ) { // 移除i++,手动控制循环 ModbusConfig modbusConfig = configMap.get(registerAd); if (Objects.isNull(modbusConfig)) { - //处理可能是 03按位运行情况,判断是否有寄存器,而且寄存器对应物模型多个 + // 处理可能是 03按位运行情况,判断是否有寄存器,而且寄存器对应物模型多个 List dataToIoList = modbusConfigMap.get(registerAd); if (!CollectionUtils.isEmpty(dataToIoList) && dataToIoList.size() > 1) { for (ModbusConfig config : dataToIoList) { @@ -262,6 +275,7 @@ public class ModbusProtocol implements IProtocol { log.warn("寄存器地址:{},不存在", registerAd); } registerAd += 1; + i += 1; // 单个寄存器,i增加1 continue; } //个数 @@ -271,9 +285,12 @@ public class ModbusProtocol implements IProtocol { simpleItem.setTs(DateUtils.getNowDate()); if (quantity == 1) { //将identity与address替换 - simpleItem.setValue(CaculateUtils.handleToUnSign16(data[i] + "", modbusConfig.getDataType())); + String handleHex = dataHex.substring(0, 4); + String value = CaculateUtils.handleToUnSign16(Long.parseLong(handleHex, 16) + "", modbusConfig.getDataType()); + simpleItem.setValue(value); simpleItemList.add(simpleItem); dataHex = dataHex.substring(4); + i += 1; // 单个寄存器,i增加1 } else if (quantity == 2) { //这里做数据处理 String handleHex = dataHex.substring(0, 8); @@ -282,20 +299,21 @@ public class ModbusProtocol implements IProtocol { simpleItemList.add(simpleItem); //处理dataHex dataHex = dataHex.substring(8); - //处理quantity ==2的情况,跳过一次循环 - i += 1; + i += 2; // 浮点数,i增加2 } - //寄存器地址+1 - registerAd += 1; + + //寄存器地址根据quantity增加 + registerAd += quantity; } } } /** * 处理下发指令设备回复消息,按照modbus协议约定会返回一样的指令 + * * @param message 解析后数据 */ - private void handleMsgReply(ModbusRtu message,DeviceReport report,ModbusCode code){ + private void handleMsgReply(ModbusRtu message, DeviceReport report, ModbusCode code) { //单个寄存器上报情况处理 String address = message.getAddress() + ""; List modbusConfig = modbusConfigCache.getSingleModbusConfig(report.getProductId(), address); @@ -313,13 +331,13 @@ public class ModbusProtocol implements IProtocol { simpleItem.setId(config.getIdentifier()); simpleItem.setTs(DateUtils.getNowDate()); int data = message.getWriteData(); - if (type == 1){ + if (type == 1) { //对于IO类型的数据做一个数据转换 0x0000 是关 0xff00 是开 对应值 1 - if (data == 0xff00){ + if (data == 0xff00) { data = 1; } } - simpleItem.setValue(data +""); + simpleItem.setValue(data + ""); values.add(simpleItem); report.setThingsModelSimpleItem(values); } @@ -356,7 +374,7 @@ public class ModbusProtocol implements IProtocol { this.read03(config, rtu); break; case Write05: - write05(config,message.getValue(), rtu); + write05(config, message.getValue(), rtu); break; case Write06: write06(config, message.getValue(), rtu); @@ -411,20 +429,39 @@ public class ModbusProtocol implements IProtocol { /** * 获取modbus地址 */ - private String getCacheModbusAddress(String serialNumber,int salveId,int code) { - String key = RedisKeyBuilder.buildModbusRuntimeCacheKey(serialNumber); - Set commandSet = redisCache.zRange(key, 0, -1); - if (commandSet.size() == 0) { - throw new ServiceException("No cache modbus address found"); + private String getCacheModbusAddress(String serialNumber, int salveId, int code) { +// String key = RedisKeyBuilder.buildModbusRuntimeCacheKey(serialNumber); +// Set commandSet = redisCache.zRange(key, 0, -1); +// +// // 1. 遍历匹配指令 +// for (String command : commandSet) { +// try { +// Mparams params = ModbusUtils.getModbusParams(command); +// redisCache.zRem(key, command); // 删除缓存 +// if (params.getSlaveId() == salveId && params.getCode() == code) { +// return String.valueOf(params.getAddress()); +// } +// } catch (Exception e) { +// log.warn("解析指令异常: {}", e.getMessage()); +// } +// } + + // 2. 无匹配时查询数据库 + try { + Device device = deviceMapper.selectDeviceBySerialNumber(serialNumber); + if (device == null) return "0"; + + List configs = modbusConfigMapper.selectModbusConfigListByProductId(device.getProductId()); + if (CollectionUtils.isEmpty(configs)) return "0"; + + return configs.stream() + .mapToInt(ModbusConfig::getAddress) + .min() + .orElse(0) + ""; + } catch (Exception e) { + log.error("数据库查询异常: {}", e.getMessage()); + return "0"; } - for (String command : commandSet) { - Mparams params = ModbusUtils.getModbusParams(command); - redisCache.zRem(key, command); - if (params.getSlaveId() == salveId && params.getCode() == code){ - return params.getAddress()+""; - } - } - throw new ServiceException("No cache modbus address found"); } } diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/ModbusConfigMapper.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/ModbusConfigMapper.java index 3e6ed0e1..881cd350 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/ModbusConfigMapper.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/ModbusConfigMapper.java @@ -90,4 +90,11 @@ public interface ModbusConfigMapper * @return */ public List selectShortListByProductId(ModbusConfig config); + + /** + * 根据产品id获取modbus配置 + * @param productId + * @return + */ + List selectModbusConfigListByProductId(Long productId); } diff --git a/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/ModbusConfigMapper.xml b/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/ModbusConfigMapper.xml index c38eeb13..2888a3d7 100644 --- a/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/ModbusConfigMapper.xml +++ b/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/ModbusConfigMapper.xml @@ -344,4 +344,13 @@ + +