From 3d441d75a3ec5c95442c76ffdab9fc7ad8304a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E4=B8=99?= <10604541+sanbing-os@user.noreply.gitee.com> Date: Thu, 7 Aug 2025 23:03:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=85=85=E7=94=B5BMS?= =?UTF-8?q?=E6=8F=A1=E6=89=8B=E8=BD=AC=E5=8F=91=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jcpp/app/service/PileProtocolService.java | 5 ++ .../impl/DefaultPileProtocolService.java | 23 ++++++++ .../ProtocolUplinkConsumerService.java | 4 ++ .../src/main/proto/protocol.proto | 38 ++++++++++--- .../JCPPLengthFieldBasedFrameDecoder.java | 2 +- jcpp-protocol-yunkuaichong/READMD.md | 5 ++ .../YunKuaiChongProtocolMessageProcessor.java | 2 +- .../cmd/YunKuaiChongV150BmsAbortULCmd.java | 5 ++ .../YunKuaiChongV150BmsChargingInfoULCmd.java | 5 ++ .../YunKuaiChongV150BmsHandshakeULCmd.java | 53 ++++++++++++------- 10 files changed, 115 insertions(+), 27 deletions(-) diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java index 6dc0562..2f36010 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java @@ -111,4 +111,9 @@ public interface PileProtocolService { */ void onBmsAbort(UplinkQueueMessage uplinkQueueMessage, Callback callback); + /** + * BMS充电握手 + */ + void onBmsHandshake(UplinkQueueMessage uplinkQueueMessage, Callback callback); + } \ No newline at end of file diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java index a284c86..e70dac6 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java @@ -378,6 +378,29 @@ public class DefaultPileProtocolService implements PileProtocolService { callback.onSuccess(); } + @Override + public void onBmsHandshake(UplinkQueueMessage uplinkQueueMessage, Callback callback) { + log.info("接收到BMS充电握手信息 {}", uplinkQueueMessage); + BmsHandshakeProto bmsHandshakeProto = uplinkQueueMessage.getBmsHandshakeProto(); + String tradeNo = bmsHandshakeProto.getTradeNo(); + String pileCode = bmsHandshakeProto.getPileCode(); + String gunCode = bmsHandshakeProto.getGunCode(); + String carVinCode = bmsHandshakeProto.getCarVinCode(); + String bmsProtocolVersion = bmsHandshakeProto.getBmsProtocolVersion(); + int bmsBatteryType = bmsHandshakeProto.getBmsBatteryType(); + int bmsPowerCapacity = bmsHandshakeProto.getBmsPowerCapacity(); + String additionalInfo = bmsHandshakeProto.getAdditionalInfo(); + + log.info("BMS充电握手信息: 交易流水号: {}, 桩编码: {}, 枪号: {}, 车辆VIN: {}, BMS协议版本: {}, " + + "电池类型: {}, 电池容量: {}Ah, 附加信息: {}", + tradeNo, pileCode, gunCode, carVinCode, bmsProtocolVersion, + bmsBatteryType, bmsPowerCapacity, additionalInfo); + + // TODO 处理相关业务逻辑,比如保存握手信息到数据库 + + callback.onSuccess(); + } + private static Period createPeriod(int sn, LocalTime beginTime, LocalTime endTime, PricingModelFlag flag) { Period period = new Period(); period.setSn(sn); diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java index 3059105..e98d7e8 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java @@ -212,6 +212,10 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService imple pileProtocolService.onRestartPileResponse(uplinkQueueMsg, callback); + } else if (uplinkQueueMsg.hasBmsHandshakeProto()) { + + pileProtocolService.onBmsHandshake(uplinkQueueMsg, callback); + } else { callback.onSuccess(); diff --git a/jcpp-infrastructure-proto/src/main/proto/protocol.proto b/jcpp-infrastructure-proto/src/main/proto/protocol.proto index be6f235..2b7dbd5 100644 --- a/jcpp-infrastructure-proto/src/main/proto/protocol.proto +++ b/jcpp-infrastructure-proto/src/main/proto/protocol.proto @@ -71,6 +71,7 @@ message UplinkQueueMessage { BmsChargingInfoProto bmsChargingInfoProto = 34; BmsAbortProto bmsAbortProto = 35; RestartPileResponse restartPileResponse = 36; + BmsHandshakeProto bmsHandshakeProto = 37; } @@ -335,15 +336,38 @@ message BmsParamConfigReport { } message BmsChargingInfoProto { - string pileCode = 1; - string gunCode = 2; - string tradeNo = 3; - optional string additionalInfo = 4; -} - -message BmsAbortProto { + int64 ts = 1; // 时间戳 string pileCode = 4; string gunCode = 5; string tradeNo = 6; optional string additionalInfo = 20; +} + +message BmsAbortProto { + int64 ts = 1; // 时间戳 + string pileCode = 4; + string gunCode = 5; + string tradeNo = 6; + optional string additionalInfo = 20; +} + +message BmsHandshakeProto { + int64 ts = 1; // 时间戳 + string pileCode = 2; // 桩编码 + string gunCode = 3; // 枪编码 + string tradeNo = 4; // 交易流水号 + string bmsProtocolVersion = 5; // BMS通信协议版本号 + int32 bmsBatteryType = 6; // BMS电池类型 + int32 bmsPowerCapacity = 7; // BMS整车动力蓄电池系统额定容量 + int32 bmsPowerMaxVoltage = 8; // BMS整车动力蓄电池系统额定总电压 + string bmsFactory = 9; // BMS电池生产厂商名称 + int32 bmsSerialNo = 10; // BMS电池组序号 + int32 bmsCreateYear = 11; // BMS电池组生产日期年 + int32 bmsCreateMonth = 12; // BMS电池组生产日期月 + int32 bmsCreateDay = 13; // BMS电池组生产日期日 + int32 bmsChargeCount = 14; // BMS电池组充电次数 + int32 bmsPropertyRightLabel = 15; // BMS电池组产权标识 + string carVinCode = 16; // 车辆识别码(VIN) + string bmsSoftwareVersion = 17; // BMS软件版本号 + optional string additionalInfo = 20; // 附加信息 } \ No newline at end of file diff --git a/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/decoder/JCPPLengthFieldBasedFrameDecoder.java b/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/decoder/JCPPLengthFieldBasedFrameDecoder.java index 2a658d1..3bdb8a6 100644 --- a/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/decoder/JCPPLengthFieldBasedFrameDecoder.java +++ b/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/listener/tcp/decoder/JCPPLengthFieldBasedFrameDecoder.java @@ -134,7 +134,7 @@ public class JCPPLengthFieldBasedFrameDecoder extends ByteToMessageDecoder { // frameLengthInt exist , just check buf if (in.readableBytes() < frameLengthInt) { - log.debug("{} 可读长度小于帧长,因此跳过 {}", ctx.channel(), frameLengthInt); + log.debug("{} 可读长度小于帧长 {},因此跳过", ctx.channel(), frameLengthInt); return BREAK; } diff --git a/jcpp-protocol-yunkuaichong/READMD.md b/jcpp-protocol-yunkuaichong/READMD.md index e5e67f6..d050784 100644 --- a/jcpp-protocol-yunkuaichong/READMD.md +++ b/jcpp-protocol-yunkuaichong/READMD.md @@ -40,6 +40,11 @@ --- +#### 0x15 充电握手 +`68 4d 00 15 00 15 32 01 02 00 00 00 00 11 15 11 16 15 55 35 02 60 20 23 12 12 00 00 10 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 a1` + +--- + #### 0x34 下发启动充电 `68 30 01 00 00 34 00 00 00 00 00 00 12 34 56 78 90 12 34 56 78 90 20 23 12 12 00 00 10 01 56 78 90 12 34 56 78 90 56 78 90 12 34 56 78 90 10 27 00 00 5f d9` #### 0x33 上行启动应答 diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java index f3a884c..7808c29 100644 --- a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/YunKuaiChongProtocolMessageProcessor.java @@ -109,7 +109,7 @@ public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcess if (!checkResult.getFirst()) { if (log.isDebugEnabled()) { // 日志惰性计算 log.debug("{} 云快充校验域一次校验失败 CMD:{} 校验和:0x{} 期望校验和:0x{}", - session, frameType, Integer.toHexString(checkSumBE), Integer.toHexString(checkSumLE)); + session, frameType, Integer.toHexString(checkSumLE), Integer.toHexString(checkResult.getSecond())); } checkResult = checkCrcSum(checkData, checkSumBE); } diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsAbortULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsAbortULCmd.java index 4ab0500..9022177 100644 --- a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsAbortULCmd.java +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsAbortULCmd.java @@ -14,6 +14,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import sanbing.jcpp.infrastructure.util.codec.BCDUtil; import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; +import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil; import sanbing.jcpp.proto.gen.ProtocolProto.BmsAbortProto; import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage; import sanbing.jcpp.protocol.ProtocolContext; @@ -37,6 +38,9 @@ public class YunKuaiChongV150BmsAbortULCmd extends YunKuaiChongUplinkCmdExe { log.debug("{} 云快充1.5.0充电阶段BMS中止", tcpSession); ByteBuf byteBuf = Unpooled.wrappedBuffer(yunKuaiChongUplinkMessage.getMsgBody()); + // 从Tracer总获取当前时间 + long ts = TracerContextUtil.getCurrentTracer().getTracerTs(); + ObjectNode additionalInfo = JacksonUtil.newObjectNode(); // 1.交易流水号 byte[] tradeNoBytes = new byte[16]; @@ -65,6 +69,7 @@ public class YunKuaiChongV150BmsAbortULCmd extends YunKuaiChongUplinkCmdExe { additionalInfo.put("BMS中止充电错误原因", parseErrorReasons(errorReasonByte)); BmsAbortProto proto = BmsAbortProto.newBuilder() + .setTs(ts) .setPileCode(pileCode) .setGunCode(gunCode) .setTradeNo(tradeNo) diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsChargingInfoULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsChargingInfoULCmd.java index 2dcbdfc..2ef9d93 100644 --- a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsChargingInfoULCmd.java +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsChargingInfoULCmd.java @@ -12,6 +12,7 @@ import io.netty.buffer.Unpooled; import lombok.extern.slf4j.Slf4j; import sanbing.jcpp.infrastructure.util.codec.BCDUtil; import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; +import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil; import sanbing.jcpp.proto.gen.ProtocolProto.BmsChargingInfoProto; import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage; import sanbing.jcpp.protocol.ProtocolContext; @@ -32,6 +33,9 @@ public class YunKuaiChongV150BmsChargingInfoULCmd extends YunKuaiChongUplinkCmdE public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) { log.debug("{} 云快充1.5.0充电过程BMS信息", tcpSession); ByteBuf byteBuf = Unpooled.wrappedBuffer(yunKuaiChongUplinkMessage.getMsgBody()); + // 从Tracer总获取当前时间 + long ts = TracerContextUtil.getCurrentTracer().getTracerTs(); + ObjectNode additionalInfo = JacksonUtil.newObjectNode(); // 1.交易流水号 byte[] tradeNoBytes = new byte[16]; @@ -73,6 +77,7 @@ public class YunKuaiChongV150BmsChargingInfoULCmd extends YunKuaiChongUplinkCmdE byteBuf.skipBytes(2); BmsChargingInfoProto bmsCharingInfoProto = BmsChargingInfoProto.newBuilder() + .setTs(ts) .setPileCode(pileCode) .setTradeNo(tradeNo) .setGunCode(gunCode) diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsHandshakeULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsHandshakeULCmd.java index 1693d0f..e2648d5 100644 --- a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsHandshakeULCmd.java +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsHandshakeULCmd.java @@ -13,6 +13,9 @@ import io.netty.buffer.Unpooled; import lombok.extern.slf4j.Slf4j; import sanbing.jcpp.infrastructure.util.codec.BCDUtil; import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; +import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil; +import sanbing.jcpp.proto.gen.ProtocolProto.BmsHandshakeProto; +import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage; import sanbing.jcpp.protocol.ProtocolContext; import sanbing.jcpp.protocol.listener.tcp.TcpSession; import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe; @@ -34,71 +37,60 @@ public class YunKuaiChongV150BmsHandshakeULCmd extends YunKuaiChongUplinkCmdExe log.debug("{} 云快充1.5.0充电握手", tcpSession); ByteBuf byteBuf = Unpooled.wrappedBuffer(yunKuaiChongUplinkMessage.getMsgBody()); + // 从Tracer总获取当前时间 + long ts = TracerContextUtil.getCurrentTracer().getTracerTs(); + ObjectNode additionalInfo = JacksonUtil.newObjectNode(); // 1.交易流水号 byte[] tradeNoBytes = new byte[16]; byteBuf.readBytes(tradeNoBytes); String tradeNo = BCDUtil.toString(tradeNoBytes); - additionalInfo.put("交易流水号", tradeNo); // 2.桩编号 byte[] pileCodeBytes = new byte[7]; byteBuf.readBytes(pileCodeBytes); String pileCode = BCDUtil.toString(pileCodeBytes); - additionalInfo.put("桩编号", pileCode); // 3.抢号 byte gunCodeByte = byteBuf.readByte(); String gunCode = BCDUtil.toString(gunCodeByte); - additionalInfo.put("抢号", gunCode); // 4.BMS 通信协议版本号 byte[] bmsConnectVersionBytes = new byte[3]; byteBuf.readBytes(bmsConnectVersionBytes); - additionalInfo.put("BMS 通信协议版本号", HexUtil.encodeHexStr(bmsConnectVersionBytes)); // 5.BMS 电池类型 int bmsBatteryType = byteBuf.readUnsignedByte(); - additionalInfo.put("BMS电池类型", bmsBatteryType); // 6.BMS 整车动力蓄电池系统额定容量 int bmsPowerCapacity = byteBuf.readUnsignedShortLE(); - additionalInfo.put("BMS整车动力蓄电池系统额定容量", bmsPowerCapacity); // 7.BMS 整车动力蓄电池系统额定总电压 int bmsPowerMaxVoltage = byteBuf.readUnsignedShortLE(); - additionalInfo.put("BMS整车动力蓄电池系统额定总电压", bmsPowerMaxVoltage); // 8.BMS 电池生产厂商名称 byte[] bmsFactoryBytes = new byte[4]; byteBuf.readBytes(bmsFactoryBytes); String bmsFactory = new String(bmsFactoryBytes, StandardCharsets.US_ASCII); - additionalInfo.put("BMS电池生产厂商名称", bmsFactory); // 9.BMS 电池组序号 int bmsSerialNo = byteBuf.readIntLE(); - additionalInfo.put("BMS 电池组序号", bmsSerialNo); // 10.BMS 电池组生产日期年 int bmsCreateYear = byteBuf.readUnsignedByte(); - additionalInfo.put("BMS 电池组生产日期年", bmsCreateYear); // 11.BMS 电池组生产日期月 int bmsCreateMonth = byteBuf.readUnsignedByte(); - additionalInfo.put("BMS 电池组生产日期月", bmsCreateMonth); // 12.BMS 电池组生产日期日 int bmsCreateDay = byteBuf.readUnsignedByte(); - additionalInfo.put("BMS 电池组生产日期日", bmsCreateDay); // 13.BMS 电池组充电次数 int bmsChargeCount = byteBuf.readUnsignedMedium(); - additionalInfo.put("BMS 电池组充电次数", bmsChargeCount); // 14.BMS 电池组产权标识 int bmsPropertyRightLabel = byteBuf.readUnsignedByte(); - additionalInfo.put("BMS 电池组产权标识", bmsPropertyRightLabel); // 15.预留位 byteBuf.skipBytes(1); @@ -107,14 +99,39 @@ public class YunKuaiChongV150BmsHandshakeULCmd extends YunKuaiChongUplinkCmdExe byte[] carVINBytes = new byte[17]; byteBuf.readBytes(carVINBytes); String bmsVinCode = new String(carVINBytes, StandardCharsets.US_ASCII); - additionalInfo.put("电动汽车唯一标识", bmsVinCode); // 17.BMS 软件版本号 byte[] bmsSoftVersionBytes = new byte[8]; byteBuf.readBytes(bmsSoftVersionBytes); - additionalInfo.put("BMS 软件版本号", HexUtil.encodeHexStr(bmsSoftVersionBytes)); - // TODO 先打印日志,暂不转发 - log.debug("{} 云快充1.5.0充电握手信息解析完成:{}", tcpSession, additionalInfo); + // 构建BmsHandshakeProto对象 + BmsHandshakeProto bmsHandshakeProto = BmsHandshakeProto.newBuilder() + .setTs(ts) + .setPileCode(pileCode) + .setGunCode(gunCode) + .setTradeNo(tradeNo) + .setBmsProtocolVersion(HexUtil.encodeHexStr(bmsConnectVersionBytes)) + .setBmsBatteryType(bmsBatteryType) + .setBmsPowerCapacity(bmsPowerCapacity) + .setBmsPowerMaxVoltage(bmsPowerMaxVoltage) + .setBmsFactory(bmsFactory) + .setBmsSerialNo(bmsSerialNo) + .setBmsCreateYear(bmsCreateYear) + .setBmsCreateMonth(bmsCreateMonth) + .setBmsCreateDay(bmsCreateDay) + .setBmsChargeCount(bmsChargeCount) + .setBmsPropertyRightLabel(bmsPropertyRightLabel) + .setCarVinCode(bmsVinCode) + .setBmsSoftwareVersion(HexUtil.encodeHexStr(bmsSoftVersionBytes)) + .setAdditionalInfo(additionalInfo.toString()) + .build(); + + // 构建上行队列消息 + UplinkQueueMessage uplinkQueueMessage = uplinkMessageBuilder(pileCode, tcpSession, yunKuaiChongUplinkMessage) + .setBmsHandshakeProto(bmsHandshakeProto) + .build(); + + // 转发到应用层 + tcpSession.getForwarder().sendMessage(uplinkQueueMessage); } } \ No newline at end of file