|
@@ -0,0 +1,248 @@
|
|
|
|
+package com.zhili.stationcontrol.chargeserver.handler;
|
|
|
|
+
|
|
|
|
+import com.zhili.stationcontrol.chargeserver.dto.ChargeMessage;
|
|
|
|
+import com.zhili.stationcontrol.chargeserver.util.ChargeCenter;
|
|
|
|
+import com.zhili.stationcontrol.util.BytesUtil;
|
|
|
|
+import io.netty.channel.ChannelHandlerContext;
|
|
|
|
+import io.netty.channel.ChannelInboundHandlerAdapter;
|
|
|
|
+import io.netty.util.AttributeKey;
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.apache.commons.lang.ArrayUtils;
|
|
|
|
+
|
|
|
|
+import java.util.Random;
|
|
|
|
+
|
|
|
|
+import static com.zhili.stationcontrol.chargeserver.dto.ChargeMessage.CommandType;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @author :HuangBin
|
|
|
|
+ * @description:TODO
|
|
|
|
+ * @date :2022/10/24 11:02
|
|
|
|
+ */
|
|
|
|
+@Slf4j
|
|
|
|
+public class ChargeMessageHandler extends ChannelInboundHandlerAdapter {
|
|
|
|
+ static Random r = new Random();
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
|
|
|
+ log.info("channel connected: ", ctx.channel().remoteAddress());
|
|
|
|
+ ChargeCenter.add(ctx.channel());
|
|
|
|
+ super.channelActive(ctx);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
|
|
|
+ if (msg instanceof ChargeMessage) {
|
|
|
|
+ ChargeMessage chrgMsg = (ChargeMessage) msg;
|
|
|
|
+ log.info("receive: " + chrgMsg);
|
|
|
|
+ ctx.writeAndFlush(chrgMsg);
|
|
|
|
+ byte[] data;
|
|
|
|
+ byte[] deviceNoBytes;
|
|
|
|
+ String deviceNo;
|
|
|
|
+ byte[] replyData;
|
|
|
|
+ byte[] gunNoBytes;
|
|
|
|
+ int gunNo;
|
|
|
|
+ byte[] startTimeBytes;
|
|
|
|
+ byte[] endTimeBytes;
|
|
|
|
+ byte[] secBytes;
|
|
|
|
+ byte[] startSocBytes;
|
|
|
|
+ byte[] endSocBytes;
|
|
|
|
+ byte[] chargeIdBytes;
|
|
|
|
+ String startTime;
|
|
|
|
+ String endTime;
|
|
|
|
+ int sec;
|
|
|
|
+ //流水号
|
|
|
|
+ String chgId;
|
|
|
|
+ int startSoc;
|
|
|
|
+ int endSoc;
|
|
|
|
+ switch (chrgMsg.getCommand()) {
|
|
|
|
+ case CommandType.SIGNIN_REPORT:
|
|
|
|
+ //签到信息,写入signin
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ byte version = chrgMsg.getVersion();
|
|
|
|
+ log.info("version:" + version);
|
|
|
|
+ deviceNoBytes = ArrayUtils.subarray(data, 4, 36);
|
|
|
|
+ deviceNo = BytesUtil.parseString(deviceNoBytes);
|
|
|
|
+ log.info("parse deviceNo: " + deviceNo);
|
|
|
|
+ ChargeCenter.mark(ctx.channel(), "signIn", deviceNo);
|
|
|
|
+ ChargeMessage signInReplyMessage = new ChargeMessage();
|
|
|
|
+ signInReplyMessage.setVersion(chrgMsg.getVersion());
|
|
|
|
+ signInReplyMessage.setSerialNo(chrgMsg.getSerialNo());
|
|
|
|
+ signInReplyMessage.setCommand(CommandType.SIGNIN_REPLY);
|
|
|
|
+ replyData = new byte[151];
|
|
|
|
+ int ri = randInt();
|
|
|
|
+ byte[] ribs = BytesUtil.fromIntWithLowerFirst(ri, 4);
|
|
|
|
+ BytesUtil.setSubBytes(replyData, 4, ribs);
|
|
|
|
+// 不启用cmd1202
|
|
|
|
+ BytesUtil.setSubBytes(replyData, 8, BytesUtil.fromIntWithLowerFirst(0, 1));
|
|
|
|
+// 启用不加密验证
|
|
|
|
+ BytesUtil.setSubBytes(replyData, 9, BytesUtil.fromIntWithLowerFirst(0, 1));
|
|
|
|
+ BytesUtil.setSubBytes(replyData, 143, BytesUtil.composeNowTimeBytes());
|
|
|
|
+ signInReplyMessage.setData(replyData);
|
|
|
|
+ ctx.writeAndFlush(signInReplyMessage);
|
|
|
|
+ log.info("signIn replyed: " + signInReplyMessage);
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.HEARTBEAT_REPORT:
|
|
|
|
+// //心跳信息,如果和签到信息一致,写入heartBeatNo
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ deviceNoBytes = ArrayUtils.subarray(data, 4, 36);
|
|
|
|
+ deviceNo = BytesUtil.parseString(deviceNoBytes);
|
|
|
|
+ byte[] heatBeatNo = ArrayUtils.subarray(data, 36, 38);
|
|
|
|
+ Object signIn = ctx.channel().attr(AttributeKey.valueOf("signIn")).get();
|
|
|
|
+ if (signIn == null) {
|
|
|
|
+ log.info("not sigin:" + deviceNo);
|
|
|
|
+ ctx.channel().close();
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (!signIn.equals(deviceNo)) {
|
|
|
|
+ log.info("heartbeat not match signin");
|
|
|
|
+ ctx.channel().close();
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ byte[] stateBytes = ArrayUtils.subarray(data, 38, 54);
|
|
|
|
+ int state = BytesUtil.toIntWithLowerFirst(stateBytes);
|
|
|
|
+ log.info("各个枪状态:" + state);
|
|
|
|
+ ChargeMessage heartBeatReplyMessage = new ChargeMessage();
|
|
|
|
+ heartBeatReplyMessage.setVersion(chrgMsg.getVersion());
|
|
|
|
+ heartBeatReplyMessage.setSerialNo(chrgMsg.getSerialNo());
|
|
|
|
+ heartBeatReplyMessage.setCommand(CommandType.HEARTBEAT_REPLY);
|
|
|
|
+ replyData = new byte[6];
|
|
|
|
+ BytesUtil.setSubBytes(replyData, 4, heatBeatNo);
|
|
|
|
+ heartBeatReplyMessage.setData(replyData);
|
|
|
|
+ ctx.writeAndFlush(heartBeatReplyMessage);
|
|
|
|
+ log.info("heartbeat replyed: " + heartBeatReplyMessage);
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.STATE_REPORT:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ byte[] cntBytes = ArrayUtils.subarray(data, 36, 37);
|
|
|
|
+ int cnt = BytesUtil.toIntWithLowerFirst(cntBytes);
|
|
|
|
+ gunNoBytes = ArrayUtils.subarray(data, 37, 38);
|
|
|
|
+ gunNo = BytesUtil.toIntWithLowerFirst(gunNoBytes);
|
|
|
|
+ log.info("状态上报: 充电枪数量(" + cnt + "), 充电口号:(" + gunNo + ")");
|
|
|
|
+ ChargeMessage stateReplyMessage = new ChargeMessage();
|
|
|
|
+ stateReplyMessage.setVersion(chrgMsg.getVersion());
|
|
|
|
+ stateReplyMessage.setSerialNo(chrgMsg.getSerialNo());
|
|
|
|
+ stateReplyMessage.setCommand(CommandType.STATE_REPLY);
|
|
|
|
+ replyData = new byte[6];
|
|
|
|
+ BytesUtil.setSubBytes(replyData, 4, gunNoBytes);
|
|
|
|
+ replyData[5] = 0;
|
|
|
|
+ stateReplyMessage.setData(replyData);
|
|
|
|
+ ctx.writeAndFlush(stateReplyMessage);
|
|
|
|
+ log.info("report replyed:" + stateReplyMessage);
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.RECORD_REPORT:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ gunNoBytes = ArrayUtils.subarray(data, 37, 38);
|
|
|
|
+ gunNo = BytesUtil.toIntWithLowerFirst(gunNoBytes);
|
|
|
|
+ startTimeBytes = ArrayUtils.subarray(data, 70, 78);
|
|
|
|
+ endTimeBytes = ArrayUtils.subarray(data, 78, 86);
|
|
|
|
+ secBytes = ArrayUtils.subarray(data, 86, 90);
|
|
|
|
+ startSocBytes = ArrayUtils.subarray(data, 90, 91);
|
|
|
|
+ endSocBytes = ArrayUtils.subarray(data, 91, 92);
|
|
|
|
+ chargeIdBytes = ArrayUtils.subarray(data, 256, 288);
|
|
|
|
+ startTime = BytesUtil.composeTimeString(startTimeBytes);
|
|
|
|
+ endTime = BytesUtil.composeTimeString(endTimeBytes);
|
|
|
|
+ sec = BytesUtil.toIntWithLowerFirst(secBytes);
|
|
|
|
+ chgId = BytesUtil.parseString(chargeIdBytes);
|
|
|
|
+ startSoc = BytesUtil.toIntWithLowerFirst(startSocBytes);
|
|
|
|
+ endSoc = BytesUtil.toIntWithLowerFirst(endSocBytes);
|
|
|
|
+ int power = BytesUtil.toIntWithLowerFirst(ArrayUtils.subarray(data, 96, 100));
|
|
|
|
+ int fee = BytesUtil.toIntWithLowerFirst(ArrayUtils.subarray(data, 108, 112));
|
|
|
|
+ log.info("充电记录上报(" + chgId + "): 充电口号:(" + gunNo + ")" + " " + startTime + "(" + startSoc + ") -> " + endTime + "(" + endSoc + ") (" + sec + " secs)");
|
|
|
|
+ //电量和单位都是0.01
|
|
|
|
+ log.info("power:" + power + " fee:" + fee);
|
|
|
|
+ ChargeMessage recordReplyMessage = new ChargeMessage();
|
|
|
|
+ recordReplyMessage.setVersion(chrgMsg.getVersion());
|
|
|
|
+ recordReplyMessage.setSerialNo(chrgMsg.getSerialNo());
|
|
|
|
+ recordReplyMessage.setCommand(CommandType.RECORD_REPLY);
|
|
|
|
+ replyData = new byte[66];
|
|
|
|
+ BytesUtil.setSubBytes(replyData, 4, gunNoBytes);
|
|
|
|
+ byte[] innerIndex = ArrayUtils.subarray(data, 112, 116);
|
|
|
|
+ BytesUtil.setSubBytes(replyData, 37, innerIndex);
|
|
|
|
+ replyData[41] = 0x01;
|
|
|
|
+ recordReplyMessage.setData(replyData);
|
|
|
|
+// ctx.writeAndFlush(recordReplyMessage);
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.ALARM_REPORT:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ byte[] alarmBytes = ArrayUtils.subarray(data, 36, 68);
|
|
|
|
+ int alarms = BytesUtil.toIntWithLowerFirst(alarmBytes);
|
|
|
|
+ log.info("收到告警:" + Integer.toBinaryString(alarms));
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.CHARGE_REPLY:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ gunNo = Byte.toUnsignedInt(data[36]);
|
|
|
|
+ byte[] chgResBytes = ArrayUtils.subarray(data, 37, 41);
|
|
|
|
+ int chgRes = BytesUtil.toIntWithLowerFirst(chgResBytes);
|
|
|
|
+ log.info("---收到" + gunNo + "号枪充电启动应答(" + (chgRes == 0 ? "成功" : "失败") + "):" + chgRes);
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.CONTROL_REPLY:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ gunNo = Byte.toUnsignedInt(data[36]);
|
|
|
|
+ int addressSign = BytesUtil.toIntWithLowerFirst(ArrayUtils.subarray(data, 37, 41));
|
|
|
|
+ if (addressSign == 2) {
|
|
|
|
+ //停止充电命令
|
|
|
|
+ int stopRes = Byte.toUnsignedInt(data[42]);
|
|
|
|
+ log.info("---收到" + gunNo + "号枪停止充电应答(" + (stopRes == 0 ? "成功" : "失败") + "):" + stopRes);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.QUERY_CHARGE_REPLY:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ gunNo = Byte.toUnsignedInt(data[37]);
|
|
|
|
+ startTimeBytes = ArrayUtils.subarray(data, 70, 78);
|
|
|
|
+ startTime = BytesUtil.composeTimeString(startTimeBytes);
|
|
|
|
+ endTimeBytes = ArrayUtils.subarray(data, 78, 86);
|
|
|
|
+ endTime = BytesUtil.composeTimeString(endTimeBytes);
|
|
|
|
+ secBytes = ArrayUtils.subarray(data, 86, 90);
|
|
|
|
+ sec = BytesUtil.toIntWithLowerFirst(secBytes);
|
|
|
|
+ startSocBytes = ArrayUtils.subarray(data, 90, 91);
|
|
|
|
+ startSoc = BytesUtil.toIntWithLowerFirst(startSocBytes);
|
|
|
|
+ endSocBytes = ArrayUtils.subarray(data, 91, 92);
|
|
|
|
+ endSoc = BytesUtil.toIntWithLowerFirst(endSocBytes);
|
|
|
|
+ chargeIdBytes = ArrayUtils.subarray(data, 256, 288);
|
|
|
|
+ chgId = BytesUtil.parseString(chargeIdBytes);
|
|
|
|
+ log.info("记录查询回复上报(" + chgId + "): 充电口号:(" + gunNo + ")" + " " + startTime + "(" + startSoc + ") -> " + endTime + "(" + endSoc + ") (" + sec + " secs)");
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.SET_RATE_REPLY:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ int res = Byte.toUnsignedInt(data[0]);
|
|
|
|
+ log.info("--费率设置" + (res == 0 ? "成功" : "失败"));
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.CHARGE_START_REPORT:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ int chrgRes = BytesUtil.toIntWithLowerFirst(ArrayUtils.subarray(data, 37, 41));
|
|
|
|
+ chargeIdBytes = ArrayUtils.subarray(data, data.length - 32, data.length);
|
|
|
|
+ chgId = BytesUtil.parseString(chargeIdBytes);
|
|
|
|
+ log.info("充电命令(chargeId = " + chgId + ")启动" + (chrgRes == 0 ? "成功" : "失败"));
|
|
|
|
+ ChargeMessage startReplyMsg = new ChargeMessage();
|
|
|
|
+ startReplyMsg.setVersion(chrgMsg.getVersion());
|
|
|
|
+ startReplyMsg.setSerialNo(chrgMsg.getSerialNo());
|
|
|
|
+ startReplyMsg.setCommand(CommandType.CHARGE_START_REPLY);
|
|
|
|
+ startReplyMsg.setData(new byte[4]);
|
|
|
|
+ ctx.writeAndFlush(startReplyMsg);
|
|
|
|
+ break;
|
|
|
|
+ case CommandType.BMS_REPORT:
|
|
|
|
+ data = chrgMsg.getData();
|
|
|
|
+ gunNoBytes = ArrayUtils.subarray(data, 6, 8);
|
|
|
|
+ gunNo = BytesUtil.toIntWithLowerFirst(gunNoBytes);
|
|
|
|
+ byte[] workStateBytes = ArrayUtils.subarray(data, 40, 41);
|
|
|
|
+ int workState = BytesUtil.toIntWithLowerFirst(workStateBytes);
|
|
|
|
+ byte[] vConnStateBytes = ArrayUtils.subarray(data, 41, 42);
|
|
|
|
+ int vConnState = BytesUtil.toIntWithLowerFirst(vConnStateBytes);
|
|
|
|
+ log.info("BMS上报信息(枪号:" + gunNo + "):工作状态(" + workState + "), 车连接状态:(" + vConnState + ")");
|
|
|
|
+ ChargeMessage bmsReplyMsg = new ChargeMessage();
|
|
|
|
+ bmsReplyMsg.setVersion(chrgMsg.getVersion());
|
|
|
|
+ bmsReplyMsg.setSerialNo(chrgMsg.getSerialNo());
|
|
|
|
+ bmsReplyMsg.setCommand(CommandType.BMS_REPLY);
|
|
|
|
+ bmsReplyMsg.setData(new byte[4]);
|
|
|
|
+ ctx.writeAndFlush(bmsReplyMsg);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static int randInt() {
|
|
|
|
+ return r.nextInt();
|
|
|
|
+ }
|
|
|
|
+}
|