mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-07-02 13:07:57 +08:00
update 电单车协议
This commit is contained in:
@@ -14,6 +14,7 @@ import com.jsowell.pile.domain.AdapayMemberAccount;
|
|||||||
import com.jsowell.pile.domain.MemberPlateNumberRelation;
|
import com.jsowell.pile.domain.MemberPlateNumberRelation;
|
||||||
import com.jsowell.pile.domain.OrderBasicInfo;
|
import com.jsowell.pile.domain.OrderBasicInfo;
|
||||||
import com.jsowell.pile.domain.ykcCommond.ReservationChargingCommand;
|
import com.jsowell.pile.domain.ykcCommond.ReservationChargingCommand;
|
||||||
|
import com.jsowell.pile.domain.ykcCommond.StartChargingCommand;
|
||||||
import com.jsowell.pile.dto.*;
|
import com.jsowell.pile.dto.*;
|
||||||
import com.jsowell.pile.service.*;
|
import com.jsowell.pile.service.*;
|
||||||
import com.jsowell.pile.service.programlogic.AbstractProgramLogic;
|
import com.jsowell.pile.service.programlogic.AbstractProgramLogic;
|
||||||
@@ -83,7 +84,11 @@ public class TempController extends BaseController {
|
|||||||
public RestApiResponse<?> tempStartCharging(@RequestBody QueryOrderDTO dto) {
|
public RestApiResponse<?> tempStartCharging(@RequestBody QueryOrderDTO dto) {
|
||||||
RestApiResponse<?> response = null;
|
RestApiResponse<?> response = null;
|
||||||
try {
|
try {
|
||||||
eBikeSendCommandService.startCharging(dto.getPileSn(), dto.getConnectorCode());
|
StartChargingCommand command = StartChargingCommand.builder()
|
||||||
|
.pileSn(dto.getPileSn())
|
||||||
|
.connectorCode(dto.getConnectorCode())
|
||||||
|
.build();
|
||||||
|
eBikeSendCommandService.sendStartChargingCommand(command);
|
||||||
response = new RestApiResponse<>();
|
response = new RestApiResponse<>();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("电单车开始充电 error", e);
|
logger.error("电单车开始充电 error", e);
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import java.math.BigDecimal;
|
|||||||
* @author jsowell
|
* @author jsowell
|
||||||
*/
|
*/
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
// 电单车协议包头
|
||||||
|
public static final String EBIKE_HEADER = "DNY";
|
||||||
|
|
||||||
// 十六进制前缀
|
// 十六进制前缀
|
||||||
public static final String HEX_PREFIX = "0x";
|
public static final String HEX_PREFIX = "0x";
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ public class BytesUtil {
|
|||||||
// int i = BytesUtil.bytesToIntLittle(length);
|
// int i = BytesUtil.bytesToIntLittle(length);
|
||||||
// System.out.println(i);
|
// System.out.println(i);
|
||||||
|
|
||||||
String testStr = "DNY";
|
String testStr = Constants.EBIKE_HEADER;
|
||||||
byte[] hexBytes = stringToHexBytes(testStr, 3);
|
byte[] hexBytes = stringToHexBytes(testStr, 3);
|
||||||
System.out.println("Hex Bytes: " + bytesToHex(hexBytes));
|
System.out.println("Hex Bytes: " + bytesToHex(hexBytes));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.jsowell.netty.decoder;
|
package com.jsowell.netty.decoder;
|
||||||
|
|
||||||
|
import com.jsowell.common.constant.Constants;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
@@ -47,7 +48,7 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
buffer.getBytes(beginReader, headerBytes, 0, HEADER_LENGTH_DNY);
|
buffer.getBytes(beginReader, headerBytes, 0, HEADER_LENGTH_DNY);
|
||||||
String header = new String(headerBytes, StandardCharsets.UTF_8);
|
String header = new String(headerBytes, StandardCharsets.UTF_8);
|
||||||
// log.info("检查包头是否是DNY, header:{}", header);
|
// log.info("检查包头是否是DNY, header:{}", header);
|
||||||
if ("DNY".equals(header)) {
|
if (Constants.EBIKE_HEADER.equals(header)) {
|
||||||
// 处理 DNY 协议
|
// 处理 DNY 协议
|
||||||
decodeDnyMessage(buffer, out, beginReader);
|
decodeDnyMessage(buffer, out, beginReader);
|
||||||
return;
|
return;
|
||||||
@@ -73,7 +74,7 @@ public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
|
|||||||
byte[] headerBytes = new byte[HEADER_LENGTH_DNY];
|
byte[] headerBytes = new byte[HEADER_LENGTH_DNY];
|
||||||
buffer.getBytes(beginReader, headerBytes, 0, HEADER_LENGTH_DNY);
|
buffer.getBytes(beginReader, headerBytes, 0, HEADER_LENGTH_DNY);
|
||||||
String header = new String(headerBytes, StandardCharsets.UTF_8);
|
String header = new String(headerBytes, StandardCharsets.UTF_8);
|
||||||
return "DNY".equals(header);
|
return Constants.EBIKE_HEADER.equals(header);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.jsowell.pile.domain.ebike.serversend;
|
|||||||
|
|
||||||
import com.google.common.primitives.Bytes;
|
import com.google.common.primitives.Bytes;
|
||||||
import com.jsowell.common.YouDianUtils;
|
import com.jsowell.common.YouDianUtils;
|
||||||
|
import com.jsowell.common.constant.Constants;
|
||||||
import com.jsowell.common.util.BytesUtil;
|
import com.jsowell.common.util.BytesUtil;
|
||||||
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
|
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@@ -35,7 +36,7 @@ public class EBikeMessageCmd82 extends AbsEBikeMessage {
|
|||||||
@Override
|
@Override
|
||||||
public byte[] getMessageBytes() {
|
public byte[] getMessageBytes() {
|
||||||
// 包头
|
// 包头
|
||||||
byte[] headerBytes = BytesUtil.stringToHexBytes(header, 3);
|
byte[] headerBytes = BytesUtil.stringToHexBytes(Constants.EBIKE_HEADER, 3);
|
||||||
// 物理ID
|
// 物理ID
|
||||||
byte[] physicalIdBytes = YouDianUtils.getPhysicalIdBytes(physicalId);
|
byte[] physicalIdBytes = YouDianUtils.getPhysicalIdBytes(physicalId);
|
||||||
// 消息ID
|
// 消息ID
|
||||||
@@ -75,13 +76,13 @@ public class EBikeMessageCmd82 extends AbsEBikeMessage {
|
|||||||
private int chargeCommand; // 充电命令 (1字节)
|
private int chargeCommand; // 充电命令 (1字节)
|
||||||
|
|
||||||
// 告知设备的充电时长/电量, 如是0x0000则说明是充满自停, 其他数值则按照时长/电量充电, 且充满不会自停,
|
// 告知设备的充电时长/电量, 如是0x0000则说明是充满自停, 其他数值则按照时长/电量充电, 且充满不会自停,
|
||||||
private int chargeDurationOrPower; // 充电时长/电量 (2字节)
|
private int chargeTimeOrPower; // 充电时长/电量 (2字节)
|
||||||
|
|
||||||
// 生成给桩的交易流水号, 桩协议叫订单编号
|
// 生成给桩的交易流水号, 桩协议叫订单编号
|
||||||
private String transactionCode; // 订单编号 (16字节)
|
private String transactionCode; // 订单编号 (16字节)
|
||||||
|
|
||||||
// 最大充电时长、过载功率:(只对当前端口当前订单有效,不影响其他端口)动态设置此参数,如果参数为0表示不修改,会使用设备的设置值,默认10小时
|
// 最大充电时长、过载功率:(只对当前端口当前订单有效,不影响其他端口)动态设置此参数,如果参数为0表示不修改,会使用设备的设置值,默认10小时
|
||||||
private int maxChargeDuration; // 最大充电时长 (2字节)
|
private int maxChargeTime; // 最大充电时长 (2字节)
|
||||||
private int overloadPower; // 过载功率 (2字节)
|
private int overloadPower; // 过载功率 (2字节)
|
||||||
|
|
||||||
// 二维码灯:0=打开,1=关闭,针对部分有二维码灯的设备有效。此设置是针对下一次插头插入时是否点亮二维码背光灯,保存在内存中,断电重启后就会失效
|
// 二维码灯:0=打开,1=关闭,针对部分有二维码灯的设备有效。此设置是针对下一次插头插入时是否点亮二维码背光灯,保存在内存中,断电重启后就会失效
|
||||||
@@ -112,13 +113,13 @@ public class EBikeMessageCmd82 extends AbsEBikeMessage {
|
|||||||
this.chargeCommand = BytesUtil.bytesToIntLittle(new byte[]{chargeCommandBytes});
|
this.chargeCommand = BytesUtil.bytesToIntLittle(new byte[]{chargeCommandBytes});
|
||||||
|
|
||||||
byte[] chargeDurationOrPowerBytes = Arrays.copyOfRange(dataBytes, 7, 9);
|
byte[] chargeDurationOrPowerBytes = Arrays.copyOfRange(dataBytes, 7, 9);
|
||||||
this.chargeDurationOrPower = BytesUtil.bytesToIntLittle(chargeDurationOrPowerBytes);
|
this.chargeTimeOrPower = BytesUtil.bytesToIntLittle(chargeDurationOrPowerBytes);
|
||||||
|
|
||||||
byte[] orderNumberBytes = Arrays.copyOfRange(dataBytes, 9, 25);
|
byte[] orderNumberBytes = Arrays.copyOfRange(dataBytes, 9, 25);
|
||||||
this.transactionCode = BytesUtil.bcd2StrLittle(orderNumberBytes);
|
this.transactionCode = BytesUtil.bcd2StrLittle(orderNumberBytes);
|
||||||
|
|
||||||
byte[] maxChargeDurationBytes = Arrays.copyOfRange(dataBytes, 25, 27);
|
byte[] maxChargeDurationBytes = Arrays.copyOfRange(dataBytes, 25, 27);
|
||||||
this.maxChargeDuration = BytesUtil.bytesToIntLittle(maxChargeDurationBytes);
|
this.maxChargeTime = BytesUtil.bytesToIntLittle(maxChargeDurationBytes);
|
||||||
|
|
||||||
byte[] overloadPowerBytes = Arrays.copyOfRange(dataBytes, 27, 29);
|
byte[] overloadPowerBytes = Arrays.copyOfRange(dataBytes, 27, 29);
|
||||||
this.overloadPower = BytesUtil.bytesToIntLittle(overloadPowerBytes);
|
this.overloadPower = BytesUtil.bytesToIntLittle(overloadPowerBytes);
|
||||||
@@ -159,11 +160,11 @@ public class EBikeMessageCmd82 extends AbsEBikeMessage {
|
|||||||
// 充电命令
|
// 充电命令
|
||||||
byte[] chargeCommandBytes = BytesUtil.intToBytesLittle(chargeCommand, 1);
|
byte[] chargeCommandBytes = BytesUtil.intToBytesLittle(chargeCommand, 1);
|
||||||
// 充电时长/电量
|
// 充电时长/电量
|
||||||
byte[] chargeDurationOrPowerBytes = BytesUtil.intToBytesLittle(chargeDurationOrPower, 2);
|
byte[] chargeDurationOrPowerBytes = BytesUtil.intToBytesLittle(chargeTimeOrPower, 2);
|
||||||
// 订单编号
|
// 订单编号
|
||||||
byte[] orderNumberBytes = BytesUtil.ensureLength(BytesUtil.str2Bcd(transactionCode), 16);
|
byte[] orderNumberBytes = BytesUtil.ensureLength(BytesUtil.str2Bcd(transactionCode), 16);
|
||||||
// 最大充电时长
|
// 最大充电时长
|
||||||
byte[] maxChargeDurationBytes = BytesUtil.intToBytesLittle(maxChargeDuration, 2);
|
byte[] maxChargeDurationBytes = BytesUtil.intToBytesLittle(maxChargeTime, 2);
|
||||||
// 过载功率
|
// 过载功率
|
||||||
byte[] overloadPowerBytes = BytesUtil.intToBytesLittle(overloadPower, 2);
|
byte[] overloadPowerBytes = BytesUtil.intToBytesLittle(overloadPower, 2);
|
||||||
// 二维码灯
|
// 二维码灯
|
||||||
|
|||||||
@@ -15,4 +15,9 @@ import lombok.NoArgsConstructor;
|
|||||||
public class StopChargingCommand {
|
public class StopChargingCommand {
|
||||||
private String pileSn;
|
private String pileSn;
|
||||||
private String connectorCode;
|
private String connectorCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易流水号
|
||||||
|
*/
|
||||||
|
private String transactionCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
package com.jsowell.pile.service;
|
package com.jsowell.pile.service;
|
||||||
|
|
||||||
|
import com.jsowell.pile.domain.ykcCommond.StartChargingCommand;
|
||||||
|
import com.jsowell.pile.domain.ykcCommond.StopChargingCommand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 电单车发送命令服务
|
* 电单车发送命令服务
|
||||||
*/
|
*/
|
||||||
public interface EBikeSendCommandService {
|
public interface EBikeSendCommandService {
|
||||||
// void send(String pileSn, AbsEBikeMessage msg);
|
|
||||||
|
|
||||||
void startCharging(String pileSn, String connectorCode);
|
/**
|
||||||
|
* 启动充电
|
||||||
|
* @param command
|
||||||
|
*/
|
||||||
|
void sendStartChargingCommand(StartChargingCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止充电
|
||||||
|
* @param command
|
||||||
|
*/
|
||||||
|
void sendStopChargingCommand(StopChargingCommand command);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ package com.jsowell.pile.service.impl;
|
|||||||
import com.jsowell.common.enums.ykc.PileChannelEntity;
|
import com.jsowell.common.enums.ykc.PileChannelEntity;
|
||||||
import com.jsowell.common.util.BytesUtil;
|
import com.jsowell.common.util.BytesUtil;
|
||||||
import com.jsowell.common.util.RandomUtil;
|
import com.jsowell.common.util.RandomUtil;
|
||||||
|
import com.jsowell.common.util.StringUtils;
|
||||||
import com.jsowell.common.util.id.IdUtils;
|
import com.jsowell.common.util.id.IdUtils;
|
||||||
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
|
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
|
||||||
import com.jsowell.pile.domain.ebike.serversend.EBikeMessageCmd82;
|
import com.jsowell.pile.domain.ebike.serversend.EBikeMessageCmd82;
|
||||||
|
import com.jsowell.pile.domain.ykcCommond.StartChargingCommand;
|
||||||
|
import com.jsowell.pile.domain.ykcCommond.StopChargingCommand;
|
||||||
import com.jsowell.pile.service.EBikeSendCommandService;
|
import com.jsowell.pile.service.EBikeSendCommandService;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
@@ -20,15 +23,23 @@ import java.util.Objects;
|
|||||||
@Service
|
@Service
|
||||||
public class EBikeSendCommandServiceImpl implements EBikeSendCommandService {
|
public class EBikeSendCommandServiceImpl implements EBikeSendCommandService {
|
||||||
|
|
||||||
|
// 过载功率, 单位0.1W, 2450 * 0.1 = 2450W
|
||||||
|
private final int OVER_LOAD_POWER = 2450;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 电单车发送启动充电指令
|
* 电单车发送启动充电指令
|
||||||
* @param pileSn 电单车桩号
|
|
||||||
* @param connectorCode 枪口号
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void startCharging(String pileSn, String connectorCode) {
|
public void sendStartChargingCommand(StartChargingCommand command) {
|
||||||
|
String pileSn = command.getPileSn();
|
||||||
|
String connectorCode = command.getConnectorCode();
|
||||||
|
String transactionCode = command.getTransactionCode();
|
||||||
|
if (StringUtils.isBlank(transactionCode)) {
|
||||||
|
transactionCode = IdUtils.generateTransactionCode(pileSn, connectorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装参数
|
||||||
EBikeMessageCmd82 message = new EBikeMessageCmd82();
|
EBikeMessageCmd82 message = new EBikeMessageCmd82();
|
||||||
message.setHeader("DNY");
|
|
||||||
message.setPhysicalId(Integer.parseInt(pileSn));
|
message.setPhysicalId(Integer.parseInt(pileSn));
|
||||||
message.setMessageId(RandomUtil.getRandomNumber(4));
|
message.setMessageId(RandomUtil.getRandomNumber(4));
|
||||||
message.setCommand("82");
|
message.setCommand("82");
|
||||||
@@ -44,16 +55,63 @@ public class EBikeSendCommandServiceImpl implements EBikeSendCommandService {
|
|||||||
data.setChargeCommand(1);
|
data.setChargeCommand(1);
|
||||||
// 充电时长/功率
|
// 充电时长/功率
|
||||||
int chargeDurationOrPower = 0;
|
int chargeDurationOrPower = 0;
|
||||||
data.setChargeDurationOrPower(chargeDurationOrPower);
|
data.setChargeTimeOrPower(chargeDurationOrPower);
|
||||||
|
|
||||||
// 订单编号
|
// 订单编号
|
||||||
String transactionCode = IdUtils.generateTransactionCode(pileSn, connectorCode);
|
|
||||||
data.setTransactionCode(transactionCode);
|
data.setTransactionCode(transactionCode);
|
||||||
|
|
||||||
// 最大充电时长
|
// 最大充电时长
|
||||||
data.setMaxChargeDuration(0);
|
data.setMaxChargeTime(0);
|
||||||
// 过载功率
|
// 过载功率
|
||||||
data.setOverloadPower(3000);
|
data.setOverloadPower(OVER_LOAD_POWER);
|
||||||
|
data.setQrCodeLight(0);
|
||||||
|
data.setLongChargeMode(0);
|
||||||
|
data.setExtraFloatChargeTime(0);
|
||||||
|
data.setSkipShortCircuitDetection(0);
|
||||||
|
data.setNoUserPullOutCheck(0);
|
||||||
|
data.setForceAutoStopWhenFull(0);
|
||||||
|
data.setFullChargePower(0);
|
||||||
|
data.setMaxFullChargePowerCheckTime(0);
|
||||||
|
message.setData(data);
|
||||||
|
this.send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送停止充电指令
|
||||||
|
* @param command
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void sendStopChargingCommand(StopChargingCommand command) {
|
||||||
|
String pileSn = command.getPileSn();
|
||||||
|
String connectorCode = command.getConnectorCode();
|
||||||
|
String transactionCode = command.getTransactionCode();
|
||||||
|
|
||||||
|
// 组装参数
|
||||||
|
EBikeMessageCmd82 message = new EBikeMessageCmd82();
|
||||||
|
message.setPhysicalId(Integer.parseInt(pileSn));
|
||||||
|
message.setMessageId(RandomUtil.getRandomNumber(4));
|
||||||
|
message.setCommand("82");
|
||||||
|
|
||||||
|
EBikeMessageCmd82.SpecificData data = new EBikeMessageCmd82.SpecificData();
|
||||||
|
// 充电模式
|
||||||
|
data.setRateMode(3);
|
||||||
|
// 余额或有效期
|
||||||
|
data.setBalanceOrValidity(1234);
|
||||||
|
// 端口号
|
||||||
|
data.setPortNumber(Integer.parseInt(connectorCode));
|
||||||
|
// 充电命令
|
||||||
|
data.setChargeCommand(0);
|
||||||
|
// 充电时长/功率
|
||||||
|
int chargeDurationOrPower = 0;
|
||||||
|
data.setChargeTimeOrPower(chargeDurationOrPower);
|
||||||
|
|
||||||
|
// 订单编号
|
||||||
|
data.setTransactionCode(transactionCode);
|
||||||
|
|
||||||
|
// 最大充电时长
|
||||||
|
data.setMaxChargeTime(0);
|
||||||
|
// 过载功率
|
||||||
|
data.setOverloadPower(OVER_LOAD_POWER);
|
||||||
data.setQrCodeLight(0);
|
data.setQrCodeLight(0);
|
||||||
data.setLongChargeMode(0);
|
data.setLongChargeMode(0);
|
||||||
data.setExtraFloatChargeTime(0);
|
data.setExtraFloatChargeTime(0);
|
||||||
|
|||||||
@@ -281,6 +281,7 @@ public class YKCPushCommandServiceImpl implements YKCPushCommandService {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("【=====平台下发充电指令=====】:订单id:{}, 桩号:{}, 枪口号:{}, 逻辑卡号:{}, 物理卡号:{}, 账户余额:{}",
|
log.info("【=====平台下发充电指令=====】:订单id:{}, 桩号:{}, 枪口号:{}, 逻辑卡号:{}, 物理卡号:{}, 账户余额:{}",
|
||||||
transactionCode, pileSn, BytesUtil.bcd2Str(connectorCodeByteArr), logicCardNum, physicsCardNum, chargeAmount);
|
transactionCode, pileSn, BytesUtil.bcd2Str(connectorCodeByteArr), logicCardNum, physicsCardNum, chargeAmount);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user