MsgCharngingRunner.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package com.tmzn.devicelinkykc.taskQueue.runner;
  2. import com.alibaba.fastjson2.JSONObject;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.tmzn.devicelinkykc.constant.Constant;
  5. import com.tmzn.devicelinkykc.constant.DeviceOnlineStatus;
  6. import com.tmzn.devicelinkykc.constant.RedisConstant;
  7. import com.tmzn.devicelinkykc.constant.ykc.StatusConstant;
  8. import com.tmzn.devicelinkykc.constant.ykc.TransConstant;
  9. import com.tmzn.devicelinkykc.entity.BillingModel;
  10. import com.tmzn.devicelinkykc.entity.Device;
  11. import com.tmzn.devicelinkykc.entity.DeviceStatus;
  12. import com.tmzn.devicelinkykc.entity.OrderStatus;
  13. import com.tmzn.devicelinkykc.frameMsg.TransMoney;
  14. import com.tmzn.devicelinkykc.frameMsg.frameType.HeartFrameSend;
  15. import com.tmzn.devicelinkykc.frameMsg.frameType.LoginFrame;
  16. import com.tmzn.devicelinkykc.frameMsg.frameType.RealTimeStatusPushFrame;
  17. import com.tmzn.devicelinkykc.frameMsg.frameType.TransactionFlowPushFrame;
  18. import com.tmzn.devicelinkykc.message.DeviceMsgHandle;
  19. import com.tmzn.devicelinkykc.redis.RedisCache;
  20. import com.tmzn.devicelinkykc.service.*;
  21. import com.tmzn.devicelinkykc.socket.DeviceConnectionMsg;
  22. import com.tmzn.devicelinkykc.socket.SocketHandle;
  23. import com.tmzn.devicelinkykc.transdata.entity.DeviceParam;
  24. import lombok.extern.slf4j.Slf4j;
  25. import org.springframework.beans.factory.annotation.Autowired;
  26. import org.springframework.scheduling.annotation.Async;
  27. import org.springframework.stereotype.Component;
  28. import java.math.BigDecimal;
  29. import java.time.Instant;
  30. import java.time.ZoneId;
  31. import java.util.HashMap;
  32. import java.util.List;
  33. import java.util.Map;
  34. import java.util.Set;
  35. import java.util.concurrent.TimeUnit;
  36. import java.util.stream.Collectors;
  37. @Component
  38. @Slf4j(topic = "MsgChargingRunner")
  39. public class MsgCharngingRunner {
  40. @Autowired
  41. private DeviceService deviceService;
  42. @Autowired
  43. private LoginFrame loginFrame;
  44. @Autowired
  45. private RedisCache redisCache;
  46. @Autowired
  47. private RealTimeStatusPushFrame realTimeStatusPushFrame;
  48. @Autowired
  49. private OrderStatusService orderStatusService;
  50. @Autowired
  51. private BillingModelService billingModelService;
  52. @Autowired
  53. private TransMoney transMoney;
  54. @Autowired
  55. private DeviceStatusService deviceStatusService;
  56. @Autowired
  57. private SocketHandle socketHandle;
  58. @Autowired
  59. DeviceMsgHandle deviceMsgHandle;
  60. @Autowired
  61. private DeviceControlerService deviceControlerService;
  62. @Autowired
  63. private TransactionFlowPushFrame transactionFlowPushFrame;
  64. private static final BigDecimal zero = new BigDecimal("0");
  65. @Async("charngingTaskAsyncPool")
  66. public void chargingMsg(Map<String, DeviceConnectionMsg> map) {
  67. log.info("======充电中数据上报检测=====");
  68. //这边需要给充电中的状态进行查询流水号,流水号是由云快充启动充电时的下发指令带来存库的,
  69. if (map.size() < 1) {
  70. return;
  71. }
  72. //查找所有充电中的订单
  73. QueryWrapper<OrderStatus> queryWrapper = new QueryWrapper<>();
  74. queryWrapper.eq("now_order_status", 0); //充电中状态上报
  75. //忽略10天前的订单
  76. long nowTime = System.currentTimeMillis();
  77. long tm = nowTime-86400*10*1000;
  78. //10天前的就算了
  79. queryWrapper.gt("create_time",tm ); //充电中状态上报
  80. queryWrapper.orderByDesc("id");
  81. //查询所有充电中设备的最新的订单记录,来上报设备状态消息.........?????????????????
  82. List<OrderStatus> list = orderStatusService.list(queryWrapper);
  83. if (list.isEmpty()) {
  84. log.info("无充电中订单上报");
  85. return;
  86. }
  87. // Set<String> devicePileCodes = map.keySet();
  88. // QueryWrapper<BillingModel> billWapper = new QueryWrapper<>();
  89. // billWapper.in("pile_code", devicePileCodes);
  90. // List<BillingModel> billingModels = billingModelService.list(billWapper);
  91. // if (billingModels.size() < 1) {
  92. // log.info("无计费可上报模型");
  93. // return;
  94. // }
  95. // Map<String, BillingModel> billingModelMap = billingModels.stream()
  96. // .collect(Collectors.toMap(BillingModel::getPileCode, billingModel -> billingModel));
  97. //只上传最近的订单
  98. Map<String, Boolean> dealMap = new HashMap<>();
  99. list.forEach(item -> {
  100. try {
  101. //检查设备是否在线
  102. QueryWrapper<DeviceStatus> deviceStatusQueryWrapper = new QueryWrapper<>();
  103. deviceStatusQueryWrapper.eq("pile_code", item.getPileCode());
  104. deviceStatusQueryWrapper.eq("gun_port", item.getGunsCode());
  105. // deviceStatusQueryWrapper.last("limit 1");
  106. DeviceStatus statusServiceOne = deviceStatusService.getOne(deviceStatusQueryWrapper);
  107. if(statusServiceOne != null && statusServiceOne.getOnlineStatus()==StatusConstant.OFFLINE){
  108. log.info("{}设备已离线不上报",item.getPileCode());
  109. return;
  110. }
  111. QueryWrapper<BillingModel> billWapper = new QueryWrapper<>();
  112. billWapper.eq("pile_code", item.getPileCode());
  113. billWapper.eq("device_imei", item.getDeviceImei());
  114. BillingModel b = billingModelService.getOne(billWapper);
  115. if (b == null) {
  116. log.info("{}上报充电中未匹配计费模型", item.getPileCode());
  117. return;
  118. }
  119. if(!deviceMsgHandle.checkConnection(item.getPileCode(),item.getDeviceImei())){
  120. log.info("{}重新连接句柄不存在等待下次执行",item.getPileCode());
  121. return;
  122. }
  123. DeviceConnectionMsg deviceConnectionMsg = map.get(item.getPileCode());
  124. String k = item.getPileCode() + "_" + item.getGunsCode();
  125. if (dealMap.containsKey(k)) {
  126. log.info("{}本轮已上报充电中只报最后一个订单", k);
  127. } else {
  128. reportOne(item, b, deviceConnectionMsg);
  129. dealMap.put(k, true);
  130. }
  131. } catch (Exception e) {
  132. log.info("{}上报充电中异常", item.getPileCode()+e.getMessage());
  133. e.printStackTrace();
  134. }
  135. });
  136. log.info("======Charging status push task ending=====");
  137. }
  138. //尝试下发103 避免下发太频繁
  139. public void try103(OrderStatus orderStatus){
  140. String key = "try103_charging:_"+orderStatus.getDeviceImei()+"_"+orderStatus.getGunsCode();
  141. if(redisCache.hasKey(key)){
  142. log.info("{}-{}忽略103", orderStatus.getPileCode(), orderStatus.getGunsCode());
  143. return;
  144. }
  145. log.info("{}-{}-5分钟内无状态103", orderStatus.getPileCode(), orderStatus.getGunsCode());
  146. deviceControlerService.sendImeiDetail(orderStatus.getDeviceImei());
  147. int timeout = 60;
  148. //订单3分钟内一分钟请求一次103 否则就1分钟半获取一次
  149. if((System.currentTimeMillis()-orderStatus.getCreateTime())<180*1000){
  150. timeout = 60;
  151. }
  152. redisCache.setCacheObject(key, System.currentTimeMillis(),timeout, TimeUnit.SECONDS);
  153. }
  154. //停止一个订单
  155. public void stopOneOrder(OrderStatus orderStatus){
  156. log.info("{}--id:{}设置订单关闭",orderStatus.getPileCode(),orderStatus.getId());
  157. int port = (int) orderStatus.getGunsCode();
  158. orderStatus.setEndTime(System.currentTimeMillis() - 1000 * 60 * 2);
  159. orderStatus.setNowOrderStatus(StatusConstant.NOW_ORDER_STATUS_CHARGING_ENDING);
  160. orderStatusService.updateById(orderStatus);
  161. deviceControlerService.stopCharge(orderStatus.getDeviceImei(), orderStatus.getDeviceImei(), port);
  162. }
  163. public void reportOne(OrderStatus orderStatus, BillingModel billingModel, DeviceConnectionMsg deviceConnectionMsg) {
  164. try103(orderStatus);
  165. //获取订单状态
  166. String cacheKey = orderStatus.getGunsCode() == 1 ? RedisConstant.ONLINE_DEVICE_ONE : RedisConstant.ONLINE_DEVICE_TWO;
  167. DeviceStatus deviceStatus = redisCache.getCacheMapValue(cacheKey, orderStatus.getPileCode());
  168. //每次下发一次103
  169. long t = System.currentTimeMillis()-orderStatus.getCreateTime();
  170. int port = (int) orderStatus.getGunsCode();
  171. if(deviceStatus==null){
  172. if(t<10*60*1000){
  173. return;
  174. }else{
  175. log.info("{}-{}无10分钟还没有记录要停止充电", orderStatus.getPileCode(), orderStatus.getGunsCode());
  176. orderStatus.setReasonStopCharging(TransConstant.OTHER_STOP);
  177. stopOneOrder(orderStatus);
  178. }
  179. return;
  180. }
  181. if(deviceStatus.getGunStatus() != StatusConstant.CHARGING){
  182. if(t<5*60*1000){
  183. log.info("{}-{}-5分钟内还未变充电状态忽略", orderStatus.getPileCode(), orderStatus.getGunsCode());
  184. return;
  185. }else{
  186. log.info("{}-{}-5分钟后还不是充电状态录要停止充电", orderStatus.getPileCode(), orderStatus.getGunsCode());
  187. //状态那我为
  188. orderStatus.setReasonStopCharging(TransConstant.OTHER_STOP);
  189. stopOneOrder(orderStatus);
  190. return;
  191. }
  192. }
  193. //上送充电状态
  194. JSONObject statusJSON = redisCache.getCacheObject(RedisConstant.DEVICE_PORT_STATUS + deviceStatus.getDeviceImei());
  195. if(statusJSON==null){
  196. log.info("无最近103数据{}",orderStatus.getPileCode());
  197. try103(orderStatus);
  198. return;
  199. }
  200. Integer voltage;
  201. Integer power;
  202. if(port==1){
  203. voltage = statusJSON.getInteger("voltage");
  204. }else{
  205. voltage = statusJSON.getInteger("voltage_1");
  206. if(voltage==null){
  207. voltage = statusJSON.getInteger("voltage");
  208. }
  209. }
  210. if(port == 1){
  211. power = statusJSON.getInteger("power");
  212. }else{
  213. power = statusJSON.getInteger("power_1");
  214. }
  215. if(power==null){
  216. power = 0;
  217. }
  218. if(voltage==null){
  219. voltage = 0;
  220. }
  221. //计算实时数据
  222. long endTime = System.currentTimeMillis();
  223. //算电量
  224. Map<String, BigDecimal> start;
  225. String transCacheKey = "ChargingTrans:"+orderStatus.getId();
  226. if(redisCache.hasKey(transCacheKey)){
  227. Map<String, BigDecimal> cached = redisCache.getCacheObject(transCacheKey);
  228. start = new HashMap<>(cached);
  229. }else{
  230. //缓存120秒避免重复计算电量
  231. try {
  232. start = transMoney.compute(port, billingModel, orderStatus.getCreateTime(), endTime,orderStatus);
  233. } catch (Exception e) {
  234. e.printStackTrace();
  235. log.error("计算订单异常{},{}",orderStatus.getPileCode(),e.getMessage());
  236. return;
  237. }
  238. redisCache.setCacheObject(transCacheKey, start, 90, TimeUnit.SECONDS);
  239. }
  240. BigDecimal elec = start.get("elec");
  241. BigDecimal money = start.get("money");
  242. if (elec.equals(new BigDecimal("0.0000"))) {
  243. elec = elec.add(new BigDecimal("0.0001").setScale(4, BigDecimal.ROUND_DOWN));
  244. }
  245. log.info("{}-{}-{}充电中=>实时elec:{}>>>实时金额>>>{}=>p:{},v:{}" ,orderStatus.getPileCode(),port,elec,orderStatus.getGunsCode(),money,power,voltage);
  246. //????????????????????????????
  247. if (money.compareTo(orderStatus.getStartMoney()) > 0) {
  248. //余额没有了,停充
  249. orderStatus.setReasonStopCharging(TransConstant.INSUFFICIENT_BALANCE_EXCEPTION_STOP);
  250. stopOneOrder(orderStatus);
  251. log.info("{},{},{}实时状态校验时余额不足{}>>>>>>停充>>>>",orderStatus.getPileCode(),orderStatus.getGunsCode(),orderStatus.getTransOrder(),money);
  252. return;
  253. }
  254. if(orderStatus.getStartMoney().subtract(money).compareTo(new BigDecimal("0.50")) < 0) {
  255. orderStatus.setReasonStopCharging(TransConstant.INSUFFICIENT_BALANCE_EXCEPTION_STOP);
  256. stopOneOrder(orderStatus);
  257. log.info("{},{},{}实时状态校验时余额不足1{}>>>>>>停充>>>>",orderStatus.getPileCode(),orderStatus.getGunsCode(),orderStatus.getTransOrder(),money);
  258. return;
  259. }
  260. int mi = (int) (System.currentTimeMillis() - orderStatus.getCreateTime()) / 1000 / 60;
  261. realTimeStatusPushFrame.deviceStatusPush(deviceConnectionMsg, orderStatus.getTransOrder(), deviceStatus.getPileCode(), deviceStatus.getGunPort(), deviceStatus.getGunStatus(), deviceStatus.getInsertGunStatus(), voltage, power, elec, money, mi);
  262. log.info("↑↑↑{},{},{}充电中实时状态上报 ",orderStatus.getPileCode(),orderStatus.getGunsCode(),orderStatus.getId());
  263. }
  264. }