From ccd5d3d943303b0b838d53095adad850fb6e2e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=9C=E9=A3=8E?= Date: Tue, 5 Aug 2025 07:32:39 +0000 Subject: [PATCH] =?UTF-8?q?!16=20=E4=BA=91=E5=BF=AB=E5=85=851.5.0=20?= =?UTF-8?q?=E5=85=85=E7=94=B5=E9=98=B6=E6=AE=B5BMS=E4=B8=AD=E6=AD=A2=20*?= =?UTF-8?q?=20Merge=20branch=20'Feat=5F0x1D'=20into=20develop=20*=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E4=B8=AD=E6=AD=A2=E5=8E=9F=E5=9B=A0;=20?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E9=A2=86=E5=9F=9F=E6=A8=A1=E5=9E=8B=20*=20ad?= =?UTF-8?q?d=20=E4=BA=91=E5=BF=AB=E5=85=851.5.0=20=E5=85=85=E7=94=B5?= =?UTF-8?q?=E9=98=B6=E6=AE=B5BMS=E4=B8=AD=E6=AD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jcpp/app/service/PileProtocolService.java | 6 + .../impl/DefaultPileProtocolService.java | 7 +- .../ProtocolUplinkConsumerService.java | 4 + .../src/main/proto/protocol.proto | 8 + jcpp-protocol-yunkuaichong/READMD.md | 9 +- ...iChongV150BmsAbortDuringChargingULCmd.java | 219 ++++++++++++++++++ 6 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsAbortDuringChargingULCmd.java 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 a88c0df..d7f4be2 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 @@ -93,4 +93,10 @@ public interface PileProtocolService { * 充电过程BMS信息 */ void onBmsCharingInfo(UplinkQueueMessage uplinkQueueMessage, Callback callback); + + /** + * 充电阶段BMS中止 + */ + void bmsAbortDuringCharging(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 308a9eb..988d357 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 @@ -6,6 +6,8 @@ */ package sanbing.jcpp.app.service.impl; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -315,11 +317,14 @@ public class DefaultPileProtocolService implements PileProtocolService { } @Override + public void onBmsChargingErrorProto(UplinkQueueMessage uplinkQueueMessage, Callback callback) { log.info("充电桩与 BMS 充电错误上报 {}", uplinkQueueMessage); + } + public void bmsAbortDuringCharging(UplinkQueueMessage uplinkQueueMessage, Callback callback) { + log.info("接收到充电阶段BMS中止报文 {}", uplinkQueueMessage); // TODO 处理相关业务逻辑 - callback.onSuccess(); } 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 212a22c..95ab83c 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 @@ -204,6 +204,10 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService imple pileProtocolService.onBmsCharingInfo(uplinkQueueMsg, callback); + } else if (uplinkQueueMsg.hasBmsAbortDuringChargingRequest()) { + + pileProtocolService.bmsAbortDuringCharging(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 2e79458..7d143ce 100644 --- a/jcpp-infrastructure-proto/src/main/proto/protocol.proto +++ b/jcpp-infrastructure-proto/src/main/proto/protocol.proto @@ -69,6 +69,7 @@ message UplinkQueueMessage { BmsChargingErrorProto bmsChargingErrorProto = 31; BmsParamConfigReport bmsParamConfigReport = 33; BmsChargingInfoProto bmsChargingInfoProto = 34; + BmsAbortDuringChargingRequest bmsAbortDuringChargingRequest = 35; } message DownlinkRequestMessage { @@ -324,4 +325,11 @@ message BmsChargingInfoProto { string gunCode = 2; string tradeNo = 3; optional string additionalInfo = 4; +} + +message BmsAbortDuringChargingRequest { + string pileCode = 4; + string gunCode = 5; + string tradeNo = 6; + optional string additionalInfo = 20; } \ No newline at end of file diff --git a/jcpp-protocol-yunkuaichong/READMD.md b/jcpp-protocol-yunkuaichong/READMD.md index 2f4ea81..64b721a 100644 --- a/jcpp-protocol-yunkuaichong/READMD.md +++ b/jcpp-protocol-yunkuaichong/READMD.md @@ -49,6 +49,7 @@ #### 0x3B 上行交易记录 `68 a2 00 46 00 3b 20 23 12 12 00 00 10 32 32 39 00 00 00 00 00 00 20 23 12 12 00 00 10 01 b0 36 04 11 6d 0c 17 a0 8c 09 11 6d 0c 17 f0 49 02 00 00 00 00 00 00 00 00 00 00 00 00 00 d0 fb 01 00 00 00 00 00 00 00 00 00 00 00 00 00 b0 ad 01 00 00 00 00 00 00 00 00 00 00 00 00 00 90 5f 01 00 72 06 00 00 72 06 00 00 78 05 00 00 00 00 00 00 00 00 00 00 00 00 72 06 00 00 72 06 00 00 78 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 a0 8c 09 11 6d 0c 17 40 00 00 00 00 00 00 00 00 03 E0` + #### 0x40 下行交易就应答 `68 15 46 00 00 40 20 23 12 12 00 00 10 32 32 39 00 00 00 00 00 00 00 9D 7B` @@ -67,4 +68,10 @@ #### 0x25 充电过程BMS信息 `68 31 01 00 00 25 32 01 02 00 00 00 00 11 15 11 16 15 55 35 02 60 20 23 12 12 00 00 10 01 01 01 01 01 01 01 00 01 00 01 00 01 00 01 00 01 00 01 00 00 00 BE C8` ---- \ No newline at end of file +--- +#### 下行交易就应答 +`68 15 00 46 00 06 20 23 12 12 00 00 10 32 32 39 00 00 00 00 00 00 00 C6 2D ` + +--- +#### 0x1D 充电阶段BMS中止 +`68 20 00 18 00 1D 20 23 12 12 00 00 01 01 11 51 11 61 55 53 50 26 20 23 12 12 00 00 10 01 00 00 00 00 5a 23` diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsAbortDuringChargingULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsAbortDuringChargingULCmd.java new file mode 100644 index 0000000..be43264 --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150BmsAbortDuringChargingULCmd.java @@ -0,0 +1,219 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.base.Joiner; +import io.netty.buffer.ByteBuf; +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.proto.gen.ProtocolProto.BmsAbortDuringChargingRequest; +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; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage; +import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd; + +import java.util.ArrayList; +import java.util.List; + +/** + * 云快充1.5.0 充电阶段BMS中止 + */ +@Slf4j +@YunKuaiChongCmd(0x1D) +public class YunKuaiChongV150BmsAbortDuringChargingULCmd extends YunKuaiChongUplinkCmdExe { + + @Override + public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) { + log.debug("{} 云快充1.5.0充电阶段BMS中止", tcpSession); + ByteBuf byteBuf = Unpooled.wrappedBuffer(yunKuaiChongUplinkMessage.getMsgBody()); + + 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 reasonByte = byteBuf.readByte(); + additionalInfo.put("BMS中止充电原因", parseAbortReasons(reasonByte)); + + // 5.BMS中止充电故障原因 + byte[] faultReasonBytes = new byte[2]; + additionalInfo.put("BMS中止充电故障原因", parseFaultReasons(faultReasonBytes)); + + // 6.BMS中止充电错误原因 + byte errorReasonByte = byteBuf.readByte(); + additionalInfo.put("BMS中止充电错误原因", parseErrorReasons(errorReasonByte)); + + BmsAbortDuringChargingRequest request = BmsAbortDuringChargingRequest.newBuilder() + .setPileCode(pileCode) + .setGunCode(gunCode) + .setTradeNo(tradeNo) + .setAdditionalInfo(additionalInfo.toString()) + .build(); + + // 转发到后端 + UplinkQueueMessage uplinkQueueMessage = uplinkMessageBuilder(pileCode, tcpSession, yunKuaiChongUplinkMessage) + .setBmsAbortDuringChargingRequest(request) + .build(); + + tcpSession.getForwarder().sendMessage(uplinkQueueMessage); + } + + /** + * BMS中止充电原因枚举 + */ + public enum AbortReasonEnum { + SOC_TARGET("需求SOC目标值"), + TOTAL_VOLTAGE("达到总电压设定值"), + CELL_VOLTAGE("达到单体电压设定值"), + CHARGER_INITIATED("充电机主动中止"); + + private final String description; + + AbortReasonEnum(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + } + + /** + * 解析BMS中止充电原因字节 + * + * @param reasonByte 1字节的原因字段值 + * @return 触发的原因描述列表 + */ + public String parseAbortReasons(byte reasonByte) { + List reasons = new ArrayList<>(); + + // 将byte转为无符号整数 (0-255) + int value = reasonByte & 0xFF; + + // 检查每组2bit的状态(从低位到高位) + for (AbortReasonEnum reason : AbortReasonEnum.values()) { + int bitPosition = reason.ordinal() * 2; + int mask = 0b11 << bitPosition; // 创建该组的位掩码 + int groupValue = (value & mask) >>> bitPosition; // 提取组值 + + if (groupValue != 0) { + reasons.add(reason.getDescription()); + } + } + return Joiner.on(",").join(reasons); + } + + /** + * BMS中止充电故障原因枚举 + */ + public enum FaultReasonsEnum { + INSULATION_FAULT("绝缘故障"), + CONNECTOR_OVERHEAT("输出连接器过温故障"), + BMS_COMPONENT_OVERHEAT("BMS元件过温故障"), + CHARGING_CONNECTOR_FAULT("充电连接器故障"), + BATTERY_OVERHEAT("电池组温度过高故障"), + HIGH_VOLTAGE_RELAY_FAULT("高压继电器故障"), + VOLTAGE_DETECTION_FAULT("检测点2电压检测故障"), + OTHER_FAULT("其他故障"); + + private final String description; + + FaultReasonsEnum(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + } + + /** + * 解析BMS中止充电故障原因 + * @param faultBytes 2字节的故障原因字段值 + * @return 触发的故障描述列表 + */ + public String parseFaultReasons(byte[] faultBytes) { + List faults = new ArrayList<>(); + + if (faultBytes == null || faultBytes.length != 2) { + throw new IllegalArgumentException("故障原因字段必须是2字节长度"); + } + + // 将2字节转换为无符号整数 (0-65535) + int value = ((faultBytes[0] & 0xFF) << 8) | (faultBytes[1] & 0xFF); + + // 检查每组2bit的状态 + for (FaultReasonsEnum fault : FaultReasonsEnum.values()) { + int bitPosition = fault.ordinal() * 2; + int mask = 0b11 << bitPosition; // 创建该组的位掩码 + int groupValue = (value & mask) >>> bitPosition; // 提取组值 + + if (groupValue != 0) { + faults.add(fault.getDescription()); + } + } + return Joiner.on(",").join(faults); + } + + /** + * BMS中止充电错误原因枚举 + */ + public enum ErrorReasonsEnum { + CURRENT_OVERFLOW("电流过大"), + VOLTAGE_ABNORMAL("电压异常"); + + private final String description; + + ErrorReasonsEnum(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + } + + /** + * 解析BMS中止充电错误原因 + * @param errorByte 1字节的错误原因字段值 + * @return 触发的错误描述列表 + */ + public String parseErrorReasons(byte errorByte) { + List errors = new ArrayList<>(); + int value = errorByte & 0xFF; + + for (ErrorReasonsEnum error : ErrorReasonsEnum.values()) { + int bitPosition = error.ordinal() * 2; + int mask = 0b11 << bitPosition; + int groupValue = (value & mask) >>> bitPosition; + + if (groupValue != 0) { + errors.add(error.getDescription()); + } + } + return Joiner.on(",").join(errors); + } +}