update 电单车协议

This commit is contained in:
Guoqs
2024-08-19 14:37:16 +08:00
parent d4dbaba14f
commit fd56072a84
5 changed files with 257 additions and 4 deletions

View File

@@ -1,10 +1,7 @@
package com.jsowell.netty.domain.ebike;
import com.jsowell.common.util.BytesUtil;
import com.jsowell.netty.domain.ebike.deviceupload.DeviceRegister;
import com.jsowell.netty.domain.ebike.deviceupload.EBikeMessageCmd03;
import com.jsowell.netty.domain.ebike.deviceupload.EBikeMessageCmd20;
import com.jsowell.netty.domain.ebike.deviceupload.SettlementInfo;
import com.jsowell.netty.domain.ebike.deviceupload.*;
import com.jsowell.netty.domain.ebike.serversend.EBikeMessageCmd82;
import com.jsowell.netty.domain.ebike.serversend.SpecificDataCmd82;
import lombok.Getter;
@@ -44,6 +41,8 @@ public abstract class AbsEBikeMessage {
return new EBikeMessageCmd03(header, length, physicalId, messageId, command, null, checksum, new SettlementInfo(dataBytes));
case "20":
return new EBikeMessageCmd20(header, length, physicalId, messageId, command, null, checksum, new DeviceRegister(dataBytes));
case "06":
return new EBikeMessageCmd06(header, length, physicalId, messageId, command, null, checksum, new PowerHeartbeat(dataBytes));
default:
throw new IllegalArgumentException("Unsupported command: " + command);
}

View File

@@ -0,0 +1,42 @@
package com.jsowell.netty.domain.ebike.deviceupload;
import com.jsowell.common.util.BytesUtil;
import lombok.Data;
import java.util.Arrays;
@Data
public class ConfirmOrder {
/**
* 端口号
*/
private String portNumber;
/**
* 在线/离线启动
*/
private String startMode;
/**
* 卡片ID
*/
private String cardId;
/**
* 充电时长
*/
private String chargingTime;
/**
* 订单编号
*/
private String orderCode;
public ConfirmOrder(byte[] dataBytes) {
this.portNumber = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 0, 1)) + "";
this.startMode = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 1, 2)) + "";
this.cardId = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 2, 6)) + "";
this.chargingTime = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 6, 8)) + "";
this.orderCode = BytesUtil.bcd2StrLittle(Arrays.copyOfRange(dataBytes, 8, 24));
}
}

View File

@@ -0,0 +1,26 @@
package com.jsowell.netty.domain.ebike.deviceupload;
import com.jsowell.netty.domain.ebike.AbsEBikeMessage;
/**
* 充电端口订单确认04指令
* 这是老版本指令和06相对应有06指令时无此命令2019年6月份后生产的机型已无此指令
*/
public class EBikeMessageCmd04 extends AbsEBikeMessage {
private ConfirmOrder confirmOrder;
public EBikeMessageCmd04(String header, int length, int physicalId, int messageId, String command, Object payload, int checksum, ConfirmOrder confirmOrder) {
super(header, length, physicalId, messageId, command, payload, checksum);
this.confirmOrder = confirmOrder;
}
@Override
public void parsePayload(byte[] dataBytes) {
this.confirmOrder = new ConfirmOrder(dataBytes);
}
public ConfirmOrder getSettlementInfo() {
return confirmOrder;
}
}

View File

@@ -0,0 +1,27 @@
package com.jsowell.netty.domain.ebike.deviceupload;
import com.jsowell.netty.domain.ebike.AbsEBikeMessage;
/**
* 端口充电时功率心跳包06指令
* 这是新版本指令和04相对应有04指令时无此命令
* 此命令设备开始充电后82命令应答后每隔设5分钟发送1次无重发机制 充电结束后即停止发送
*/
public class EBikeMessageCmd06 extends AbsEBikeMessage {
private PowerHeartbeat powerHeartbeat;
public EBikeMessageCmd06(String header, int length, int physicalId, int messageId, String command, Object payload, int checksum, PowerHeartbeat powerHeartbeat) {
super(header, length, physicalId, messageId, command, payload, checksum);
this.powerHeartbeat = powerHeartbeat;
}
@Override
public void parsePayload(byte[] dataBytes) {
this.powerHeartbeat = new PowerHeartbeat(dataBytes);
}
public PowerHeartbeat getPowerHeartbeat() {
return powerHeartbeat;
}
}

View File

@@ -0,0 +1,159 @@
package com.jsowell.netty.domain.ebike.deviceupload;
import com.jsowell.common.util.BytesUtil;
import lombok.Getter;
import lombok.Setter;
import java.util.Arrays;
/**
* 功率心跳包
*/
@Getter
@Setter
public class PowerHeartbeat {
/**
* 端口号当前充电的端口号。注00表示1号端口01表示2号端口
*/
private String port;
/**
* 各端口状态: 1=充电中, 2=已扫码暂未检测到功率等待插入充电器充电柜专有如单车桩出现此值为出错值请忽略3=有充电器但未充电已充满电5=浮充,其他值=出错值请忽略
*/
private String portStatus;
/**
* 充电时长:开始充电到当前为止,已经充电多长时间
*/
private String chargingTime;
/**
* 当前订单累计电量:当前端口的订单,开始充电到当前为止,已经消耗的电量
*/
private String totalUsedElectricity;
/**
* 在线/离线启动:=0表示启动时处于离线状态 =1表示启动时处于在线状态 3=验证码启动(仅支持带按键和屏幕的机型)
*/
private String startMode;
/**
* 实时功率:心跳包发送时的当前功率
*/
private String realTimePower;
/**
* 心跳包期间最大功率:心跳包期间出现过的最大功率
*/
private String maxPower;
/**
* 心跳包期间最小功率:心跳包期间出现过的最小功率
*/
private String minPower;
/**
* 心跳包期间平均功率:心跳包期间出现过的平均功率
*/
private String avgPower;
/**
* 订单编号:当前充电的订单编号
*/
private String orderCode;
/**
* 该时间段内消耗电量此数据需除以4800后才是真实的电量该字段属于调试使用服务器无需关心此字段
*/
private String timePeriodElectricity;
/**
* 峰值功率:整个充电过程中出现过的最大功率,有些版本无此字段
*/
private String peakPower;
/**
* 设备的当前电压
*/
private String voltage;
/**
* 设备的当前电流,可以计量芯片采集也可以通过计算得出,0.001A为单位1000表示1A电流
*/
private String current;
/**
* 设备的当前环境温度,仅针对有此功能的机型
*/
private String ambientTemperature;
/**
* 端口温度,仅针对有此功能的机型
*/
private String portTemperature;
/**
* 上发指令当时的时间,有时候不准确,该字段属于调试使用,服务器无需关心此字段
*/
private String timestamp;
/**
* 占位时长:(充电柜专用,其他设备忽略此字段)表示充满后占用设备的时长,单位为分钟
*/
private String occupancyTime;
public PowerHeartbeat(byte[] dataBytes) {
int startIndex = 0;
int length = 1;
this.port = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 1;
this.portStatus = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.chargingTime = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.totalUsedElectricity = BytesUtil.bcd2StrLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length));
length = 1;
this.startMode = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.realTimePower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.maxPower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.minPower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.avgPower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 16;
this.orderCode = BytesUtil.bcd2StrLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length));
length = 2;
this.peakPower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.voltage = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.current = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 1;
this.ambientTemperature = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 1;
this.portTemperature = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 4;
this.timestamp = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
length = 2;
this.occupancyTime = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, startIndex, startIndex = startIndex + length)) + "";
}
}