羽信预约充电

This commit is contained in:
Guoqs
2026-06-18 13:06:06 +08:00
parent bde9d450e9
commit da1da312c7
4 changed files with 200 additions and 111 deletions

View File

@@ -66,23 +66,39 @@ public class ReservationChargingResponseHandler extends AbstractYkcHandler {
startIndex += length; startIndex += length;
length = 1; length = 1;
byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
String connectorCode = BytesUtil.bcd2Str(connectorCodeByteArr); String responseFrameType = YKCUtils.frameType2Str(ykcDataProtocol.getFrameType());
boolean yuxinResponse = StringUtils.equals(responseFrameType, yuxinType);
String connectorCode = yuxinResponse ? parseYuxinConnectorCode(connectorCodeByteArr) : BytesUtil.bcd2Str(connectorCodeByteArr);
String reservationType = null;
if (yuxinResponse) {
// 羽信0xB1在枪号后多一个预约方式字段: 0x00 立即预约, 0x01 取消预约。
startIndex += length;
length = 1;
byte[] reservationTypeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
reservationType = BytesUtil.bin2HexStr(reservationTypeByteArr);
}
// 启动结果 0x00失败 0x01成功 // 启动结果 0x00失败 0x01成功
startIndex += length; startIndex += length;
length = 1; length = 1;
byte[] resultCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); byte[] resultCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
String resultCode = BytesUtil.bcd2Str(resultCodeByteArr); String resultCode = yuxinResponse ? BytesUtil.bin2HexStr(resultCodeByteArr) : BytesUtil.bcd2Str(resultCodeByteArr);
// 失败原因 // 失败原因
startIndex += length; startIndex += length;
length = 1; length = 1;
byte[] failedReasonByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); byte[] failedReasonByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
String failedReason = BytesUtil.bcd2Str(failedReasonByteArr); String failedReason = yuxinResponse ? BytesUtil.bin2HexStr(failedReasonByteArr) : BytesUtil.bcd2Str(failedReasonByteArr);
String failedReasonMsg = yuxinResponse ? getYuxinFailedReasonMsg(failedReason) : failedReason;
String responseFrameType = YKCUtils.frameType2Str(ykcDataProtocol.getFrameType()); if (yuxinResponse) {
log.info("{}预约充电响应, 交易流水号:{}, 桩SN:{}, 枪口号:{}, 结果:{}, 失败原因:{}", log.info("{}预约充电响应, 交易流水号:{}, 桩SN:{}, 枪口号:{}, 预约方式:{}, 结果:{}, 失败原因:{}",
responseFrameType, transactionCode, pileSn, connectorCode, resultCode, failedReason); responseFrameType, transactionCode, pileSn, connectorCode, reservationType, resultCode, failedReasonMsg);
} else {
log.info("{}预约充电响应, 交易流水号:{}, 桩SN:{}, 枪口号:{}, 结果:{}, 失败原因:{}",
responseFrameType, transactionCode, pileSn, connectorCode, resultCode, failedReason);
}
// 根据请求id在集合中找到与外部线程通信的SyncPromise对象 // 根据请求id在集合中找到与外部线程通信的SyncPromise对象
String requestFrameType = YKCFrameTypeCode.PileAnswersRelation.getRequestFrameType(responseFrameType); String requestFrameType = YKCFrameTypeCode.PileAnswersRelation.getRequestFrameType(responseFrameType);
@@ -114,4 +130,21 @@ public class ReservationChargingResponseHandler extends AbstractYkcHandler {
} }
return null; return null;
} }
private String parseYuxinConnectorCode(byte[] connectorCodeByteArr) {
return String.format("%02d", connectorCodeByteArr[0] & 0xFF);
}
private String getYuxinFailedReasonMsg(String failedReason) {
if (StringUtils.equals(failedReason, "00")) {
return "";
} else if (StringUtils.equals(failedReason, "01")) {
return "保存失败";
} else if (StringUtils.equals(failedReason, "02")) {
return "系统当前时间小于主板时间";
} else if (StringUtils.equals(failedReason, "03")) {
return "预约时间小于当前时间";
}
return failedReason;
}
} }

View File

@@ -5,6 +5,7 @@ import com.google.common.collect.Lists;
import com.jsowell.common.constant.CacheConstants; import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.constant.Constants; import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ykc.YKCDataProtocol; import com.jsowell.common.core.domain.ykc.YKCDataProtocol;
import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode;
import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.ebike.EBikeChargeResponseEnum; import com.jsowell.common.enums.ebike.EBikeChargeResponseEnum;
import com.jsowell.common.enums.ykc.ChargingFailedReasonEnum; import com.jsowell.common.enums.ykc.ChargingFailedReasonEnum;
@@ -513,13 +514,16 @@ public class PileRemoteService {
* @return result: 1-成功; 0-失败 * @return result: 1-成功; 0-失败
*/ */
public String reservationCharging(ReservationChargingCommand command) { public String reservationCharging(ReservationChargingCommand command) {
String result = "1"; String result = "0";
byte[] bytes = ykcPushCommandService.pushReservationChargingCommand(command); byte[] bytes = ykcPushCommandService.pushReservationChargingCommand(command);
// 解析结果 // 解析结果
if (Objects.isNull(bytes)) { if (Objects.isNull(bytes)) {
result = "0"; result = "0";
} else { } else {
YKCDataProtocol ykcDataProtocol = new YKCDataProtocol(bytes); YKCDataProtocol ykcDataProtocol = new YKCDataProtocol(bytes);
String responseFrameType = YKCUtils.frameType2Str(ykcDataProtocol.getFrameType());
boolean yuxinResponse = StringUtils.equals(responseFrameType,
YKCUtils.frameType2Str(YKCFrameTypeCode.YUXIN_RESERVATION_CHARGING_SETUP_ANSWER_CODE.getBytes()));
byte[] msgBody = ykcDataProtocol.getMsgBody(); byte[] msgBody = ykcDataProtocol.getMsgBody();
int startIndex = 0; int startIndex = 0;
int length = 16; int length = 16;
@@ -538,17 +542,24 @@ public class PileRemoteService {
startIndex += length; startIndex += length;
length = 1; length = 1;
byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
String connectorCode = BytesUtil.bcd2Str(connectorCodeByteArr); String connectorCode = yuxinResponse ? parseYuxinConnectorCode(connectorCodeByteArr) : BytesUtil.bcd2Str(connectorCodeByteArr);
String reservationType = null;
if (yuxinResponse) {
// 羽信0xB1在枪号后多一个预约方式字段: 0x00 立即预约, 0x01 取消预约。
startIndex += length;
length = 1;
byte[] reservationTypeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
reservationType = BytesUtil.bin2HexStr(reservationTypeByteArr);
}
// 启动结果 0x00失败 0x01成功 // 启动结果 0x00失败 0x01成功
startIndex += length; startIndex += length;
length = 1; length = 1;
byte[] resultCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); byte[] resultCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
String resultCode = BytesUtil.bcd2Str(resultCodeByteArr); String resultCode = yuxinResponse ? BytesUtil.bin2HexStr(resultCodeByteArr) : BytesUtil.bcd2Str(resultCodeByteArr);
if (StringUtils.equals(resultCode, "00")) { if (StringUtils.equals(resultCode, "01")) {
result = "0";
} else {
result = "1"; result = "1";
} }
@@ -556,15 +567,38 @@ public class PileRemoteService {
startIndex += length; startIndex += length;
length = 1; length = 1;
byte[] failedReasonByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); byte[] failedReasonByteArr = BytesUtil.copyBytes(msgBody, startIndex, length);
String failedReason = BytesUtil.bcd2Str(failedReasonByteArr); String failedReason = yuxinResponse ? BytesUtil.bin2HexStr(failedReasonByteArr) : BytesUtil.bcd2Str(failedReasonByteArr);
String failedReasonMsg = ChargingFailedReasonEnum.getMsgByCode(Integer.parseInt(failedReason, 16)); String failedReasonMsg = yuxinResponse
? getYuxinFailedReasonMsg(failedReason)
: ChargingFailedReasonEnum.getMsgByCode(Integer.parseInt(failedReason, 16));
String responseFrameType = YKCUtils.frameType2Str(ykcDataProtocol.getFrameType()); if (yuxinResponse) {
log.info("{}预约充电响应sync, 交易流水号:{}, 桩SN:{}, 枪口号:{}, 结果(00-失败; 01成功):{}, 失败原因:{}", log.info("{}预约充电响应sync, 交易流水号:{}, 桩SN:{}, 枪口号:{}, 预约方式:{}, 结果(00-失败; 01成功):{}, 失败原因:{}",
responseFrameType, transactionCode, pileSn, connectorCode, resultCode, failedReasonMsg); responseFrameType, transactionCode, pileSn, connectorCode, reservationType, resultCode, failedReasonMsg);
} else {
log.info("{}预约充电响应sync, 交易流水号:{}, 桩SN:{}, 枪口号:{}, 结果(00-失败; 01成功):{}, 失败原因:{}",
responseFrameType, transactionCode, pileSn, connectorCode, resultCode, failedReasonMsg);
}
} }
return result; return result;
} }
private String parseYuxinConnectorCode(byte[] connectorCodeByteArr) {
return String.format("%02d", connectorCodeByteArr[0] & 0xFF);
}
private String getYuxinFailedReasonMsg(String failedReason) {
if (StringUtils.equals(failedReason, "00")) {
return "";
} else if (StringUtils.equals(failedReason, "01")) {
return "保存失败";
} else if (StringUtils.equals(failedReason, "02")) {
return "系统当前时间小于主板时间";
} else if (StringUtils.equals(failedReason, "03")) {
return "预约时间小于当前时间";
}
return failedReason;
}
} }

View File

@@ -136,56 +136,17 @@ public class PileReservationInfoServiceImpl implements PileReservationInfoServic
*/ */
@Override @Override
public void activateReserved(PileReservationDTO dto) { public void activateReserved(PileReservationDTO dto) {
// 查询其他生效中的预约
// List<PileReservationInfo> infoList = pileReservationInfoMapper.findByMemberIdAndPileSnAndStatus(dto.getMemberId(), dto.getPileSn(), "1");
// if (CollectionUtils.isNotEmpty(infoList)) {
// throw new BusinessException(ReturnCodeEnum.CODE_RESERVATION_ALREADY_EXISTS_ERROR);
// }
PileReservationInfo pileReservationInfo = pileReservationInfoMapper.selectByPrimaryKey(Integer.parseInt(dto.getReservedId())); PileReservationInfo pileReservationInfo = pileReservationInfoMapper.selectByPrimaryKey(Integer.parseInt(dto.getReservedId()));
if (pileReservationInfo == null) { if (pileReservationInfo == null) {
return; return;
} }
// if (!StringUtils.equals(dto.getMemberId(), pileReservationInfo.getMemberId())) {
// return;
// }
pileReservationInfo.setStatus(Constants.ONE); pileReservationInfo.setStatus(Constants.ONE);
// 保存之前,校验时间是否重叠 if (!isTimeSlotAvailable(pileReservationInfo.getMemberId(), pileReservationInfo.getPileSn(),
int i = saveReservation(pileReservationInfo); pileReservationInfo.getStartTime(), pileReservationInfo.getEndTime(), pileReservationInfo.getId())) {
if (i > 0) { throw new BusinessException(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_REFUSED);
// 查询会员的绑定vin列表
List<MemberPlateNumberVO> plateNumberVOList = memberPlateNumberRelationService.selectMemberPlateNumberRelation(pileReservationInfo.getMemberId());
List<String> vinCodes = Lists.newArrayList();
int count = 0;
for (MemberPlateNumberVO vo : plateNumberVOList) {
if (count < 3 && StringUtils.isNotBlank(vo.getVinCode())) {
vinCodes.add(vo.getVinCode());
count++;
}
}
// 如果 vinCodes 的数量少于 3用 "0" 补足
while (vinCodes.size() < 3) {
vinCodes.add("");
}
String type = StringUtils.equals(pileReservationInfo.getReservationType(), "single") ? "00" : "01";
// 发送指令
ReservationChargingCommand command = ReservationChargingCommand.builder()
.transactionCode(Constants.ILLEGAL_TRANSACTION_CODE)
.pileSn(pileReservationInfo.getPileSn())
.connectorCode(pileReservationInfo.getPileConnectorCode().replace(pileReservationInfo.getPileSn(), ""))
.operation("01")
.reservationType(type)
.verifyIdentity(pileReservationInfo.getVerifyIdentity())
.vin1(vinCodes.get(0))
.vin2(vinCodes.get(1))
.vin3(vinCodes.get(2))
.reservedStartTime(pileReservationInfo.getStartTime().toLocalTime())
.reservedEndTime(pileReservationInfo.getEndTime().toLocalTime())
.amount(Constants.WHITELIST_DEFAULT_AMOUNT)
.build();
// pileRemoteService.reservationCharging(command);
} }
sendReservationCommandAndAssertSuccess(pileReservationInfo, pileReservationInfo.getMemberId(), "01");
this.insertOrUpdateSelective(pileReservationInfo);
} }
/** /**
@@ -197,48 +158,55 @@ public class PileReservationInfoServiceImpl implements PileReservationInfoServic
if (pileReservationInfo == null) { if (pileReservationInfo == null) {
return; return;
} }
// if (!StringUtils.equals(dto.getMemberId(), pileReservationInfo.getMemberId())) {
// return;
// }
// 校验通过可以修改预约
pileReservationInfo.setStatus(Constants.ZERO); pileReservationInfo.setStatus(Constants.ZERO);
int i = pileReservationInfoMapper.updateByPrimaryKeySelective(pileReservationInfo); sendReservationCommandAndAssertSuccess(pileReservationInfo, pileReservationInfo.getMemberId(), "02");
if (i > 0) { this.insertOrUpdateSelective(pileReservationInfo);
// 查询会员的绑定vin列表 }
List<MemberPlateNumberVO> plateNumberVOList = memberPlateNumberRelationService.selectMemberPlateNumberRelation(pileReservationInfo.getMemberId());
List<String> vinCodes = Lists.newArrayList();
int count = 0;
for (MemberPlateNumberVO vo : plateNumberVOList) {
if (count < 3 && StringUtils.isNotBlank(vo.getVinCode())) {
vinCodes.add(vo.getVinCode());
count++;
}
}
// 如果 vinCodes 的数量少于 3用 "0" 补足
while (vinCodes.size() < 3) {
vinCodes.add("");
}
String type = StringUtils.equals(pileReservationInfo.getReservationType(), "single") ? "00" : "01"; private void sendReservationCommandAndAssertSuccess(PileReservationInfo pileReservationInfo, String memberId, String operation) {
// 发送指令 ReservationChargingCommand command = buildReservationChargingCommand(pileReservationInfo, memberId, operation);
ReservationChargingCommand command = ReservationChargingCommand.builder() String result = pileRemoteService.reservationCharging(command);
.transactionCode(Constants.ILLEGAL_TRANSACTION_CODE) if (!StringUtils.equals(result, Constants.ONE)) {
.pileSn(pileReservationInfo.getPileSn()) throw new BusinessException(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR.getValue(),
.connectorCode(pileReservationInfo.getPileConnectorCode().replace(pileReservationInfo.getPileSn(), "")) ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR.getLabel() + ": 充电桩返回修改失败");
.operation("02")
.reservationType(type)
.verifyIdentity(pileReservationInfo.getVerifyIdentity())
.vin1(vinCodes.get(0))
.vin2(vinCodes.get(1))
.vin3(vinCodes.get(2))
.reservedStartTime(pileReservationInfo.getStartTime().toLocalTime())
.reservedEndTime(pileReservationInfo.getEndTime().toLocalTime())
.amount(Constants.WHITELIST_DEFAULT_AMOUNT)
.build();
// pileRemoteService.reservationCharging(command);
} }
} }
private ReservationChargingCommand buildReservationChargingCommand(PileReservationInfo pileReservationInfo, String memberId, String operation) {
List<String> vinCodes = getReservationVinCodes(memberId);
String type = StringUtils.equals(pileReservationInfo.getReservationType(), "single") ? "00" : "01";
return ReservationChargingCommand.builder()
.transactionCode(Constants.ILLEGAL_TRANSACTION_CODE)
.pileSn(pileReservationInfo.getPileSn())
.connectorCode(pileReservationInfo.getPileConnectorCode().replace(pileReservationInfo.getPileSn(), ""))
.operation(operation)
.reservationType(type)
.verifyIdentity(pileReservationInfo.getVerifyIdentity())
.vin1(vinCodes.get(0))
.vin2(vinCodes.get(1))
.vin3(vinCodes.get(2))
.reservedStartTime(pileReservationInfo.getStartTime().toLocalTime())
.reservedEndTime(pileReservationInfo.getEndTime().toLocalTime())
.amount(Constants.WHITELIST_DEFAULT_AMOUNT)
.build();
}
private List<String> getReservationVinCodes(String memberId) {
List<MemberPlateNumberVO> plateNumberVOList = memberPlateNumberRelationService.selectMemberPlateNumberRelation(memberId);
List<String> vinCodes = Lists.newArrayList();
int count = 0;
for (MemberPlateNumberVO vo : plateNumberVOList) {
if (count < 3 && StringUtils.isNotBlank(vo.getVinCode())) {
vinCodes.add(vo.getVinCode());
count++;
}
}
while (vinCodes.size() < 3) {
vinCodes.add("");
}
return vinCodes;
}
/** /**
* 校验时间是否重叠 * 校验时间是否重叠
* @param memberId * @param memberId
@@ -621,4 +589,3 @@ public class PileReservationInfoServiceImpl implements PileReservationInfoServic
pileReservationInfoMapper.deleteByPileSn(pileSn); pileReservationInfoMapper.deleteByPileSn(pileSn);
} }
} }

View File

@@ -33,6 +33,8 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -765,6 +767,25 @@ public class YKCPushCommandServiceImpl implements YKCPushCommandService {
*/ */
@Override @Override
public byte[] pushReservationChargingCommand(ReservationChargingCommand command) { public byte[] pushReservationChargingCommand(ReservationChargingCommand command) {
String pileSn = command.getPileSn();
YKCFrameTypeCode frameTypeCode = getReservationChargingFrameType(pileSn);
byte[] msg = frameTypeCode == YKCFrameTypeCode.YUXIN_RESERVATION_CHARGING_SETUP_CODE
? buildYuxinReservationChargingMsg(command)
: buildReservationChargingMsg(command);
byte[] response;
try {
response = this.supplySend(msg, pileSn, frameTypeCode);
} catch (Exception e) {
log.error("发送消息异常", e);
response = null;
}
log.info("【=====平台下发指令=====】: 预约充电指令, 帧类型:{}, 交易流水号:{}, 桩编号:{}, 枪口号:{}, 操作(01-启动; 02-取消; 03-修改):{}, 身份验证:{}, 开始时间:{}, 结束时间:{}, 启动金额:{}",
YKCUtils.frameType2Str(frameTypeCode.getBytes()), command.getTransactionCode(), pileSn, command.getConnectorCode(), command.getOperation(), command.getVerifyIdentity(), DateUtils.formatDateTime(command.getReservedStartTime()), DateUtils.formatDateTime(command.getReservedEndTime()), command.getAmount());
return response;
}
private byte[] buildReservationChargingMsg(ReservationChargingCommand command) {
// 交易流水号 // 交易流水号
String transactionCode = command.getTransactionCode(); String transactionCode = command.getTransactionCode();
byte[] transactionCodeArr = BytesUtil.str2Bcd(transactionCode); byte[] transactionCodeArr = BytesUtil.str2Bcd(transactionCode);
@@ -815,23 +836,57 @@ public class YKCPushCommandServiceImpl implements YKCPushCommandService {
BigDecimal amount = command.getAmount(); BigDecimal amount = command.getAmount();
byte[] amountByteArr = YKCUtils.getPriceByte(amount.toString(), 2); byte[] amountByteArr = YKCUtils.getPriceByte(amount.toString(), 2);
// 拼装msg信息 return Bytes.concat(transactionCodeArr, pileSnByteArr, connectorCodeByteArr, operateByteArr,
byte[] msg = Bytes.concat(transactionCodeArr, pileSnByteArr, connectorCodeByteArr, operateByteArr,
reservationTypeByteArr, verifyIdentityByteArr, vin1ByteArr, vin2ByteArr, vin3ByteArr, reservationTypeByteArr, verifyIdentityByteArr, vin1ByteArr, vin2ByteArr, vin3ByteArr,
reservedStartTimeByteArr, reservedEndTimeByteArr, amountByteArr); reservedStartTimeByteArr, reservedEndTimeByteArr, amountByteArr);
}
YKCFrameTypeCode frameTypeCode = getReservationChargingFrameType(pileSn); private byte[] buildYuxinReservationChargingMsg(ReservationChargingCommand command) {
byte[] response; byte[] transactionCodeArr = BytesUtil.ensureLengthPrependZero(BytesUtil.str2Bcd(command.getTransactionCode()), 16);
try { byte[] pileSnByteArr = BytesUtil.ensureLengthPrependZero(BytesUtil.str2Bcd(command.getPileSn()), 7);
response = this.supplySend(msg, pileSn, frameTypeCode); byte[] connectorCodeByteArr = BytesUtil.intToBytes(parseDecimalByte(command.getConnectorCode(), "枪口号"), 1);
} catch (Exception e) { byte[] accountBalanceByteArr = YKCUtils.getPriceByte(getAmount(command).toString(), 2);
log.error("发送消息异常", e); byte[] reservationTypeByteArr = BytesUtil.intToBytes(StringUtils.equals(command.getOperation(), "02") ? 0x01 : 0x00, 1);
response = null; byte[] chargingStrategyByteArr = BytesUtil.intToBytes(0x00, 1);
byte[] chargingParamByteArr = YKCUtils.getPriceByte(BigDecimal.ZERO.toString(), 2);
byte[] systemTimeByteArr = Cp56Time2aUtil.date2Hbyte(new Date());
byte[] reservedStartTimeByteArr = Cp56Time2aUtil.date2Hbyte(getYuxinReservedStartDate(command.getReservedStartTime()));
byte[] reservationTimeoutByteArr = BytesUtil.intToBytes(getYuxinReservationTimeout(command), 1);
return Bytes.concat(transactionCodeArr, pileSnByteArr, connectorCodeByteArr, accountBalanceByteArr,
reservationTypeByteArr, chargingStrategyByteArr, chargingParamByteArr, systemTimeByteArr,
reservedStartTimeByteArr, reservationTimeoutByteArr);
}
private BigDecimal getAmount(ReservationChargingCommand command) {
return command.getAmount() == null ? BigDecimal.ZERO : command.getAmount();
}
private Date getYuxinReservedStartDate(LocalTime reservedStartTime) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime reservedStartDateTime = now.toLocalDate().atTime(reservedStartTime);
if (!reservedStartDateTime.isAfter(now)) {
reservedStartDateTime = reservedStartDateTime.plusDays(1);
} }
return DateUtils.localDateTime2Date(reservedStartDateTime);
}
log.info("【=====平台下发指令=====】: 预约充电指令, 帧类型:{}, 交易流水号:{}, 桩编号:{}, 枪口号:{}, 操作(01-启动; 02-取消; 03-修改):{}, 身份验证:{}, 开始时间:{}, 结束时间:{}, 启动金额:{}", private int getYuxinReservationTimeout(ReservationChargingCommand command) {
YKCUtils.frameType2Str(frameTypeCode.getBytes()), transactionCode, pileSn, connectorCode, operation, verifyIdentity, DateUtils.formatDateTime(reservedStartTime), DateUtils.formatDateTime(reservedEndTime), amount); LocalTime reservedStartTime = command.getReservedStartTime();
return response; LocalTime reservedEndTime = command.getReservedEndTime();
long timeout = Duration.between(reservedStartTime, reservedEndTime).toMinutes();
if (timeout <= 0) {
timeout += TimeUnit.DAYS.toMinutes(1);
}
return (int) Math.min(timeout, 0xFF);
}
private int parseDecimalByte(String value, String fieldName) {
int result = Integer.parseInt(value);
if (result < 0 || result > 0xFF) {
throw new IllegalArgumentException(fieldName + "超出1字节范围:" + value);
}
return result;
} }
private YKCFrameTypeCode getReservationChargingFrameType(String pileSn) { private YKCFrameTypeCode getReservationChargingFrameType(String pileSn) {