update 电单车协议

This commit is contained in:
Guoqs
2024-09-02 19:55:02 +08:00
parent a41264d1b9
commit 256e358be5
16 changed files with 245 additions and 115 deletions

View File

@@ -72,6 +72,25 @@ public class TempController extends BaseController {
@Autowired
private PileRemoteService pileRemoteService;
@Autowired
private EBikeSendCommandService eBikeSendCommandService;
/**
* 电单车开始充电
* http://localhost:8080/temp/tempStartCharging
*/
@PostMapping("/tempStartCharging")
public RestApiResponse<?> tempStartCharging(@RequestBody QueryOrderDTO dto) {
RestApiResponse<?> response = null;
try {
eBikeSendCommandService.startCharging(dto.getPileSn());
} catch (Exception e) {
logger.error("电单车开始充电 error", e);
response = new RestApiResponse<>(ReturnCodeEnum.CODE_FAILED);
}
return response;
}
/**
* 对时
* http://localhost:8080/temp/proofreadTimeTest

View File

@@ -55,6 +55,7 @@ public class PileChannelEntity {
* @return
*/
public static ChannelHandlerContext getChannelByPileSn(String pileSn) {
output();
return manager.get(pileSn);
}
@@ -78,7 +79,7 @@ public class PileChannelEntity {
public static void output() {
for (HashMap.Entry<String, ChannelHandlerContext> entry : manager.entrySet()) {
System.out.println("pileSn:" + entry.getKey() +
",ChannelId:" + entry.getValue().channel().id().asLongText());
",ChannelId:" + entry.getValue().channel().id().asShortText());
}
}

View File

@@ -272,6 +272,55 @@ public class BytesUtil {
return stringBuilder.toString();
}
/**
* 将字符串转换为指定长度的16进制字节数组。
*
* @param str 需要转换的字符串
* @param targetLength 目标字节数组的长度
* @return 对应的16进制字节数组
*/
public static byte[] stringToHexBytes(String str, int targetLength) {
if (str == null) {
throw new IllegalArgumentException("字符串不能为null");
}
int strLength = str.length();
if (targetLength < strLength) {
throw new IllegalArgumentException("目标字节数组长度必须大于等于字符串长度");
}
byte[] hexBytes = new byte[targetLength];
for (int i = 0; i < strLength; i++) {
char c = str.charAt(i);
hexBytes[i] = (byte) c;
}
// 剩余部分用0填充
for (int i = strLength; i < targetLength; i++) {
hexBytes[i] = 0;
}
return hexBytes;
}
/**
* 将字节数组转换为十六进制字符串,用于打印查看。
*
* @param bytes 字节数组
* @return 十六进制字符串
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
/**
* @函数功能: 10进制串转为BCD码
* @输入参数: 10进制串
@@ -326,12 +375,14 @@ public class BytesUtil {
return revert(temp);
}
public static void main(String[] args) {
byte[] length = new byte[] {0x09, 0x00};
int i = BytesUtil.bytesToIntLittle(length);
System.out.println(i);
// byte[] length = new byte[] {0x09, 0x00};
// int i = BytesUtil.bytesToIntLittle(length);
// System.out.println(i);
String testStr = "DNY";
byte[] hexBytes = stringToHexBytes(testStr, 3);
System.out.println("Hex Bytes: " + bytesToHex(hexBytes));
}
/**

View File

@@ -14,7 +14,7 @@ import java.util.Set;
public class RandomUtil {
private static final String SYMBOLS_NUM = "0123456789"; // 纯数字
//如果需加入字母就改成0123456789abcdefg...........
private static final String SYMBOLS_NUM_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
// private static final String SYMBOLS_NUM_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
private static final Random RANDOM = new SecureRandom();
@@ -24,7 +24,7 @@ public class RandomUtil {
* @return 随机数字
*/
public static String getSMSVerificationCode() {
return getRandomNumber(6);
return getRandomNumberStr(6);
}
/**
@@ -33,7 +33,7 @@ public class RandomUtil {
* @param length 需要的长度
* @return 随机数
*/
public static String getRandomNumber(int length) {
public static String getRandomNumberStr(int length) {
char[] nonceChars = new char[length]; //指定长度,自己可以设置
for (int index = 0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS_NUM.charAt(RANDOM.nextInt(SYMBOLS_NUM.length()));
@@ -41,6 +41,10 @@ public class RandomUtil {
return new String(nonceChars);
}
public static int getRandomNumber(int length) {
return Integer.parseInt(getRandomNumberStr(length));
}
/**
* 获取一组不重复的6位数随机数
*

View File

@@ -87,7 +87,7 @@ public class IdUtils {
public static String generateTransactionCode(String pileConnectorCode) {
String timeNow = DateUtils.dateTimeNow(DateUtils.YYMMDDHHMMSS);
// 随机生成一个四位整数
String randomNumber = RandomUtil.getRandomNumber(4);
String randomNumber = RandomUtil.getRandomNumberStr(4);
return pileConnectorCode + timeNow + randomNumber;
}

View File

@@ -3,6 +3,7 @@ package com.jsowell.netty.handler.electricbicycles;
import com.alibaba.fastjson2.JSON;
import com.jsowell.common.core.domain.ebike.EBikeDataProtocol;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.netty.factory.EBikeOperateFactory;
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
import com.jsowell.pile.domain.ebike.EBikeCommandEnum;
@@ -17,7 +18,8 @@ import org.springframework.stereotype.Component;
@Slf4j
@Component
public class DeviceGetServerTimeHandler extends AbstractEBikeHandler {
private final String type = EBikeCommandEnum.DEVICE_GET_SERVER_TIME.getCode();
// private final String type = EBikeCommandEnum.DEVICE_GET_SERVER_TIME.getCode();
private final String type = YKCUtils.frameType2Str(EBikeCommandEnum.DEVICE_GET_SERVER_TIME.getBytes());
@Override
public void afterPropertiesSet() throws Exception {

View File

@@ -5,6 +5,7 @@ import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ebike.EBikeDataProtocol;
import com.jsowell.common.enums.ebike.PortStatusEnum;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.netty.factory.EBikeOperateFactory;
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
import com.jsowell.pile.domain.ebike.EBikeCommandEnum;
@@ -24,7 +25,7 @@ import java.util.List;
@Slf4j
@Component
public class HeartbeatHandler extends AbstractEBikeHandler {
private final String type = EBikeCommandEnum.HEARTBEAT_2.getCode();
private final String type = YKCUtils.frameType2Str(EBikeCommandEnum.HEARTBEAT_2.getBytes());
@Autowired
private PileBasicInfoService pileBasicInfoService;

View File

@@ -3,6 +3,7 @@ package com.jsowell.netty.handler.electricbicycles;
import com.alibaba.fastjson2.JSON;
import com.jsowell.common.core.domain.ebike.EBikeDataProtocol;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.netty.factory.EBikeOperateFactory;
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
import com.jsowell.pile.domain.ebike.EBikeCommandEnum;
@@ -17,7 +18,8 @@ import org.springframework.stereotype.Component;
@Slf4j
@Component
public class HostGetServerTimeHandler extends AbstractEBikeHandler {
private final String type = EBikeCommandEnum.HOST_GET_SERVER_TIME.getCode();
// private final String type = EBikeCommandEnum.HOST_GET_SERVER_TIME.getCode();
private final String type = YKCUtils.frameType2Str(EBikeCommandEnum.HOST_GET_SERVER_TIME.getBytes());
@Override
public void afterPropertiesSet() throws Exception {

View File

@@ -3,6 +3,7 @@ package com.jsowell.netty.handler.electricbicycles;
import com.alibaba.fastjson2.JSON;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.domain.ebike.EBikeDataProtocol;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.netty.factory.EBikeOperateFactory;
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
import com.jsowell.pile.domain.ebike.EBikeCommandEnum;
@@ -19,7 +20,8 @@ import org.springframework.stereotype.Component;
@Slf4j
@Component
public class RegistrationHandler extends AbstractEBikeHandler {
private final String type = EBikeCommandEnum.REGISTRATION.getCode();
// private final String type = EBikeCommandEnum.REGISTRATION.getCode();
private final String type = YKCUtils.frameType2Str(EBikeCommandEnum.REGISTRATION.getBytes());
@Autowired
private PileBasicInfoService pileBasicInfoService;

View File

@@ -2,6 +2,7 @@ package com.jsowell.netty.handler.electricbicycles;
import com.alibaba.fastjson2.JSON;
import com.jsowell.common.core.domain.ebike.EBikeDataProtocol;
import com.jsowell.common.util.YKCUtils;
import com.jsowell.netty.factory.EBikeOperateFactory;
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
import com.jsowell.pile.domain.ebike.EBikeCommandEnum;
@@ -16,7 +17,8 @@ import org.springframework.stereotype.Component;
@Slf4j
@Component
public class SettlementUploadHandler extends AbstractEBikeHandler {
private final String type = EBikeCommandEnum.SETTLEMENT_UPLOAD.getCode();
// private final String type = EBikeCommandEnum.SETTLEMENT_UPLOAD.getCode();
private final String type = YKCUtils.frameType2Str(EBikeCommandEnum.SETTLEMENT_UPLOAD.getBytes());
@Override
public void afterPropertiesSet() throws Exception {

View File

@@ -1,18 +1,19 @@
package com.jsowell.pile.domain.ebike;
import com.google.common.primitives.Bytes;
import com.jsowell.common.YouDianUtils;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.pile.domain.ebike.deviceupload.*;
import lombok.Getter;
import lombok.Setter;
import lombok.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@Getter
@Setter
public abstract class AbsEBikeMessage {
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AbsEBikeMessage {
protected String header; // 包头 (3字节)
protected int length; // 长度 (2字节)
protected int physicalId; // 物理ID (4字节)
@@ -21,17 +22,9 @@ public abstract class AbsEBikeMessage {
protected Object payload; // 数据 (n字节)
protected int checksum; // 校验 (2字节)
public AbsEBikeMessage(String header, int length, int physicalId, int messageId, String command, Object payload, int checksum) {
this.header = header;
this.length = length;
this.physicalId = physicalId;
this.messageId = messageId;
this.command = command;
this.payload = payload;
this.checksum = checksum;
}
public void parsePayload(byte[] dataBytes) {
public abstract void parsePayload(byte[] dataBytes);
};
private static AbsEBikeMessage createMessageInstance(String command, String header, int length, int physicalId, int messageId, int checksum, byte[] dataBytes) {
switch (command) {
@@ -104,10 +97,13 @@ public abstract class AbsEBikeMessage {
}
}
public abstract byte[] getMessageBytes();
public byte[] getMessageBytes() {
return null;
};
public static void main(String[] args) {
String s = "44 4E 59 26 00 3B 37 AB 04 02 00 82 00 64 01 00 00 01 01 00 00 12 34 56 78 12 34 56 78 12 34 56 78 12 34 56 78 80 70 88 13 F8 08";
String s = "444e592700198bca00072482333000000030313000300000000000000000000000000000003000300030e104";
String msg82 = "44 4E 59 26 00 3B 37 AB 04 02 00 82 00 64 01 00 00 01 01 00 00 12 34 56 78 12 34 56 78 12 34 56 78 12 34 56 78 80 70 88 13 F8 08";
s = s.replace(" ", "");
byte[] messageBytes = BytesUtil.hexStringToByteArray(s);
// 读取包头
@@ -115,36 +111,36 @@ public abstract class AbsEBikeMessage {
String header = new String(headerBytes, StandardCharsets.UTF_8);
System.out.println("header: " + header);
byte[] header2 = header.getBytes();
System.out.println("反序列header: " + header2);
// byte[] header2 = header.getBytes();
// System.out.println("反序列header: " + header2);
// 读取长度
byte[] lengthBytes = Arrays.copyOfRange(messageBytes, 3, 5);
int length = BytesUtil.bytesToIntLittle(lengthBytes);
System.out.println("length: " + length);
byte[] length2 = BytesUtil.intToBytesLittle(length);
System.out.println("反序列length: " + length2);
// byte[] length2 = BytesUtil.intToBytesLittle(length);
// System.out.println("反序列length: " + length2);
// 读取物理ID
byte[] physicalIdBytes = Arrays.copyOfRange(messageBytes, 5, 9);
int physicalId = BytesUtil.bytesToIntLittle(physicalIdBytes);
System.out.println("physicalId: " + physicalId);
byte[] physicalId2 = BytesUtil.intToBytesLittle(physicalId, 4);
System.out.println("反序列physicalId: " + physicalId2);
// byte[] physicalId2 = BytesUtil.intToBytesLittle(physicalId, 4);
// System.out.println("反序列physicalId: " + physicalId2);
// 读取消息ID
byte[] messageIdBytes = Arrays.copyOfRange(messageBytes, 9, 11);
int messageId = BytesUtil.bytesToIntLittle(messageIdBytes);
System.out.println("messageId: " + messageId);
byte[] messageId2 = BytesUtil.intToBytesLittle(messageId);
System.out.println("反序列messageId: " + messageId2);
// byte[] messageId2 = BytesUtil.intToBytesLittle(messageId);
// System.out.println("反序列messageId: " + messageId2);
// 读取命令
byte commandByte = messageBytes[11];
String command = BytesUtil.bcd2StrLittle(new byte[]{commandByte});
System.out.println("command: " + command);
byte[] command2 = BytesUtil.str2Bcd(command);
System.out.println("反序列command: " + command2);
// byte[] command2 = BytesUtil.str2Bcd(command);
// System.out.println("反序列command: " + command2);
// 读取数据
byte[] dataBytes = Arrays.copyOfRange(messageBytes, 12, messageBytes.length - 2);
@@ -156,8 +152,8 @@ public abstract class AbsEBikeMessage {
int checksum = BytesUtil.bytesToIntLittle(checksumBytes);
System.out.println("checksum: " + checksum);
byte[] concat = Bytes.concat(header2, length2, physicalId2, messageId2, command2);
System.out.println("concat: " + BytesUtil.printHexBinary(concat));
// byte[] concat = Bytes.concat(header2, length2, physicalId2, messageId2, command2);
// System.out.println("concat: " + BytesUtil.printHexBinary(concat));
}
}

View File

@@ -1,5 +1,6 @@
package com.jsowell.pile.domain.ebike;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.pile.domain.ebike.deviceupload.*;
import lombok.extern.slf4j.Slf4j;
@@ -9,14 +10,14 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public enum EBikeCommandEnum {
// HEARTBEAT("01", "设备心跳包"),
HOST_GET_SERVER_TIME("12", "主机获取服务器时间", EBikeMessageCmd12.class),
REGISTRATION("20", "设备注册包", EBikeMessageCmd20.class),
DEVICE_GET_SERVER_TIME("22", "设备获取服务器时间", EBikeMessageCmd22.class),
HEARTBEAT_2("21", "设备心跳包", EBikeMessageCmd21.class),
CARD_OPERATION("02", "刷卡操作", EBikeMessageCmd02.class),
SETTLEMENT_UPLOAD("03", "结算消费信息上传", EBikeMessageCmd03.class),
CHARGE_PORT_CONFIRMATION("04", "充电端口订单确认", EBikeMessageCmd04.class),
POWER_HEARTBEAT("06", "端口充电时功率心跳包", EBikeMessageCmd06.class),
HOST_GET_SERVER_TIME(0x12, "主机获取服务器时间", EBikeMessageCmd12.class),
REGISTRATION(0x20, "设备注册包", EBikeMessageCmd20.class),
DEVICE_GET_SERVER_TIME(0x22, "设备获取服务器时间", EBikeMessageCmd22.class),
HEARTBEAT_2(0x21, "设备心跳包", EBikeMessageCmd21.class),
CARD_OPERATION(0x02, "刷卡操作", EBikeMessageCmd02.class),
SETTLEMENT_UPLOAD(0x03, "结算消费信息上传", EBikeMessageCmd03.class),
CHARGE_PORT_CONFIRMATION(0x04, "充电端口订单确认", EBikeMessageCmd04.class),
POWER_HEARTBEAT(0x06, "端口充电时功率心跳包", EBikeMessageCmd06.class),
// CHARGER_HEARTBEAT("41", "充电柜专有心跳包", EBikeMessageCmd41.class),
// ALARM_PUSH("42", "报警推送指令", EBikeMessageCmd20.class),
// CHARGE_COMPLETE("43", "充电完成通知,但不结算", EBikeMessageCmd20.class),
@@ -24,17 +25,17 @@ public enum EBikeCommandEnum {
;
EBikeCommandEnum(String code, String desc, Class<? extends AbsEBikeMessage> msgClass) {
EBikeCommandEnum(int code, String desc, Class<? extends AbsEBikeMessage> msgClass) {
this.code = code;
this.desc = desc;
this.msgClass = msgClass;
}
private final String code; // 帧类型code
private final int code; // 帧类型code
private final String desc; // 帧类型名称
private final Class<? extends AbsEBikeMessage> msgClass;
public String getCode() {
public int getCode() {
return code;
}
@@ -46,13 +47,17 @@ public enum EBikeCommandEnum {
return msgClass;
}
public static Class<? extends AbsEBikeMessage> getMsgClassByCode(String code) {
for (EBikeCommandEnum e : EBikeCommandEnum.values()) {
if (e.getCode().equals(code)) {
return e.getMsgClass();
}
}
return null;
public byte[] getBytes() {
return BytesUtil.intToBytesLittle(code, 1);
}
// public static Class<? extends AbsEBikeMessage> getMsgClassByCode(String code) {
// for (EBikeCommandEnum e : EBikeCommandEnum.values()) {
// if (e.getCode().equals(code)) {
// return e.getMsgClass();
// }
// }
// return null;
// }
}

View File

@@ -9,10 +9,6 @@ import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
*/
public class EBikeMessageCmd81 extends AbsEBikeMessage {
public EBikeMessageCmd81(String header, int length, int physicalId, int messageId, String command, Object payload, int checksum) {
super(header, length, physicalId, messageId, command, payload, checksum);
}
@Override
public void parsePayload(byte[] dataBytes) {

View File

@@ -4,42 +4,59 @@ import com.google.common.primitives.Bytes;
import com.jsowell.common.YouDianUtils;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
import lombok.Getter;
import lombok.Setter;
import lombok.*;
import java.util.Arrays;
/**
* 服务器开始、停止充电操作82指令
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EBikeMessageCmd82 extends AbsEBikeMessage {
private SpecificData specificData;
private SpecificData data;
public EBikeMessageCmd82(String header, int length, int physicalId, int messageId, String command, Object payload, int checksum, SpecificData specificData) {
super(header, length, physicalId, messageId, command, payload, checksum);
this.specificData = specificData;
}
// public EBikeMessageCmd82(String header, int length, int physicalId, int messageId, String command, Object payload, int checksum, SpecificData specificData) {
// super(header, length, physicalId, messageId, command, payload, checksum);
// this.specificData = specificData;
// }
// public EBikeMessageCmd82(SpecificData specificData) {
// super(header, length, physicalId, messageId, command, payload, checksum);
// this.specificData = specificData;
// }
@Override
public void parsePayload(byte[] dataBytes) {
this.specificData = new SpecificData(dataBytes);
this.data = new SpecificData(dataBytes);
}
public static void main(String[] args) {
int i = 0x82;
byte[] commandBytes = new byte[]{(byte) i};
System.out.println(BytesUtil.bcd2StrLittle(commandBytes));
int i2 = 82;
byte[] commandBytes2 = new byte[]{(byte) i2};
System.out.println(BytesUtil.bcd2StrLittle(commandBytes2));
}
@Override
public byte[] getMessageBytes() {
// 包头
byte[] headerBytes = BytesUtil.str2AscLittle(header);
// 长度
byte[] lengthBytes = BytesUtil.intToBytesLittle(length);
byte[] headerBytes = BytesUtil.stringToHexBytes(header, 3);
// 物理ID
byte[] physicalIdBytes = BytesUtil.intToBytesLittle(physicalId);
byte[] physicalIdBytes = BytesUtil.intToBytesLittle(physicalId, 4);
// 消息ID
byte[] messageIdBytes = BytesUtil.intToBytesLittle(messageId);
byte[] messageIdBytes = BytesUtil.intToBytesLittle(messageId, 2);
// 命令
byte[] commandBytes = BytesUtil.str2Bcd(command);
// byte[] commandBytes = BytesUtil.intToBytesLittle(Integer.parseInt(command), 1);
byte[] commandBytes = new byte[]{(byte) 0x82};
// 数据
byte[] payloadBytes = specificData.getBytes();
byte[] payloadBytes = data.getBytes();
// 长度 物理ID+消息ID+命令+数据(n) +校验(2)每包最多256字节
byte[] lengthBytes = BytesUtil.intToBytesLittle(9 + payloadBytes.length);
// 拼接
byte[] concat = Bytes.concat(headerBytes, lengthBytes, physicalIdBytes, messageIdBytes, commandBytes, payloadBytes);
// 校验和
@@ -47,12 +64,13 @@ public class EBikeMessageCmd82 extends AbsEBikeMessage {
return Bytes.concat(concat, checksumBytes);
}
public SpecificData getSpecificData() {
return specificData;
public SpecificData getData() {
return data;
}
@Getter
@Setter
@NoArgsConstructor
public static class SpecificData {
private String rateMode; // 费率模式 (1字节)
private String balanceOrValidity; // 余额/有效期 (4字节)
@@ -124,42 +142,43 @@ public class EBikeMessageCmd82 extends AbsEBikeMessage {
// 获取字节数组
public byte[] getBytes() {
// 费率模式
byte[] rateModeBytes = BytesUtil.str2Bcd(rateMode);
byte[] rateModeBytes = BytesUtil.stringToHexBytes(rateMode, 1);
// 余额/有效期
byte[] balanceOrValidityBytes = BytesUtil.str2Bcd(balanceOrValidity);
byte[] balanceOrValidityBytes = BytesUtil.stringToHexBytes(balanceOrValidity, 4);
// 端口号
byte[] portNumberBytes = BytesUtil.str2Bcd(portNumber);
byte[] portNumberBytes = BytesUtil.stringToHexBytes(portNumber, 1);
// 充电命令
byte[] chargeCommandBytes = BytesUtil.str2Bcd(chargeCommand);
byte[] chargeCommandBytes = BytesUtil.stringToHexBytes(chargeCommand, 1);
// 充电时长/电量
byte[] chargeDurationOrPowerBytes = BytesUtil.str2Bcd(chargeDurationOrPower);
byte[] chargeDurationOrPowerBytes = BytesUtil.stringToHexBytes(chargeDurationOrPower, 2);
// 订单编号
byte[] orderNumberBytes = BytesUtil.str2Bcd(orderNumber);
byte[] orderNumberBytes = BytesUtil.stringToHexBytes(orderNumber, 16);
// 最大充电时长
byte[] maxChargeDurationBytes = BytesUtil.str2Bcd(maxChargeDuration);
byte[] maxChargeDurationBytes = BytesUtil.stringToHexBytes(maxChargeDuration, 2);
// 过载功率
byte[] overloadPowerBytes = BytesUtil.str2Bcd(overloadPower);
byte[] overloadPowerBytes = BytesUtil.stringToHexBytes(overloadPower, 2);
// 二维码灯
byte[] qrCodeLightBytes = BytesUtil.str2Bcd(qrCodeLight);
byte[] qrCodeLightBytes = BytesUtil.stringToHexBytes(qrCodeLight, 1);
// 长充模式
byte[] longChargeModeBytes = BytesUtil.str2Bcd(longChargeMode);
// byte[] longChargeModeBytes = BytesUtil.stringToHexBytes(longChargeMode, 1);
// 额外浮充时间
byte[] extraFloatChargeTimeBytes = BytesUtil.str2Bcd(extraFloatChargeTime);
// byte[] extraFloatChargeTimeBytes = BytesUtil.stringToHexBytes(extraFloatChargeTime, 2);
// 是否跳过短路检测
byte[] skipShortCircuitDetectionBytes = BytesUtil.str2Bcd(skipShortCircuitDetection);
// byte[] skipShortCircuitDetectionBytes = BytesUtil.stringToHexBytes(skipShortCircuitDetection, 1);
// 不判断用户拔出
byte[] noUserPullOutCheckBytes = BytesUtil.str2Bcd(noUserPullOutCheck);
// byte[] noUserPullOutCheckBytes = BytesUtil.stringToHexBytes(noUserPullOutCheck, 1);
// 强制带充满自停
byte[] forceAutoStopWhenFullBytes = BytesUtil.str2Bcd(forceAutoStopWhenFull);
// byte[] forceAutoStopWhenFullBytes = BytesUtil.stringToHexBytes(forceAutoStopWhenFull, 1);
// 充满功率
byte[] fullChargePowerBytes = BytesUtil.str2Bcd(fullChargePower);
// byte[] fullChargePowerBytes = BytesUtil.stringToHexBytes(fullChargePower, 1);
// 最大充满功率最长判断时间
byte[] maxFullChargePowerCheckTimeBytes = BytesUtil.str2Bcd(maxFullChargePowerCheckTime);
// byte[] maxFullChargePowerCheckTimeBytes = BytesUtil.stringToHexBytes(maxFullChargePowerCheckTime, 1);
return Bytes.concat(rateModeBytes, balanceOrValidityBytes, portNumberBytes, chargeCommandBytes,
chargeDurationOrPowerBytes, orderNumberBytes, maxChargeDurationBytes, overloadPowerBytes,
qrCodeLightBytes, longChargeModeBytes, extraFloatChargeTimeBytes, skipShortCircuitDetectionBytes,
noUserPullOutCheckBytes, forceAutoStopWhenFullBytes, fullChargePowerBytes,
maxFullChargePowerCheckTimeBytes);
chargeDurationOrPowerBytes, orderNumberBytes, maxChargeDurationBytes, overloadPowerBytes, qrCodeLightBytes
// ,longChargeModeBytes, extraFloatChargeTimeBytes, skipShortCircuitDetectionBytes,
// noUserPullOutCheckBytes, forceAutoStopWhenFullBytes, fullChargePowerBytes,
// maxFullChargePowerCheckTimeBytes
);
}
}
}

View File

@@ -1,10 +1,10 @@
package com.jsowell.pile.service;
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
/**
* 电单车发送命令服务
*/
public interface EBikeSendCommandService {
void send(String pileSn, AbsEBikeMessage msg);
// void send(String pileSn, AbsEBikeMessage msg);
void startCharging(String pileSn);
}

View File

@@ -2,7 +2,9 @@ package com.jsowell.pile.service.impl;
import com.jsowell.common.enums.ykc.PileChannelEntity;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.common.util.RandomUtil;
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
import com.jsowell.pile.domain.ebike.serversend.EBikeMessageCmd82;
import com.jsowell.pile.service.EBikeSendCommandService;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
@@ -14,21 +16,49 @@ import java.util.Objects;
@Service
public class EBikeSendCommandServiceImpl implements EBikeSendCommandService {
@Override
public void send(String pileSn, AbsEBikeMessage msg) {
public void startCharging(String pileSn) {
EBikeMessageCmd82 message = new EBikeMessageCmd82();
message.setHeader("DNY");
message.setPhysicalId(Integer.parseInt(pileSn));
message.setMessageId(RandomUtil.getRandomNumber(4));
message.setCommand("82");
EBikeMessageCmd82.SpecificData data = new EBikeMessageCmd82.SpecificData();
data.setRateMode("3");
data.setBalanceOrValidity("0");
data.setPortNumber("0");
data.setChargeCommand("1");
data.setChargeDurationOrPower("0");
data.setOrderNumber("0");
data.setMaxChargeDuration("0");
data.setOverloadPower("0");
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 msg
*/
private void send(AbsEBikeMessage msg) {
String pileSn = msg.getPhysicalId() + "";
byte[] messageBytes = msg.getMessageBytes();
PileChannelEntity.output();
log.info("发送电单车命令, pileSn:{}, messageBytes:{}", pileSn, BytesUtil.binary(messageBytes, 16));
// 获取桩的channel
ChannelHandlerContext ctx = PileChannelEntity.getChannelByPileSn(pileSn);
if (Objects.isNull(ctx)) {
log.error("电单车send命令失败, 桩号:{}无法获取到长连接, 请检查充电桩连接状态!", pileSn);
throw new NullPointerException("channel");
}
if (Objects.isNull(msg)) {
log.error("电单车send命令失败, msg为空!");
throw new NullPointerException("msg");
}
String str = "44 4E 59 26 00 3B 37 AB 04 02 00 82 00 64 01 00 00 01 01 00 00 12 34 56 78 12 34 56 78 12 34 56 78 12 34 56 78 80 70 88 13 F8 08";
byte[] messageBytes = BytesUtil.hexStringToByteArray(str);
ctx.writeAndFlush(messageBytes);
// ctx.writeAndFlush(messageBytes);
}
}