mirror of
https://gitee.com/san-bing/JChargePointProtocol
synced 2026-05-03 17:39:55 +08:00
!16 云快充1.5.0 充电阶段BMS中止
* Merge branch 'Feat_0x1D' into develop * 解析中止原因; 定义领域模型 * add 云快充1.5.0 充电阶段BMS中止
This commit is contained in:
@@ -93,4 +93,10 @@ public interface PileProtocolService {
|
||||
* 充电过程BMS信息
|
||||
*/
|
||||
void onBmsCharingInfo(UplinkQueueMessage uplinkQueueMessage, Callback callback);
|
||||
|
||||
/**
|
||||
* 充电阶段BMS中止
|
||||
*/
|
||||
void bmsAbortDuringCharging(UplinkQueueMessage uplinkQueueMessage, Callback callback);
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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`
|
||||
|
||||
---
|
||||
---
|
||||
#### 下行交易就应答
|
||||
`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`
|
||||
|
||||
@@ -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<String> 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<String> 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<String> 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user