package com.tmzn.devicelinkykc.message; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.tmzn.devicelinkykc.constant.Constant; import com.tmzn.devicelinkykc.constant.DeviceOnlineStatus; import com.tmzn.devicelinkykc.constant.PortStatusConstant; import com.tmzn.devicelinkykc.constant.RedisConstant; import com.tmzn.devicelinkykc.constant.ykc.StatusConstant; import com.tmzn.devicelinkykc.constant.ykc.TransConstant; import com.tmzn.devicelinkykc.entity.*; import com.tmzn.devicelinkykc.frameMsg.DataConversion; import com.tmzn.devicelinkykc.frameMsg.FrameDataSplicing; import com.tmzn.devicelinkykc.frameMsg.TransMoney; import com.tmzn.devicelinkykc.frameMsg.frameType.CharngingPushFrame; import com.tmzn.devicelinkykc.frameMsg.frameType.LoginFrame; import com.tmzn.devicelinkykc.frameMsg.frameType.RealTimeStatusPushFrame; import com.tmzn.devicelinkykc.frameMsg.frameType.TransactionFlowPushFrame; import com.tmzn.devicelinkykc.openfeign.transdata.RpcResult; import com.tmzn.devicelinkykc.redis.RedisCache; import com.tmzn.devicelinkykc.service.*; import com.tmzn.devicelinkykc.socket.DeviceConnectionMsg; import com.tmzn.devicelinkykc.socket.SocketHandle; import com.tmzn.devicelinkykc.transdata.constant.NormalChargeConstant; import com.tmzn.devicelinkykc.transdata.entity.DeviceParam; import org.apache.logging.log4j.util.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.TimeUnit; /** * @author xp * @date 2024/3/13 * @explain " 设备消息处理 " * //TODO:考虑设备上来的消息只走数据库查询不走redis订阅数据 */ @Component public class DeviceMsgHandle { @Autowired private DeviceStatusService deviceStatusService; @Autowired private SocketHandle socketHandle; @Autowired private RedisCache redisCache; @Autowired private RealTimeStatusPushFrame realTimeStatusPushFrame; @Autowired private TransactionFlowPushFrame transactionFlowPushFrame; @Autowired private LoginFrame loginFrame; @Autowired private CharngingPushFrame charngingPushFrame; @Autowired private DeviceService deviceService; @Autowired private OrderStatusService orderStatusService; @Autowired private DeviceControlerService deviceControlerService; @Autowired private BillingModelService billingModelService; @Autowired private TransMoney transMoney; private static final Logger logger = LoggerFactory.getLogger(DeviceMsgHandle.class); private Long lastLogTime; private static final Long gap = 1000 * 30L; private static final BigDecimal zero = new BigDecimal("0"); public void deviceMsg(String msg) throws Exception { //必须过滤调非云快充设备 //logger.info("redis中msg>>>" + msg); msg = msg.substring(1, msg.length() - 1); msg = msg.replace("\\", ""); // checkActive(msg); JSONObject jsonObject = null; try { jsonObject = JSONObject.parseObject(msg); } catch (Exception e) { //这里正常格式才走,不正常的格式不打印报错了;可能有其他格式的数据过来;正常要解析的数据是能走到JSON中的 logger.info("device msg conversion exception not processed!!!" + msg); return; //e.printStackTrace(); } String imei = jsonObject.getString("imei"); if (Strings.isEmpty(imei)) { return; } String pileCode = ""; try { pileCode = redisCache.getCacheMapValue(RedisConstant.DEVICE_IMEI_PILE_MAP, imei); if (Strings.isEmpty(pileCode)) { return; } } catch (Exception e) { return; } logger.info("{},msg>>>" + msg, imei); //设备状态更新,true:没有type不是设备上送类型不往云快充处理 false:需要根据设备消息类型往下处理是不是需要上报云快充 try { handleDeviceMsg(jsonObject, pileCode); } catch (Exception e) { logger.error("处理消息失败{},{}", imei, e.getMessage()); e.printStackTrace(); } } public void testMsg(String msg) throws Exception { logger.info("testmsg>>>" + msg); JSONObject jsonObject = null; jsonObject = JSONObject.parseObject(msg); String imei = jsonObject.getString("imei"); try { String pileCode = redisCache.getCacheMapValue(RedisConstant.DEVICE_IMEI_PILE_MAP, imei); if (Strings.isEmpty(pileCode)) { logger.info("非云快充设备"); return; } handleDeviceMsg(jsonObject, pileCode); } catch (Exception e) { return; } //设备状态更新,true:没有type不是设备上送类型不往云快充处理 false:需要根据设备消息类型往下处理是不是需要上报云快充 } private void checkActive(String s) { Long now = System.currentTimeMillis(); if (lastLogTime == null) { lastLogTime = now; } Long gap = now - lastLogTime; if (gap > gap) { //logger.info("message:,{}", s); lastLogTime = now; } } //处理离线消息 //查找所有端口状态置为下线 并推送状态给云快充 private void handleOffline(String imei) { QueryWrapper deviceStatusQueryWrapper = new QueryWrapper<>(); deviceStatusQueryWrapper.eq("device_imei", imei); List list = deviceStatusService.list(deviceStatusQueryWrapper); if (!list.isEmpty()) { for (DeviceStatus deviceStatus : list) { //deviceStatus.setInsertGunStatus(StatusConstant.INSERT_GUNS_NO); //deviceStatus.setGunStatus(StatusConstant.OFFLINE); deviceStatus.setOnlineStatus(DeviceOnlineStatus.OFFLINE); deviceStatus.setUpdateTime(System.currentTimeMillis()); deviceStatusService.updateById(deviceStatus); if (socketHandle.existDeviceConnection(deviceStatus.getPileCode())) { String pilecode = deviceStatus.getPileCode(); DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(pilecode); byte[] transactionNum = new byte[16]; //FrameDataSplicing.transactionNum(pilecode, deviceConnection.getMessageCount()); if (deviceStatus.getGunStatus() == PortStatusConstant.EMERGENCY_STOP) { deviceStatus.setGunStatus(StatusConstant.FREE); } realTimeStatusPushFrame.deviceStatusPush(deviceConnection, transactionNum, pilecode, (byte) deviceStatus.getGunPort(), deviceStatus.getGunStatus(), deviceStatus.getInsertGunStatus(), 0, 0, zero, zero, 0); socketHandle.removeDeviceConnection(deviceStatus.getPileCode()); redisCache.deleteObject(RedisConstant.DEVICE_PORT_STATUS + imei); } } } } private void checkNoPowerAutoStop(int power, String imei, int portId) { try { String hkey = imei + "_" + portId; Integer lastPower0Times = 0; if (power > 0) { } else { lastPower0Times = redisCache.getCacheMapValue(RedisConstant.POWER_ZERO_TIMES, hkey); if (lastPower0Times == null) { lastPower0Times = 0; } lastPower0Times = lastPower0Times + 1; } redisCache.setCacheMapValue(RedisConstant.POWER_ZERO_TIMES, hkey, lastPower0Times); if (lastPower0Times < 5) { return; } //查找订单开始时间 如果开始时间过过2分钟 且连续power为0 就需要停止充电 QueryWrapper orderStatusQueryWrapper = new QueryWrapper<>(); orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", portId).orderByDesc("create_time").last("limit 1"); OrderStatus one = orderStatusService.getOne(orderStatusQueryWrapper); if (one.getNowOrderStatus() != StatusConstant.NOW_ORDER_STATUS_CHARGING) { return; } if ((System.currentTimeMillis() - one.getCreateTime()) < 120 * 1000) { return; } //连续3次功率0 就要停止充电 RpcResult rpcResult = deviceControlerService.stopCharge(imei, imei, (int) portId); logger.info("{}-{}触发无功率自停{}", imei, portId, lastPower0Times); } catch (Exception e) { logger.error("无功率检测异常{}", e.getMessage()); e.printStackTrace(); } } public boolean checkConnection(String pileCode, String imei) throws IOException { boolean needLogin = false; if (!socketHandle.existDeviceConnection(pileCode)) { needLogin = true; } else { DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(pileCode); if (!deviceConnection.getSocket().isConnected()) { socketHandle.removeDeviceConnection(pileCode); needLogin = true; } } if (!needLogin) { return true; } logger.info("桩上线{}", imei); QueryWrapper deviceQueryWrapper = new QueryWrapper<>(); deviceQueryWrapper.eq("pile_code", pileCode).eq("disabled", DeviceOnlineStatus.NORMAL); Device device = deviceService.getOne(deviceQueryWrapper); if (device == null) { logger.info("{}已禁用{}", imei, pileCode); return false; } socketHandle.addDeviceConnection(device.getIp(), device.getPort(), device.getPileCode(), device.getDeviceImei(), device.getDeviceSn(), device.getCommProtocolVer()); loginFrame.loginMsgSend(socketHandle.getDeviceConnection(device.getPileCode()), device); return false; } /** * 设备状态按照设备上报和设备心跳上送时间校验修改,这里就必须更新状态的修改时间;通过定时任务判断在线设备接收心跳包超10分钟改为离线 * * @param jsonObject */ private void handleDeviceMsg(JSONObject jsonObject, String pileCode) throws Exception { String imei = jsonObject.getString("imei"); Integer cmd = jsonObject.getInteger("cmd"); if (!jsonObject.containsKey("type")) { //TODO:离线判断:设备上报+?设备心跳时间校验? //没有type但是cmd指令是离线时37896========= if (cmd == 37896) { //处理离线消息 handleOffline(imei); } return; } try { checkConnection(pileCode, imei); } catch (Exception e) { logger.info("桩{}连接异常", imei); } Integer type = jsonObject.getInteger("type"); if (!NormalChargeConstant.CMD_SET_MAINBOARD.equals(cmd)) { // logger.error("不支持的命令"); return; } //端口状态 if (NormalChargeConstant.KEY_PORT_DETAIL.equals(type)) { handle103(jsonObject, imei, type); return; } if (NormalChargeConstant.PORT_STATUS.equals(type)) { //116端口详情也会变化 JSONArray data = jsonObject.getJSONArray("data"); checkPort(data.getInteger(4), data.getInteger(3), imei, type); return; } //指定端口状态 if (NormalChargeConstant.KEY_PORT_STATUS.equals(type)) { handle101(jsonObject, imei, type); return; } //104消息启动充电 if (NormalChargeConstant.KEY_STARTCHARGE.equals(type)) { handle104(jsonObject, imei); return; } //结束充电 if (NormalChargeConstant.KEY_END_NOTICE.equals(type)) { handle113(jsonObject, imei); return; } //TODO:设备状态的修改这里进行监听变化 ,?? // 1.设备消息cmd:75960设备上报消息是的命令,只要设备报的不是离线当做设备在线 // 2.设备上报指令后根据type类型来分类处理消息包括:设备设为在线 是否插枪状态 枪状态(端口状态) if (NormalChargeConstant.EMERGENCY_STOP_CHARGING.equals(type)) { handleEmergency(jsonObject, imei); return; } if (NormalChargeConstant.REPORT_PORT_STATUS.equals(type)) { //114设备主动上报 JSONArray data = jsonObject.getJSONArray("data"); Integer integer = data.getInteger(2); if (integer > 5) { //双枪 checkPort(data.getInteger(7), 1, imei, type); checkPort(data.getInteger(8), 2, imei, type); } else { checkPort(data.getInteger(7), 1, imei, type); } } } //生产上根本进不来 不考虑 临时调试ykc上报急停状态 private void handleEmergency(JSONObject jsonObject, String imei) throws Exception { //急停停充 JSONArray data = jsonObject.getJSONArray("data"); int port = data.getInteger(2); int status = data.getInteger(3); //关闭急停和急停完,停止充电,获取设备状态 DeviceParam dataParam = new DeviceParam(); dataParam.setDeviceId(imei); dataParam.setCcid(imei); deviceControlerService.sendPortDetailCmd(dataParam); deviceControlerService.stopCharge(imei, imei, port); //查询计费模板 QueryWrapper billingModelQueryWrapper = new QueryWrapper<>(); billingModelQueryWrapper.eq("device_imei", imei); BillingModel model = billingModelService.getOne(billingModelQueryWrapper); QueryWrapper orderStatusQueryWrapper = new QueryWrapper<>(); orderStatusQueryWrapper.eq("device_imei", imei) .eq("guns_code", port) .orderByDesc("create_time" ).last("limit 1"); OrderStatus statusServiceOne = orderStatusService.getOne(orderStatusQueryWrapper); statusServiceOne.setEndTime(System.currentTimeMillis()); DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(statusServiceOne.getPileCode()); if (status == 1) { logger.info(statusServiceOne.getPileCode() + ":急停停充>>>上报交易记录>>>"); byte[] encrypt = new byte[0]; if (port == 1) { //急停停充:急停状态下:1.向设备发起结束充电,结算交易订单(交给结束充电处理;但是要考虑是急停的原因),2.上报的充电结束的订单式 Map map = transMoney.compute(1, model, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime()); encrypt = transactionFlowPushFrame.sendTrans(deviceConnection, statusServiceOne.getTransOrder(), statusServiceOne.getPileCode(), (byte) 1, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime(), model, statusServiceOne.getCard(), map, TransConstant.EMERGENCY_STOP_EXCEPTION_STOP); } else if (port == 2) { //TODO:这里还是模拟数据上报 Map map = transMoney.compute(2, model, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime()); //模拟3.5千瓦 encrypt = transactionFlowPushFrame.sendTrans(deviceConnection, statusServiceOne.getTransOrder(), statusServiceOne.getPileCode(), (byte) 2, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime(), model, statusServiceOne.getCard(), map, TransConstant.EMERGENCY_STOP_EXCEPTION_STOP); } statusServiceOne.setOriginalText(encrypt); statusServiceOne.setReasonStopCharging(TransConstant.EMERGENCY_STOP_EXCEPTION_STOP); statusServiceOne.setStopChargingReply(StatusConstant.STOP_CHARGING_REPLY_OK); statusServiceOne.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING); statusServiceOne.setTransactionOrderReportingActionStatus(StatusConstant.TRANSACTION_ORDER_REPORTING_ACTION_STATUS_OK); orderStatusService.updateById(statusServiceOne); } } //启动充电 private void handle104(JSONObject jsonObject, String imei) { //开启充电设备上报结果 JSONObject data = jsonObject.getJSONObject("real_data"); Integer result = data.getInteger("result"); Integer port = data.getInteger("port"); QueryWrapper orderStatusQueryWrapper = new QueryWrapper<>(); orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1"); OrderStatus statusServiceOne = orderStatusService.getOne(orderStatusQueryWrapper); byte[] bytes = statusServiceOne.getTransOrder(); logger.info(statusServiceOne.getPileCode() + ":设备开启充电流水号:" + DataConversion.bytesToHexString(bytes)); DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(statusServiceOne.getPileCode()); int reson = 0x00; if (result == 0x01) { //启充成功上报充电开启成功 charngingPushFrame.startStatus(deviceConnection, bytes, port, result, 0x00); logger.info("上报启动充电成功{},{}", statusServiceOne.getId(), statusServiceOne.getPileCode()); } else { //启机不成功,根据设备状态判断,并且要结束充电并上报订单 String cacheKey; if (port == 1) { cacheKey = RedisConstant.ONLINE_DEVICE_ONE; } else { cacheKey = RedisConstant.ONLINE_DEVICE_TWO; } if (redisCache.hasKey(cacheKey)) { DeviceStatus oneStatus = redisCache.getCacheMapValue(cacheKey, statusServiceOne.getPileCode()); if (StatusConstant.FAULT == oneStatus.getGunStatus()) { reson = 0x03; } else if (StatusConstant.OFFLINE == oneStatus.getGunStatus()) { reson = 0x04; } else if (StatusConstant.CHARGING == oneStatus.getGunStatus()) { reson = 0x02; } charngingPushFrame.startStatus(deviceConnection, bytes, port, result, reson); logger.info("上报启动充电失败{},{}", statusServiceOne.getId(), statusServiceOne.getPileCode()); } } new Thread(() -> { try { Thread.sleep(4000); // 延迟 5 秒 DeviceParam dataParam = new DeviceParam(); dataParam.setDeviceId(imei); dataParam.setCcid(imei); deviceControlerService.sendPortDetailCmd(dataParam); logger.info(statusServiceOne.getPileCode() + ":延迟主动下发103消息" + imei); } catch (Exception e) { logger.info(statusServiceOne.getPileCode() + ":延迟主动下发103消息异常" + e.getMessage() + imei); } }).start(); } //单个端口状态 private void handle101(JSONObject jsonObject, String imei, int type) { try { //状态查询101 JSONObject data = jsonObject.getJSONObject("real_data"); Integer port_first_status = data.getInteger("port_first_status"); Integer port_second_status = data.getInteger("port_second_status"); if (port_first_status != null) { checkPort(port_first_status, 1, imei, type); } if (port_second_status != null) { checkPort(port_second_status, 2, imei, type); } } catch (Exception e) { logger.info("处理101失败{}", imei); } } private void handle103(JSONObject jsonObject, String imei, int type) throws Exception { //103状态是带电压功率等信息的,所以需要对该信息进行处理操作 JSONObject data = jsonObject.getJSONObject("real_data"); Integer port_first_status = data.getInteger("port_first_status"); Integer port_second_status = data.getInteger("port_second_status"); //功率为0时,还是充电中状态,将状态转换成空闲,结束充电 // 20240608现场使用时出现充电状态第一次103上来就是power是0情况 // if (port_first_status != null&&power==0&&port_first_status==PortStatusConstant.CHARGING){ // port_first_status=PortStatusConstant.FREE; // } // if (port_second_status != null&&power==0&&port_second_status==PortStatusConstant.CHARGING){ // port_second_status=PortStatusConstant.FREE; // } //判断连续无功率就自动停止 redisCache.setCacheObject(RedisConstant.DEVICE_PORT_STATUS + imei, data, 30, TimeUnit.MINUTES); if (port_first_status != null) { checkPort(port_first_status, 1, imei, type); if (port_first_status == PortStatusConstant.CHARGING) { Integer power = data.getInteger("power"); checkNoPowerAutoStop(power, imei, 1); } } if (port_second_status != null) { checkPort(port_second_status, 2, imei, type); if (port_second_status == PortStatusConstant.CHARGING) { Integer power = data.getInteger("power_1"); checkNoPowerAutoStop(power, imei, 2); } } } //处理停止充电情况 private void handle113(JSONObject jsonObject, String imei) { //停止充电通知触发情况:1.急停,收到停充时主动要去发停充,所以这里不能处理急停的交易订单;2.手动停充,正常的远程停止指令 // 1.设备已经在接收到云快充指令的时候进行了停充操作,2.结算订单,上报云快充停止回复 try { JSONObject data = jsonObject.getJSONObject("real_data"); logger.info("{}接收到设备上送113停止充电msg>>" + jsonObject.toString(), imei); int port = data.getIntValue("port"); byte reson = data.getByte("reason"); QueryWrapper orderStatusQueryWrapper = new QueryWrapper<>(); orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1"); OrderStatus statusServiceOne = orderStatusService.getOne(orderStatusQueryWrapper); if (statusServiceOne == null) { logger.info("没有待处理订单{}", imei); deviceControlerService.sendImeiDetail(imei); return; } if (statusServiceOne.getTransactionOrderReplyStatus() == StatusConstant.TRANSACTION_ORDER_REPLY_STATUS_SUCC) { logger.info("订单状态已上报成功{},id:{}", imei, statusServiceOne.getId()); deviceControlerService.sendImeiDetail(imei); return; } //如果是用户手动停止充电 则不处理状态 if (statusServiceOne.getReasonStopCharging() == TransConstant.APP_REMOTE_STOP) { logger.info(statusServiceOne.getPileCode() + ":云快充>>>>>>远程停充>>>>"); } else { if(statusServiceOne.getReasonStopCharging()==0){ logger.info(statusServiceOne.getPileCode() + ":充满主动>>>>>>停充>>>>"); }else{ //不处理急停 if (reson == 0x01) { logger.info(statusServiceOne.getPileCode() + ":用户主动停充>>>>>>停充>>>>"); statusServiceOne.setReasonStopCharging(TransConstant.APP_REMOTE_STOP); } else if (reson == 0x00) { logger.info(statusServiceOne.getPileCode() + ":设备余额不足>>>>>>停充>>>>"); statusServiceOne.setReasonStopCharging(TransConstant.INSUFFICIENT_BALANCE_EXCEPTION_STOP); } else if (reson == 0x03) { logger.info(statusServiceOne.getPileCode() + ":设备充电充满>>>>>>停充>>>>"); statusServiceOne.setReasonStopCharging(TransConstant.SOC_FULL_OF_STOP); } else { logger.info(statusServiceOne.getPileCode() + ":设备充电停止>>>>其他>>>"); statusServiceOne.setReasonStopCharging(TransConstant.OTHER_STOP); } } } //设置订单已停止充电和结束时间 statusServiceOne.setEndTime(System.currentTimeMillis()); statusServiceOne.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING); DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(statusServiceOne.getPileCode()); if (deviceConnection == null || deviceConnection.getLoginStatus() != 1) { //未上报 statusServiceOne.setTransactionOrderReportingActionStatus(StatusConstant.TRANSACTION_ORDER_REPORTING_ACTION_STATUS_NO); logger.info("socket 未连接 需要重新上报异常上报{}", statusServiceOne.getPileCode()); orderStatusService.updateById(statusServiceOne); return; } byte[] encrypt = new byte[0]; //查询计费模板 QueryWrapper billingModelQueryWrapper = new QueryWrapper<>(); billingModelQueryWrapper.eq("device_imei", imei); BillingModel model = billingModelService.getOne(billingModelQueryWrapper); Map map = transMoney.compute(port, model, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime()); logger.info(statusServiceOne.getPileCode() + "计算电费" + DataConversion.bytesToHexString(statusServiceOne.getTransOrder())); encrypt = transactionFlowPushFrame.sendTrans(deviceConnection, statusServiceOne.getTransOrder(), statusServiceOne.getPileCode(), statusServiceOne.getGunsCode(), statusServiceOne.getCreateTime(), statusServiceOne.getEndTime(), model, statusServiceOne.getCard(), map, statusServiceOne.getReasonStopCharging()); if (encrypt == null || encrypt.length <= 0) { logger.info("订单上送消息异常 需要重新上报{}", statusServiceOne.getPileCode()); orderStatusService.updateById(statusServiceOne); return; } else { logger.info("订单上送成功{}", statusServiceOne.getPileCode()); statusServiceOne.setTransactionOrderReportingActionStatus(StatusConstant.TRANSACTION_ORDER_REPORTING_ACTION_STATUS_OK); statusServiceOne.setOriginalText(encrypt); } boolean res = charngingPushFrame.endStatus(deviceConnection, port, 0x01, 0x00); if (res) { //更新远程停止充电 logger.info("停止充电回复成功{}", imei); statusServiceOne.setStopChargingReply(StatusConstant.STOP_CHARGING_REPLY_OK); } else { logger.info("停止充电回复失败{}", imei); } orderStatusService.updateById(statusServiceOne); // //获取一设备状态 // DeviceParam dataParam = new DeviceParam(); // dataParam.setDeviceId(imei); // dataParam.setCcid(imei); // realTimeStatusPushFrame.deviceStatusPush(deviceConnection, FrameDataSplicing.transactionNum(deviceConnection.getDeviceId(), deviceConnection.getMessageCount()), deviceConnection.getDeviceId(), (byte) 1, StatusConstant.FREE, StatusConstant.CHARGING_INIT_STATUS_OK, 0, 0, zero, zero, 0); deviceControlerService.sendImeiDetail(deviceConnection.getImei()); } catch (Exception e) { logger.info("{}处理113消息异常{}", imei, e.getMessage()); // DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(imei); // realTimeStatusPushFrame.deviceStatusPush(deviceConnection, FrameDataSplicing.transactionNum(deviceConnection.getDeviceId(), deviceConnection.getMessageCount()), deviceConnection.getDeviceId(), (byte) 1, StatusConstant.FREE, StatusConstant.CHARGING_INIT_STATUS_OK, 0, 0, zero, zero, 0); e.printStackTrace(); } } /** * 设备端口状态转成云快充识别状态 * * @param portStatus * @param port * @param imei */ private void checkPort(Integer portStatus, int port, String imei, int type) throws Exception { if (portStatus.equals(PortStatusConstant.FREE)) { //处理特殊情况之后还要看枪状态变位上送 deviceOnline(portStatus, imei, port, StatusConstant.FREE, StatusConstant.INSERT_GUNS_NO); return; } if (portStatus.equals(PortStatusConstant.CHARGING)) { deviceOnline(portStatus, imei, port, StatusConstant.CHARGING, StatusConstant.INSERT_GUNS_YES); return; } if (portStatus.equals(PortStatusConstant.DISABLED) || portStatus.equals(PortStatusConstant.FAULT)) { //禁用或故障上报云快充为故障信息 deviceOnline(portStatus, imei, port, StatusConstant.FAULT, StatusConstant.NO); return; } if (portStatus.equals(PortStatusConstant.INSERT_GUN) || portStatus.equals(PortStatusConstant.BOOKED)) { deviceOnline(portStatus, imei, port, StatusConstant.FREE, StatusConstant.INSERT_GUNS_YES); return; } if (portStatus.equals(PortStatusConstant.CHARGING_END)) { //7状态的时候 充满停止以后 认为未插枪 不允许充电 因为启动不了,必须要重新拔枪 deviceOnline(portStatus, imei, port, (byte) StatusConstant.FREE, StatusConstant.INSERT_GUNS_NO); return; } if (portStatus.equals(PortStatusConstant.EMERGENCY_STOP)) { //急停中按要求需要上报空闲状态;急停保存原始状态 deviceOnline(portStatus, imei, port, (byte) PortStatusConstant.EMERGENCY_STOP, StatusConstant.INSERT_GUNS_NO); } } /** * 1.这里接收到消息就是设备在线;2.对状态进行处理,不同类型消息的枪状态不同进行落库;3.并且状态变化的一个变位上送 * 枪充满会变成状7 然后必须要拔了再插 才能启动充电 * 但是拔了再插 会短暂的从1 变成5 所以在判断空闲的时候 要加上订单60秒的变位限制 6如果有订单60秒后才关闭 * @param imei 设备imei码 * @param port 设备port(枪号) * @param gunsStatus 枪状态 */ private void deviceOnline(int portStatus, String imei, int port, byte gunsStatus, byte insertGunStatus) throws Exception { QueryWrapper deviceStatusQueryWrapper = new QueryWrapper<>(); deviceStatusQueryWrapper.eq("device_imei", imei).eq("gun_port", port); DeviceStatus statusServiceOne = deviceStatusService.getOne(deviceStatusQueryWrapper); DeviceStatus statusServiceOneTemp = new DeviceStatus(); if(statusServiceOne!=null && insertGunStatus == StatusConstant.INSERT_GUNS_YES){ String waitingKey = RedisConstant.WAITING_INSERT_GUN+":"+statusServiceOne.getPileCode()+"_"+statusServiceOne.getGunPort(); if (redisCache.hasKey(waitingKey)) { //未插枪启充的操作会保存订单,但是订单号不是因为断网中停充造成的订单结束原因是0,所以redis有当前设备的订单值,就不是结束充电 int waitingId = redisCache.getCacheObject(waitingKey); //启动充电 QueryWrapper orderStatusQueryWrapper = new QueryWrapper<>(); orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1"); OrderStatus waitingOrder = orderStatusService.getOne(orderStatusQueryWrapper); if(waitingOrder!= null && waitingOrder.getId()==waitingId && waitingOrder.getNowOrderStatus()==StatusConstant.NOW_ORDER_STATUS_CHARGING){ logger.info("订单{}已就绪启动充电{}-{}",waitingOrder.getId(),waitingOrder.getPileCode(),waitingOrder.getGunsCode()); deviceControlerService.startCharge(waitingOrder.getDeviceImei(), waitingOrder.getDeviceImei(), (int) waitingOrder.getGunsCode(),0); redisCache.deleteObject(waitingKey); return; } } } //创建设备端口号 if (statusServiceOne != null) { BeanUtils.copyProperties(statusServiceOne, statusServiceOneTemp); } else { //禁用的设备不再上线,只看正常设备 QueryWrapper deviceQueryWrapper = new QueryWrapper<>(); QueryWrapper device_imei = deviceQueryWrapper.eq("device_imei", imei).eq("disabled", DeviceOnlineStatus.NORMAL); Device one = deviceService.getOne(device_imei); if (one == null) { logger.info("当前设备imei:" + imei + ",没有绑定ykc桩编码!!!!!!!!!!!!!!!!!!"); return; } statusServiceOne = new DeviceStatus(); statusServiceOne.setDeviceImei(imei); statusServiceOne.setDeviceSn(one.getDeviceSn()); statusServiceOne.setPileCode(one.getPileCode()); statusServiceOne.setGunPort((byte) port); statusServiceOne.setCreateTime(System.currentTimeMillis()); statusServiceOne.setUpdateTime(System.currentTimeMillis()); statusServiceOne.setOnlineStatus(DeviceOnlineStatus.ONLINE); statusServiceOne.setUpdateTime(System.currentTimeMillis()); statusServiceOne.setPortStatus(portStatus); deviceStatusService.saveOrUpdate(statusServiceOne); } statusServiceOne.setPortStatus(portStatus); statusServiceOne.setGunStatus(gunsStatus); statusServiceOne.setInsertGunStatus(insertGunStatus); statusServiceOne.setOnlineStatus(DeviceOnlineStatus.ONLINE); statusServiceOne.setUpdateTime(System.currentTimeMillis()); deviceStatusService.updateById(statusServiceOne); logger.info("{}设备状态持久化>>>" + statusServiceOne.toString(), imei); redisCache.setCacheMapValue(port == 1 ? RedisConstant.ONLINE_DEVICE_ONE : RedisConstant.ONLINE_DEVICE_TWO, statusServiceOne.getPileCode(), statusServiceOne); //为啥要过期20分 redisCache.expire(port == 1 ? RedisConstant.ONLINE_DEVICE_ONE : RedisConstant.ONLINE_DEVICE_TWO, 60 * 1001 * 20, TimeUnit.MILLISECONDS); DeviceConnectionMsg deviceConnectionMsg = socketHandle.getDeviceConnection(statusServiceOne.getPileCode()); if (deviceConnectionMsg == null || deviceConnectionMsg.getLoginStatus() != Constant.DEVICE_LOGIN_STATUS) { logger.info("设备{}未登录成功不上报", statusServiceOne.getDeviceImei()); return; } QueryWrapper orderStatusQueryWrapper = new QueryWrapper<>(); orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1"); OrderStatus one = orderStatusService.getOne(orderStatusQueryWrapper); //没有充电中的订单 if (one == null || one.getNowOrderStatus() != StatusConstant.NOW_ORDER_STATUS_CHARGING) { logger.info("没有订单上报空闲{}", imei); realTimeStatusPushFrame.deviceStatusPush(deviceConnectionMsg, FrameDataSplicing.transactionNum(null, 0), statusServiceOne.getPileCode(), (byte) port, gunsStatus, insertGunStatus, 0, 0, zero, zero, 0); return; } //充电中 if (portStatus == PortStatusConstant.CHARGING) { byte[] transactionNum = one.getTransOrder(); if (one.getChargingInitStatus() == StatusConstant.CHARGING_INIT_STATUS_NO) { logger.info("{}变位为充电中且当前订单还没首次上报过初始状态:" + DataConversion.bytesToHexString(transactionNum), imei); realTimeStatusPushFrame.deviceStatusPush(deviceConnectionMsg, transactionNum, statusServiceOneTemp.getPileCode(), (byte) port, gunsStatus, insertGunStatus, 0, 0, zero, zero, 0); //这里上报开始充电初始化状态并记录已经上报首次状态 one.setChargingInitStatus(StatusConstant.CHARGING_INIT_STATUS_OK); orderStatusService.updateById(one); } return; } //充电结束 if (portStatus == PortStatusConstant.CHARGING_END) { //7状态小于30秒内且订单原因不是远程停充 if (one.getNowOrderStatus() == StatusConstant.NOW_ORDER_STATUS_CHARGING) { if ((System.currentTimeMillis() - one.getCreateTime()) < 60 * 1000 && one.getReasonStopCharging() != TransConstant.APP_REMOTE_STOP) { logger.info("下订单60秒内{}不处理7状态", one.getPileCode()); return; } //充电已完成 //发送结束充电命令 顺利的话113会收到 状态还是7 logger.info("下订单60秒后{}仍然处于7状态发送止充电指令", one.getPileCode()); //标记订单为已停充 标记为未上送 one.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING); one.setEndTime(System.currentTimeMillis()); one.setReasonStopCharging(TransConstant.SOC_FULL_OF_STOP); orderStatusService.updateById(one); RpcResult rpcResult = deviceControlerService.stopCharge(imei, imei, port); return; } return; } //先拔 再插 //订单还在充电中 但是枪不在充电中状态 就结束订单 // 但是拔了再插 会短暂的从1 变成5 所以在判断空闲的时候 要加上订单60秒的变位限制 6如果有订单60秒后才关闭 if (one.getNowOrderStatus() == StatusConstant.NOW_ORDER_STATUS_CHARGING) { if ((System.currentTimeMillis() - one.getCreateTime()) < 60 * 1000 && one.getReasonStopCharging() != TransConstant.APP_REMOTE_STOP) { logger.info("下订单60秒内{}不处理空闲这个状态", one.getPileCode()); return; } logger.info("{}枪非充电中状态,结束订单状态 等待任务重试上报订单", one.getPileCode()); one.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING); one.setEndTime(System.currentTimeMillis()); one.setReasonStopCharging(TransConstant.OTHER_STOP); orderStatusService.updateById(one); } logger.info("上传空闲状态{}",imei); realTimeStatusPushFrame.deviceStatusPush(deviceConnectionMsg, FrameDataSplicing.transactionNum(null, 0), statusServiceOne.getPileCode(), (byte) port, gunsStatus, insertGunStatus, 0, 0, zero, zero, 0); } }