diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java index 75a6038..6e0517d 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/PileProtocolService.java @@ -122,9 +122,20 @@ public interface PileProtocolService { */ void onOtaResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback); - /* - * BMS充电握手 + /** + * 处理BMS握手信息 + * + * @param uplinkQueueMessage 上行消息 + * @param callback 回调 */ void onBmsHandshake(UplinkQueueMessage uplinkQueueMessage, Callback callback); + /** + * 处理地锁状态信息 + * + * @param uplinkQueueMessage 上行消息 + * @param callback 回调 + */ + void onLockStatus(UplinkQueueMessage uplinkQueueMessage, Callback callback); + } \ No newline at end of file diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java index f2fa5af..cd1f3a6 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/impl/DefaultPileProtocolService.java @@ -434,6 +434,25 @@ public class DefaultPileProtocolService implements PileProtocolService { callback.onSuccess(); } + @Override + public void onLockStatus(UplinkQueueMessage uplinkQueueMessage, Callback callback) { + log.info("接收到地锁状态信息 {}", uplinkQueueMessage); + GroundLockStatusProto groundLockStatusProto = uplinkQueueMessage.getGroundLockStatusProto(); + String pileCode = groundLockStatusProto.getPileCode(); + String gunCode = groundLockStatusProto.getGunCode(); + int lockStatus = groundLockStatusProto.getLockStatus(); + int parkStatus = groundLockStatusProto.getParkStatus(); + int lockBattery = groundLockStatusProto.getLockBattery(); + int alarmStatus = groundLockStatusProto.getAlarmStatus(); + + log.info("地锁状态信息: 桩编码: {}, 枪号: {}, 车位锁状态: {}, 车位状态: {}, 地锁电量: {}%, 报警状态: {}", + pileCode, gunCode, lockStatus, parkStatus, lockBattery, alarmStatus); + + // TODO 处理相关业务逻辑,比如保存地锁状态信息到数据库 + + callback.onSuccess(); + } + private static Period createPeriod(int sn, LocalTime beginTime, LocalTime endTime, PricingModelFlag flag) { Period period = new Period(); period.setSn(sn); diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java b/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java index 93d1fc7..4d0bb18 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/service/queue/consumer/ProtocolUplinkConsumerService.java @@ -220,6 +220,10 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService imple pileProtocolService.onOtaResponse(uplinkQueueMsg, callback); + } else if (uplinkQueueMsg.hasGroundLockStatusProto()) { + + pileProtocolService.onLockStatus(uplinkQueueMsg, callback); + } else { callback.onSuccess(); diff --git a/jcpp-infrastructure-proto/src/main/proto/protocol.proto b/jcpp-infrastructure-proto/src/main/proto/protocol.proto index bf41b26..d6c6d4f 100644 --- a/jcpp-infrastructure-proto/src/main/proto/protocol.proto +++ b/jcpp-infrastructure-proto/src/main/proto/protocol.proto @@ -73,6 +73,7 @@ message UplinkQueueMessage { RestartPileResponse restartPileResponse = 36; BmsHandshakeProto bmsHandshakeProto = 37; OtaResponse otaResponse = 38; + GroundLockStatusProto groundLockStatusProto = 39; } @@ -420,4 +421,16 @@ message BmsHandshakeProto { string carVinCode = 16; // 车辆识别码(VIN) string bmsSoftwareVersion = 17; // BMS软件版本号 optional string additionalInfo = 20; // 附加信息 +} + +message GroundLockStatusProto { + int64 ts = 1; // 时间戳 + string pileCode = 2; // 桩编号 + string gunCode = 3; // 枪号 + int32 lockStatus = 4; // 车位锁状态 + int32 parkStatus = 5; // 车位状态 + int32 lockBattery = 6; // 地锁电量状态 (百分比值0~100) + int32 alarmStatus = 7; // 报警状态 + int32 reserved = 8; // 预留位 + optional string additionalInfo = 20; // 附加信息 } \ No newline at end of file diff --git a/jcpp-protocol-yunkuaichong/READMD.md b/jcpp-protocol-yunkuaichong/READMD.md index a690c08..65f1c02 100644 --- a/jcpp-protocol-yunkuaichong/READMD.md +++ b/jcpp-protocol-yunkuaichong/READMD.md @@ -96,3 +96,8 @@ #### 0x93 远程更新应答 `68 0C 0300 00 93 20231212000010 00 7E9B` + +--- + +#### 0x61 地锁数据上送 +`68 14 00 01 00 61 20 23 12 12 00 00 10 01 00 00 00 00 00 00 00 00 3D 6D` \ No newline at end of file diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LockStatusULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LockStatusULCmd.java new file mode 100644 index 0000000..895030f --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150LockStatusULCmd.java @@ -0,0 +1,103 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + +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.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.listener.tcp.TcpSession; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkCmdExe; +import sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongUplinkMessage; +import sanbing.jcpp.protocol.yunkuaichong.annotation.YunKuaiChongCmd; + +/** + * 云快充协议上行命令处理类 - 地锁状态/报警信息帧 (V1.5.0版本) + * 命令码:0x61 (地锁状态/报警信息帧上行命令) + */ +@Slf4j +@YunKuaiChongCmd(0x61) +public class YunKuaiChongV150LockStatusULCmd extends YunKuaiChongUplinkCmdExe { + + /** + * 执行命令解析 + * @param tcpSession TCP会话对象 + * @param yunKuaiChongUplinkMessage 上行消息对象 + * @param ctx 协议上下文 + */ + @Override + public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) { + log.info("{} 云快充1.5.0地锁状态/报警信息帧请求", tcpSession); + // 将消息体包装为ByteBuf以便读取 + ByteBuf byteBuf = Unpooled.wrappedBuffer(yunKuaiChongUplinkMessage.getMsgBody()); + // 从Tracer总获取当前时间 + long ts = TracerContextUtil.getCurrentTracer().getTracerTs(); + + /* 按协议顺序解析消息体 */ + + // 1. 桩编号:7字节BCD编码字符串 + String pileCode = readBcdString(byteBuf, 7); + + // 2. 枪号:1字节 + int gunNo = byteBuf.readUnsignedByte(); + String gunCode = String.valueOf(gunNo); + + // 3. 车位锁状态:1字节 + int lockStatus = byteBuf.readUnsignedByte(); + + // 4. 车位状态:1字节 + int parkStatus = byteBuf.readUnsignedByte(); + + // 5. 地锁电量状态:1字节 (百分比值0~100) + int lockBattery = byteBuf.readUnsignedByte(); + + // 6. 报警状态:1字节 + int alarmStatus = byteBuf.readUnsignedByte(); + + // 7. 预留位:4字节 + int reserved = byteBuf.readInt(); + + // 记录日志 + log.info("地锁状态信息 - 桩编号:{}, 枪号:{}, 车位锁状态:{}, 车位状态:{}, 地锁电量:{}, 报警状态:{}", + pileCode, gunCode, lockStatus, parkStatus, lockBattery, alarmStatus); + + // 构建转发消息 + GroundLockStatusProto groundLockStatusProto = GroundLockStatusProto.newBuilder() + .setTs(ts) + .setPileCode(pileCode) + .setGunCode(gunCode) + .setLockStatus(lockStatus) + .setParkStatus(parkStatus) + .setLockBattery(lockBattery) + .setAlarmStatus(alarmStatus) + .setReserved(reserved) + .build(); + + UplinkQueueMessage uplinkQueueMessage = uplinkMessageBuilder(groundLockStatusProto.getPileCode(), tcpSession, yunKuaiChongUplinkMessage) + .setGroundLockStatusProto(groundLockStatusProto) + .build(); + tcpSession.getForwarder().sendMessage(uplinkQueueMessage); + } + + //=== 协议数据解析辅助方法 ===// + + /** + * 读取BCD编码字符串 + * @param buf 字节缓冲区 + * @param length 读取字节长度 + * @return 解析后的字符串 + */ + private String readBcdString(ByteBuf buf, int length) { + byte[] bytes = new byte[length]; + buf.readBytes(bytes); + return BCDUtil.toString(bytes); // 调用BCD工具类转换 + } +} \ No newline at end of file