1103,1104,5,6指令,充电桩二维码下发和响应3,4指令

This commit is contained in:
红中
2025-09-03 17:44:46 +08:00
parent eff49bb3c0
commit 0582135995
16 changed files with 639 additions and 1 deletions

View File

@@ -67,6 +67,21 @@ public class TestController extends BaseController {
return ResponseEntity.ok("success");
}
@GetMapping("/setQrcode")
public ResponseEntity<String> 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<String> restartPile() {

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -253,6 +253,10 @@ public class ProtocolUplinkConsumerService extends AbstractConsumerService {
pileProtocolService.onStartChargeRequest(uplinkQueueMsg, callback);
} else if (uplinkQueueMsg.hasSetQrcodeResponse()) {
pileProtocolService.onSetQrcodeResponse(uplinkQueueMsg, callback);
} else {
callback.onSuccess();

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -23,6 +23,8 @@ public enum DownlinkCmdEnum {
SET_PRICING,
SET_QRCODE,
REMOTE_START_CHARGING,
REMOTE_STOP_CHARGING,

View File

@@ -33,4 +33,25 @@
#### 101 服务器应答心跳包信息
`AA F5 0F 00 10 03 65 00 00 00 00 00 00 00 65`
---
---
#### 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`
---

View File

@@ -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<String, LvnengGunCodeNameEnum> 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();
}
}

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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<DownlinkProto.TimePeriodItemProto> 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}