!31 新增云快充1.7 0x3D

* 新增云快充1.7 0x3D
* 添加停止充电的TestController
This commit is contained in:
三丙
2025-08-25 11:09:24 +00:00
parent 9133ed749b
commit 7c26534dff
45 changed files with 636 additions and 63 deletions

View File

@@ -52,9 +52,12 @@
---
#### 0x3B 上行交易记录
#### 0x3B 上行交易记录(<云快充1.7)
`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`
#### 0x3D 上行交易记录≥云快充1.7)
`68cd8001003d55031412782305012018061910262392202312120000100198b70e1110031498b70e111003140100000000008b778bec241e05e4e7e18403a6f28c05edf6b18d5afa8da73be8fd605510cef3860c000000d0fb0100000000000000000000000000d0fb0100000000000000000000000000d0fb0100000000000000000000000000d0fb01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000298b70e111003140000000000d14b0a540a90`
#### 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`

View File

@@ -0,0 +1,43 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.yunkuaichong;
/**
* 云快充协议常量定义
*
* @author sanbing
* @since 2024-12-16
*/
public final class YunKuaiChongProtocolConstants {
private YunKuaiChongProtocolConstants() {
// 工具类,禁止实例化
}
/**
* 协议名称常量
*/
public static final class ProtocolNames {
/** 云快充协议 v1.5.0 */
public static final String YUNKUAICHONG_V150 = "yunkuaichongV150";
/** 云快充协议 v1.6.0 */
public static final String YUNKUAICHONG_V160 = "yunkuaichongV160";
/** 云快充协议 v1.7.0 */
public static final String YUNKUAICHONG_V170 = "yunkuaichongV170";
// 注解专用简短别名
public static final String V150 = YUNKUAICHONG_V150;
public static final String V160 = YUNKUAICHONG_V160;
public static final String V170 = YUNKUAICHONG_V170;
private ProtocolNames() {
// 工具类,禁止实例化
}
}
}

View File

@@ -34,8 +34,9 @@ import static sanbing.jcpp.infrastructure.util.codec.ByteUtil.checkCrcSum;
@Slf4j
public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcessor {
private final Map<Integer, YunKuaiChongUplinkCmdExe> uplinkCmdExeMap = new ConcurrentHashMap<>();
private final Map<Integer, YunKuaiChongDownlinkCmdExe> downlinkCmdExeMap = new ConcurrentHashMap<>();
// 修改为基于协议名+cmd的路由映射格式为 "protocolName:cmd" -> CommandExecutor
private final Map<String, YunKuaiChongUplinkCmdExe> uplinkCmdExeMap = new ConcurrentHashMap<>();
private final Map<String, YunKuaiChongDownlinkCmdExe> downlinkCmdExeMap = new ConcurrentHashMap<>();
public YunKuaiChongProtocolMessageProcessor(Forwarder forwarder, ProtocolContext protocolContext) {
super(forwarder, protocolContext);
@@ -43,10 +44,16 @@ public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcess
Set<Class<?>> cmdClasses = ClassUtil.scanPackageByAnnotation(ClassUtil.getPackage(this.getClass()), YunKuaiChongCmd.class);
cmdClasses.stream().filter(YunKuaiChongUplinkCmdExe.class::isAssignableFrom)
.forEach(clazz -> {
int cmd = clazz.getAnnotation(YunKuaiChongCmd.class).value();
YunKuaiChongCmd annotation = clazz.getAnnotation(YunKuaiChongCmd.class);
int cmd = annotation.value();
String[] protocolNames = annotation.protocolNames();
try {
YunKuaiChongUplinkCmdExe yunKuaiChongUplinkCmdExe = (YunKuaiChongUplinkCmdExe) clazz.getDeclaredConstructor().newInstance();
uplinkCmdExeMap.put(cmd, yunKuaiChongUplinkCmdExe);
// 为每个支持的协议名注册命令执行器
for (String protocolName : protocolNames) {
String key = protocolName + ":" + cmd;
uplinkCmdExeMap.put(key, yunKuaiChongUplinkCmdExe);
}
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException |
@@ -57,10 +64,16 @@ public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcess
cmdClasses.stream().filter(YunKuaiChongDownlinkCmdExe.class::isAssignableFrom)
.forEach(clazz -> {
int cmd = clazz.getAnnotation(YunKuaiChongCmd.class).value();
YunKuaiChongCmd annotation = clazz.getAnnotation(YunKuaiChongCmd.class);
int cmd = annotation.value();
String[] protocolNames = annotation.protocolNames();
try {
YunKuaiChongDownlinkCmdExe yunKuaiChongDownlinkCmdExe = (YunKuaiChongDownlinkCmdExe) clazz.getDeclaredConstructor().newInstance();
downlinkCmdExeMap.put(cmd, yunKuaiChongDownlinkCmdExe);
// 为每个支持的协议名注册命令执行器
for (String protocolName : protocolNames) {
String key = protocolName + ":" + cmd;
downlinkCmdExeMap.put(key, yunKuaiChongDownlinkCmdExe);
}
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException |
@@ -176,12 +189,15 @@ public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcess
}
private void exeCmd(YunKuaiChongUplinkMessage message, TcpSession session) {
YunKuaiChongUplinkCmdExe uplinkCmdExe = uplinkCmdExeMap.get(message.getCmd());
String protocolName = session.getProtocolName();
int cmd = message.getCmd();
String key = protocolName + ":" + cmd;
YunKuaiChongUplinkCmdExe uplinkCmdExe = uplinkCmdExeMap.get(key);
if (uplinkCmdExe == null) {
log.info("{} 云快充协议接收到未知的上行指令 0x{}", session, Integer.toHexString(message.getCmd()));
log.info("{} 云快充协议接收到未知的上行指令,协议: {}, 指令: 0x{}",
session, protocolName, Integer.toHexString(cmd));
return;
}
@@ -189,12 +205,15 @@ public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcess
}
private void exeCmd(YunKuaiChongDwonlinkMessage message, TcpSession session) {
YunKuaiChongDownlinkCmdExe downlinkCmdExe = downlinkCmdExeMap.get(message.getCmd());
String protocolName = session.getProtocolName();
int cmd = message.getCmd();
String key = protocolName + ":" + cmd;
YunKuaiChongDownlinkCmdExe downlinkCmdExe = downlinkCmdExeMap.get(key);
if (downlinkCmdExe == null) {
log.info("{} 云快充协议接收到未知的下行指令 0x{}", session, Integer.toHexString(message.getCmd()));
log.info("{} 云快充协议接收到未知的下行指令,协议: {}, 指令: 0x{}",
session, protocolName, Integer.toHexString(cmd));
return;
}

View File

@@ -18,4 +18,9 @@ public @interface YunKuaiChongCmd {
int value();
/**
* 支持的协议名列表,必须明确指定
*/
String[] protocolNames();
}

View File

@@ -12,17 +12,17 @@ import sanbing.jcpp.protocol.ProtocolBootstrap;
import sanbing.jcpp.protocol.ProtocolMessageProcessor;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolMessageProcessor;
import static sanbing.jcpp.protocol.yunkuaichong.v150.YunkuaichongV150ProtocolBootstrap.PROTOCOL_NAME;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.YUNKUAICHONG_V150;
/**
* @author baigod
*/
@ProtocolComponent(PROTOCOL_NAME)
@ProtocolComponent(YUNKUAICHONG_V150)
@Slf4j
public class YunkuaichongV150ProtocolBootstrap extends ProtocolBootstrap {
public static final String PROTOCOL_NAME = "yunkuaichongV150";
public static final String PROTOCOL_NAME = YUNKUAICHONG_V150;
@Override
protected String getProtocolName() {

View File

@@ -26,11 +26,13 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.util.ArrayList;
import java.util.List;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 充电阶段BMS中止
*/
@Slf4j
@YunKuaiChongCmd(0x1D)
@YunKuaiChongCmd(value = 0x1D, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsAbortULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -21,11 +21,13 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0充电桩错误报文
*/
@Slf4j
@YunKuaiChongCmd(0x1B)
@YunKuaiChongCmd(value = 0x1B, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsChargingErrorULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -21,13 +21,15 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 充电过程BMS信息
*
* @author facai
*/
@Slf4j
@YunKuaiChongCmd(0x25)
@YunKuaiChongCmd(value = 0x25, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsChargingInfoULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -24,13 +24,15 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.nio.charset.StandardCharsets;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 充电握手
*
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x15)
@YunKuaiChongCmd(value = 0x15, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsHandshakeULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -21,12 +21,14 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.math.BigDecimal;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充协议上行命令处理类 - 参数配置帧解析 (V1.5.0版本)
* 命令码0x17 (参数配置帧上行命令)
*/
@Slf4j
@YunKuaiChongCmd(0x17)
@YunKuaiChongCmd(value = 0x17, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsParamConfigReportULCmd extends YunKuaiChongUplinkCmdExe {
// 电流值偏移量常量(单位:安培)
private static final BigDecimal CURRENT_OFFSET = new BigDecimal("-400.0");

View File

@@ -20,6 +20,7 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.HEARTBEAT;
/**
@@ -28,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x03)
@YunKuaiChongCmd(value = 0x03, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150HeartbeatULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -19,12 +19,14 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充协议上行命令处理类 - 地锁状态/报警信息帧 (V1.5.0版本)
* 命令码0x61 (地锁状态/报警信息帧上行命令)
*/
@Slf4j
@YunKuaiChongCmd(0x61)
@YunKuaiChongCmd(value = 0x61, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150LockStatusULCmd extends YunKuaiChongUplinkCmdExe {
/**

View File

@@ -32,6 +32,7 @@ import static sanbing.jcpp.protocol.domain.SessionCloseReason.MANUALLY;
import static sanbing.jcpp.protocol.listener.tcp.TcpSession.SCHEDULE_KEY_AUTO_SYNC_TIME;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage.FAILURE_BYTE;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage.SUCCESS_BYTE;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.LOGIN_ACK;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.SYNC_TIME;
@@ -41,7 +42,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x02)
@YunKuaiChongCmd(value = 0x02, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150LoginAckDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -22,11 +22,13 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.nio.charset.StandardCharsets;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0充电桩登录认证
*/
@Slf4j
@YunKuaiChongCmd(0x01)
@YunKuaiChongCmd(value = 0x01, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150LoginULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -19,6 +19,7 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.math.BigDecimal;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OFFLINE_CARD_BALANCE_UPDATE_REQUEST;
@@ -28,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(0x42)
@YunKuaiChongCmd(value = 0x42, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardBalanceUpdateRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -21,6 +21,8 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.util.Map;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 余额更新应答
@@ -28,7 +30,7 @@ import java.util.Map;
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(0x41)
@YunKuaiChongCmd(value = 0x41, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardBalanceUpdateResponseULCmd extends YunKuaiChongUplinkCmdExe {
private static final Map<Byte, String> UPDATE_RESULT;

View File

@@ -6,8 +6,6 @@
*/
package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OFFLINE_CARD_SYNC_REQUEST;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
@@ -19,6 +17,9 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OFFLINE_CARD_SYNC_REQUEST;
/**
* 云快充1.5.0 离线卡数据同步
@@ -26,7 +27,7 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(0x44)
@YunKuaiChongCmd(value = 0x44, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardSyncRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -7,8 +7,6 @@
package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import java.util.Map;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
@@ -20,6 +18,10 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.util.Map;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 离线卡数据同步应答
@@ -27,7 +29,7 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(0x43)
@YunKuaiChongCmd(value = 0x43, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardSyncResponseULCmd extends YunKuaiChongUplinkCmdExe {
private static final Map<Byte, Map<Byte, String>> FAILURE_REASON;

View File

@@ -16,6 +16,7 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OTA_REQUEST;
@@ -25,7 +26,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(0x94)
@YunKuaiChongCmd(value = 0x94, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OtaRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -19,6 +19,8 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.util.Map;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 远程更新应答
@@ -26,7 +28,7 @@ import java.util.Map;
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(0x93)
@YunKuaiChongCmd(value = 0x93, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OtaResponseULCmd extends YunKuaiChongUplinkCmdExe {
private static final Map<Byte, String> UPGRADE_STATUS;

View File

@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import static sanbing.jcpp.proto.gen.ProtocolProto.PricingModelFlag.*;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.QUERY_PRICING_ACK;
/**
@@ -33,7 +34,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x0A)
@YunKuaiChongCmd(value = 0x0A, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150QueryPricingModelAckDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -20,12 +20,14 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0充电桩计费模型请求
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x09)
@YunKuaiChongCmd(value = 0x09, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150QueryPricingModelULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -28,13 +28,15 @@ import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0上传实时监测数据
*
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x13)
@YunKuaiChongCmd(value = 0x13, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RealTimeDataULCmd extends YunKuaiChongUplinkCmdExe {
// 故障说明列表

View File

@@ -20,6 +20,7 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.math.BigDecimal;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_START_CHARGING;
/**
@@ -28,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x34)
@YunKuaiChongCmd(value = 0x34, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RemoteStartDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -21,13 +21,15 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 远程启动充电命令回复
*
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x33)
@YunKuaiChongCmd(value = 0x33, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RemoteStartResultULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -16,6 +16,7 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_STOP_CHARGING;
/**
@@ -24,7 +25,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x36)
@YunKuaiChongCmd(value = 0x36, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RemoteStopDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -21,13 +21,15 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 远程停机命令回复
*
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x35)
@YunKuaiChongCmd(value = 0x35, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RemoteStopResultULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -19,11 +19,13 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 远程重启充电命令回复
*/
@Slf4j
@YunKuaiChongCmd(0x91)
@YunKuaiChongCmd(value = 0x91, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RestartPileAckULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -16,13 +16,14 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_RESTART_PILE;
/**
* 云快充1.5.0 运营平台远程重启充电桩
*/
@Slf4j
@YunKuaiChongCmd(0x92)
@YunKuaiChongCmd(value = 0x92, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RestartPileDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -18,6 +18,7 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.SET_PRICING;
/**
@@ -26,7 +27,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x57)
@YunKuaiChongCmd(value = 0x57, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150SetPricingModelAckULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import static sanbing.jcpp.proto.gen.ProtocolProto.PricingModelFlag.*;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.SET_PRICING;
/**
@@ -33,7 +34,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x58)
@YunKuaiChongCmd(value = 0x58, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150SetPricingModelDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -18,6 +18,7 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.SYNC_TIME;
/**
@@ -27,7 +28,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @since 1.0.0
*/
@Slf4j
@YunKuaiChongCmd(0x56)
@YunKuaiChongCmd(value = 0x56, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150TimeSyncDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -21,6 +21,8 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.time.LocalDateTime;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0 对时结果
*
@@ -28,7 +30,7 @@ import java.time.LocalDateTime;
* @since 1.0.0
*/
@Slf4j
@YunKuaiChongCmd(0x55)
@YunKuaiChongCmd(value = 0x55, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150TimeSyncResultULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -20,6 +20,7 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage.FAILURE_BYTE;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage.SUCCESS_BYTE;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.TRANSACTION_RECORD_ACK;
/**
@@ -27,7 +28,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x40)
@YunKuaiChongCmd(value = 0x40, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150TransactionRecordAckDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -25,13 +25,16 @@ import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneId;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V150;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
/**
* 云快充1.5.0 交易记录
*
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x3B)
@YunKuaiChongCmd(value = 0x3B, protocolNames = {V150, V160})
public class YunKuaiChongV150TransactionRecordULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -22,6 +22,7 @@ import java.util.Arrays;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage.FAILURE_BYTE;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage.SUCCESS_BYTE;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.VERIFY_PRICING_ACK;
/**
@@ -30,7 +31,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x06)
@YunKuaiChongCmd(value = 0x06, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150VerifyPricingModelAckDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -21,6 +21,8 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
/**
* 云快充1.5.0计费模型验证请求
@@ -28,7 +30,7 @@ import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0x05)
@YunKuaiChongCmd(value = 0x05, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150VerifyPricingModelULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -12,17 +12,17 @@ import sanbing.jcpp.protocol.ProtocolBootstrap;
import sanbing.jcpp.protocol.ProtocolMessageProcessor;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolMessageProcessor;
import static sanbing.jcpp.protocol.yunkuaichong.v160.YunkuaichongV160ProtocolBootstrap.PROTOCOL_NAME;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.YUNKUAICHONG_V160;
/**
* @author baigod
*/
@ProtocolComponent(PROTOCOL_NAME)
@ProtocolComponent(YUNKUAICHONG_V160)
@Slf4j
public class YunkuaichongV160ProtocolBootstrap extends ProtocolBootstrap {
public static final String PROTOCOL_NAME = "yunkuaichongV160";
public static final String PROTOCOL_NAME = YUNKUAICHONG_V160;
@Override
protected String getProtocolName() {

View File

@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_PARALLEL_START_CHARGING;
/**
@@ -30,7 +31,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0xA4)
@YunKuaiChongCmd(value = 0xA4, protocolNames = {V160})
public class YunKuaiChongV160RemoteParallelStartDLCmd extends YunKuaiChongDownlinkCmdExe {
static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

View File

@@ -21,13 +21,15 @@ import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
/**
* 云快充1.6.0 远程并充启机命令回复
*
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(0xA3)
@YunKuaiChongCmd(value = 0xA3, protocolNames = {V160})
public class YunKuaiChongV160RemoteParallelStartResultULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -0,0 +1,48 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.yunkuaichong.v170;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.annotation.ProtocolComponent;
import sanbing.jcpp.protocol.ProtocolBootstrap;
import sanbing.jcpp.protocol.ProtocolMessageProcessor;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolMessageProcessor;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.YUNKUAICHONG_V170;
/**
* @author baigod
*/
@ProtocolComponent(YUNKUAICHONG_V170)
@Slf4j
public class YunkuaichongV170ProtocolBootstrap extends ProtocolBootstrap {
public static final String PROTOCOL_NAME = YUNKUAICHONG_V170;
@Override
protected String getProtocolName() {
return PROTOCOL_NAME;
}
@Override
protected void _init() {
// do nothing
}
@Override
protected void _destroy() {
// do nothing
}
@Override
protected ProtocolMessageProcessor messageProcessor() {
return new YunKuaiChongProtocolMessageProcessor(forwarder, protocolContext);
}
}

View File

@@ -0,0 +1,325 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.yunkuaichong.v170.cmd;
import cn.hutool.core.util.HexUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
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.codec.CP56Time2aUtil;
import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.*;
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.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneId;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170;
/**
* 云快充1.7.0 交易记录
*
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x3D, protocolNames = {V170})
public class YunKuaiChongV170TransactionRecordULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {
log.info("{} 云快充1.7.0交易记录", tcpSession);
ByteBuf byteBuf = Unpooled.wrappedBuffer(yunKuaiChongUplinkMessage.getMsgBody());
ObjectNode additionalInfo = JacksonUtil.newObjectNode();
// 1.交易流水号
byte[] tradeNoBytes = new byte[16];
byteBuf.readBytes(tradeNoBytes);
String tradeNo = decodeTradeNo(tradeNoBytes);
// 2.桩编号
byte[] pileCodeBytes = new byte[7];
byteBuf.readBytes(pileCodeBytes);
String pileCode = BCDUtil.toString(pileCodeBytes);
// 3.抢号
byte gunCodeByte = byteBuf.readByte();
String gunCode = BCDUtil.toString(gunCodeByte);
// 4.开始时间
byte[] startTimeBytes = new byte[7];
byteBuf.readBytes(startTimeBytes);
Instant startTime = CP56Time2aUtil.decode(startTimeBytes).atZone(ZoneId.systemDefault()).toInstant();
// 5.结束时间
byte[] endTimeBytes = new byte[7];
byteBuf.readBytes(endTimeBytes);
Instant endTime = CP56Time2aUtil.decode(endTimeBytes).atZone(ZoneId.systemDefault()).toInstant();
// ========== V1.7.0 新增字段 - 在结束时间后立即读取 ==========
// 6.电表表号
byte[] meterNoBytes = new byte[6];
byteBuf.readBytes(meterNoBytes);
String meterNo = BCDUtil.toString(meterNoBytes);
additionalInfo.put("电表表号", meterNo);
// 7.电表密文
byte[] meterContextEncyptB = new byte[34];
byteBuf.readBytes(meterContextEncyptB);
additionalInfo.put("电表密文", HexUtil.encodeHexStr(meterContextEncyptB));
// 8.电表协议版本号
additionalInfo.put("电表协议版本号", byteBuf.readUnsignedShortLE());
// 9.加密方式
additionalInfo.put("加密方式", byteBuf.readUnsignedByte());
// 10.尖单价
BigDecimal topPrice = reduceMagnification(byteBuf.readUnsignedIntLE(), 100000);
additionalInfo.put("尖单价", topPrice);
// 11. 尖电量
BigDecimal topEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 12.计损尖电量
BigDecimal topLoseEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
additionalInfo.put("计损尖电量", topLoseEnergy);
// 13.尖金额
BigDecimal topAmount = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 14.峰单价
BigDecimal peakPrice = reduceMagnification(byteBuf.readUnsignedIntLE(), 100000);
additionalInfo.put("峰单价", peakPrice);
// 15. 峰电量
BigDecimal peakEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 16.计损峰电量
BigDecimal peakLoseEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
additionalInfo.put("计损峰电量", peakLoseEnergy);
// 17.峰金额
BigDecimal peakAmount = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 18.平单价
BigDecimal flatPrice = reduceMagnification(byteBuf.readUnsignedIntLE(), 100000);
additionalInfo.put("平单价", flatPrice);
// 19. 平电量
BigDecimal flatEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 20.计损平电量
BigDecimal flatLoseEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
additionalInfo.put("计损平电量", flatLoseEnergy);
// 21.平金额
BigDecimal flatAmount = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 22.谷单价
BigDecimal valleyPrice = reduceMagnification(byteBuf.readUnsignedIntLE(), 100000);
additionalInfo.put("谷单价", valleyPrice);
// 23. 谷电量
BigDecimal valleyEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 24.计损谷电量
BigDecimal valleyLoseEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
additionalInfo.put("计损谷电量", valleyLoseEnergy);
// 25.谷金额
BigDecimal valleyAmount = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 26.电表总起值
byte[] meterStartValueBytes = new byte[5];
byteBuf.readBytes(meterStartValueBytes);
BigDecimal startMeterValue = reduceMagnification(readLongLE5Byte(meterStartValueBytes), 10000, 4);
additionalInfo.put("电表总起值", startMeterValue);
// 27.电表总止值
byte[] meterEndValueBytes = new byte[5];
byteBuf.readBytes(meterEndValueBytes);
BigDecimal endMeterValue = reduceMagnification(readLongLE5Byte(meterEndValueBytes), 10000, 4);
additionalInfo.put("电表总止值", endMeterValue);
// 28.总电量
BigDecimal totalEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000, 4);
// 29.计损总电量
BigDecimal totalLoseEnergy = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000, 4);
additionalInfo.put("计损总电量", totalLoseEnergy);
// 30 .消费金额
BigDecimal totalAmount = reduceMagnification(byteBuf.readUnsignedIntLE(), 10000);
// 31.电动汽车唯一标识
byte[] carVINBytes = new byte[17];
byteBuf.readBytes(carVINBytes);
String bmsVinCode = new String(carVINBytes, StandardCharsets.US_ASCII);
additionalInfo.put("电动汽车唯一标识", bmsVinCode);
// 32.交易标识 0x01app 启动0x02卡启动 0x04离线卡启动 0x05: vin 码启动充电
byte tradeFlag = byteBuf.readByte();
additionalInfo.put("交易标识", mapStartFlag(tradeFlag));
// 33.交易日期、时间
byte[] tradeTimeBytes = new byte[7];
byteBuf.readBytes(tradeTimeBytes);
Instant tradeTime = CP56Time2aUtil.decode(tradeTimeBytes).atZone(ZoneId.systemDefault()).toInstant();
// 34.停止原因
byte stopReasonByte = byteBuf.readByte();
String stopReason = mapStopReason(stopReasonByte);
// 35. 物理卡号
byte[] cardNoBytes = new byte[8];
byteBuf.readBytes(cardNoBytes);
String cardNo = BCDUtil.toString(cardNoBytes);
additionalInfo.put("物理卡号", cardNo);
// 构建峰谷电量明细
PeakValleyDetail peakValleyDetail = PeakValleyDetail.newBuilder()
.setTopEnergyKWh(topEnergy.toPlainString())
.setTopAmountYuan(topAmount.toPlainString())
.setPeakEnergyKWh(peakEnergy.toPlainString())
.setPeakAmountYuan(peakAmount.toPlainString())
.setFlatEnergyKWh(flatEnergy.toPlainString())
.setFlatAmountYuan(flatAmount.toPlainString())
.setValleyEnergyKWh(valleyEnergy.toPlainString())
.setValleyAmountYuan(valleyAmount.toPlainString())
.build();
// 构建交易明细
TransactionDetail transactionDetail = TransactionDetail.newBuilder()
.setType(DetailType.PEAK_VALLEY)
.setPeakValley(peakValleyDetail)
.build();
// 构建交易记录
TransactionRecordRequest transactionRecordRequest = TransactionRecordRequest.newBuilder()
.setPileCode(pileCode)
.setGunCode(gunCode)
.setTradeNo(tradeNo)
.setStartTs(startTime.toEpochMilli())
.setEndTs(endTime.toEpochMilli())
.setTotalEnergyKWh(totalEnergy.toPlainString())
.setTotalAmountYuan(totalAmount.toPlainString())
.setTradeTs(tradeTime.toEpochMilli())
.setStopReason(stopReason)
.setDetail(transactionDetail)
.setAdditionalInfo(additionalInfo.toString())
.build();
// 转发到后端
UplinkQueueMessage uplinkQueueMessage = uplinkMessageBuilder(pileCode, tcpSession, yunKuaiChongUplinkMessage)
.setTransactionRecordRequest(transactionRecordRequest)
.build();
tcpSession.getForwarder().sendMessage(uplinkQueueMessage);
}
public static long readLongLE5Byte(byte[] bytes) {
// 确保字节数组的长度至少为 5
if (bytes.length < 5) {
throw new IllegalArgumentException("Byte array must contain at least 5 bytes.");
}
// 使用小端字节序读取 5 字节数字
int byte1 = bytes[0] & 0xFF;
int byte2 = bytes[1] & 0xFF;
int byte3 = bytes[2] & 0xFF;
int byte4 = bytes[3] & 0xFF;
int byte5 = bytes[4] & 0xFF;
// 将读取的字节合并成一个 long 值
return ((long) byte1) |
((long) byte2 << 8) |
((long) byte3 << 16) |
((long) byte4 << 24) |
((long) byte5 << 32);
}
public static String mapStartFlag(byte startFlag) {
return switch (startFlag) {
case 0x01 -> "app 启动";
case 0x02 -> "卡启动";
case 0x04 -> "离线卡启动";
case 0x05 -> "vin 码启动充电";
default -> "未知启动方式";
};
}
public static String mapStopReason(byte stopReasonCode) {
return switch (stopReasonCode) {
case (byte) 0x40 -> "结束充电APP 远程停止";
case (byte) 0x41 -> "结束充电SOC 达到 100%";
case (byte) 0x42 -> "结束充电,充电电量满足设定条件";
case (byte) 0x43 -> "结束充电,充电金额满足设定条件";
case (byte) 0x44 -> "结束充电,充电时间满足设定条件";
case (byte) 0x45 -> "结束充电,手动停止充电";
case (byte) 0x46, (byte) 0x47, (byte) 0x48, (byte) 0x49 -> "结束充电,其他方式(预留)";
case (byte) 0x4A -> "充电启动失败,充电桩控制系统故障(需要重启或自动恢复)";
case (byte) 0x4B -> "充电启动失败,控制导引断开";
case (byte) 0x4C -> "充电启动失败,断路器跳位";
case (byte) 0x4D -> "充电启动失败,电表通信中断";
case (byte) 0x4E -> "充电启动失败,余额不足";
case (byte) 0x4F -> "充电启动失败,充电模块故障";
case (byte) 0x50 -> "充电启动失败,急停开入";
case (byte) 0x51 -> "充电启动失败,防雷器异常";
case (byte) 0x52 -> "充电启动失败BMS 未就绪";
case (byte) 0x53 -> "充电启动失败,温度异常";
case (byte) 0x54 -> "充电启动失败,电池反接故障";
case (byte) 0x55 -> "充电启动失败,电子锁异常";
case (byte) 0x56 -> "充电启动失败,合闸失败";
case (byte) 0x57 -> "充电启动失败,绝缘异常";
case (byte) 0x58 -> "充电启动失败,预留";
case (byte) 0x59 -> "充电启动失败,接收 BMS 握手报文 BHM 超时";
case (byte) 0x5A -> "充电启动失败,接收 BMS 和车辆的辨识报文超时 BRM";
case (byte) 0x5B -> "充电启动失败,接收电池充电参数报文超时 BCP";
case (byte) 0x5C -> "充电启动失败,接收 BMS 完成充电准备报文超时 BRO AA";
case (byte) 0x5D -> "充电启动失败,接收电池充电总状态报文超时 BCS";
case (byte) 0x5E -> "充电启动失败,接收电池充电要求报文超时 BCL";
case (byte) 0x5F -> "充电启动失败,接收电池状态信息报文超时 BSM";
case (byte) 0x60 -> "充电启动失败GB2015 电池在 BHM 阶段有电压不允许充电";
case (byte) 0x61 -> "充电启动失败GB2015 辨识阶段在 BRO_AA 时候电池实际电压与 BCP 报文电池电压差距大于 5%";
case (byte) 0x62 -> "充电启动失败B2015 充电机在预充电阶段从 BRO_AA 变成BRO_00 状态";
case (byte) 0x63 -> "充电启动失败,接收主机配置报文超时";
case (byte) 0x64 -> "充电启动失败,充电机未准备就绪,我们没有回 CRO AA对应老国标";
case (byte) 0x65, (byte) 0x66, (byte) 0x67, (byte) 0x68, (byte) 0x69 -> "充电启动失败,其他原因(预留)";
case (byte) 0x6A -> "充电异常中止,系统闭锁";
case (byte) 0x6B -> "充电异常中止,导引断开";
case (byte) 0x6C -> "充电异常中止,断路器跳位";
case (byte) 0x6D -> "充电异常中止,电表通信中断";
case (byte) 0x6E -> "充电异常中止,余额不足";
case (byte) 0x6F -> "充电异常中止,交流保护动作";
case (byte) 0x70 -> "充电异常中止,直流保护动作";
case (byte) 0x71 -> "充电异常中止,充电模块故障";
case (byte) 0x72 -> "充电异常中止,急停开入";
case (byte) 0x73 -> "充电异常中止,防雷器异常";
case (byte) 0x74 -> "充电异常中止,温度异常";
case (byte) 0x75 -> "充电异常中止,输出异常";
case (byte) 0x76 -> "充电异常中止,充电无流";
case (byte) 0x77 -> "充电异常中止,电子锁异常";
case (byte) 0x78 -> "充电异常中止,预留";
case (byte) 0x79 -> "充电异常中止,总充电电压异常";
case (byte) 0x7A -> "充电异常中止,总充电电流异常";
case (byte) 0x7B -> "充电异常中止,单体充电电压异常";
case (byte) 0x7C -> "充电异常中止,电池组过温";
case (byte) 0x7D -> "充电异常中止,最高单体充电电压异常";
case (byte) 0x7E -> "充电异常中止,最高电池组过温";
case (byte) 0x7F -> "充电异常中止BMV 单体充电电压异常";
case (byte) 0x80 -> "充电异常中止BMT 电池组过温";
case (byte) 0x81 -> "充电异常中止,电池状态异常停止充电";
case (byte) 0x82 -> "充电异常中止,车辆发报文禁止充电";
case (byte) 0x83 -> "充电异常中止,充电桩断电";
case (byte) 0x84 -> "充电异常中止,接收电池充电总状态报文超时";
case (byte) 0x85 -> "充电异常中止,接收电池充电要求报文超时";
case (byte) 0x86 -> "充电异常中止,接收电池状态信息报文超时";
case (byte) 0x87 -> "充电异常中止,接收 BMS 中止充电报文超时";
case (byte) 0x88 -> "充电异常中止,接收 BMS 充电统计报文超时";
case (byte) 0x89 -> "充电异常中止,接收对侧 CCS 报文超时";
case (byte) 0x8A, (byte) 0x8B, (byte) 0x8C, (byte) 0x8D, (byte) 0x8E, (byte) 0x8F ->
"充电异常中止,其他原因(预留)";
case (byte) 0x90 -> "未知原因停止";
default -> "无效的错误码";
};
}
}