!33 新增云快充启动充电的逻辑卡号和物理卡号,和双枪并充序号以及双枪并充的测试接口

* 新增云快充启动充电的逻辑卡号和物理卡号,和双枪并充序号以及双枪并充的测试接口
* CMD路由优化
* Merge remote-tracking branch 'gitee/master' into Feat_Lvneng_module_optimize
* cmd路由优化
* cmd路由优化
* 绿能模块优化
* 新增云快充1.7 0x3D
* 添加停止充电的TestController
This commit is contained in:
三丙
2025-08-25 14:04:25 +00:00
parent 7c26534dff
commit 921045af8f
63 changed files with 795 additions and 380 deletions

View File

@@ -8,6 +8,7 @@ package sanbing.jcpp.app.adapter;
import com.google.common.collect.Lists;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -32,7 +33,26 @@ public class TestController {
@GetMapping("/api/startCharge")
public ResponseEntity<String> startCharge() {
pileProtocolService.startCharge("20231212000010", "01", new BigDecimal("50"), "12345678901234567890");
String orderNo = "ORD" + RandomStringUtils.secure().nextNumeric(20);
String logicalCardNo = RandomStringUtils.secure().nextNumeric(12);
String physicalCardNo = RandomStringUtils.secure().nextNumeric(12);
pileProtocolService.startCharge("20231212000010", "01", new BigDecimal("50"), orderNo,
logicalCardNo, physicalCardNo, null);
return ResponseEntity.ok("success");
}
@GetMapping("/api/parallelStartCharge")
public ResponseEntity<String> parallelStartCharge() {
String orderNo = "PAR" + RandomStringUtils.secure().nextNumeric(20);
String logicalCardNo = RandomStringUtils.secure().nextNumeric(12);
String physicalCardNo = RandomStringUtils.secure().nextNumeric(12);
String parallelNo = RandomStringUtils.secure().nextNumeric(6);
pileProtocolService.startCharge("20231212000010", "01", new BigDecimal("100"),
orderNo, logicalCardNo, physicalCardNo, parallelNo);
return ResponseEntity.ok("success");
}

View File

@@ -74,9 +74,11 @@ public interface PileProtocolService {
void onTransactionRecordRequest(UplinkQueueMessage uplinkQueueMessage, Callback callback);
/**
* 启动充电
* 启动充电(支持卡号和并充序号)
* 当 parallelNo 不为空时,自动使用并充启机命令
*/
void startCharge(String pileCode, String gunCode, BigDecimal limitYuan, String orderNo);
void startCharge(String pileCode, String gunCode, BigDecimal limitYuan, String orderNo,
String logicalCardNo, String physicalCardNo, String parallelNo);
/**
* 停止充电
@@ -163,8 +165,15 @@ public interface PileProtocolService {
* 离线卡数据同步应答
*/
void onOfflineCardSyncResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback);
/**
* 实时同步桩时间
*/
void timeSync(String pileCode, LocalDateTime time);
void onTimeSync(UplinkQueueMessage uplinkQueueMessage, Callback callback);
/**
* 实时同步桩时间应答
*/
void onTimeSyncResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback);
}

View File

@@ -281,24 +281,42 @@ public class DefaultPileProtocolService implements PileProtocolService {
}
@Override
public void startCharge(String pileCode, String gunCode, BigDecimal limitYuan, String orderNo) {
public void startCharge(String pileCode, String gunCode, BigDecimal limitYuan, String orderNo,
String logicalCardNo, String physicalCardNo, String parallelNo) {
UUID messageId = UUID.randomUUID();
UUID requestId = UUID.randomUUID();
RemoteStartChargingRequest.Builder requestBuilder = RemoteStartChargingRequest.newBuilder()
.setPileCode(pileCode)
.setGunCode(gunCode)
.setLimitYuan(limitYuan.toPlainString())
.setTradeNo(orderNo);
// 添加可选字段
if (logicalCardNo != null) {
requestBuilder.setLogicalCardNo(logicalCardNo);
}
if (physicalCardNo != null) {
requestBuilder.setPhysicalCardNo(physicalCardNo);
}
if (parallelNo != null) {
requestBuilder.setParallelNo(parallelNo);
}
// 根据是否有并充序号自动选择命令类型
DownlinkCmdEnum downlinkCmd = (parallelNo != null && !parallelNo.trim().isEmpty())
? DownlinkCmdEnum.REMOTE_PARALLEL_START_CHARGING
: DownlinkCmdEnum.REMOTE_START_CHARGING;
DownlinkRequestMessage.Builder downlinkRequestMessageBuilder = DownlinkRequestMessage.newBuilder()
.setMessageIdMSB(messageId.getMostSignificantBits())
.setMessageIdLSB(messageId.getLeastSignificantBits())
.setPileCode(pileCode)
.setRequestIdMSB(requestId.getMostSignificantBits())
.setRequestIdLSB(requestId.getLeastSignificantBits())
.setDownlinkCmd(DownlinkCmdEnum.REMOTE_START_CHARGING.name())
.setRemoteStartChargingRequest(RemoteStartChargingRequest.newBuilder()
.setPileCode(pileCode)
.setGunCode(gunCode)
.setLimitYuan(limitYuan.toPlainString())
.setTradeNo(orderNo)
.build());
.setDownlinkCmd(downlinkCmd.name())
.setRemoteStartChargingRequest(requestBuilder.build());
downlinkCallService.sendDownlinkMessage(downlinkRequestMessageBuilder, pileCode);
}
@@ -476,7 +494,7 @@ public class DefaultPileProtocolService implements PileProtocolService {
}
@Override
public void onTimeSync(UplinkQueueMessage uplinkQueueMessage, Callback callback) {
public void onTimeSyncResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback) {
log.info("对时设置应答 {}", uplinkQueueMessage);
TimeSyncResponse timeSyncResponse = uplinkQueueMessage.getTimeSyncResponse();
String pileCode = timeSyncResponse.getPileCode();

View File

@@ -234,7 +234,7 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService imple
} else if (uplinkQueueMsg.hasTimeSyncResponse()) {
pileProtocolService.onTimeSync(uplinkQueueMsg, callback);
pileProtocolService.onTimeSyncResponse(uplinkQueueMsg, callback);
} else {

View File

@@ -252,6 +252,9 @@ message RemoteStartChargingRequest {
string gunCode = 5;
string tradeNo = 6;
string limitYuan = 7;
optional string logicalCardNo = 8; // 逻辑卡号
optional string physicalCardNo = 9; // 物理卡号
optional string parallelNo = 10; // 并充序号
optional string additionalInfo = 20;
}

View File

@@ -4,23 +4,29 @@
* 抖音程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.yunkuaichong.annotation;
package sanbing.jcpp.protocol.annotation;
import java.lang.annotation.*;
/**
* @author baigod
* 通用协议命令注解
* 所有协议的命令类都应该使用此注解
*
* @author sanbing
* @since 2024-12-16
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface YunKuaiChongCmd {
public @interface ProtocolCmd {
/**
* 命令字值
*/
int value();
/**
* 支持的协议名列表必须明确指定
*/
String[] protocolNames();
}

View File

@@ -13,10 +13,14 @@ public enum DownlinkCmdEnum {
LOGIN_ACK,
HEARTBEAT_ACK,
VERIFY_PRICING_ACK,
QUERY_PRICING_ACK,
REAL_TIME_DATA_ACK,
SET_PRICING,
REMOTE_START_CHARGING,

View File

@@ -0,0 +1,29 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.executor;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.domain.ProtocolSession;
/**
* 通用协议下行命令执行器接口
*
* @param <T> 下行消息类型
* @author sanbing
* @since 2024-12-16
*/
public interface ProtocolDownlinkCmdExe<T> {
/**
* 执行下行命令
*
* @param session TCP会话
* @param downlinkMessage 下行消息
* @param protocolContext 协议上下文
*/
void execute(ProtocolSession session, T downlinkMessage, ProtocolContext protocolContext);
}

View File

@@ -0,0 +1,29 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.executor;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.domain.ProtocolSession;
/**
* 通用协议上行命令执行器接口
*
* @param <T> 上行消息类型
* @author sanbing
* @since 2024-12-16
*/
public interface ProtocolUplinkCmdExe<T> {
/**
* 执行上行命令
*
* @param session TCP会话
* @param uplinkMessage 上行消息
* @param protocolContext 协议上下文
*/
void execute(ProtocolSession session, T uplinkMessage, ProtocolContext protocolContext);
}

View File

@@ -0,0 +1,45 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.mapping;
import sanbing.jcpp.protocol.domain.DownlinkCmdEnum;
/**
* 下行命令转换器接口
*
* 每个协议模块都应该实现此接口,提供从通用下行命令到协议特定命令的转换
*
* @author sanbing
* @since 2024-12-16
*/
public interface DownlinkCmdConverter {
/**
* 将通用下行命令转换为协议特定的命令字
*
* @param downlinkCmd 通用下行命令
* @return 协议特定的命令字,如果不支持该命令则返回 null
*/
Integer convertToCmd(DownlinkCmdEnum downlinkCmd);
/**
* 检查是否支持指定的下行命令
*
* @param downlinkCmd 通用下行命令
* @return 是否支持
*/
default boolean supports(DownlinkCmdEnum downlinkCmd) {
return convertToCmd(downlinkCmd) != null;
}
/**
* 获取协议名称
*
* @return 协议名称
*/
String getProtocolName();
}

View File

@@ -0,0 +1,105 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.routing;
import cn.hutool.core.util.ClassUtil;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
/**
* 通用命令路由器
*
* 提供基于协议名+命令字的路由功能,支持多版本协议
*
* @param <T> 命令执行器类型
* @author sanbing
* @since 2025-08-25
*/
@Slf4j
public class ProtocolCommandRouter<T> {
private final Map<String, T> executorMap = new ConcurrentHashMap<>();
/**
* 构造函数
*
* @param scanBaseClass 要扫描的包的代表类
* @param executorFilter 执行器过滤器,判断类是否为目标执行器类型
*/
public ProtocolCommandRouter(Class<?> scanBaseClass, Predicate<Class<?>> executorFilter) {
initializeRoutes(scanBaseClass, executorFilter);
}
/**
* 初始化路由表
*/
private void initializeRoutes(Class<?> scanBaseClass, Predicate<Class<?>> executorFilter) {
Set<Class<?>> cmdClasses = ClassUtil.scanPackageByAnnotation(
ClassUtil.getPackage(scanBaseClass),
ProtocolCmd.class
);
cmdClasses.stream()
.filter(executorFilter)
.forEach(this::registerExecutor);
}
/**
* 注册命令执行器
*/
private void registerExecutor(Class<?> executorClass) {
ProtocolCmd annotation = executorClass.getAnnotation(ProtocolCmd.class);
if (annotation == null) {
log.warn("类 {} 没有 @ProtocolCmd 注解", executorClass.getName());
return;
}
int cmd = annotation.value();
String[] protocolNames = annotation.protocolNames();
try {
@SuppressWarnings("unchecked")
T executor = (T) executorClass.getDeclaredConstructor().newInstance();
for (String protocolName : protocolNames) {
String key = buildKey(protocolName, cmd);
executorMap.put(key, executor);
log.debug("注册命令执行器: {} -> {}", key, executorClass.getSimpleName());
}
} catch (InstantiationException | IllegalAccessException |
InvocationTargetException | NoSuchMethodException e) {
log.error("无法实例化命令执行器 {}: {}", executorClass.getName(), e.getMessage());
throw new RuntimeException("Failed to instantiate command executor: " + executorClass.getName(), e);
}
}
/**
* 获取命令执行器
*
* @param protocolName 协议名称
* @param cmd 命令字
* @return 命令执行器,如果未找到则返回 null
*/
public T getExecutor(String protocolName, int cmd) {
String key = buildKey(protocolName, cmd);
return executorMap.get(key);
}
/**
* 构建路由键
*/
private String buildKey(String protocolName, int cmd) {
return protocolName + ":" + cmd;
}
}

View File

@@ -9,9 +9,11 @@ package sanbing.jcpp.protocol.lvneng;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import sanbing.jcpp.infrastructure.util.codec.ByteUtil;
import sanbing.jcpp.protocol.domain.DownlinkCmdEnum;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.listener.tcp.enums.SequenceNumberLength;
import sanbing.jcpp.protocol.lvneng.enums.LvnengDownlinkCmdEnum;
import sanbing.jcpp.protocol.lvneng.mapping.LvnengDownlinkCmdConverter;
import sanbing.jcpp.protocol.mapping.DownlinkCmdConverter;
/**
* 绿能协议基础类
@@ -21,11 +23,16 @@ public class AbstractLvnengCmdExe {
protected static final int LVNENG_HEAD = 0xAAF5;
protected static final int LVNENG_ENCRYPTION_FLAG = 0x10;
/**
* 下行命令转换器单例,用于将通用命令转换为协议特定命令值
*/
private static final DownlinkCmdConverter DOWNLINK_CMD_CONVERTER = LvnengDownlinkCmdConverter.getInstance();
/**
* 编码下行消息
* 格式:帧头(2) + 长度(2) + 加密标识(1) + 序号(1) + 命令字(2) + 数据域(n) + 校验和(1)
*/
protected byte[] encode(LvnengDownlinkCmdEnum downlinkCmd,
protected byte[] encode(int downlinkCmd,
int seqNo,
int encryptionFlag,
ByteBuf msgBody) {
@@ -39,13 +46,13 @@ public class AbstractLvnengCmdExe {
response.writeShortLE(totalLength); // 长度
response.writeByte(encryptionFlag); // 加密标识
response.writeByte(seqNo); // 序号
response.writeShortLE(downlinkCmd.getCmd()); // 命令字
response.writeShortLE(downlinkCmd); // 命令字
response.writeBytes(msgBody); // 数据域
// 3. 准备校验和计算的数据(命令字 + 数据域)
byte[] sumData = new byte[2 + msgBodyLength]; // 2字节命令字 + 数据域
sumData[0] = (byte) (downlinkCmd.getCmd() & 0xFF);
sumData[1] = (byte) ((downlinkCmd.getCmd() >> 8) & 0xFF);
sumData[0] = (byte) (downlinkCmd & 0xFF);
sumData[1] = (byte) ((downlinkCmd >> 8) & 0xFF);
if (msgBodyLength > 0) {
System.arraycopy(response.array(), 8, sumData, 2, msgBodyLength);
}
@@ -60,7 +67,7 @@ public class AbstractLvnengCmdExe {
/**
* 编码并发送消息(完整参数版本)
*/
protected void encodeAndWriteFlush(LvnengDownlinkCmdEnum downlinkCmd,
protected void encodeAndWriteFlush(int downlinkCmd,
int seqNo,
int encryptionFlag,
ByteBuf msgBody,
@@ -73,7 +80,7 @@ public class AbstractLvnengCmdExe {
* 编码并发送消息(简化参数版本)
* 使用默认的加密标识和自增序号
*/
protected void encodeAndWriteFlush(LvnengDownlinkCmdEnum downlinkCmd,
protected void encodeAndWriteFlush(int downlinkCmd,
ByteBuf msgBody,
TcpSession tcpSession) {
byte[] encode = encode(downlinkCmd,
@@ -82,4 +89,32 @@ public class AbstractLvnengCmdExe {
msgBody);
tcpSession.writeAndFlush(Unpooled.copiedBuffer(encode));
}
/**
* 便捷方法:直接使用 DownlinkCmdEnum 发送命令
*/
protected void encodeAndWriteFlush(DownlinkCmdEnum downlinkCmdEnum,
int seqNo,
int encryptionFlag,
ByteBuf msgBody,
TcpSession tcpSession) {
if (!DOWNLINK_CMD_CONVERTER.supports(downlinkCmdEnum)) {
throw new IllegalArgumentException("绿能协议不支持下行命令: " + downlinkCmdEnum);
}
Integer cmd = DOWNLINK_CMD_CONVERTER.convertToCmd(downlinkCmdEnum);
encodeAndWriteFlush(cmd, seqNo, encryptionFlag, msgBody, tcpSession);
}
/**
* 便捷方法:直接使用 DownlinkCmdEnum 发送命令(自动生成序列号)
*/
protected void encodeAndWriteFlush(DownlinkCmdEnum downlinkCmdEnum,
ByteBuf msgBody,
TcpSession tcpSession) {
if (!DOWNLINK_CMD_CONVERTER.supports(downlinkCmdEnum)) {
throw new IllegalArgumentException("绿能协议不支持下行命令: " + downlinkCmdEnum);
}
Integer cmd = DOWNLINK_CMD_CONVERTER.convertToCmd(downlinkCmdEnum);
encodeAndWriteFlush(cmd, msgBody, tcpSession);
}
}

View File

@@ -0,0 +1,35 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.lvneng;
/**
* 绿能协议常量定义
*
* @author sanbing
* @since 2024-12-16
*/
public final class LvnengProtocolConstants {
private LvnengProtocolConstants() {
// 工具类,禁止实例化
}
/**
* 协议名称常量
*/
public static final class ProtocolNames {
/** 绿能协议 v3.4.0 */
public static final String LVNENG_V340 = "lvnengV340";
// 注解专用简短别名
public static final String V340 = LVNENG_V340;
private ProtocolNames() {
// 工具类,禁止实例化
}
}
}

View File

@@ -6,7 +6,7 @@
*/
package sanbing.jcpp.protocol.lvneng;
import cn.hutool.core.util.ClassUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
@@ -16,18 +16,16 @@ import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.ProtocolMessageProcessor;
import sanbing.jcpp.protocol.domain.DownlinkCmdEnum;
import sanbing.jcpp.protocol.domain.ListenerToHandlerMsg;
import sanbing.jcpp.protocol.domain.SessionToHandlerMsg;
import sanbing.jcpp.protocol.forwarder.Forwarder;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.lvneng.annotation.LvnengCmd;
import sanbing.jcpp.protocol.lvneng.enums.LvnengDownlinkCmdEnum;
import sanbing.jcpp.protocol.lvneng.mapping.LvnengDownlinkCmdConverter;
import sanbing.jcpp.protocol.mapping.DownlinkCmdConverter;
import sanbing.jcpp.protocol.routing.ProtocolCommandRouter;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
public class LvnengProtocolMessageProcessor extends ProtocolMessageProcessor {
@@ -35,40 +33,26 @@ public class LvnengProtocolMessageProcessor extends ProtocolMessageProcessor {
private static final int HEADER_SIZE = 9; // 帧头(2) + 长度(2) + 加密标识(1) + 序号(1) + 命令字(2) + 校验和(1)
private static final int FRAME_MIN_LENGTH = 9; // 最小帧长度(无数据域的情况)
private final Map<Integer, LvnengUplinkCmdExe> uplinkCmdExeMap = new ConcurrentHashMap<>();
private final Map<Integer, LvnengDownlinkCmdExe> downlinkCmdExeMap = new ConcurrentHashMap<>();
private final ProtocolCommandRouter<LvnengUplinkCmdExe> uplinkRouter;
private final ProtocolCommandRouter<LvnengDownlinkCmdExe> downlinkRouter;
private final DownlinkCmdConverter downlinkCmdConverter;
public LvnengProtocolMessageProcessor(Forwarder forwarder, ProtocolContext protocolContext) {
super(forwarder, protocolContext);
Set<Class<?>> cmdClasses = ClassUtil.scanPackageByAnnotation(ClassUtil.getPackage(this.getClass()), LvnengCmd.class);
cmdClasses.stream().filter(LvnengUplinkCmdExe.class::isAssignableFrom)
.forEach(clazz -> {
int cmd = clazz.getAnnotation(LvnengCmd.class).value();
try {
LvnengUplinkCmdExe lvnengUplinkCmdExe = (LvnengUplinkCmdExe) clazz.getDeclaredConstructor().newInstance();
uplinkCmdExeMap.put(cmd, lvnengUplinkCmdExe);
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
// 使用 CommandRouter 替代手动注册逻辑
this.uplinkRouter = new ProtocolCommandRouter<>(
this.getClass(),
LvnengUplinkCmdExe.class::isAssignableFrom
);
cmdClasses.stream().filter(LvnengDownlinkCmdExe.class::isAssignableFrom)
.forEach(clazz -> {
int cmd = clazz.getAnnotation(LvnengCmd.class).value();
try {
LvnengDownlinkCmdExe lvnengDownlinkCmdExe = (LvnengDownlinkCmdExe) clazz.getDeclaredConstructor().newInstance();
downlinkCmdExeMap.put(cmd, lvnengDownlinkCmdExe);
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
this.downlinkRouter = new ProtocolCommandRouter<>(
this.getClass(),
LvnengDownlinkCmdExe.class::isAssignableFrom
);
// 获取下行命令转换器单例
this.downlinkCmdConverter = LvnengDownlinkCmdConverter.getInstance();
}
@Override
@@ -143,7 +127,16 @@ public class LvnengProtocolMessageProcessor extends ProtocolMessageProcessor {
ProtocolProto.DownlinkRequestMessage protocolDownlinkMsg = sessionToHandlerMsg.downlinkMsg();
int cmd = LvnengDownlinkCmdEnum.valueOf(protocolDownlinkMsg.getDownlinkCmd()).getCmd();
DownlinkCmdEnum downlinkCmd = DownlinkCmdEnum.valueOf(protocolDownlinkMsg.getDownlinkCmd());
// 首先检查是否支持该命令
if (!downlinkCmdConverter.supports(downlinkCmd)) {
log.warn("绿能协议不支持下行命令: {}", downlinkCmd);
return;
}
// 支持的命令直接转换这里不会返回null
Integer cmd = downlinkCmdConverter.convertToCmd(downlinkCmd);
LvnengDwonlinkMessage message = new LvnengDwonlinkMessage();
message.setId(new UUID(protocolDownlinkMsg.getMessageIdMSB(), protocolDownlinkMsg.getMessageIdLSB()));
@@ -163,12 +156,13 @@ public class LvnengProtocolMessageProcessor extends ProtocolMessageProcessor {
private void exeCmd(LvnengUplinkMessage message, TcpSession session) {
LvnengUplinkCmdExe uplinkCmdExe = uplinkCmdExeMap.get(message.getCmd());
String protocolName = session.getProtocolName();
int cmd = message.getCmd();
LvnengUplinkCmdExe uplinkCmdExe = uplinkRouter.getExecutor(protocolName, cmd);
if (uplinkCmdExe == null) {
log.info("{} 绿能协议接收到未知的上行指令 0x{}", session, Integer.toHexString(message.getCmd()));
log.info("{} 绿能协议[{}]接收到未知的上行指令 0x{}", session, protocolName, Integer.toHexString(cmd));
return;
}
@@ -176,12 +170,13 @@ public class LvnengProtocolMessageProcessor extends ProtocolMessageProcessor {
}
private void exeCmd(LvnengDwonlinkMessage message, TcpSession session) {
LvnengDownlinkCmdExe downlinkCmdExe = downlinkCmdExeMap.get(message.getCmd());
String protocolName = session.getProtocolName();
int cmd = message.getCmd();
LvnengDownlinkCmdExe downlinkCmdExe = downlinkRouter.getExecutor(protocolName, cmd);
if (downlinkCmdExe == null) {
log.info("{} 绿能协议接收到未知的下行指令 0x{}", session, Integer.toHexString(message.getCmd()));
log.info("{} 绿能协议[{}]接收到未知的下行指令 0x{}", session, protocolName, Integer.toHexString(cmd));
return;
}

View File

@@ -1,21 +0,0 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.lvneng.annotation;
import java.lang.annotation.*;
/**
* @author baigod
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LvnengCmd {
int value();
}

View File

@@ -1,31 +0,0 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.lvneng.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author baigod
*/
@AllArgsConstructor
@Getter
public enum LvnengDownlinkCmdEnum {
LOGIN_ACK((short) 105),
SYNC_TIME((short) 3),
HEARTBEAT_ACK((short) 101),
REAL_TIME_DATA_ACK((short) 103),
TRANSACTION_RECORD_ACK((short) 201);
private final short cmd;
}

View File

@@ -0,0 +1,72 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.lvneng.mapping;
import sanbing.jcpp.protocol.domain.DownlinkCmdEnum;
import sanbing.jcpp.protocol.mapping.DownlinkCmdConverter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 绿能协议下行命令转换器(单例)
*
* 建立通用下行命令与绿能协议特定命令字的显式转换关系
* 使用Map存储转换关系提供O(1)性能
*
* 采用单例模式,避免重复实例化
*
* @author sanbing
* @since 2024-12-16
*/
public class LvnengDownlinkCmdConverter implements DownlinkCmdConverter {
/**
* 单例实例
*/
private static final LvnengDownlinkCmdConverter INSTANCE = new LvnengDownlinkCmdConverter();
/**
* 命令映射表使用Map提供O(1)查找性能
*/
private static final Map<DownlinkCmdEnum, Integer> COMMAND_MAP = new ConcurrentHashMap<>();
static {
// 初始化绿能协议的命令映射
COMMAND_MAP.put(DownlinkCmdEnum.LOGIN_ACK, 105);
COMMAND_MAP.put(DownlinkCmdEnum.SYNC_TIME_REQUEST, 3);
COMMAND_MAP.put(DownlinkCmdEnum.TRANSACTION_RECORD_ACK, 201);
COMMAND_MAP.put(DownlinkCmdEnum.HEARTBEAT_ACK, 101); // 心跳应答
COMMAND_MAP.put(DownlinkCmdEnum.REAL_TIME_DATA_ACK, 103); // 实时数据应答
// 绿能协议支持以上命令其他命令返回null
}
/**
* 私有构造函数,防止外部实例化
*/
private LvnengDownlinkCmdConverter() {
}
/**
* 获取单例实例
*
* @return 单例实例
*/
public static LvnengDownlinkCmdConverter getInstance() {
return INSTANCE;
}
@Override
public Integer convertToCmd(DownlinkCmdEnum downlinkCmd) {
return COMMAND_MAP.get(downlinkCmd);
}
@Override
public String getProtocolName() {
return "绿能协议";
}
}

View File

@@ -12,13 +12,13 @@ import sanbing.jcpp.protocol.ProtocolBootstrap;
import sanbing.jcpp.protocol.ProtocolMessageProcessor;
import sanbing.jcpp.protocol.lvneng.LvnengProtocolMessageProcessor;
import static sanbing.jcpp.protocol.lvneng.v340.LvnengV340ProtocolBootstrap.PROTOCOL_NAME;
import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.LVNENG_V340;
@ProtocolComponent(PROTOCOL_NAME)
@ProtocolComponent(LVNENG_V340)
@Slf4j
public class LvnengV340ProtocolBootstrap extends ProtocolBootstrap {
public static final String PROTOCOL_NAME = "lvnengV340";
public static final String PROTOCOL_NAME = LVNENG_V340;
@Override
protected String getProtocolName() {
return PROTOCOL_NAME;

View File

@@ -15,20 +15,21 @@ import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.HeartBeatRequest;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkCmdExe;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkMessage;
import sanbing.jcpp.protocol.lvneng.annotation.LvnengCmd;
import java.nio.charset.StandardCharsets;
import static sanbing.jcpp.protocol.lvneng.enums.LvnengDownlinkCmdEnum.HEARTBEAT_ACK;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.HEARTBEAT_ACK;
import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340;
/**
* 绿能3.4 充电桩上传心跳包
*/
@Slf4j
@LvnengCmd(102)
@ProtocolCmd(value = 102, protocolNames = {V340})
public class LvnengV340HeartbeatULCmd extends LvnengUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, LvnengUplinkMessage lvnengUplinkMessage, ProtocolContext ctx) {

View File

@@ -16,28 +16,29 @@ import sanbing.jcpp.infrastructure.util.mdc.MDCUtils;
import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.LoginResponse;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.listener.tcp.enums.SequenceNumberLength;
import sanbing.jcpp.protocol.lvneng.LvnengDownlinkCmdExe;
import sanbing.jcpp.protocol.lvneng.LvnengDwonlinkMessage;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkMessage;
import sanbing.jcpp.protocol.lvneng.annotation.LvnengCmd;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import static sanbing.jcpp.infrastructure.util.config.ThreadPoolConfiguration.PROTOCOL_SESSION_SCHEDULED;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.LOGIN_ACK;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.SYNC_TIME_REQUEST;
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.lvneng.enums.LvnengDownlinkCmdEnum.LOGIN_ACK;
import static sanbing.jcpp.protocol.lvneng.enums.LvnengDownlinkCmdEnum.SYNC_TIME;
import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340;
/**
* 绿能3.4 服务器应答充电桩签到命令
*/
@Slf4j
@LvnengCmd(105)
@ProtocolCmd(value = 105, protocolNames = {V340})
public class LvnengV340LoginAckDLCmd extends LvnengDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, LvnengDwonlinkMessage lvnengDwonlinkMessage, ProtocolContext ctx) {
@@ -121,7 +122,7 @@ public class LvnengV340LoginAckDLCmd extends LvnengDownlinkCmdExe {
//7 命令参数数据
msgBodyBuf.writeBytes(BCDUtil.dateToBcd8(LocalDateTime.now()));
encodeAndWriteFlush(SYNC_TIME,
encodeAndWriteFlush(SYNC_TIME_REQUEST,
tcpSession.nextSeqNo(SequenceNumberLength.SHORT),
requestData.getEncryptionFlag(),
msgBodyBuf,

View File

@@ -16,20 +16,22 @@ import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.LoginRequest;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkCmdExe;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkMessage;
import sanbing.jcpp.protocol.lvneng.annotation.LvnengCmd;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneId;
import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340;
/**
* 绿能3.4 充电桩签到信息上报
*/
@Slf4j
@LvnengCmd(106)
@ProtocolCmd(value = 106, protocolNames = {V340})
public class LvnengV340LoginULCmd extends LvnengUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, LvnengUplinkMessage lvnengUplinkMessage, ProtocolContext ctx) {

View File

@@ -19,10 +19,10 @@ import sanbing.jcpp.proto.gen.ProtocolProto.GunRunStatus;
import sanbing.jcpp.proto.gen.ProtocolProto.GunRunStatusProto;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkCmdExe;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkMessage;
import sanbing.jcpp.protocol.lvneng.annotation.LvnengCmd;
import sanbing.jcpp.protocol.lvneng.enums.LvnengAlarmCodeEnum;
import sanbing.jcpp.protocol.lvneng.enums.LvnengPileStartTypeEnum;
import sanbing.jcpp.protocol.lvneng.enums.LvnengPileStatusEnum;
@@ -35,13 +35,14 @@ import java.time.ZoneId;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static sanbing.jcpp.protocol.lvneng.enums.LvnengDownlinkCmdEnum.REAL_TIME_DATA_ACK;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.REAL_TIME_DATA_ACK;
import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340;
/**
* 绿能3.4 充电桩状态信息包上报
*/
@Slf4j
@LvnengCmd(109)
@ProtocolCmd(value = 109, protocolNames = {V340})
public class LvnengV340RealTimeDataULCmd extends LvnengUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, LvnengUplinkMessage lvnengUplinkMessage, ProtocolContext ctx) {

View File

@@ -12,22 +12,23 @@ import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.TransactionRecordResponse;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.lvneng.LvnengDownlinkCmdExe;
import sanbing.jcpp.protocol.lvneng.LvnengDwonlinkMessage;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkMessage;
import sanbing.jcpp.protocol.lvneng.annotation.LvnengCmd;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import static sanbing.jcpp.protocol.lvneng.enums.LvnengDownlinkCmdEnum.TRANSACTION_RECORD_ACK;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.TRANSACTION_RECORD_ACK;
import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340;
/**
* 绿能3.4 服务器应答订单信息
*/
@Slf4j
@LvnengCmd(201)
@ProtocolCmd(value = 201, protocolNames = {V340})
public class LvnengV340TransactionRecordAckDLCmd extends LvnengDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, LvnengDwonlinkMessage lvnengDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -20,10 +20,10 @@ import sanbing.jcpp.proto.gen.ProtocolProto.TransactionDetail;
import sanbing.jcpp.proto.gen.ProtocolProto.TransactionRecordRequest;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkCmdExe;
import sanbing.jcpp.protocol.lvneng.LvnengUplinkMessage;
import sanbing.jcpp.protocol.lvneng.annotation.LvnengCmd;
import sanbing.jcpp.protocol.lvneng.enums.LvnengPileFinishReasonEnum;
import sanbing.jcpp.protocol.lvneng.enums.LvnengPileStartTypeEnum;
@@ -37,11 +37,13 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340;
/**
* 绿能3.4 充电桩上报充电订单
*/
@Slf4j
@LvnengCmd(203)
@ProtocolCmd(value = 203, protocolNames = {V340})
public class LvnengV340TransactionRecordULCmd extends LvnengUplinkCmdExe {
@@ -213,7 +215,6 @@ public class LvnengV340TransactionRecordULCmd extends LvnengUplinkCmdExe {
.build();
tcpSession.getForwarder().sendMessage(uplinkQueueMessage);
}

View File

@@ -12,9 +12,11 @@ import io.netty.buffer.Unpooled;
import org.apache.commons.lang3.StringUtils;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.protocol.domain.DownlinkCmdEnum;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.listener.tcp.enums.SequenceNumberLength;
import sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum;
import sanbing.jcpp.protocol.mapping.DownlinkCmdConverter;
import sanbing.jcpp.protocol.yunkuaichong.mapping.YunKuaiChongDownlinkCmdConverter;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -39,6 +41,11 @@ public class AbstractYunKuaiChongCmdExe {
protected static final byte YUNKUAICHONG_HEAD = 0x68;
protected static final int YUNKUAICHONG_NORMAL_ENCRYPTION_FLAG = 0;
/**
* 下行命令转换器单例,用于将通用命令转换为协议特定命令值
*/
private static final DownlinkCmdConverter DOWNLINK_CMD_CONVERTER = YunKuaiChongDownlinkCmdConverter.getInstance();
private static final DecimalFormat PRICING_ID_DECIMAL_FORMAT = new DecimalFormat("0000");
@@ -104,8 +111,21 @@ public class AbstractYunKuaiChongCmdExe {
return BCDUtil.toBytes(tradeNoStr);
}
/**
* 编码卡号为BCD格式
* 云快充协议卡号为6字节12位BCD码需要做长度校验和补0操作
*/
protected static byte[] encodeCardNo(String cardNo) {
if (StringUtils.length(cardNo) > 12) {
throw new IllegalArgumentException("云快充可接受最大卡号为12位");
}
protected byte[] encode(YunKuaiChongDownlinkCmdEnum downlinkCmd,
String cardNoStr = StringUtils.leftPad(cardNo, 12, '0');
return BCDUtil.toBytes(cardNoStr);
}
protected byte[] encode(int downlinkCmd,
int seqNo,
int encryptionFlag,
ByteBuf msgBody) {
@@ -115,7 +135,7 @@ public class AbstractYunKuaiChongCmdExe {
response.writeByte(msgBodyLength + 4);
response.writeShortLE(seqNo);
response.writeByte(encryptionFlag);
response.writeByte(downlinkCmd.getCmd());
response.writeByte(downlinkCmd);
response.writeBytes(msgBody);
// 帧校验域:从序列号域到数据域的 CRC 校验,校验多项式为 0x180D,低字节在前,高字节在后
@@ -127,7 +147,7 @@ public class AbstractYunKuaiChongCmdExe {
return toBytes(response);
}
protected void encodeAndWriteFlush(YunKuaiChongDownlinkCmdEnum downlinkCmd,
protected void encodeAndWriteFlush(int downlinkCmd,
int seqNo,
int encryptionFlag,
ByteBuf msgBody,
@@ -138,7 +158,7 @@ public class AbstractYunKuaiChongCmdExe {
tcpSession.writeAndFlush(Unpooled.copiedBuffer(encode));
}
protected void encodeAndWriteFlush(YunKuaiChongDownlinkCmdEnum downlinkCmd,
protected void encodeAndWriteFlush(int downlinkCmd,
ByteBuf msgBody,
TcpSession tcpSession) {
@@ -150,6 +170,34 @@ public class AbstractYunKuaiChongCmdExe {
tcpSession.writeAndFlush(Unpooled.copiedBuffer(encode));
}
/**
* 便捷方法:直接使用 DownlinkCmdEnum 发送命令
*/
protected void encodeAndWriteFlush(DownlinkCmdEnum downlinkCmdEnum,
int seqNo,
int encryptionFlag,
ByteBuf msgBody,
TcpSession tcpSession) {
if (!DOWNLINK_CMD_CONVERTER.supports(downlinkCmdEnum)) {
throw new IllegalArgumentException("云快充协议不支持下行命令: " + downlinkCmdEnum);
}
Integer cmd = DOWNLINK_CMD_CONVERTER.convertToCmd(downlinkCmdEnum);
encodeAndWriteFlush(cmd, seqNo, encryptionFlag, msgBody, tcpSession);
}
/**
* 便捷方法:直接使用 DownlinkCmdEnum 发送命令(自动生成序列号)
*/
protected void encodeAndWriteFlush(DownlinkCmdEnum downlinkCmdEnum,
ByteBuf msgBody,
TcpSession tcpSession) {
if (!DOWNLINK_CMD_CONVERTER.supports(downlinkCmdEnum)) {
throw new IllegalArgumentException("云快充协议不支持下行命令: " + downlinkCmdEnum);
}
Integer cmd = DOWNLINK_CMD_CONVERTER.convertToCmd(downlinkCmdEnum);
encodeAndWriteFlush(cmd, msgBody, tcpSession);
}
protected static BigDecimal reduceMagnification(long value, int magnification) {
return new BigDecimal(value).divide(new BigDecimal(magnification), 4, RoundingMode.HALF_UP);
}

View File

@@ -6,7 +6,7 @@
*/
package sanbing.jcpp.protocol.yunkuaichong;
import cn.hutool.core.util.ClassUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
@@ -16,71 +16,43 @@ import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.DownlinkRequestMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.ProtocolMessageProcessor;
import sanbing.jcpp.protocol.domain.DownlinkCmdEnum;
import sanbing.jcpp.protocol.domain.ListenerToHandlerMsg;
import sanbing.jcpp.protocol.domain.SessionToHandlerMsg;
import sanbing.jcpp.protocol.forwarder.Forwarder;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum;
import sanbing.jcpp.protocol.mapping.DownlinkCmdConverter;
import sanbing.jcpp.protocol.routing.ProtocolCommandRouter;
import sanbing.jcpp.protocol.yunkuaichong.mapping.YunKuaiChongDownlinkCmdConverter;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import static sanbing.jcpp.infrastructure.util.codec.ByteUtil.checkCrcSum;
@Slf4j
public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcessor {
// 修改为基于协议名+cmd的路由映射格式为 "protocolName:cmd" -> CommandExecutor
private final Map<String, YunKuaiChongUplinkCmdExe> uplinkCmdExeMap = new ConcurrentHashMap<>();
private final Map<String, YunKuaiChongDownlinkCmdExe> downlinkCmdExeMap = new ConcurrentHashMap<>();
private final ProtocolCommandRouter<YunKuaiChongUplinkCmdExe> uplinkRouter;
private final ProtocolCommandRouter<YunKuaiChongDownlinkCmdExe> downlinkRouter;
private final DownlinkCmdConverter downlinkCmdConverter;
public YunKuaiChongProtocolMessageProcessor(Forwarder forwarder, ProtocolContext protocolContext) {
super(forwarder, protocolContext);
Set<Class<?>> cmdClasses = ClassUtil.scanPackageByAnnotation(ClassUtil.getPackage(this.getClass()), YunKuaiChongCmd.class);
cmdClasses.stream().filter(YunKuaiChongUplinkCmdExe.class::isAssignableFrom)
.forEach(clazz -> {
YunKuaiChongCmd annotation = clazz.getAnnotation(YunKuaiChongCmd.class);
int cmd = annotation.value();
String[] protocolNames = annotation.protocolNames();
try {
YunKuaiChongUplinkCmdExe yunKuaiChongUplinkCmdExe = (YunKuaiChongUplinkCmdExe) clazz.getDeclaredConstructor().newInstance();
// 为每个支持的协议名注册命令执行器
for (String protocolName : protocolNames) {
String key = protocolName + ":" + cmd;
uplinkCmdExeMap.put(key, yunKuaiChongUplinkCmdExe);
}
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
// 使用 CommandRouter 替代手动注册逻辑
this.uplinkRouter = new ProtocolCommandRouter<>(
this.getClass(),
YunKuaiChongUplinkCmdExe.class::isAssignableFrom
);
cmdClasses.stream().filter(YunKuaiChongDownlinkCmdExe.class::isAssignableFrom)
.forEach(clazz -> {
YunKuaiChongCmd annotation = clazz.getAnnotation(YunKuaiChongCmd.class);
int cmd = annotation.value();
String[] protocolNames = annotation.protocolNames();
try {
YunKuaiChongDownlinkCmdExe yunKuaiChongDownlinkCmdExe = (YunKuaiChongDownlinkCmdExe) clazz.getDeclaredConstructor().newInstance();
// 为每个支持的协议名注册命令执行器
for (String protocolName : protocolNames) {
String key = protocolName + ":" + cmd;
downlinkCmdExeMap.put(key, yunKuaiChongDownlinkCmdExe);
}
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
this.downlinkRouter = new ProtocolCommandRouter<>(
this.getClass(),
YunKuaiChongDownlinkCmdExe.class::isAssignableFrom
);
// 获取下行命令转换器单例
this.downlinkCmdConverter = YunKuaiChongDownlinkCmdConverter.getInstance();
}
@Override
@@ -170,7 +142,16 @@ public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcess
DownlinkRequestMessage protocolDownlinkMsg = sessionToHandlerMsg.downlinkMsg();
int cmd = YunKuaiChongDownlinkCmdEnum.valueOf(protocolDownlinkMsg.getDownlinkCmd()).getCmd();
DownlinkCmdEnum downlinkCmd = DownlinkCmdEnum.valueOf(protocolDownlinkMsg.getDownlinkCmd());
// 首先检查是否支持该命令
if (!downlinkCmdConverter.supports(downlinkCmd)) {
log.warn("云快充协议不支持下行命令: {}", downlinkCmd);
return;
}
// 支持的命令直接转换这里不会返回null
Integer cmd = downlinkCmdConverter.convertToCmd(downlinkCmd);
YunKuaiChongDwonlinkMessage message = new YunKuaiChongDwonlinkMessage();
message.setId(new UUID(protocolDownlinkMsg.getMessageIdMSB(), protocolDownlinkMsg.getMessageIdLSB()));
@@ -191,9 +172,8 @@ public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcess
private void exeCmd(YunKuaiChongUplinkMessage message, TcpSession session) {
String protocolName = session.getProtocolName();
int cmd = message.getCmd();
String key = protocolName + ":" + cmd;
YunKuaiChongUplinkCmdExe uplinkCmdExe = uplinkCmdExeMap.get(key);
YunKuaiChongUplinkCmdExe uplinkCmdExe = uplinkRouter.getExecutor(protocolName, cmd);
if (uplinkCmdExe == null) {
log.info("{} 云快充协议接收到未知的上行指令,协议: {}, 指令: 0x{}",
@@ -207,9 +187,8 @@ public class YunKuaiChongProtocolMessageProcessor extends ProtocolMessageProcess
private void exeCmd(YunKuaiChongDwonlinkMessage message, TcpSession session) {
String protocolName = session.getProtocolName();
int cmd = message.getCmd();
String key = protocolName + ":" + cmd;
YunKuaiChongDownlinkCmdExe downlinkCmdExe = downlinkCmdExeMap.get(key);
YunKuaiChongDownlinkCmdExe downlinkCmdExe = downlinkRouter.getExecutor(protocolName, cmd);
if (downlinkCmdExe == null) {
log.info("{} 云快充协议接收到未知的下行指令,协议: {}, 指令: 0x{}",

View File

@@ -1,52 +0,0 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.yunkuaichong.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author baigod
*/
@AllArgsConstructor
@Getter
public enum YunKuaiChongDownlinkCmdEnum {
LOGIN_ACK(0x02),
SYNC_TIME(0x56),
HEARTBEAT(0x04),
VERIFY_PRICING_ACK(0x06),
QUERY_PRICING_ACK(0X0A),
SET_PRICING(0x58),
REMOTE_START_CHARGING(0x34),
REMOTE_STOP_CHARGING(0x36),
TRANSACTION_RECORD_ACK(0x40),
REMOTE_PARALLEL_START_CHARGING(0xA4),
REMOTE_RESTART_PILE(0x92),
OTA_REQUEST(0x94),
OFFLINE_CARD_BALANCE_UPDATE_REQUEST(0x42),
OFFLINE_CARD_SYNC_REQUEST(0x44),
SYNC_TIME_REQUEST(0x56),
;
private final Integer cmd;
}

View File

@@ -0,0 +1,80 @@
/**
* 开源代码,仅供学习和交流研究使用,商用请联系三丙
* 微信mohan_88888
* 抖音:程序员三丙
* 付费课程知识星球https://t.zsxq.com/aKtXo
*/
package sanbing.jcpp.protocol.yunkuaichong.mapping;
import sanbing.jcpp.protocol.domain.DownlinkCmdEnum;
import sanbing.jcpp.protocol.mapping.DownlinkCmdConverter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 云快充协议下行命令转换器(单例)
*
* 建立通用下行命令与云快充协议特定命令字的显式转换关系
* 使用Map存储转换关系提供O(1)性能
*
* 采用单例模式,避免重复实例化
*
* @author sanbing
* @since 2024-12-16
*/
public class YunKuaiChongDownlinkCmdConverter implements DownlinkCmdConverter {
/**
* 单例实例
*/
private static final YunKuaiChongDownlinkCmdConverter INSTANCE = new YunKuaiChongDownlinkCmdConverter();
/**
* 命令映射表使用Map提供O(1)查找性能
*/
private static final Map<DownlinkCmdEnum, Integer> COMMAND_MAP = new ConcurrentHashMap<>();
static {
// 初始化云快充协议的命令映射
COMMAND_MAP.put(DownlinkCmdEnum.LOGIN_ACK, 0x02);
COMMAND_MAP.put(DownlinkCmdEnum.HEARTBEAT_ACK, 0x04); // 心跳应答
COMMAND_MAP.put(DownlinkCmdEnum.VERIFY_PRICING_ACK, 0x06);
COMMAND_MAP.put(DownlinkCmdEnum.QUERY_PRICING_ACK, 0X0A);
COMMAND_MAP.put(DownlinkCmdEnum.SET_PRICING, 0x58);
COMMAND_MAP.put(DownlinkCmdEnum.REMOTE_START_CHARGING, 0x34);
COMMAND_MAP.put(DownlinkCmdEnum.REMOTE_STOP_CHARGING, 0x36);
COMMAND_MAP.put(DownlinkCmdEnum.TRANSACTION_RECORD_ACK, 0x40);
COMMAND_MAP.put(DownlinkCmdEnum.REMOTE_PARALLEL_START_CHARGING, 0xA4);
COMMAND_MAP.put(DownlinkCmdEnum.REMOTE_RESTART_PILE, 0x92);
COMMAND_MAP.put(DownlinkCmdEnum.OTA_REQUEST, 0x94);
COMMAND_MAP.put(DownlinkCmdEnum.OFFLINE_CARD_BALANCE_UPDATE_REQUEST, 0x42);
COMMAND_MAP.put(DownlinkCmdEnum.OFFLINE_CARD_SYNC_REQUEST, 0x44);
COMMAND_MAP.put(DownlinkCmdEnum.SYNC_TIME_REQUEST, 0x56);
}
/**
* 私有构造函数,防止外部实例化
*/
private YunKuaiChongDownlinkCmdConverter() {
}
/**
* 获取单例实例
*
* @return 单例实例
*/
public static YunKuaiChongDownlinkCmdConverter getInstance() {
return INSTANCE;
}
@Override
public Integer convertToCmd(DownlinkCmdEnum downlinkCmd) {
return COMMAND_MAP.get(downlinkCmd);
}
@Override
public String getProtocolName() {
return "云快充协议";
}
}

View File

@@ -18,10 +18,10 @@ 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;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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;
@@ -32,7 +32,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* 云快充1.5.0 充电阶段BMS中止
*/
@Slf4j
@YunKuaiChongCmd(value = 0x1D, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x1D, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsAbortULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -16,10 +16,10 @@ import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.BmsChargingErrorProto;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
@@ -27,7 +27,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* 云快充1.5.0充电桩错误报文
*/
@Slf4j
@YunKuaiChongCmd(value = 0x1B, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x1B, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsChargingErrorULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -16,10 +16,10 @@ 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;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
@@ -29,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author facai
*/
@Slf4j
@YunKuaiChongCmd(value = 0x25, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x25, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsChargingInfoULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -17,10 +17,10 @@ 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.annotation.ProtocolCmd;
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.nio.charset.StandardCharsets;
@@ -32,7 +32,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x15, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x15, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsHandshakeULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -14,10 +14,10 @@ import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.BmsParamConfigReportProto;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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;
@@ -28,7 +28,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* 命令码0x17 (参数配置帧上行命令)
*/
@Slf4j
@YunKuaiChongCmd(value = 0x17, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x17, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150BmsParamConfigReportULCmd extends YunKuaiChongUplinkCmdExe {
// 电流值偏移量常量(单位:安培)
private static final BigDecimal CURRENT_OFFSET = new BigDecimal("-400.0");

View File

@@ -15,13 +15,13 @@ import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.HeartBeatRequest;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.HEARTBEAT_ACK;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.HEARTBEAT;
/**
* 云快充1.5.0 充电桩心跳包
@@ -29,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x03, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x03, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150HeartbeatULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {
@@ -76,7 +76,7 @@ public class YunKuaiChongV150HeartbeatULCmd extends YunKuaiChongUplinkCmdExe {
pingAckMsgBody.writeByte(gunCodeByte);
pingAckMsgBody.writeByte(0);
encodeAndWriteFlush(HEARTBEAT,
encodeAndWriteFlush(HEARTBEAT_ACK,
yunKuaiChongUplinkMessage.getSequenceNumber(),
yunKuaiChongUplinkMessage.getEncryptionFlag(),
pingAckMsgBody,

View File

@@ -14,10 +14,10 @@ import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.GroundLockStatusProto;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
@@ -26,7 +26,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* 命令码0x61 (地锁状态/报警信息帧上行命令)
*/
@Slf4j
@YunKuaiChongCmd(value = 0x61, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x61, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150LockStatusULCmd extends YunKuaiChongUplinkCmdExe {
/**

View File

@@ -16,25 +16,25 @@ import sanbing.jcpp.infrastructure.util.mdc.MDCUtils;
import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.LoginResponse;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.listener.tcp.enums.SequenceNumberLength;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import static sanbing.jcpp.infrastructure.util.config.ThreadPoolConfiguration.PROTOCOL_SESSION_SCHEDULED;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.LOGIN_ACK;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.SYNC_TIME_REQUEST;
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;
/**
* 云快充1.5.0登录认证应答
@@ -42,7 +42,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x02, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x02, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150LoginAckDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
@@ -113,7 +113,7 @@ public class YunKuaiChongV150LoginAckDLCmd extends YunKuaiChongDownlinkCmdExe {
syncTimeMsgBody.writeBytes(pileCodeBytes);
syncTimeMsgBody.writeBytes(CP56Time2aUtil.encode(LocalDateTime.now()));
encodeAndWriteFlush(SYNC_TIME,
encodeAndWriteFlush(SYNC_TIME_REQUEST,
tcpSession.nextSeqNo(SequenceNumberLength.SHORT),
requestData.getEncryptionFlag(),
syncTimeMsgBody,

View File

@@ -15,10 +15,10 @@ import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.LoginRequest;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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.nio.charset.StandardCharsets;
@@ -28,7 +28,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* 云快充1.5.0充电桩登录认证
*/
@Slf4j
@YunKuaiChongCmd(value = 0x01, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x01, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150LoginULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -12,16 +12,15 @@ import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.OfflineCardBalanceUpdateRequest;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.math.BigDecimal;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.OFFLINE_CARD_BALANCE_UPDATE_REQUEST;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OFFLINE_CARD_BALANCE_UPDATE_REQUEST;
/**
* 云快充1.5.0 远程账户余额更新
@@ -29,7 +28,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(value = 0x42, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x42, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardBalanceUpdateRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -14,10 +14,10 @@ import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.OfflineCardBalanceUpdateResponse;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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.Map;
@@ -30,7 +30,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(value = 0x41, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x41, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardBalanceUpdateResponseULCmd extends YunKuaiChongUplinkCmdExe {
private static final Map<Byte, String> UPDATE_RESULT;

View File

@@ -12,13 +12,13 @@ import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.OFFLINE_CARD_SYNC_REQUEST;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OFFLINE_CARD_SYNC_REQUEST;
/**
@@ -27,7 +27,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(value = 0x44, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x44, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardSyncRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -13,10 +13,10 @@ import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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.Map;
@@ -29,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(value = 0x43, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x43, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OfflineCardSyncResponseULCmd extends YunKuaiChongUplinkCmdExe {
private static final Map<Byte, Map<Byte, String>> FAILURE_REASON;

View File

@@ -11,13 +11,13 @@ import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.proto.gen.ProtocolProto.OtaRequest;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.OTA_REQUEST;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.OTA_REQUEST;
/**
@@ -26,7 +26,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(value = 0x94, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x94, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OtaRequestDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -12,10 +12,10 @@ import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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.Map;
@@ -28,7 +28,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author bawan
*/
@Slf4j
@YunKuaiChongCmd(value = 0x93, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x93, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150OtaResponseULCmd extends YunKuaiChongUplinkCmdExe {
private static final Map<Byte, String> UPGRADE_STATUS;

View File

@@ -14,10 +14,10 @@ import sanbing.jcpp.proto.gen.ProtocolProto.PeriodProto;
import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelProto;
import sanbing.jcpp.proto.gen.ProtocolProto.QueryPricingResponse;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.math.BigDecimal;
import java.time.LocalTime;
@@ -25,8 +25,8 @@ import java.util.List;
import java.util.Map;
import static sanbing.jcpp.proto.gen.ProtocolProto.PricingModelFlag.*;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.QUERY_PRICING_ACK;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.QUERY_PRICING_ACK;
/**
* 计费模型请求应答
@@ -34,7 +34,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x0A, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x0A, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150QueryPricingModelAckDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -15,10 +15,10 @@ import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.QueryPricingRequest;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
@@ -27,7 +27,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x09, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x09, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150QueryPricingModelULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -19,10 +19,10 @@ import sanbing.jcpp.proto.gen.ProtocolProto.GunRunStatus;
import sanbing.jcpp.proto.gen.ProtocolProto.GunRunStatusProto;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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.util.ArrayList;
@@ -36,7 +36,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x13, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x13, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RealTimeDataULCmd extends YunKuaiChongUplinkCmdExe {
// 故障说明列表

View File

@@ -9,19 +9,17 @@ package sanbing.jcpp.protocol.yunkuaichong.v150.cmd;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.RemoteStartChargingRequest;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.math.BigDecimal;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.REMOTE_START_CHARGING;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_START_CHARGING;
/**
* 云快充1.5.0 运营平台远程控制启机
@@ -29,7 +27,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x34, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x34, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RemoteStartDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
@@ -46,7 +44,11 @@ public class YunKuaiChongV150RemoteStartDLCmd extends YunKuaiChongDownlinkCmdExe
String tradeNo = remoteStartChargingRequest.getTradeNo();
String limitYuan = remoteStartChargingRequest.getLimitYuan();
byte[] cardNo = encodeCardNo(tradeNo);
// 优先使用传入的卡号,如果没有则使用交易流水号生成
String logicalCardNo = remoteStartChargingRequest.hasLogicalCardNo() ?
remoteStartChargingRequest.getLogicalCardNo() : tradeNo;
String physicalCardNo = remoteStartChargingRequest.hasPhysicalCardNo() ?
remoteStartChargingRequest.getPhysicalCardNo() : tradeNo;
ByteBuf msgBody = Unpooled.buffer(44);
// 交易流水号
@@ -56,9 +58,9 @@ public class YunKuaiChongV150RemoteStartDLCmd extends YunKuaiChongDownlinkCmdExe
// 枪号
msgBody.writeBytes(encodeGunCode(gunCode));
// 逻辑卡号 BCD码
msgBody.writeBytes(cardNo);
msgBody.writeBytes(encodeCardNo(logicalCardNo));
// 物理卡号
msgBody.writeBytes(cardNo);
msgBody.writeBytes(encodeCardNo(physicalCardNo));
// 账户余额
msgBody.writeIntLE(new BigDecimal(limitYuan).multiply(new BigDecimal("100")).intValue());
@@ -67,12 +69,4 @@ public class YunKuaiChongV150RemoteStartDLCmd extends YunKuaiChongDownlinkCmdExe
tcpSession);
}
/**
* 用交易流水号做卡号
*/
private static byte[] encodeCardNo(String tradeNo) {
tradeNo = StringUtils.right(tradeNo, 16);
tradeNo = StringUtils.leftPad(tradeNo, 16, '0');
return BCDUtil.toBytes(tradeNo);
}
}

View File

@@ -16,10 +16,10 @@ import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.RemoteStartChargingResponse;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
@@ -29,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x33, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x33, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RemoteStartResultULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -11,13 +11,13 @@ import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.proto.gen.ProtocolProto.RemoteStopChargingRequest;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.REMOTE_STOP_CHARGING;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_STOP_CHARGING;
/**
* 云快充1.5.0 运营平台远程停机
@@ -25,7 +25,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x36, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x36, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RemoteStopDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -16,10 +16,10 @@ import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.RemoteStopChargingResponse;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
@@ -29,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x35, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x35, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RemoteStopResultULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -14,10 +14,10 @@ import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.RestartPileResponse;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
@@ -25,7 +25,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* 云快充1.5.0 远程重启充电命令回复
*/
@Slf4j
@YunKuaiChongCmd(value = 0x91, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x91, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RestartPileAckULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -11,19 +11,19 @@ import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.proto.gen.ProtocolProto.RestartPileRequest;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.REMOTE_RESTART_PILE;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_RESTART_PILE;
/**
* 云快充1.5.0 运营平台远程重启充电桩
*/
@Slf4j
@YunKuaiChongCmd(value = 0x92, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x92, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150RestartPileDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override

View File

@@ -13,13 +13,14 @@ import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.SetPricingResponse;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 sanbing.jcpp.protocol.yunkuaichong.mapping.YunKuaiChongDownlinkCmdConverter;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.SET_PRICING;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.SET_PRICING;
/**
* 云快充1.5.0 计费模型应答
@@ -27,7 +28,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x57, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x57, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150SetPricingModelAckULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {
@@ -43,7 +44,7 @@ public class YunKuaiChongV150SetPricingModelAckULCmd extends YunKuaiChongUplinkC
boolean isSuccess = (byteBuf.readByte() == 0x01);
// 从缓存取上个请求的pricingId
Object pricingId = tcpSession.getRequestCache().asMap().getOrDefault(pileCode + SET_PRICING.getCmd(), null);
Object pricingId = tcpSession.getRequestCache().asMap().getOrDefault(pileCode + YunKuaiChongDownlinkCmdConverter.getInstance().convertToCmd(SET_PRICING), null);
if (pricingId instanceof Long pricingIdL) {
// 转发到后端

View File

@@ -14,10 +14,11 @@ import sanbing.jcpp.proto.gen.ProtocolProto.PeriodProto;
import sanbing.jcpp.proto.gen.ProtocolProto.PricingModelProto;
import sanbing.jcpp.proto.gen.ProtocolProto.SetPricingRequest;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import sanbing.jcpp.protocol.yunkuaichong.mapping.YunKuaiChongDownlinkCmdConverter;
import java.math.BigDecimal;
import java.time.LocalTime;
@@ -25,8 +26,8 @@ import java.util.List;
import java.util.Map;
import static sanbing.jcpp.proto.gen.ProtocolProto.PricingModelFlag.*;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.SET_PRICING;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.SET_PRICING;
/**
* 云快充1.5.0 计费模型设置
@@ -34,7 +35,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x58, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x58, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150SetPricingModelDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {
@@ -84,7 +85,7 @@ public class YunKuaiChongV150SetPricingModelDLCmd extends YunKuaiChongDownlinkCm
setPricingAckMsgBody.writeBytes(bytes);
// 放进缓存后再下发
tcpSession.getRequestCache().put(pileCode + SET_PRICING.getCmd(), pricingId);
tcpSession.getRequestCache().put(pileCode + YunKuaiChongDownlinkCmdConverter.getInstance().convertToCmd(SET_PRICING), pricingId);
encodeAndWriteFlush(SET_PRICING,
setPricingAckMsgBody,

View File

@@ -13,13 +13,13 @@ import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.codec.CP56Time2aUtil;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.SYNC_TIME_REQUEST;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.SYNC_TIME;
/**
* 云快充1.5.0对时设置
@@ -28,7 +28,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @since 1.0.0
*/
@Slf4j
@YunKuaiChongCmd(value = 0x56, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x56, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150TimeSyncDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {
@@ -42,6 +42,6 @@ public class YunKuaiChongV150TimeSyncDLCmd extends YunKuaiChongDownlinkCmdExe {
ByteBuf syncTimeMsgBody = Unpooled.buffer(14);
syncTimeMsgBody.writeBytes(encodePileCode(pileCode));
syncTimeMsgBody.writeBytes(CP56Time2aUtil.encode(DateUtil.parseLocalDateTime(time)));
encodeAndWriteFlush(SYNC_TIME, syncTimeMsgBody, tcpSession);
encodeAndWriteFlush(SYNC_TIME_REQUEST, syncTimeMsgBody, tcpSession);
}
}

View File

@@ -14,10 +14,10 @@ import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.infrastructure.util.codec.CP56Time2aUtil;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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.time.LocalDateTime;
@@ -30,7 +30,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @since 1.0.0
*/
@Slf4j
@YunKuaiChongCmd(value = 0x55, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x55, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150TimeSyncResultULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -12,23 +12,23 @@ import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.TransactionRecordResponse;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.TRANSACTION_RECORD_ACK;
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;
/**
* 云快充1.5.0 交易记录确认
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x40, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x40, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150TransactionRecordAckDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -15,10 +15,10 @@ 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.annotation.ProtocolCmd;
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;
@@ -34,7 +34,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x3B, protocolNames = {V150, V160})
@ProtocolCmd(value = 0x3B, protocolNames = {V150, V160})
public class YunKuaiChongV150TransactionRecordULCmd extends YunKuaiChongUplinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {

View File

@@ -12,18 +12,18 @@ import lombok.extern.slf4j.Slf4j;
import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.VerifyPricingResponse;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.util.Arrays;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.VERIFY_PRICING_ACK;
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;
/**
* 云快充1.5.0计费模型验证请求应答
@@ -31,7 +31,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x06, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x06, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150VerifyPricingModelAckDLCmd extends YunKuaiChongDownlinkCmdExe {
@Override
public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage yunKuaiChongDwonlinkMessage, ProtocolContext ctx) {

View File

@@ -16,10 +16,10 @@ import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.proto.gen.ProtocolProto.VerifyPricingRequest;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.*;
@@ -30,7 +30,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x05, protocolNames = {V150, V160, V170})
@ProtocolCmd(value = 0x05, protocolNames = {V150, V160, V170})
public class YunKuaiChongV150VerifyPricingModelULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -9,21 +9,22 @@ package sanbing.jcpp.protocol.yunkuaichong.v160.cmd;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import sanbing.jcpp.infrastructure.util.codec.BCDUtil;
import sanbing.jcpp.proto.gen.ProtocolProto;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
import sanbing.jcpp.protocol.listener.tcp.TcpSession;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDownlinkCmdExe;
import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongDwonlinkMessage;
import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.REMOTE_PARALLEL_START_CHARGING;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEnum.REMOTE_PARALLEL_START_CHARGING;
import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170;
// 移除枚举导入: REMOTE_PARALLEL_START_CHARGING
/**
* 云快充1.6.0 运营平台远程控制并充启机
@@ -31,7 +32,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.enums.YunKuaiChongDownlinkCmdEn
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0xA4, protocolNames = {V160})
@ProtocolCmd(value = 0xA4, protocolNames = {V160, V170})
public class YunKuaiChongV160RemoteParallelStartDLCmd extends YunKuaiChongDownlinkCmdExe {
static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
@@ -50,7 +51,11 @@ public class YunKuaiChongV160RemoteParallelStartDLCmd extends YunKuaiChongDownli
String tradeNo = remoteStartChargingRequest.getTradeNo();
String limitYuan = remoteStartChargingRequest.getLimitYuan();
byte[] cardNo = encodeCardNo(tradeNo);
// 优先使用传入的卡号,如果没有则使用交易流水号生成
String logicalCardNo = remoteStartChargingRequest.hasLogicalCardNo() ?
remoteStartChargingRequest.getLogicalCardNo() : tradeNo;
String physicalCardNo = remoteStartChargingRequest.hasPhysicalCardNo() ?
remoteStartChargingRequest.getPhysicalCardNo() : tradeNo;
ByteBuf msgBody = Unpooled.buffer(44);
// 交易流水号
@@ -60,25 +65,19 @@ public class YunKuaiChongV160RemoteParallelStartDLCmd extends YunKuaiChongDownli
// 枪号
msgBody.writeBytes(encodeGunCode(gunCode));
// 逻辑卡号 BCD码
msgBody.writeBytes(cardNo);
msgBody.writeBytes(encodeCardNo(logicalCardNo));
// 物理卡号
msgBody.writeBytes(cardNo);
msgBody.writeBytes(encodeCardNo(physicalCardNo));
// 账户余额
msgBody.writeIntLE(new BigDecimal(limitYuan).intValue());
// 并充序号
msgBody.writeBytes(BCDUtil.toBytes(LocalDateTime.now().format(dateTimeFormatter)));
String parallelNo = remoteStartChargingRequest.hasParallelNo() ?
remoteStartChargingRequest.getParallelNo() : LocalDateTime.now().format(dateTimeFormatter);
msgBody.writeBytes(BCDUtil.toBytes(parallelNo));
encodeAndWriteFlush(REMOTE_PARALLEL_START_CHARGING,
msgBody,
tcpSession);
}
/**
* 用交易流水号做卡号
*/
private static byte[] encodeCardNo(String tradeNo) {
tradeNo = StringUtils.right(tradeNo, 16);
tradeNo = StringUtils.leftPad(tradeNo, 16, '0');
return BCDUtil.toBytes(tradeNo);
}
}

View File

@@ -16,10 +16,10 @@ import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.RemoteStartChargingResponse;
import sanbing.jcpp.proto.gen.ProtocolProto.UplinkQueueMessage;
import sanbing.jcpp.protocol.ProtocolContext;
import sanbing.jcpp.protocol.annotation.ProtocolCmd;
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 static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160;
@@ -29,7 +29,7 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0xA3, protocolNames = {V160})
@ProtocolCmd(value = 0xA3, protocolNames = {V160})
public class YunKuaiChongV160RemoteParallelStartResultULCmd extends YunKuaiChongUplinkCmdExe {
@Override

View File

@@ -16,10 +16,10 @@ 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.annotation.ProtocolCmd;
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;
@@ -34,8 +34,14 @@ import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.P
* @author baigod
*/
@Slf4j
@YunKuaiChongCmd(value = 0x3D, protocolNames = {V170})
@ProtocolCmd(value = 0x3D, protocolNames = {V170})
public class YunKuaiChongV170TransactionRecordULCmd extends YunKuaiChongUplinkCmdExe {
// V1.7.0 新增字段常量定义
private static final String METER_NO_KEY = "meterNo";
private static final String METER_ENCRYPTED_CONTEXT_KEY = "meterEncryptedContext";
private static final String METER_PROTOCOL_VERSION_KEY = "meterProtocolVersion";
private static final String ENCRYPTION_METHOD_KEY = "encryptionMethod";
@Override
public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) {
log.info("{} 云快充1.7.0交易记录", tcpSession);
@@ -72,18 +78,18 @@ public class YunKuaiChongV170TransactionRecordULCmd extends YunKuaiChongUplinkCm
byte[] meterNoBytes = new byte[6];
byteBuf.readBytes(meterNoBytes);
String meterNo = BCDUtil.toString(meterNoBytes);
additionalInfo.put("电表表号", meterNo);
additionalInfo.put(METER_NO_KEY, meterNo);
// 7.电表密文
byte[] meterContextEncyptB = new byte[34];
byteBuf.readBytes(meterContextEncyptB);
additionalInfo.put("电表密文", HexUtil.encodeHexStr(meterContextEncyptB));
additionalInfo.put(METER_ENCRYPTED_CONTEXT_KEY, HexUtil.encodeHexStr(meterContextEncyptB));
// 8.电表协议版本号
additionalInfo.put("电表协议版本号", byteBuf.readUnsignedShortLE());
additionalInfo.put(METER_PROTOCOL_VERSION_KEY, byteBuf.readUnsignedShortLE());
// 9.加密方式
additionalInfo.put("加密方式", byteBuf.readUnsignedByte());
additionalInfo.put(ENCRYPTION_METHOD_KEY, byteBuf.readUnsignedByte());
// 10.尖单价
BigDecimal topPrice = reduceMagnification(byteBuf.readUnsignedIntLE(), 100000);