From 058213599511282cdde19e46c4a17cf31b47ef0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=A2=E4=B8=AD?= <851474045@qq.com> Date: Wed, 3 Sep 2025 17:44:46 +0800 Subject: [PATCH] =?UTF-8?q?1103,1104=EF=BC=8C5,6=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=EF=BC=8C=E5=85=85=E7=94=B5=E6=A1=A9=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E4=B8=8B=E5=8F=91=E5=92=8C=E5=93=8D=E5=BA=943,4=E6=8C=87?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/controller/TestController.java | 15 +++ .../jcpp/app/service/PileProtocolService.java | 9 ++ .../impl/DefaultPileProtocolService.java | 27 +++++ .../ProtocolUplinkConsumerService.java | 4 + .../src/main/proto/downlink.proto | 11 +++ .../src/main/proto/uplink.proto | 9 ++ .../jcpp/protocol/domain/DownlinkCmdEnum.java | 2 + jcpp-protocol-lvneng/READMD.md | 23 ++++- .../lvneng/enums/LvnengGunCodeNameEnum.java | 88 +++++++++++++++++ .../mapping/LvnengDownlinkCmdConverter.java | 3 + .../cmd/LvnengV340RemoteStopAckULCmd.java | 91 +++++++++++++++++ .../v340/cmd/LvnengV340RemoteStopDLCmd.java | 67 +++++++++++++ .../LvnengV340SetPricingModelAckULCmd.java | 49 ++++++++++ .../cmd/LvnengV340SetPricingModelDLCmd.java | 98 +++++++++++++++++++ .../cmd/LvnengV340SetQrcodeModelAckULCmd.java | 70 +++++++++++++ .../cmd/LvnengV340SetQrcodeModelDLCmd.java | 74 ++++++++++++++ 16 files changed, 639 insertions(+), 1 deletion(-) create mode 100644 jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/enums/LvnengGunCodeNameEnum.java create mode 100644 jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopAckULCmd.java create mode 100644 jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java create mode 100644 jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelAckULCmd.java create mode 100644 jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java create mode 100644 jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetQrcodeModelAckULCmd.java create mode 100644 jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetQrcodeModelDLCmd.java 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 15d4710..c2f9113 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 @@ -67,6 +67,21 @@ public class TestController extends BaseController { return ResponseEntity.ok("success"); } + @GetMapping("/setQrcode") + public ResponseEntity setQrcode() { + QrcodeModelProto rcodeModelProto = QrcodeModelProto.newBuilder() + .setGunName("1号枪二维码") + .setCode("www.baidu.com/rcode=1") + .build(); + SetQrcodeRequest setQrcodeRequest = SetQrcodeRequest.newBuilder() + .setPileCode("20231212000010") + .setQrcodeModel(rcodeModelProto) + .build(); + + pileProtocolService.setQrcode(setQrcodeRequest); + + return ResponseEntity.ok("success"); + } @GetMapping("/restartPile") public ResponseEntity restartPile() { 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 485be10..17a6fdf 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 @@ -12,6 +12,7 @@ import sanbing.jcpp.proto.gen.DownlinkProto.OfflineCardSyncRequest; import sanbing.jcpp.proto.gen.DownlinkProto.OtaRequest; import sanbing.jcpp.proto.gen.DownlinkProto.SetPricingRequest; import sanbing.jcpp.proto.gen.UplinkProto.UplinkQueueMessage; +import sanbing.jcpp.proto.gen.DownlinkProto.SetQrcodeRequest; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -189,4 +190,12 @@ public interface PileProtocolService { */ void postBmsDemandChargerOutput(UplinkQueueMessage uplinkQueueMessage, Callback callback); + /** + * 服务器下发充电桩字符型参数 + */ + void setQrcode( SetQrcodeRequest setQrcodeRequest ); + /** + * 服务器下发充电桩字符型参数反馈 + */ + void onSetQrcodeResponse(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 2c0e0f9..869a898 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 @@ -657,6 +657,33 @@ public class DefaultPileProtocolService implements PileProtocolService { callback.onSuccess(); } + @Override + public void setQrcode(SetQrcodeRequest setQrcodeRequest) { + UUID messageId = UUID.randomUUID(); + UUID requestId = UUID.randomUUID(); + String pileCode = setQrcodeRequest.getPileCode(); + + DownlinkRequestMessage.Builder downlinkRequestMessageBuilder = DownlinkRequestMessage.newBuilder() + .setMessageIdMSB(messageId.getMostSignificantBits()) + .setMessageIdLSB(messageId.getLeastSignificantBits()) + .setPileCode(pileCode) + .setRequestIdMSB(requestId.getMostSignificantBits()) + .setRequestIdLSB(requestId.getLeastSignificantBits()) + .setDownlinkCmd(DownlinkCmdEnum.SET_QRCODE.name()) + .setSetQrcodeRequest(setQrcodeRequest); + + downlinkCallService.sendDownlinkMessage(downlinkRequestMessageBuilder, pileCode); + } + + @Override + public void onSetQrcodeResponse(UplinkQueueMessage uplinkQueueMessage, Callback callback) { + log.info("下发充电桩字符型应答 {}", uplinkQueueMessage); + + // TODO 处理相关业务逻辑 + + callback.onSuccess(); + } + @Override public void postLockStatus(UplinkQueueMessage uplinkQueueMessage, Callback callback) { log.info("接收到地锁状态信息 {}", uplinkQueueMessage); 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 e7b9c05..0df0dfb 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 @@ -253,6 +253,10 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService { pileProtocolService.onStartChargeRequest(uplinkQueueMsg, callback); + } else if (uplinkQueueMsg.hasSetQrcodeResponse()) { + + pileProtocolService.onSetQrcodeResponse(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 14cd479..5220abe 100644 --- a/jcpp-infrastructure-proto/src/main/proto/downlink.proto +++ b/jcpp-infrastructure-proto/src/main/proto/downlink.proto @@ -36,6 +36,7 @@ message DownlinkRequestMessage { OfflineCardSyncRequest offlineCardSyncRequest = 31; TimeSyncRequest timeSyncRequest = 32; StartChargeResponse startChargeResponse = 33; + SetQrcodeRequest setQrcodeRequest = 34; } // 下行响应消息 @@ -246,3 +247,13 @@ message TimeSyncRequest { string pileCode = 1; string time = 2; } +// 设置二维码请求 +message SetQrcodeRequest { + string pileCode = 4; + QrcodeModelProto qrcodeModel = 1; +} + +message QrcodeModelProto { + string gunName = 11; + string code = 12; +} diff --git a/jcpp-infrastructure-proto/src/main/proto/uplink.proto b/jcpp-infrastructure-proto/src/main/proto/uplink.proto index 262d957..5789c7d 100644 --- a/jcpp-infrastructure-proto/src/main/proto/uplink.proto +++ b/jcpp-infrastructure-proto/src/main/proto/uplink.proto @@ -45,6 +45,8 @@ message UplinkQueueMessage { TimeSyncResponse timeSyncResponse = 42; BmsDemandChargerOutputProto bmsDemandChargerOutputProto = 43; StartChargeRequest startChargeRequest = 44; + SetQrcodeResponse setQrcodeResponse = 45; + } // 会话关闭事件 @@ -346,3 +348,10 @@ message BmsDemandChargerOutputProto { string tradeNo = 6; optional string additionalInfo = 20; } +// 设置二维码响应 +message SetQrcodeResponse { + bool success = 1; + string pileCode = 4; + int32 type = 7; + int32 startAddr = 8; +} \ No newline at end of file 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 715c837..268013a 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 @@ -23,6 +23,8 @@ public enum DownlinkCmdEnum { SET_PRICING, + SET_QRCODE, + REMOTE_START_CHARGING, REMOTE_STOP_CHARGING, diff --git a/jcpp-protocol-lvneng/READMD.md b/jcpp-protocol-lvneng/READMD.md index 8bd2b46..9f91f04 100644 --- a/jcpp-protocol-lvneng/READMD.md +++ b/jcpp-protocol-lvneng/READMD.md @@ -33,4 +33,25 @@ #### 101 服务器应答心跳包信息 `AA F5 0F 00 10 03 65 00 00 00 00 00 00 00 65` ---- \ No newline at end of file +--- + +#### 1103 服务器设置 24 时电费计价策略信息 +`AA F5 49 02 10 02 4F 04 00 00 00 1E 1C 69 00 00 F1 49 00 00 00 1E 01 00 B3 93 00 00 D4 DF 00 00 01 00 01 1E E0 56 00 00 08 76 00 00 01 1E 02 00 C8 A4 00 00 48 A1 00 00 02 00 02 1E 90 BC 00 00 50 25 00 00 02 1E 03 00 BD 34 00 00 E9 85 00 00 03 00 03 1E 12 40 00 00 BA 71 00 00 03 1E 04 00 2C 2A 00 00 10 47 00 00 04 00 04 1E 8C 25 00 00 3D 92 00 00 04 1E 05 00 41 CC 00 00 BD B6 00 00 05 00 05 1E 28 79 00 00 F6 42 00 00 05 1E 06 00 BC BC 00 00 A6 B2 00 00 06 00 06 1E 18 66 00 00 47 E9 00 00 06 1E 07 00 99 C0 00 00 02 E9 00 00 07 00 07 1E 3B 74 00 00 45 92 00 00 07 1E 08 00 05 5D 00 00 C6 E5 00 00 08 00 08 1E C4 D9 00 00 FC 8C 00 00 08 1E 09 00 53 D7 00 00 EA B2 00 00 09 00 09 1E 98 0A 00 00 6D E1 00 00 09 1E 0A 00 E7 D7 00 00 F8 9E 00 00 0A 00 0A 1E 39 25 00 00 54 27 00 00 0A 1E 0B 00 82 A6 00 00 78 3A 00 00 0B 00 0B 1E BF A8 00 00 1C 70 00 00 0B 1E 0C 00 EF 81 00 00 7A 18 00 00 0C 00 0C 1E D1 8D 00 00 B9 6F 00 00 0C 1E 0D 00 FC 91 00 00 4B 05 00 00 0D 00 0D 1E 9A 82 00 00 2C 3D 00 00 0D 1E 0E 00 4C 26 00 00 C7 02 00 00 0E 00 0E 1E 6D 87 00 00 50 A7 00 00 0E 1E 0F 00 EB E4 00 00 4D 8F 00 00 0F 00 0F 1E 23 9C 00 00 10 32 00 00 0F 1E 10 00 74 1B 00 00 C5 6A 00 00 10 00 10 1E 5A 9F 00 00 E8 1D 00 00 10 1E 11 00 F8 CE 00 00 A2 75 00 00 11 00 11 1E 9F 39 00 00 67 66 00 00 11 1E 12 00 CA 89 00 00 4E 35 00 00 12 00 12 1E 5D 8A 00 00 91 CE 00 00 12 1E 13 00 0E 47 00 00 FC 7A 00 00 13 00 13 1E 7E CD 00 00 06 14 00 00 13 1E 14 00 96 B0 00 00 24 E9 00 00 14 00 14 1E AC 20 00 00 7D 35 00 00 14 1E 15 00 45 BD 00 00 17 C1 00 00 15 00 15 1E 67 2B 00 00 9E DF 00 00 15 1E 16 00 16 83 00 00 7F 6B 00 00 16 00 16 1E 88 D2 00 00 76 5A 00 00 16 1E 17 00 15 C0 00 00 77 C6 00 00 17 00 17 1E 1E 35 00 00 1F 46 00 00 17 1E 00 00 30 DF 00 00 47 17 00 00 35 ` +#### 1104 充电桩应答服务器设置 24 时电费计价策略信息 +`AA F5 0A 00 10 02 50 04 00 54` + +--- + +#### 5 服务器下发充电桩控制命令(停止充电) +`AA F5 19 00 10 02 05 00 00 00 00 00 01 02 00 00 00 01 04 00 55 00 00 00 62` +#### 6 充电桩对服务器控制命令应答(停止充电应答) +`AA F5 34 00 10 03 06 00 00 00 00 00 32 30 32 33 31 32 31 32 30 30 30 30 31 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 00 00 00 01 00 B8` + +--- + +#### 3 服务器下发充电桩字符型参数 +`AA F5 29 00 10 03 03 00 00 00 00 00 01 0D 00 00 00 00 01 77 77 77 2E 62 61 69 64 75 2E 63 6F 6D 2F 72 63 6F 64 65 3D 31 C1 ` +### 4 充电桩参数字符形设置/查询应答 +`AA F5 33 00 10 04 04 00 00 00 00 00 32 30 32 33 31 32 31 32 30 30 30 30 31 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 0D 00 00 00 00 C0` + +--- diff --git a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/enums/LvnengGunCodeNameEnum.java b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/enums/LvnengGunCodeNameEnum.java new file mode 100644 index 0000000..dd87367 --- /dev/null +++ b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/enums/LvnengGunCodeNameEnum.java @@ -0,0 +1,88 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.lvneng.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; + +/** + * 充电桩状态枚举 + */ +@AllArgsConstructor +@Getter +public enum LvnengGunCodeNameEnum { + + GUN_QR_CODE_1(13, "1号枪二维码"), + GUN_QR_CODE_2(14, "2号枪二维码"), + GUN_QR_CODE_3(15, "3号枪二维码"), + GUN_QR_CODE_4(16, "4号枪二维码"), + GUN_QR_CODE_5(17, "5号枪二维码"), + GUN_QR_CODE_6(18, "6号枪二维码"), + GUN_QR_CODE_7(19, "7号枪二维码"), + GUN_QR_CODE_8(20, "8号枪二维码"), + GUN_QR_CODE_9(21, "9号枪二维码"), + GUN_QR_CODE_10(22, "10号枪二维码"), + GUN_QR_CODE_11(23, "11号枪二维码"), + GUN_QR_CODE_12(24, "12号枪二维码"), + GUN_QR_CODE_13(25, "13号枪二维码"), + GUN_QR_CODE_14(26, "14号枪二维码"), + GUN_QR_CODE_15(27, "15号枪二维码"), + GUN_QR_CODE_16(28, "16号枪二维码"), + GUN_QR_CODE_17(29, "17号枪二维码"), + GUN_QR_CODE_18(30, "18号枪二维码"), + GUN_QR_CODE_19(31, "19号枪二维码"), + GUN_QR_CODE_20(32, "20号枪二维码"), + GUN_QR_CODE_21(33, "21号枪二维码"), + GUN_QR_CODE_22(34, "22号枪二维码"), + GUN_QR_CODE_23(35, "23号枪二维码"), + GUN_QR_CODE_24(36, "24号枪二维码"), + GUN_QR_CODE_25(37, "25号枪二维码"), + GUN_QR_CODE_26(38, "26号枪二维码"), + GUN_QR_CODE_27(39, "27号枪二维码"), + GUN_QR_CODE_28(40, "28号枪二维码"), + GUN_QR_CODE_29(41, "29号枪二维码"), + GUN_QR_CODE_30(42, "30号枪二维码"), + GUN_QR_CODE_31(43, "31号枪二维码"), + GUN_QR_CODE_32(44, "32号枪二维码"); + + /** + * 参数地址 + */ + private final int parameterAddress; + + /** + * 枪二维码描述(便于理解枚举含义) + */ + private final String description; + + + + + + private static final String UNKNOWN_DESC = "未知状态"; + private static final Map CODE_TO_ENUM_MAP = new HashMap<>(); + + static { + for (LvnengGunCodeNameEnum enumValue : LvnengGunCodeNameEnum.values()) { + CODE_TO_ENUM_MAP.put(enumValue.getDescription(), enumValue); + } + } + + public static Integer getParameterAddress(String description) { + LvnengGunCodeNameEnum lvnengPileStatusEnum = CODE_TO_ENUM_MAP.get(description); + if (lvnengPileStatusEnum == null) { + return null; + } + return lvnengPileStatusEnum.getParameterAddress(); + + + } + +} \ No newline at end of file diff --git a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java index d99ac0d..3eeea07 100644 --- a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java +++ b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java @@ -42,6 +42,9 @@ public class LvnengDownlinkCmdConverter implements DownlinkCmdConverter { COMMAND_MAP.put(DownlinkCmdEnum.TRANSACTION_RECORD_ACK, 201); COMMAND_MAP.put(DownlinkCmdEnum.HEARTBEAT_ACK, 101); // 心跳应答 COMMAND_MAP.put(DownlinkCmdEnum.REAL_TIME_DATA_ACK, 103); // 实时数据应答 + COMMAND_MAP.put(DownlinkCmdEnum.SET_PRICING, 1103);//设置价格模型应答 + COMMAND_MAP.put(DownlinkCmdEnum.REMOTE_STOP_CHARGING, 5);//远程停止充电 + COMMAND_MAP.put(DownlinkCmdEnum.SET_QRCODE, 3);//设置二维码 // 绿能协议支持以上命令,其他命令返回null } diff --git a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopAckULCmd.java b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopAckULCmd.java new file mode 100644 index 0000000..c9b0816 --- /dev/null +++ b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopAckULCmd.java @@ -0,0 +1,91 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.lvneng.v340.cmd; + +import com.fasterxml.jackson.databind.node.ObjectNode; +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.jackson.JacksonUtil; +import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil; +import sanbing.jcpp.proto.gen.UplinkProto.RemoteStopChargingResponse; +import sanbing.jcpp.proto.gen.UplinkProto.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 java.nio.charset.StandardCharsets; + +import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340; + +/** + * 绿能3.4 充电桩对服务器控制命令应答 + */ +@Slf4j +@ProtocolCmd(value = 6, protocolNames = {V340}) +public class LvnengV340RemoteStopAckULCmd extends LvnengUplinkCmdExe { + + + + @Override + public void execute(TcpSession tcpSession, LvnengUplinkMessage lvnengUplinkMessage, ProtocolContext ctx) { + log.debug("{} 绿能3.4 充电桩对服务器控制命令应答", tcpSession); + ByteBuf byteBuf = Unpooled.wrappedBuffer(lvnengUplinkMessage.getMsgBody()); + + ObjectNode additionalInfo = JacksonUtil.newObjectNode(); + // 从Tracer总获取当前时间 + long ts = TracerContextUtil.getCurrentTracer().getTracerTs(); + //1预留 + byteBuf.skipBytes(2); + //2预留 + byteBuf.skipBytes(2); + + //3充电桩编码 + byte[] pileCodeBytes = new byte[32]; + byteBuf.readBytes(pileCodeBytes); + String pileCode = StringUtils.trim(new String(pileCodeBytes, StandardCharsets.US_ASCII)); + + + //4 充电枪口 + int gunCode = byteBuf.readByte(); + additionalInfo.put("充电枪口", gunCode); + + //5 命令启始标志 + long flag = byteBuf.readUnsignedIntLE(); + additionalInfo.put("命令启始标志", flag); + + //6 命令个数 + int paramCount = byteBuf.readByte(); + additionalInfo.put("命令个数", paramCount); + + // 7 命令执行结果 0x00成功 0x01失败 + boolean isSuccess = (byteBuf.readByte() == 0x00); + + + tcpSession.addPileCode(pileCode); + + + RemoteStopChargingResponse remoteStopChargingResponse = RemoteStopChargingResponse.newBuilder() + .setPileCode(pileCode) + .setGunCode(gunCode+"") + .setSuccess(isSuccess) + .setAdditionalInfo(additionalInfo.toString()) + .build(); + + // 转发到后端 + UplinkQueueMessage uplinkQueueMessage = uplinkMessageBuilder(pileCode, tcpSession, lvnengUplinkMessage) + .setRemoteStopChargingResponse(remoteStopChargingResponse) + .build(); + + tcpSession.getForwarder().sendMessage(uplinkQueueMessage); + + } + +} diff --git a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java new file mode 100644 index 0000000..c6e7fbb --- /dev/null +++ b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java @@ -0,0 +1,67 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.lvneng.v340.cmd; + +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.lvneng.LvnengDownlinkCmdExe; +import sanbing.jcpp.protocol.lvneng.LvnengDwonlinkMessage; + +import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.REMOTE_STOP_CHARGING; +import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340; + +/** + * 绿能3.4 服务器下发充电桩控制命令 + * 目前只支持停止充电 + */ +@Slf4j +@ProtocolCmd(value = 5, protocolNames = {V340}) +public class LvnengV340RemoteStopDLCmd extends LvnengDownlinkCmdExe { + @Override + public void execute(TcpSession tcpSession, LvnengDwonlinkMessage lvnengDwonlinkMessage, ProtocolContext ctx) { + log.debug("{} 绿能3.4 服务器下发充电桩控制命令", tcpSession); + + if (!lvnengDwonlinkMessage.getMsg().hasRemoteStopChargingRequest()) { + return; + + } + + + DownlinkProto.RemoteStopChargingRequest remoteStopChargingRequest = lvnengDwonlinkMessage.getMsg().getRemoteStopChargingRequest(); + String pileCode = remoteStopChargingRequest.getPileCode(); + String gunCode = remoteStopChargingRequest.getGunCode(); + + ByteBuf msgBody = Unpooled.buffer(44); + //1预留 + msgBody.writeShortLE(0x00); + //2预留 + msgBody.writeShortLE(0x00); + //3充电枪口 + msgBody.writeByte(Integer.parseInt(gunCode)); + //启始命令地址 + msgBody.writeIntLE(2); + //命令个数 + msgBody.writeByte(1); + //命令参数长度 + msgBody.writeShortLE(4); + //命令参数 + msgBody.writeIntLE(0x55); + encodeAndWriteFlush(REMOTE_STOP_CHARGING, + msgBody, + tcpSession); + + } + + + + +} diff --git a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelAckULCmd.java b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelAckULCmd.java new file mode 100644 index 0000000..7c4e805 --- /dev/null +++ b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelAckULCmd.java @@ -0,0 +1,49 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.lvneng.v340.cmd; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import lombok.extern.slf4j.Slf4j; +import sanbing.jcpp.proto.gen.UplinkProto; +import sanbing.jcpp.proto.gen.UplinkProto.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 static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340; + +/** + * 绿能3.4 充电桩应答服务器设置 24 时电费计价策略信息 + * + * + * + */ +@Slf4j +@ProtocolCmd(value = 1104, protocolNames = {V340}) +public class LvnengV340SetPricingModelAckULCmd extends LvnengUplinkCmdExe { + @Override + public void execute(TcpSession tcpSession, LvnengUplinkMessage lvnengUplinkMessage, ProtocolContext ctx) { + log.debug("{} 绿能3.4 充电桩应答服务器设置 24 时电费计价策略信息", tcpSession); + ByteBuf byteBuf = Unpooled.wrappedBuffer(lvnengUplinkMessage.getMsgBody()); + // 1.设置结果 0x00:成功 0x01:失败 + boolean isSuccess = (byteBuf.readByte() == 0x00); + + // 转发到后端 + UplinkProto.SetPricingResponse setPricingResponse = UplinkProto.SetPricingResponse.newBuilder() + .setSuccess(isSuccess) + .build(); + UplinkQueueMessage uplinkQueueMessage = uplinkMessageBuilder(setPricingResponse.getPileCode(), tcpSession, lvnengUplinkMessage) + .setSetPricingResponse(setPricingResponse) + .build(); + tcpSession.getForwarder().sendMessage(uplinkQueueMessage); + + } + +} diff --git a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java new file mode 100644 index 0000000..f554702 --- /dev/null +++ b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java @@ -0,0 +1,98 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.lvneng.v340.cmd; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import lombok.extern.slf4j.Slf4j; +import sanbing.jcpp.proto.gen.DownlinkProto; +import sanbing.jcpp.proto.gen.DownlinkProto.SetPricingRequest; +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.mapping.LvnengDownlinkCmdConverter; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.SET_PRICING; +import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340; + +/** + * 绿能3.4 服务器设置 24 时电费计价策略信息 + */ +@Slf4j +@ProtocolCmd(value = 1103, protocolNames = {V340}) +public class LvnengV340SetPricingModelDLCmd extends LvnengDownlinkCmdExe { + + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); + @Override + public void execute(TcpSession tcpSession, LvnengDwonlinkMessage lvnengDwonlinkMessage, ProtocolContext ctx) { + log.debug("{} 绿能3.4服务器设置 24 时电费计价策略信息", tcpSession); + + if (!lvnengDwonlinkMessage.getMsg().hasSetPricingRequest()) { + return; + } + + SetPricingRequest setPricingRequest = lvnengDwonlinkMessage.getMsg().getSetPricingRequest(); + + long pricingId = setPricingRequest.getPricingId(); + String pileCode = setPricingRequest.getPileCode(); + DownlinkProto.PricingModelProto pricingModel = setPricingRequest.getPricingModel(); + // 适配新的protobuf结构:根据计费规则获取价格信息 + List periodList = null; + + if (pricingModel.hasTimePeriodPricing()) { + // 时段计价:使用运营商自定义时段计费 + DownlinkProto.TimePeriodPricingProto timePeriodPricing = pricingModel.getTimePeriodPricing(); + periodList = timePeriodPricing.getPeriodsList(); + + + } else { + // 未知计费模式 + log.error("未知的计费模式,桩编号: {}, 计费ID: {}, 计费规则: {}", pileCode, pricingId, pricingModel.getRule()); + throw new IllegalArgumentException("未知的计费模式: " + pricingModel.getRule()); + } + + // 一个时间段(开始小时1+开始分钟1+结束小时1+结束分钟1+4电费+4服务费)*48个时间段 + ByteBuf setPricingAckMsgBody = Unpooled.buffer(576); + for (DownlinkProto.TimePeriodItemProto x : periodList) { + LocalTime startTime = dateFormat(x.getStartTime()); + setPricingAckMsgBody.writeByte(startTime.getHour()); + setPricingAckMsgBody.writeByte(startTime.getMinute()); + + LocalTime endTime = dateFormat(x.getEndTime()); + setPricingAckMsgBody.writeByte(endTime.getHour()); + setPricingAckMsgBody.writeByte(endTime.getMinute()); + + setPricingAckMsgBody.writeIntLE(buildPrice(x.getElecPrice())); + setPricingAckMsgBody.writeIntLE(buildPrice(x.getServPrice())); + } + + + // 放进缓存后再下发 + tcpSession.getRequestCache().put(pileCode + LvnengDownlinkCmdConverter.getInstance().convertToCmd(SET_PRICING), pricingId); + + encodeAndWriteFlush(SET_PRICING, + setPricingAckMsgBody, + tcpSession); + } + + protected static LocalTime dateFormat(String time) { + return LocalTime.parse(time, DATE_TIME_FORMATTER); + } + + protected static int buildPrice(String price) { + return new BigDecimal(price).setScale(4, RoundingMode.HALF_UP).multiply(new BigDecimal(10000)).intValueExact(); + + } +} diff --git a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetQrcodeModelAckULCmd.java b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetQrcodeModelAckULCmd.java new file mode 100644 index 0000000..fda6b34 --- /dev/null +++ b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetQrcodeModelAckULCmd.java @@ -0,0 +1,70 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.lvneng.v340.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.proto.gen.UplinkProto.UplinkQueueMessage; +import sanbing.jcpp.proto.gen.UplinkProto.SetQrcodeResponse; + +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 java.nio.charset.StandardCharsets; + +import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340; + +/** + * 绿能3.4 充电桩参数字符形设置应答 + */ +@Slf4j +@ProtocolCmd(value = 4, protocolNames = {V340}) +public class LvnengV340SetQrcodeModelAckULCmd extends LvnengUplinkCmdExe { + @Override + public void execute(TcpSession tcpSession, LvnengUplinkMessage lvnengUplinkMessage, ProtocolContext ctx) { + log.debug("{} 绿能3.4 充电桩参数字符形设置/查询应答", tcpSession); + ByteBuf byteBuf = Unpooled.wrappedBuffer(lvnengUplinkMessage.getMsgBody()); + //1预留 + byteBuf.skipBytes(2); + //2预留 + byteBuf.skipBytes(2); + + //3充电桩编码 + byte[] pileCodeBytes = new byte[32]; + byteBuf.readBytes(pileCodeBytes); + String pileCode = StringUtils.trim(new String(pileCodeBytes, StandardCharsets.US_ASCII)); + + //4 0-査询 1-设置 + int type = byteBuf.readByte(); + + //5启始地址 + long startAddress = byteBuf.readUnsignedIntLE(); + + // 6.设置结果 0x00:成功 0x01:失败 + boolean isSuccess = (byteBuf.readByte() == 0x00); + //todo 查询应答逻辑没有处理 + + // 转发到后端 + SetQrcodeResponse setQrcodeResponse = SetQrcodeResponse.newBuilder() + .setPileCode(pileCode) + .setType(type) + .setStartAddr((int) startAddress) + .setSuccess(isSuccess) + .build(); + UplinkQueueMessage uplinkQueueMessage = uplinkMessageBuilder(setQrcodeResponse.getPileCode(), tcpSession, lvnengUplinkMessage) + .setSetQrcodeResponse(setQrcodeResponse) + .build(); + tcpSession.getForwarder().sendMessage(uplinkQueueMessage); + + } + +} diff --git a/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetQrcodeModelDLCmd.java b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetQrcodeModelDLCmd.java new file mode 100644 index 0000000..a2d6697 --- /dev/null +++ b/jcpp-protocol-lvneng/src/main/java/sanbing/jcpp/protocol/lvneng/v340/cmd/LvnengV340SetQrcodeModelDLCmd.java @@ -0,0 +1,74 @@ +/** + * 开源代码,仅供学习和交流研究使用,商用请联系三丙 + * 微信:mohan_88888 + * 抖音:程序员三丙 + * 付费课程知识星球:https://t.zsxq.com/aKtXo + */ +package sanbing.jcpp.protocol.lvneng.v340.cmd; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import lombok.extern.slf4j.Slf4j; +import sanbing.jcpp.proto.gen.DownlinkProto.QrcodeModelProto; +import sanbing.jcpp.proto.gen.DownlinkProto.SetQrcodeRequest; +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.enums.LvnengGunCodeNameEnum; + +import java.nio.charset.StandardCharsets; + +import static sanbing.jcpp.protocol.domain.DownlinkCmdEnum.SET_QRCODE; +import static sanbing.jcpp.protocol.lvneng.LvnengProtocolConstants.ProtocolNames.V340; + +/** + * 绿能3.4 服务器下发充电桩字符型参数 + */ +@Slf4j +@ProtocolCmd(value = 3, protocolNames = {V340}) +public class LvnengV340SetQrcodeModelDLCmd extends LvnengDownlinkCmdExe { + + @Override + public void execute(TcpSession tcpSession, LvnengDwonlinkMessage lvnengDwonlinkMessage, ProtocolContext ctx) { + log.debug("{} 绿能3.4 服务器下发充电桩字符型参数", tcpSession); + + if (!lvnengDwonlinkMessage.getMsg().hasSetQrcodeRequest()) { + return; + } + + SetQrcodeRequest setQrcodeRequest = lvnengDwonlinkMessage.getMsg().getSetQrcodeRequest(); + QrcodeModelProto qrcodeModel = setQrcodeRequest.getQrcodeModel(); + Integer parameterAddress = LvnengGunCodeNameEnum.getParameterAddress(qrcodeModel.getGunName()); + if (parameterAddress == null) { + log.error("{} 充电桩参数地址不存在", qrcodeModel.getGunName()); + return; + } + + ByteBuf msgBody = Unpooled.buffer(267); + // 预留1 + msgBody.writeShortLE(0); + // 预留1 + msgBody.writeShortLE(0); + //0-查询 1-设置 + msgBody.writeByte(1); + // 4 参数起始地址,子命令 + msgBody.writeIntLE(parameterAddress); + //6 参数字节长度 + msgBody.writeShortLE(256); + //7 命令参数数据 + msgBody.writeBytes(qrcodeModel.getCode().getBytes(StandardCharsets.US_ASCII)); + //获取二维码参数地址 + + + // 放进缓存后再下发 + // tcpSession.getRequestCache().put(pileCode + LvnengDownlinkCmdConverter.getInstance().convertToCmd(SET_PRICING), pricingId); + + encodeAndWriteFlush(SET_QRCODE, + msgBody, + tcpSession); + } + + +}