mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-04-20 02:55:04 +08:00
update 电单车协议
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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位数随机数
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user