DeviceMsgHandle.java 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. package com.tmzn.devicelinkykc.message;
  2. import com.alibaba.fastjson2.JSONArray;
  3. import com.alibaba.fastjson2.JSONObject;
  4. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  5. import com.tmzn.devicelinkykc.constant.Constant;
  6. import com.tmzn.devicelinkykc.constant.DeviceOnlineStatus;
  7. import com.tmzn.devicelinkykc.constant.PortStatusConstant;
  8. import com.tmzn.devicelinkykc.constant.RedisConstant;
  9. import com.tmzn.devicelinkykc.constant.ykc.StatusConstant;
  10. import com.tmzn.devicelinkykc.constant.ykc.TransConstant;
  11. import com.tmzn.devicelinkykc.entity.*;
  12. import com.tmzn.devicelinkykc.frameMsg.DataConversion;
  13. import com.tmzn.devicelinkykc.frameMsg.FrameDataSplicing;
  14. import com.tmzn.devicelinkykc.frameMsg.TransMoney;
  15. import com.tmzn.devicelinkykc.frameMsg.frameType.CharngingPushFrame;
  16. import com.tmzn.devicelinkykc.frameMsg.frameType.LoginFrame;
  17. import com.tmzn.devicelinkykc.frameMsg.frameType.RealTimeStatusPushFrame;
  18. import com.tmzn.devicelinkykc.frameMsg.frameType.TransactionFlowPushFrame;
  19. import com.tmzn.devicelinkykc.openfeign.transdata.RpcResult;
  20. import com.tmzn.devicelinkykc.redis.RedisCache;
  21. import com.tmzn.devicelinkykc.service.*;
  22. import com.tmzn.devicelinkykc.socket.DeviceConnectionMsg;
  23. import com.tmzn.devicelinkykc.socket.SocketHandle;
  24. import com.tmzn.devicelinkykc.transdata.constant.NormalChargeConstant;
  25. import com.tmzn.devicelinkykc.transdata.entity.DeviceParam;
  26. import org.apache.logging.log4j.util.Strings;
  27. import org.slf4j.Logger;
  28. import org.slf4j.LoggerFactory;
  29. import org.springframework.beans.BeanUtils;
  30. import org.springframework.beans.factory.annotation.Autowired;
  31. import org.springframework.stereotype.Component;
  32. import java.io.IOException;
  33. import java.math.BigDecimal;
  34. import java.util.*;
  35. import java.util.concurrent.TimeUnit;
  36. /**
  37. * @author xp
  38. * @date 2024/3/13
  39. * @explain " 设备消息处理 "
  40. * //TODO:考虑设备上来的消息只走数据库查询不走redis订阅数据
  41. */
  42. @Component
  43. public class DeviceMsgHandle {
  44. @Autowired
  45. private DeviceStatusService deviceStatusService;
  46. @Autowired
  47. private SocketHandle socketHandle;
  48. @Autowired
  49. private RedisCache redisCache;
  50. @Autowired
  51. private RealTimeStatusPushFrame realTimeStatusPushFrame;
  52. @Autowired
  53. private TransactionFlowPushFrame transactionFlowPushFrame;
  54. @Autowired
  55. private LoginFrame loginFrame;
  56. @Autowired
  57. private CharngingPushFrame charngingPushFrame;
  58. @Autowired
  59. private DeviceService deviceService;
  60. @Autowired
  61. private OrderStatusService orderStatusService;
  62. @Autowired
  63. private DeviceControlerService deviceControlerService;
  64. @Autowired
  65. private BillingModelService billingModelService;
  66. @Autowired
  67. private TransMoney transMoney;
  68. private static final Logger logger = LoggerFactory.getLogger(DeviceMsgHandle.class);
  69. private Long lastLogTime;
  70. private static final Long gap = 1000 * 30L;
  71. private static final BigDecimal zero = new BigDecimal("0");
  72. public void deviceMsg(String msg) throws Exception {
  73. //必须过滤调非云快充设备
  74. //logger.info("redis中msg>>>" + msg);
  75. msg = msg.substring(1, msg.length() - 1);
  76. msg = msg.replace("\\", "");
  77. // checkActive(msg);
  78. JSONObject jsonObject = null;
  79. try {
  80. jsonObject = JSONObject.parseObject(msg);
  81. } catch (Exception e) {
  82. //这里正常格式才走,不正常的格式不打印报错了;可能有其他格式的数据过来;正常要解析的数据是能走到JSON中的
  83. logger.info("device msg conversion exception not processed!!!" + msg);
  84. return;
  85. //e.printStackTrace();
  86. }
  87. String imei = jsonObject.getString("imei");
  88. if (Strings.isEmpty(imei)) {
  89. return;
  90. }
  91. String pileCode = "";
  92. try {
  93. pileCode = redisCache.getCacheMapValue(RedisConstant.DEVICE_IMEI_PILE_MAP, imei);
  94. if (Strings.isEmpty(pileCode)) {
  95. return;
  96. }
  97. } catch (Exception e) {
  98. return;
  99. }
  100. logger.info("{},msg>>>" + msg, imei);
  101. //设备状态更新,true:没有type不是设备上送类型不往云快充处理 false:需要根据设备消息类型往下处理是不是需要上报云快充
  102. try {
  103. handleDeviceMsg(jsonObject, pileCode);
  104. } catch (Exception e) {
  105. logger.error("处理消息失败{},{}", imei, e.getMessage());
  106. e.printStackTrace();
  107. }
  108. }
  109. public void testMsg(String msg) throws Exception {
  110. logger.info("testmsg>>>" + msg);
  111. JSONObject jsonObject = null;
  112. jsonObject = JSONObject.parseObject(msg);
  113. String imei = jsonObject.getString("imei");
  114. try {
  115. String pileCode = redisCache.getCacheMapValue(RedisConstant.DEVICE_IMEI_PILE_MAP, imei);
  116. if (Strings.isEmpty(pileCode)) {
  117. logger.info("非云快充设备");
  118. return;
  119. }
  120. handleDeviceMsg(jsonObject, pileCode);
  121. } catch (Exception e) {
  122. return;
  123. }
  124. //设备状态更新,true:没有type不是设备上送类型不往云快充处理 false:需要根据设备消息类型往下处理是不是需要上报云快充
  125. }
  126. private void checkActive(String s) {
  127. Long now = System.currentTimeMillis();
  128. if (lastLogTime == null) {
  129. lastLogTime = now;
  130. }
  131. Long gap = now - lastLogTime;
  132. if (gap > gap) {
  133. //logger.info("message:,{}", s);
  134. lastLogTime = now;
  135. }
  136. }
  137. //处理离线消息
  138. //查找所有端口状态置为下线 并推送状态给云快充
  139. private void handleOffline(String imei) {
  140. QueryWrapper<DeviceStatus> deviceStatusQueryWrapper = new QueryWrapper<>();
  141. deviceStatusQueryWrapper.eq("device_imei", imei);
  142. List<DeviceStatus> list = deviceStatusService.list(deviceStatusQueryWrapper);
  143. if (!list.isEmpty()) {
  144. for (DeviceStatus deviceStatus : list) {
  145. //deviceStatus.setInsertGunStatus(StatusConstant.INSERT_GUNS_NO);
  146. //deviceStatus.setGunStatus(StatusConstant.OFFLINE);
  147. deviceStatus.setOnlineStatus(DeviceOnlineStatus.OFFLINE);
  148. deviceStatus.setUpdateTime(System.currentTimeMillis());
  149. deviceStatusService.updateById(deviceStatus);
  150. if (socketHandle.existDeviceConnection(deviceStatus.getPileCode())) {
  151. String pilecode = deviceStatus.getPileCode();
  152. DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(pilecode);
  153. byte[] transactionNum = new byte[16]; //FrameDataSplicing.transactionNum(pilecode, deviceConnection.getMessageCount());
  154. if (deviceStatus.getGunStatus() == PortStatusConstant.EMERGENCY_STOP) {
  155. deviceStatus.setGunStatus(StatusConstant.FREE);
  156. }
  157. realTimeStatusPushFrame.deviceStatusPush(deviceConnection, transactionNum, pilecode, (byte) deviceStatus.getGunPort(), deviceStatus.getGunStatus(), deviceStatus.getInsertGunStatus(), 0, 0, zero, zero, 0);
  158. socketHandle.removeDeviceConnection(deviceStatus.getPileCode());
  159. redisCache.deleteObject(RedisConstant.DEVICE_PORT_STATUS + imei);
  160. }
  161. }
  162. }
  163. }
  164. private void checkNoPowerAutoStop(int power, String imei, int portId) {
  165. try {
  166. String hkey = imei + "_" + portId;
  167. Integer lastPower0Times = 0;
  168. if (power > 0) {
  169. } else {
  170. lastPower0Times = redisCache.getCacheMapValue(RedisConstant.POWER_ZERO_TIMES, hkey);
  171. if (lastPower0Times == null) {
  172. lastPower0Times = 0;
  173. }
  174. lastPower0Times = lastPower0Times + 1;
  175. }
  176. redisCache.setCacheMapValue(RedisConstant.POWER_ZERO_TIMES, hkey, lastPower0Times);
  177. if (lastPower0Times < 5) {
  178. return;
  179. }
  180. //查找订单开始时间 如果开始时间过过2分钟 且连续power为0 就需要停止充电
  181. QueryWrapper<OrderStatus> orderStatusQueryWrapper = new QueryWrapper<>();
  182. orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", portId).orderByDesc("create_time").last("limit 1");
  183. OrderStatus one = orderStatusService.getOne(orderStatusQueryWrapper);
  184. if (one.getNowOrderStatus() != StatusConstant.NOW_ORDER_STATUS_CHARGING) {
  185. return;
  186. }
  187. if ((System.currentTimeMillis() - one.getCreateTime()) < 120 * 1000) {
  188. return;
  189. }
  190. //连续3次功率0 就要停止充电
  191. RpcResult rpcResult = deviceControlerService.stopCharge(imei, imei, (int) portId);
  192. logger.info("{}-{}触发无功率自停{}", imei, portId, lastPower0Times);
  193. } catch (Exception e) {
  194. logger.error("无功率检测异常{}", e.getMessage());
  195. e.printStackTrace();
  196. }
  197. }
  198. private void checkConnection(String pileCode, String imei) throws IOException {
  199. boolean needLogin = false;
  200. if (!socketHandle.existDeviceConnection(pileCode)) {
  201. needLogin = true;
  202. } else {
  203. DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(pileCode);
  204. if (!deviceConnection.getSocket().isConnected()) {
  205. socketHandle.removeDeviceConnection(pileCode);
  206. needLogin = true;
  207. }
  208. }
  209. if (!needLogin) {
  210. return;
  211. }
  212. logger.info("桩上线{}", imei);
  213. QueryWrapper<Device> deviceQueryWrapper = new QueryWrapper<>();
  214. deviceQueryWrapper.eq("pile_code", pileCode).eq("disabled", DeviceOnlineStatus.NORMAL);
  215. Device device = deviceService.getOne(deviceQueryWrapper);
  216. if (device == null) {
  217. logger.info("{}已禁用{}", imei, pileCode);
  218. return;
  219. }
  220. socketHandle.addDeviceConnection(device.getIp(), device.getPort(), device.getPileCode(), device.getDeviceImei(), device.getDeviceSn(), device.getCommProtocolVer());
  221. loginFrame.loginMsgSend(socketHandle.getDeviceConnection(device.getPileCode()), device);
  222. }
  223. /**
  224. * 设备状态按照设备上报和设备心跳上送时间校验修改,这里就必须更新状态的修改时间;通过定时任务判断在线设备接收心跳包超10分钟改为离线
  225. *
  226. * @param jsonObject
  227. */
  228. private void handleDeviceMsg(JSONObject jsonObject, String pileCode) throws Exception {
  229. String imei = jsonObject.getString("imei");
  230. Integer cmd = jsonObject.getInteger("cmd");
  231. if (!jsonObject.containsKey("type")) {
  232. //TODO:离线判断:设备上报+?设备心跳时间校验?
  233. //没有type但是cmd指令是离线时37896=========
  234. if (cmd == 37896) {
  235. //处理离线消息
  236. handleOffline(imei);
  237. }
  238. return;
  239. }
  240. try {
  241. checkConnection(pileCode, imei);
  242. } catch (Exception e) {
  243. logger.info("桩{}连接异常", imei);
  244. }
  245. Integer type = jsonObject.getInteger("type");
  246. if (!NormalChargeConstant.CMD_SET_MAINBOARD.equals(cmd)) {
  247. // logger.error("不支持的命令");
  248. return;
  249. }
  250. //端口状态
  251. if (NormalChargeConstant.KEY_PORT_DETAIL.equals(type)) {
  252. handle103(jsonObject, imei, type);
  253. return;
  254. }
  255. if (NormalChargeConstant.PORT_STATUS.equals(type)) {
  256. //116端口详情也会变化
  257. JSONArray data = jsonObject.getJSONArray("data");
  258. checkPort(data.getInteger(4), data.getInteger(3), imei, type);
  259. return;
  260. }
  261. //指定端口状态
  262. if (NormalChargeConstant.KEY_PORT_STATUS.equals(type)) {
  263. handle101(jsonObject, imei, type);
  264. return;
  265. }
  266. //104消息启动充电
  267. if (NormalChargeConstant.KEY_STARTCHARGE.equals(type)) {
  268. handle104(jsonObject, imei);
  269. return;
  270. }
  271. //结束充电
  272. if (NormalChargeConstant.KEY_END_NOTICE.equals(type)) {
  273. handle113(jsonObject, imei);
  274. return;
  275. }
  276. //TODO:设备状态的修改这里进行监听变化 ,??
  277. // 1.设备消息cmd:75960设备上报消息是的命令,只要设备报的不是离线当做设备在线
  278. // 2.设备上报指令后根据type类型来分类处理消息包括:设备设为在线 是否插枪状态 枪状态(端口状态)
  279. if (NormalChargeConstant.EMERGENCY_STOP_CHARGING.equals(type)) {
  280. handleEmergency(jsonObject, imei);
  281. return;
  282. }
  283. if (NormalChargeConstant.REPORT_PORT_STATUS.equals(type)) {
  284. //114设备主动上报
  285. JSONArray data = jsonObject.getJSONArray("data");
  286. Integer integer = data.getInteger(2);
  287. if (integer > 5) {
  288. //双枪
  289. checkPort(data.getInteger(7), 1, imei, type);
  290. checkPort(data.getInteger(8), 2, imei, type);
  291. } else {
  292. checkPort(data.getInteger(7), 1, imei, type);
  293. }
  294. }
  295. }
  296. //生产上根本进不来 不考虑 临时调试ykc上报急停状态
  297. private void handleEmergency(JSONObject jsonObject, String imei) throws Exception {
  298. //急停停充
  299. JSONArray data = jsonObject.getJSONArray("data");
  300. int port = data.getInteger(2);
  301. int status = data.getInteger(3);
  302. //关闭急停和急停完,停止充电,获取设备状态
  303. DeviceParam dataParam = new DeviceParam();
  304. dataParam.setDeviceId(imei);
  305. dataParam.setCcid(imei);
  306. deviceControlerService.sendPortDetailCmd(dataParam);
  307. deviceControlerService.stopCharge(imei, imei, port);
  308. //查询计费模板
  309. QueryWrapper<BillingModel> billingModelQueryWrapper = new QueryWrapper<>();
  310. billingModelQueryWrapper.eq("device_imei", imei);
  311. BillingModel model = billingModelService.getOne(billingModelQueryWrapper);
  312. QueryWrapper<OrderStatus> orderStatusQueryWrapper = new QueryWrapper<>();
  313. orderStatusQueryWrapper.eq("device_imei", imei)
  314. .eq("guns_code", port)
  315. .orderByDesc("create_time"
  316. ).last("limit 1");
  317. OrderStatus statusServiceOne = orderStatusService.getOne(orderStatusQueryWrapper);
  318. statusServiceOne.setEndTime(System.currentTimeMillis());
  319. DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(statusServiceOne.getPileCode());
  320. if (status == 1) {
  321. logger.info(statusServiceOne.getPileCode() + ":急停停充>>>上报交易记录>>>");
  322. byte[] encrypt = new byte[0];
  323. if (port == 1) {
  324. //急停停充:急停状态下:1.向设备发起结束充电,结算交易订单(交给结束充电处理;但是要考虑是急停的原因),2.上报的充电结束的订单式
  325. Map<String, BigDecimal> map = transMoney.compute(1, model, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime());
  326. encrypt = transactionFlowPushFrame.sendTrans(deviceConnection, statusServiceOne.getTransOrder(), statusServiceOne.getPileCode(), (byte) 1, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime(), model, statusServiceOne.getCard(), map, TransConstant.EMERGENCY_STOP_EXCEPTION_STOP);
  327. } else if (port == 2) {
  328. //TODO:这里还是模拟数据上报
  329. Map<String, BigDecimal> map = transMoney.compute(2, model, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime());
  330. //模拟3.5千瓦
  331. encrypt = transactionFlowPushFrame.sendTrans(deviceConnection, statusServiceOne.getTransOrder(), statusServiceOne.getPileCode(), (byte) 2, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime(), model, statusServiceOne.getCard(), map, TransConstant.EMERGENCY_STOP_EXCEPTION_STOP);
  332. }
  333. statusServiceOne.setOriginalText(encrypt);
  334. statusServiceOne.setReasonStopCharging(TransConstant.EMERGENCY_STOP_EXCEPTION_STOP);
  335. statusServiceOne.setStopChargingReply(StatusConstant.STOP_CHARGING_REPLY_OK);
  336. statusServiceOne.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING);
  337. statusServiceOne.setTransactionOrderReportingActionStatus(StatusConstant.TRANSACTION_ORDER_REPORTING_ACTION_STATUS_OK);
  338. orderStatusService.updateById(statusServiceOne);
  339. }
  340. }
  341. //启动充电
  342. private void handle104(JSONObject jsonObject, String imei) {
  343. //开启充电设备上报结果
  344. JSONObject data = jsonObject.getJSONObject("real_data");
  345. Integer result = data.getInteger("result");
  346. Integer port = data.getInteger("port");
  347. QueryWrapper<OrderStatus> orderStatusQueryWrapper = new QueryWrapper<>();
  348. orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1");
  349. OrderStatus statusServiceOne = orderStatusService.getOne(orderStatusQueryWrapper);
  350. byte[] bytes = statusServiceOne.getTransOrder();
  351. logger.info(statusServiceOne.getPileCode() + ":设备开启充电流水号:" + DataConversion.bytesToHexString(bytes));
  352. DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(statusServiceOne.getPileCode());
  353. int reson = 0x00;
  354. if (result == 0x01) {
  355. //启充成功上报充电开启成功
  356. charngingPushFrame.startStatus(deviceConnection, bytes, port, result, 0x00);
  357. logger.info("上报启动充电成功{},{}", statusServiceOne.getId(), statusServiceOne.getPileCode());
  358. } else {
  359. //启机不成功,根据设备状态判断,并且要结束充电并上报订单
  360. String cacheKey;
  361. if (port == 1) {
  362. cacheKey = RedisConstant.ONLINE_DEVICE_ONE;
  363. } else {
  364. cacheKey = RedisConstant.ONLINE_DEVICE_TWO;
  365. }
  366. if (redisCache.hasKey(cacheKey)) {
  367. DeviceStatus oneStatus = redisCache.getCacheMapValue(cacheKey, statusServiceOne.getPileCode());
  368. if (StatusConstant.FAULT == oneStatus.getGunStatus()) {
  369. reson = 0x03;
  370. } else if (StatusConstant.OFFLINE == oneStatus.getGunStatus()) {
  371. reson = 0x04;
  372. } else if (StatusConstant.CHARGING == oneStatus.getGunStatus()) {
  373. reson = 0x02;
  374. }
  375. charngingPushFrame.startStatus(deviceConnection, bytes, port, result, reson);
  376. logger.info("上报启动充电失败{},{}", statusServiceOne.getId(), statusServiceOne.getPileCode());
  377. }
  378. }
  379. new Thread(() -> {
  380. try {
  381. Thread.sleep(5000); // 延迟 5 秒
  382. DeviceParam dataParam = new DeviceParam();
  383. dataParam.setDeviceId(imei);
  384. dataParam.setCcid(imei);
  385. deviceControlerService.sendPortDetailCmd(dataParam);
  386. logger.info(statusServiceOne.getPileCode() + ":延迟主动下发103消息" + imei);
  387. } catch (Exception e) {
  388. logger.info(statusServiceOne.getPileCode() + ":延迟主动下发103消息异常" + e.getMessage() + imei);
  389. }
  390. }).start();
  391. }
  392. //单个端口状态
  393. private void handle101(JSONObject jsonObject, String imei, int type) {
  394. try {
  395. //状态查询101
  396. JSONObject data = jsonObject.getJSONObject("real_data");
  397. Integer port_first_status = data.getInteger("port_first_status");
  398. Integer port_second_status = data.getInteger("port_second_status");
  399. if (port_first_status != null) {
  400. checkPort(port_first_status, 1, imei, type);
  401. }
  402. if (port_second_status != null) {
  403. checkPort(port_second_status, 2, imei, type);
  404. }
  405. } catch (Exception e) {
  406. logger.info("处理101失败{}", imei);
  407. }
  408. }
  409. private void handle103(JSONObject jsonObject, String imei, int type) throws Exception {
  410. //103状态是带电压功率等信息的,所以需要对该信息进行处理操作
  411. JSONObject data = jsonObject.getJSONObject("real_data");
  412. Integer port_first_status = data.getInteger("port_first_status");
  413. Integer port_second_status = data.getInteger("port_second_status");
  414. Integer power = data.getInteger("power");
  415. //功率为0时,还是充电中状态,将状态转换成空闲,结束充电
  416. // 20240608现场使用时出现充电状态第一次103上来就是power是0情况
  417. // if (port_first_status != null&&power==0&&port_first_status==PortStatusConstant.CHARGING){
  418. // port_first_status=PortStatusConstant.FREE;
  419. // }
  420. // if (port_second_status != null&&power==0&&port_second_status==PortStatusConstant.CHARGING){
  421. // port_second_status=PortStatusConstant.FREE;
  422. // }
  423. //判断连续无功率就自动停止
  424. redisCache.setCacheObject(RedisConstant.DEVICE_PORT_STATUS + imei, data, 30, TimeUnit.MINUTES);
  425. if (port_first_status != null) {
  426. checkPort(port_first_status, 1, imei, type);
  427. if (port_first_status == PortStatusConstant.CHARGING) {
  428. checkNoPowerAutoStop(power, imei, 1);
  429. }
  430. }
  431. if (port_second_status != null) {
  432. checkPort(port_second_status, 2, imei, type);
  433. if (port_second_status == PortStatusConstant.CHARGING) {
  434. checkNoPowerAutoStop(power, imei, 2);
  435. }
  436. }
  437. }
  438. //处理停止充电情况
  439. private void handle113(JSONObject jsonObject, String imei) {
  440. //停止充电通知触发情况:1.急停,收到停充时主动要去发停充,所以这里不能处理急停的交易订单;2.手动停充,正常的远程停止指令
  441. // 1.设备已经在接收到云快充指令的时候进行了停充操作,2.结算订单,上报云快充停止回复
  442. try {
  443. JSONObject data = jsonObject.getJSONObject("real_data");
  444. logger.info("{}接收到设备上送113停止充电msg>>" + jsonObject.toString(), imei);
  445. int port = data.getIntValue("port");
  446. byte reson = data.getByte("reason");
  447. QueryWrapper<OrderStatus> orderStatusQueryWrapper = new QueryWrapper<>();
  448. orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1");
  449. OrderStatus statusServiceOne = orderStatusService.getOne(orderStatusQueryWrapper);
  450. if (statusServiceOne == null) {
  451. logger.info("没有待处理订单{}", imei);
  452. return;
  453. }
  454. if (statusServiceOne.getTransactionOrderReplyStatus() == StatusConstant.TRANSACTION_ORDER_REPLY_STATUS_SUCC) {
  455. logger.info("订单状态已上报成功{},id:{}", imei, statusServiceOne.getId());
  456. return;
  457. }
  458. //如果是用户手动停止充电 则不处理状态
  459. if (statusServiceOne.getReasonStopCharging() == TransConstant.APP_REMOTE_STOP) {
  460. logger.info(statusServiceOne.getPileCode() + ":云快充>>>>>>远程停充>>>>");
  461. } else {
  462. //不处理急停
  463. if (reson == 0x01) {
  464. logger.info(statusServiceOne.getPileCode() + ":用户主动停充>>>>>>停充>>>>");
  465. statusServiceOne.setReasonStopCharging(TransConstant.APP_REMOTE_STOP);
  466. } else if (reson == 0x00) {
  467. logger.info(statusServiceOne.getPileCode() + ":设备余额不足>>>>>>停充>>>>");
  468. statusServiceOne.setReasonStopCharging(TransConstant.INSUFFICIENT_BALANCE_EXCEPTION_STOP);
  469. } else if (reson == 0x03) {
  470. logger.info(statusServiceOne.getPileCode() + ":设备充电充满>>>>>>停充>>>>");
  471. statusServiceOne.setReasonStopCharging(TransConstant.SOC_FULL_OF_STOP);
  472. } else {
  473. logger.info(statusServiceOne.getPileCode() + ":设备充电停止>>>>其他>>>");
  474. statusServiceOne.setReasonStopCharging(TransConstant.OTHER_STOP);
  475. }
  476. }
  477. //设置订单已停止充电和结束时间
  478. statusServiceOne.setEndTime(System.currentTimeMillis());
  479. statusServiceOne.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING);
  480. DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(statusServiceOne.getPileCode());
  481. if (deviceConnection == null || deviceConnection.getLoginStatus() != 1) {
  482. //未上报
  483. statusServiceOne.setTransactionOrderReportingActionStatus(StatusConstant.TRANSACTION_ORDER_REPORTING_ACTION_STATUS_NO);
  484. logger.info("socket 未连接 需要重新上报异常上报{}", statusServiceOne.getPileCode());
  485. orderStatusService.updateById(statusServiceOne);
  486. return;
  487. }
  488. byte[] encrypt = new byte[0];
  489. //查询计费模板
  490. QueryWrapper<BillingModel> billingModelQueryWrapper = new QueryWrapper<>();
  491. billingModelQueryWrapper.eq("device_imei", imei);
  492. BillingModel model = billingModelService.getOne(billingModelQueryWrapper);
  493. Map<String, BigDecimal> map = transMoney.compute(port, model, statusServiceOne.getCreateTime(), statusServiceOne.getEndTime());
  494. logger.info(statusServiceOne.getPileCode() + "计算电费" + DataConversion.bytesToHexString(statusServiceOne.getTransOrder()));
  495. encrypt = transactionFlowPushFrame.sendTrans(deviceConnection, statusServiceOne.getTransOrder(), statusServiceOne.getPileCode(), statusServiceOne.getGunsCode(), statusServiceOne.getCreateTime(), statusServiceOne.getEndTime(), model, statusServiceOne.getCard(), map, statusServiceOne.getReasonStopCharging());
  496. if (encrypt == null || encrypt.length <= 0) {
  497. logger.info("订单上送消息异常 需要重新上报{}", statusServiceOne.getPileCode());
  498. orderStatusService.updateById(statusServiceOne);
  499. return;
  500. } else {
  501. logger.info("订单上送成功{}", statusServiceOne.getPileCode());
  502. statusServiceOne.setTransactionOrderReportingActionStatus(StatusConstant.TRANSACTION_ORDER_REPORTING_ACTION_STATUS_OK);
  503. statusServiceOne.setOriginalText(encrypt);
  504. }
  505. boolean res = charngingPushFrame.endStatus(deviceConnection, port, 0x01, 0x00);
  506. if (res) {
  507. //更新远程停止充电
  508. logger.info("停止充电回复成功{}", imei);
  509. statusServiceOne.setStopChargingReply(StatusConstant.STOP_CHARGING_REPLY_OK);
  510. } else {
  511. logger.info("停止充电回复失败{}", imei);
  512. }
  513. orderStatusService.updateById(statusServiceOne);
  514. // //获取一设备状态
  515. // DeviceParam dataParam = new DeviceParam();
  516. // dataParam.setDeviceId(imei);
  517. // dataParam.setCcid(imei);
  518. // deviceControlerService.sendPortDetailCmd(dataParam);
  519. } catch (Exception e) {
  520. logger.info("{}处理113消息异常{}", imei, e.getMessage());
  521. // DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(imei);
  522. // 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);
  523. e.printStackTrace();
  524. }
  525. }
  526. /**
  527. * 设备端口状态转成云快充识别状态
  528. *
  529. * @param portStatus
  530. * @param port
  531. * @param imei
  532. */
  533. private void checkPort(Integer portStatus, int port, String imei, int type) throws Exception {
  534. if (portStatus.equals(PortStatusConstant.FREE)) {
  535. //处理特殊情况之后还要看枪状态变位上送
  536. deviceOnline(portStatus, imei, port, StatusConstant.FREE, StatusConstant.INSERT_GUNS_NO);
  537. return;
  538. }
  539. if (portStatus.equals(PortStatusConstant.CHARGING)) {
  540. deviceOnline(portStatus, imei, port, StatusConstant.CHARGING, StatusConstant.INSERT_GUNS_YES);
  541. return;
  542. }
  543. if (portStatus.equals(PortStatusConstant.DISABLED) || portStatus.equals(PortStatusConstant.FAULT)) {
  544. //禁用或故障上报云快充为故障信息
  545. deviceOnline(portStatus, imei, port, StatusConstant.FAULT, StatusConstant.NO);
  546. return;
  547. }
  548. if (portStatus.equals(PortStatusConstant.INSERT_GUN) || portStatus.equals(PortStatusConstant.BOOKED)) {
  549. deviceOnline(portStatus, imei, port, StatusConstant.FREE, StatusConstant.INSERT_GUNS_YES);
  550. return;
  551. }
  552. if (portStatus.equals(PortStatusConstant.CHARGING_END)) {
  553. deviceOnline(portStatus, imei, port, (byte) StatusConstant.FREE, StatusConstant.INSERT_GUNS_NO);
  554. return;
  555. }
  556. if (portStatus.equals(PortStatusConstant.EMERGENCY_STOP)) {
  557. //急停中按要求需要上报空闲状态;急停保存原始状态
  558. deviceOnline(portStatus, imei, port, (byte) PortStatusConstant.EMERGENCY_STOP, StatusConstant.INSERT_GUNS_NO);
  559. }
  560. }
  561. /**
  562. * 端口状态是7时的特殊处理充满;端口状态是1时特殊处理直接拔枪
  563. *
  564. * @param imei
  565. * @param port
  566. * @param gunsStatus
  567. * @param insertGunStatus
  568. * @param type 指令类型
  569. */
  570. private boolean handleStatus7(String imei, int port, byte gunsStatus, byte insertGunStatus, int type) throws Exception {
  571. logger.info("处理7状态>>>>>>");
  572. QueryWrapper<BillingModel> billingModelQueryWrapper = new QueryWrapper<>();
  573. billingModelQueryWrapper.eq("device_imei", imei);
  574. BillingModel model = billingModelService.getOne(billingModelQueryWrapper);
  575. if (model == null) {
  576. logger.info("无计费模型>>>>>>");
  577. //说明设备不是云快充设备或者还没登录,获取一次103?
  578. DeviceParam deviceParam = new DeviceParam();
  579. deviceParam.setDeviceId(imei);
  580. deviceParam.setCcid(imei);
  581. deviceControlerService.sendPortDetailCmd(deviceParam);
  582. return false;
  583. }
  584. //只有指令116时进入处理
  585. //20240620:所有7状态当充满,116不处理
  586. if (type == NormalChargeConstant.PORT_STATUS) {
  587. return true;
  588. }
  589. if (gunsStatus == PortStatusConstant.CHARGING_END) {
  590. //特殊处理端口状态是7充电已完成(充满),TODO:但是116的端口状态拔枪和充满都是7;103上报是7的话会一只走状态7的处理>就是一只查库看订单状态
  591. QueryWrapper<OrderStatus> orderStatusQueryWrapper = new QueryWrapper<>();
  592. orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1");
  593. OrderStatus one = orderStatusService.getOne(orderStatusQueryWrapper);
  594. //7状态小于30秒内且订单原因不是远程停充
  595. if ((System.currentTimeMillis() - one.getCreateTime()) < 60 * 1000
  596. && one.getReasonStopCharging() != TransConstant.APP_REMOTE_STOP) {
  597. logger.info("启动状态还没变化--->当前7状态不处理");
  598. // //发送一条103消息
  599. // try{
  600. // DeviceParam dataParam = new DeviceParam();
  601. // dataParam.setDeviceId(imei);
  602. // dataParam.setCcid(imei);
  603. // deviceControlerService.sendPortDetailCmd(dataParam);
  604. // logger.info(imei+ ":7状态主动下发103消息");
  605. // }catch (Exception e){
  606. // logger.info(imei+ ":7状态主动下发103消息异常"+e.getMessage());
  607. // }
  608. return true;
  609. }
  610. //7状态:充电完成未拔枪会一直上报,只有当订单完成并回复解析订单成功,7状态当空闲状态上报
  611. if (one.getTransactionOrderReportingActionStatus() == StatusConstant.TRANSACTION_ORDER_REPORTING_ACTION_STATUS_OK
  612. && one.getTransactionOrderReplyStatus() == StatusConstant.TRANSACTION_ORDER_REPLY_STATUS_SUCC) {
  613. return false;
  614. }
  615. //如果当前设备的最新订单状态已经是'已经充满'的原因并且订单现在的情况是'充电结束'说明不需要再处理,已经处理过了,
  616. if (one.getReasonStopCharging() == TransConstant.SOC_FULL_OF_STOP || one.getNowOrderStatus() == StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING) {
  617. return false;
  618. }
  619. //订单充电中,103端口状态2变7:认为充满.//充满情况,因为可能没拔枪113结束充电通知还没上来;手动发停充;在113中处理交易记录上送
  620. // DeviceParam deviceParam = new DeviceParam();
  621. // deviceParam.setDeviceId(imei);
  622. // deviceParam.setCcid(imei);
  623. // deviceControlerService.sendPortDetailCmd(deviceParam);
  624. deviceControlerService.stopCharge(imei, imei, port);
  625. DeviceConnectionMsg deviceConnection = socketHandle.getDeviceConnection(model.getPileCode());
  626. QueryWrapper<DeviceStatus> deviceStatusQueryWrapper = new QueryWrapper<>();
  627. deviceStatusQueryWrapper.eq("device_imei", imei).eq("gun_port", port);
  628. DeviceStatus statusServiceOne = deviceStatusService.getOne(deviceStatusQueryWrapper);
  629. one.setEndTime(System.currentTimeMillis());
  630. //后台计费
  631. //Map<String, BigDecimal> start = transMoney.compute(port, model, one.getCreateTime(), one.getEndTime(),true);
  632. //byte[] encrypt = transactionFlowPushFrame.sendTrans(deviceConnection, one.getTransOrder(), one.getPileCode(), (byte) port, one.getCreateTime(), one.getEndTime(), model, one.getCard(), start, TransConstant.SOC_FULL_OF_STOP);
  633. //one.setOriginalText(encrypt);
  634. if (one.getReasonStopCharging() == 0) {
  635. one.setReasonStopCharging(TransConstant.SOC_FULL_OF_STOP);//充满
  636. }
  637. one.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING);//已结束
  638. one.setStopChargingReply(StatusConstant.STOP_CHARGING_REPLY_NO);//记录为停充回复
  639. one.setTransactionOrderReportingActionStatus(StatusConstant.TRANSACTION_ORDER_REPORTING_ACTION_STATUS_NO);//未送交易
  640. orderStatusService.updateById(one);
  641. } else if (gunsStatus == PortStatusConstant.FREE) {
  642. //特俗处理:校验是不是最新订单是充电中原因没有等等,也就是订单未结束时直接状态成了未插枪状态
  643. QueryWrapper<OrderStatus> orderStatusQueryWrapper = new QueryWrapper<>();
  644. orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1");
  645. OrderStatus one = orderStatusService.getOne(orderStatusQueryWrapper);
  646. if (one == null) {
  647. return false;
  648. }
  649. if (one.getReasonStopCharging() == 0 && one.getNowOrderStatus() == StatusConstant.NOW_ORDER_STATUS_CHARGING) {
  650. //校验通过,说明是直接拔枪了,拔枪设备会主动上报113结束充电通知
  651. one.setEndTime(System.currentTimeMillis());
  652. //手动停充
  653. one.setReasonStopCharging(TransConstant.MANUAL_STOP);
  654. one.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING);
  655. one.setStopChargingReply(StatusConstant.STOP_CHARGING_REPLY_OK);//已停充
  656. orderStatusService.updateById(one);
  657. }
  658. }
  659. return false;
  660. }
  661. /**
  662. * 1.这里接收到消息就是设备在线;2.对状态进行处理,不同类型消息的枪状态不同进行落库;3.并且状态变化的一个变位上送
  663. *
  664. * @param imei 设备imei码
  665. * @param port 设备port(枪号)
  666. * @param gunsStatus 枪状态
  667. */
  668. private void deviceOnline(int portStatus, String imei, int port, byte gunsStatus, byte insertGunStatus) throws Exception {
  669. QueryWrapper<DeviceStatus> deviceStatusQueryWrapper = new QueryWrapper<>();
  670. deviceStatusQueryWrapper.eq("device_imei", imei).eq("gun_port", port);
  671. DeviceStatus statusServiceOne = deviceStatusService.getOne(deviceStatusQueryWrapper);
  672. DeviceStatus statusServiceOneTemp = new DeviceStatus();
  673. //创建设备端口号
  674. if (statusServiceOne != null) {
  675. BeanUtils.copyProperties(statusServiceOne, statusServiceOneTemp);
  676. } else {
  677. //禁用的设备不再上线,只看正常设备
  678. QueryWrapper<Device> deviceQueryWrapper = new QueryWrapper<>();
  679. QueryWrapper<Device> device_imei = deviceQueryWrapper.eq("device_imei", imei).eq("disabled", DeviceOnlineStatus.NORMAL);
  680. Device one = deviceService.getOne(device_imei);
  681. if (one == null) {
  682. logger.info("当前设备imei:" + imei + ",没有绑定ykc桩编码!!!!!!!!!!!!!!!!!!");
  683. return;
  684. }
  685. statusServiceOne = new DeviceStatus();
  686. statusServiceOne.setDeviceImei(imei);
  687. statusServiceOne.setDeviceSn(one.getDeviceSn());
  688. statusServiceOne.setPileCode(one.getPileCode());
  689. statusServiceOne.setGunPort((byte) port);
  690. statusServiceOne.setCreateTime(System.currentTimeMillis());
  691. statusServiceOne.setUpdateTime(System.currentTimeMillis());
  692. statusServiceOne.setOnlineStatus(DeviceOnlineStatus.ONLINE);
  693. statusServiceOne.setUpdateTime(System.currentTimeMillis());
  694. deviceStatusService.saveOrUpdate(statusServiceOne);
  695. }
  696. statusServiceOne.setGunStatus(gunsStatus);
  697. statusServiceOne.setInsertGunStatus(insertGunStatus);
  698. statusServiceOne.setOnlineStatus(DeviceOnlineStatus.ONLINE);
  699. statusServiceOne.setUpdateTime(System.currentTimeMillis());
  700. deviceStatusService.updateById(statusServiceOne);
  701. logger.info("{}设备状态持久化>>>" + statusServiceOne.toString(), imei);
  702. redisCache.setCacheMapValue(port == 1 ? RedisConstant.ONLINE_DEVICE_ONE : RedisConstant.ONLINE_DEVICE_TWO, statusServiceOne.getPileCode(), statusServiceOne);
  703. //为啥要过期20分
  704. redisCache.expire(port == 1 ? RedisConstant.ONLINE_DEVICE_ONE : RedisConstant.ONLINE_DEVICE_TWO, 60 * 1001 * 20, TimeUnit.MILLISECONDS);
  705. DeviceConnectionMsg deviceConnectionMsg = socketHandle.getDeviceConnection(statusServiceOne.getPileCode());
  706. if (deviceConnectionMsg == null || deviceConnectionMsg.getLoginStatus() != Constant.DEVICE_LOGIN_STATUS) {
  707. logger.info("设备{}未登录成功不上报", statusServiceOne.getDeviceImei());
  708. return;
  709. }
  710. QueryWrapper<OrderStatus> orderStatusQueryWrapper = new QueryWrapper<>();
  711. orderStatusQueryWrapper.eq("device_imei", imei).eq("guns_code", port).orderByDesc("create_time").last("limit 1");
  712. OrderStatus one = orderStatusService.getOne(orderStatusQueryWrapper);
  713. //没有充电中的订单
  714. if (one == null || one.getNowOrderStatus() != StatusConstant.NOW_ORDER_STATUS_CHARGING) {
  715. logger.info("没有订单上报空闲{}", imei);
  716. realTimeStatusPushFrame.deviceStatusPush(deviceConnectionMsg, FrameDataSplicing.transactionNum(null, 0), statusServiceOne.getPileCode(), (byte) port, gunsStatus, insertGunStatus, 0, 0, zero, zero, 0);
  717. return;
  718. }
  719. //充电中
  720. if (portStatus == PortStatusConstant.CHARGING) {
  721. byte[] transactionNum = one.getTransOrder();
  722. if (one.getChargingInitStatus() == StatusConstant.CHARGING_INIT_STATUS_NO) {
  723. logger.info("{}变位为充电中且当前订单还没首次上报过初始状态:" + DataConversion.bytesToHexString(transactionNum), imei);
  724. realTimeStatusPushFrame.deviceStatusPush(deviceConnectionMsg, transactionNum, statusServiceOneTemp.getPileCode(), (byte) port, gunsStatus, insertGunStatus, 0, 0, zero, zero, 0);
  725. //这里上报开始充电初始化状态并记录已经上报首次状态
  726. one.setChargingInitStatus(StatusConstant.CHARGING_INIT_STATUS_OK);
  727. orderStatusService.updateById(one);
  728. }
  729. return;
  730. }
  731. //充电结束
  732. if (portStatus == PortStatusConstant.CHARGING_END) {
  733. //7状态小于30秒内且订单原因不是远程停充
  734. if (one.getNowOrderStatus() == StatusConstant.NOW_ORDER_STATUS_CHARGING) {
  735. if ((System.currentTimeMillis() - one.getCreateTime()) < 60 * 1000 && one.getReasonStopCharging() != TransConstant.APP_REMOTE_STOP) {
  736. logger.info("订单60秒内{}不处理7这个状态", one.getPileCode());
  737. return;
  738. } else {
  739. //充电已完成
  740. //发送结束充电命令 顺利的话113会收到 状态还是7
  741. logger.info("订单60秒后{}7状态发送止充电指令", one.getPileCode());
  742. //标记订单为已停充 标记为未上送
  743. one.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING);
  744. one.setEndTime(System.currentTimeMillis());
  745. one.setReasonStopCharging(TransConstant.SOC_FULL_OF_STOP);
  746. orderStatusService.updateById(one);
  747. RpcResult rpcResult = deviceControlerService.stopCharge(imei, imei, port);
  748. return;
  749. }
  750. }
  751. return;
  752. }
  753. //订单还在充电中 但是枪不在充电中状态 就结束订单
  754. if (one.getNowOrderStatus() == StatusConstant.NOW_ORDER_STATUS_CHARGING) {
  755. logger.info("{}枪非充电中状态,结束订单状态 等待任务重试上报订单", one.getPileCode());
  756. one.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING);
  757. one.setEndTime(System.currentTimeMillis());
  758. one.setReasonStopCharging(TransConstant.OTHER_STOP);
  759. orderStatusService.updateById(one);
  760. }
  761. logger.info("上传空闲状态{}",imei);
  762. realTimeStatusPushFrame.deviceStatusPush(deviceConnectionMsg, FrameDataSplicing.transactionNum(null, 0), statusServiceOne.getPileCode(), (byte) port, gunsStatus, insertGunStatus, 0, 0, zero, zero, 0);
  763. }
  764. }