diff --git a/jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/TestController.java b/jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/TestController.java index 1b29e9e..51c7bda 100644 --- a/jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/TestController.java +++ b/jcpp-app/src/main/java/sanbing/jcpp/app/adapter/controller/TestController.java @@ -373,7 +373,7 @@ public class TestController extends BaseController { return ResponseEntity.ok("success"); } - @GetMapping("/api/offlineCardClearRequest") + @GetMapping("/offlineCardClearRequest") public ResponseEntity offlineCardClearRequest() { List cardNoList = Lists.newArrayList("1000000000123456", "1000000000123457", "1000000000123458", "1000000000123459", "1000000000123460"); @@ -387,7 +387,7 @@ public class TestController extends BaseController { return ResponseEntity.ok("success"); } - @GetMapping("/api/offlineCardQueryRequest") + @GetMapping("/offlineCardQueryRequest") public ResponseEntity offlineCardQueryRequest() { List cardNoList = Lists.newArrayList("1000000000123456", "1000000000123457", "1000000000123458", "1000000000123459", "1000000000123460"); @@ -402,4 +402,18 @@ public class TestController extends BaseController { return ResponseEntity.ok("success"); } + @GetMapping("/workParamSettingRequest") + public ResponseEntity workParamSettingRequest() { + + pileProtocolService.workParamSettingRequest(WorkParamSettingRequest.newBuilder() + .setPileCode("20231212000010") + .setAllow(true) + .setMaxAllowOutPower(240) + .build()); + + return ResponseEntity.ok("success"); + } + + + } \ No newline at end of file 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 3a18ff8..f15d294 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 @@ -214,4 +214,19 @@ public interface PileProtocolService { * 服务器下发充电桩字符型参数反馈 */ void onSetQrcodeResponse(UplinkQueueMessage uplinkQueueMsg, Callback callback); + + /** + * 充电桩工作参数设置 + */ + void workParamSettingRequest(DownlinkProto.WorkParamSettingRequest request); + + /** + * 充电桩工作参数设置应答 + */ + void onWorkParamSettingRequest(UplinkQueueMessage uplinkQueueMsg, Callback callback); + + /** + * 结束充电 + */ + void onEndCharge(UplinkQueueMessage uplinkQueueMsg, 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 f96db59..a93bf4c 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 @@ -970,4 +970,40 @@ public class DefaultPileProtocolService implements PileProtocolService { } } + @Override + public void workParamSettingRequest(WorkParamSettingRequest request) { + UUID messageId = UUID.randomUUID(); + UUID requestId = UUID.randomUUID(); + + DownlinkRequestMessage.Builder downlinkRequestMessageBuilder = DownlinkRequestMessage.newBuilder() + .setMessageIdMSB(messageId.getMostSignificantBits()) + .setMessageIdLSB(messageId.getLeastSignificantBits()) + .setPileCode(request.getPileCode()) + .setRequestIdMSB(requestId.getMostSignificantBits()) + .setRequestIdLSB(requestId.getLeastSignificantBits()) + .setDownlinkCmd(DownlinkCmdEnum.WORK_PARAM_SETTING_REQUEST.name()) + .setWorkParamSettingRequest(request); + downlinkCallService.sendDownlinkMessage(downlinkRequestMessageBuilder,request.getPileCode()); + } + + @Override + public void onWorkParamSettingRequest(UplinkQueueMessage uplinkQueueMsg, Callback callback) { + log.info("接收到充电桩工作参数设置应答 {}", uplinkQueueMsg); + + + // TODO 处理相关业务逻辑 + + callback.onSuccess(); + } + + @Override + public void onEndCharge(UplinkQueueMessage uplinkQueueMsg, Callback callback) { + log.info("接收到 结束充电 {}", uplinkQueueMsg); + + + // TODO 处理相关业务逻辑 + + callback.onSuccess(); + + } } \ No newline at end of file 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 2b5a398..997b8da 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 @@ -265,7 +265,15 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService { pileProtocolService.onSetQrcodeResponse(uplinkQueueMsg, callback); - } else { + } else if (uplinkQueueMsg.hasWorkParamSettingResponse()) { + + pileProtocolService.onWorkParamSettingRequest(uplinkQueueMsg, callback); + + } else if (uplinkQueueMsg.hasEndChargeProto()) { + + pileProtocolService.onEndCharge(uplinkQueueMsg, callback); + + } else { callback.onSuccess(); } diff --git a/jcpp-infrastructure-proto/src/main/proto/downlink.proto b/jcpp-infrastructure-proto/src/main/proto/downlink.proto index 67e6a25..e566a46 100644 --- a/jcpp-infrastructure-proto/src/main/proto/downlink.proto +++ b/jcpp-infrastructure-proto/src/main/proto/downlink.proto @@ -39,6 +39,7 @@ message DownlinkRequestMessage { SetQrcodeRequest setQrcodeRequest = 34; OfflineCardClearRequest offlineCardClearRequest = 35; OfflineCardQueryRequest offlineCardQueryRequest = 36; + WorkParamSettingRequest workParamSettingRequest = 37; } // 下行响应消息 @@ -273,3 +274,9 @@ message OfflineCardQueryRequest { repeated string cardNo = 3; // 物理卡号集合 } +message WorkParamSettingRequest { + string pileCode = 1; // 桩编号 + bool allow = 2; // 是否允许工作 + int32 maxAllowOutPower = 3; // 充电桩最大允许输出功率 +} + diff --git a/jcpp-infrastructure-proto/src/main/proto/uplink.proto b/jcpp-infrastructure-proto/src/main/proto/uplink.proto index 33d82f4..4bbb1cf 100644 --- a/jcpp-infrastructure-proto/src/main/proto/uplink.proto +++ b/jcpp-infrastructure-proto/src/main/proto/uplink.proto @@ -48,6 +48,8 @@ message UplinkQueueMessage { SetQrcodeResponse setQrcodeResponse = 45; OfflineCardClearResponse offlineCardClearResponse = 46; OfflineCardQueryResponse offlineCardQueryResponse = 47; + EndChargeProto endChargeProto = 48; + WorkParamSettingResponse workParamSettingResponse = 49; } // 会话关闭事件 @@ -384,3 +386,19 @@ message SetQrcodeResponse { int32 type = 7; int32 startAddr = 8; } + + +message EndChargeProto { + string tradeNo = 1; // 交易流水号 + string pileCode = 2; // 桩编号枪号 + string gunCode = 3; // 枪号 + optional string additionalInfo = 4; +} + +message WorkParamSettingResponse { + string pileCode = 1; + bool success = 2; +} + + + diff --git a/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java b/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java index d7d80ea..1800099 100644 --- a/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java +++ b/jcpp-protocol-api/src/main/java/sanbing/jcpp/protocol/domain/DownlinkCmdEnum.java @@ -47,5 +47,9 @@ public enum DownlinkCmdEnum { OFFLINE_CARD_QUERY_REQUEST, - START_CHARGE_ACK + START_CHARGE_ACK, + + WORK_PARAM_SETTING_REQUEST, + + ; } \ No newline at end of file diff --git a/jcpp-protocol-yunkuaichong/READMD.md b/jcpp-protocol-yunkuaichong/READMD.md index bb34048..9ffb0d1 100644 --- a/jcpp-protocol-yunkuaichong/READMD.md +++ b/jcpp-protocol-yunkuaichong/READMD.md @@ -180,4 +180,14 @@ c0 57 01 00 #### 成功 `68 38 19 00 00 47 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 01 10 00 00 00 00 12 34 57 01 10 00 00 00 00 12 34 58 01 10 00 00 00 00 12 34 59 01 10 00 00 00 00 12 34 60 01 9a 7c` #### 失败 -`68 38 19 00 00 47 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 00 10 00 00 00 00 12 34 57 00 10 00 00 00 00 12 34 58 00 10 00 00 00 00 12 34 59 00 10 00 00 00 00 12 34 60 00 28 95` \ No newline at end of file +`68 38 19 00 00 47 20 23 12 12 00 00 10 10 00 00 00 00 12 34 56 00 10 00 00 00 00 12 34 57 00 10 00 00 00 00 12 34 58 00 10 00 00 00 00 12 34 59 00 10 00 00 00 00 12 34 60 00 28 95` + +#### 0x19 结束充电(充电桩 -> JCPP) +`68 2c 19 00 00 19 00 00 00 00 00 00 00 00 00 20 23 12 12 00 00 10 20 23 12 12 00 00 10 01 09 09 00 09 00 0f 0f 0f 00 0f 00 01 00 00 00 00 4a 37` + +#### 0x51 充电桩工作参数设置应答(充电桩 -> JCPP) +`68 0c 19 00 00 51 20 23 12 12 00 00 10 01 2f d9` + +#### 0x52 充电桩工作参数设置(JCPP -> 充电桩) +`68 0d 02 00 00 52 20 23 12 12 00 00 10 00 f0 4d 1c` + diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/mapping/YunKuaiChongDownlinkCmdConverter.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/mapping/YunKuaiChongDownlinkCmdConverter.java index 012466e..f379119 100644 --- a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/mapping/YunKuaiChongDownlinkCmdConverter.java +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/mapping/YunKuaiChongDownlinkCmdConverter.java @@ -54,6 +54,9 @@ public class YunKuaiChongDownlinkCmdConverter implements DownlinkCmdConverter { COMMAND_MAP.put(DownlinkCmdEnum.SYNC_TIME_REQUEST, 0x56); COMMAND_MAP.put(DownlinkCmdEnum.OFFLINE_CARD_CLEAR_REQUEST, 0x46); COMMAND_MAP.put(DownlinkCmdEnum.OFFLINE_CARD_QUERY_REQUEST, 0x48); + COMMAND_MAP.put(DownlinkCmdEnum.WORK_PARAM_SETTING_REQUEST, 0x52); + + } diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150EndChargeULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150EndChargeULCmd.java new file mode 100644 index 0000000..a11e9e5 --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150EndChargeULCmd.java @@ -0,0 +1,98 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + + +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V150; +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160; +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import lombok.extern.slf4j.Slf4j; +import sanbing.jcpp.infrastructure.util.codec.BCDUtil; +import sanbing.jcpp.infrastructure.util.jackson.JacksonUtil; +import sanbing.jcpp.proto.gen.UplinkProto; +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; + +/** + * 云快充1.5.0 充电结束 + * + * @author bawan + */ +@Slf4j +@ProtocolCmd(value = 0x19, protocolNames = {V150, V160, V170}) +public class YunKuaiChongV150EndChargeULCmd extends YunKuaiChongUplinkCmdExe { + + @Override + public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage yunKuaiChongUplinkMessage, ProtocolContext ctx) { + log.debug("{} 云快充1.5.0充电结束", tcpSession); + + ByteBuf byteBuf = Unpooled.wrappedBuffer(yunKuaiChongUplinkMessage.getMsgBody()); + + // 交易流水号 + byte[] tradeNoBytes = new byte[16]; + byteBuf.readBytes(tradeNoBytes); + String tradeNo = BCDUtil.toString(tradeNoBytes); + + // 桩编号 + byte[] pileCodeBytes = new byte[7]; + byteBuf.readBytes(pileCodeBytes); + String pileCode = BCDUtil.toString(pileCodeBytes); + + // 枪号 + byte gunCodeByte = byteBuf.readByte(); + String gunCode = BCDUtil.toString(gunCodeByte); + + ObjectNode additionalInfo = JacksonUtil.newObjectNode(); + + // 4 BMS 中止荷电状态 + additionalInfo.put("BMS 中止荷电状态 SOC", byteBuf.readByte()); + + // 5 BMS 动力蓄电池单体最低电压 + additionalInfo.put("BMS 动力蓄电池单体最低电压", byteBuf.readShortLE()); + + // 6 BMS 动力蓄电池单体最高电压 + additionalInfo.put("BMS 动力蓄电池单体最高电压", byteBuf.readShortLE()); + + // 7 BMS 动力蓄电池最低温度 + additionalInfo.put("BMS 动力蓄电池最低温度", byteBuf.readByte()); + + // 8 BMS 动力蓄电池最高温度 + additionalInfo.put("BMS 动力蓄电池最高温度", byteBuf.readByte()); + + // 9 电桩累计充电时间 + additionalInfo.put("电桩累计充电时间", byteBuf.readShortLE()); + + // 10 电桩输出能量 + additionalInfo.put("电桩输出能量", byteBuf.readShortLE()); + + // 11 电桩充电机编号 + byte[] chargerCode = new byte[4]; + byteBuf.readBytes(chargerCode); + additionalInfo.put("电桩充电机编号", BCDUtil.toString(chargerCode)); + + // 转发到后端 + UplinkProto.UplinkQueueMessage uplinkQueueMessage = uplinkMessageBuilder(pileCode, tcpSession, yunKuaiChongUplinkMessage) + .setEndChargeProto(UplinkProto.EndChargeProto.newBuilder() + .setTradeNo(tradeNo) + .setPileCode(pileCode) + .setGunCode(gunCode) + .setAdditionalInfo(additionalInfo.toString()) + .build()) + .build(); + + tcpSession.getForwarder().sendMessage(uplinkQueueMessage); + } + +} \ No newline at end of file diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150WorkParamSettingRequestDLCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150WorkParamSettingRequestDLCmd.java new file mode 100644 index 0000000..77d1643 --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150WorkParamSettingRequestDLCmd.java @@ -0,0 +1,54 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + +import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.WORK_PARAM_SETTING_REQUEST; +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V150; +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160; +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import lombok.extern.slf4j.Slf4j; +import sanbing.jcpp.proto.gen.DownlinkProto; +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; + + +/** + * 云快充1.5.0 充电桩工作参数设置 + * + * @author bawan + */ +@Slf4j +@ProtocolCmd(value = 0x52, protocolNames = {V150, V160, V170}) +public class YunKuaiChongV150WorkParamSettingRequestDLCmd extends YunKuaiChongDownlinkCmdExe { + + @Override + public void execute(TcpSession tcpSession, YunKuaiChongDwonlinkMessage message, ProtocolContext ctx) { + log.info("{} 云快充1.5.0 充电桩工作参数设置", tcpSession); + + if (!message.getMsg().hasWorkParamSettingRequest()) { + log.error("云快充1.5.0 充电桩工作参数设置消息体为空"); + return; + } + + DownlinkProto.WorkParamSettingRequest request = message.getMsg().getWorkParamSettingRequest(); + + // 初始化 buf + ByteBuf msgBody = Unpooled.buffer(9); + msgBody.writeBytes(encodePileCode(request.getPileCode())); + msgBody.writeByte(request.getAllow()?0x00:0x01); + msgBody.writeByte(request.getMaxAllowOutPower()); + + super.encodeAndWriteFlush(WORK_PARAM_SETTING_REQUEST, msgBody, tcpSession); + } + +} diff --git a/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150WorkParamSettingResponseULCmd.java b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150WorkParamSettingResponseULCmd.java new file mode 100644 index 0000000..a2827c6 --- /dev/null +++ b/jcpp-protocol-yunkuaichong/src/main/java/sanbing/jcpp/protocol/yunkuaichong/v150/cmd/YunKuaiChongV150WorkParamSettingResponseULCmd.java @@ -0,0 +1,60 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.yunkuaichong.v150.cmd; + + +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V150; +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V160; +import static sanbing.jcpp.protocol.yunkuaichong.YunKuaiChongProtocolConstants.ProtocolNames.V170; + +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.proto.gen.UplinkProto; +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; + +/** + * 云快充1.5.0 充电桩工作参数设置应答 + * + * @author bawan + */ +@Slf4j +@ProtocolCmd(value = 0x51, protocolNames = {V150, V160, V170}) +public class YunKuaiChongV150WorkParamSettingResponseULCmd extends YunKuaiChongUplinkCmdExe { + + + @Override + public void execute(TcpSession tcpSession, YunKuaiChongUplinkMessage message, ProtocolContext ctx) { + log.info("{} 云快充1.5.0 充电桩工作参数设置应答", tcpSession); + + ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getMsgBody()); + // 桩编号 + byte[] pileCodeBytes = new byte[7]; + byteBuf.readBytes(pileCodeBytes); + String pileCode = BCDUtil.toString(pileCodeBytes); + // 设置结果 + byte settingResult = byteBuf.readByte(); + + UplinkProto.UplinkQueueMessage queueMessage = uplinkMessageBuilder(pileCode, tcpSession, message) + .setWorkParamSettingResponse(UplinkProto.WorkParamSettingResponse.newBuilder() + .setPileCode(pileCode) + .setSuccess(settingResult==0x01) + .build()) + .build(); + // 转发到后端 + tcpSession.getForwarder().sendMessage(queueMessage); + } + + + +} +