package com.ssi.task; import com.alibaba.fastjson.JSONObject; import com.ssi.constant.URL; import com.ssi.entity.VmsChargingEquipmentInfo; import com.ssi.entity.VmsTosOrders; import com.ssi.constant.enums.ElecLevelEnum; import com.ssi.model.RedisDataModel; import com.ssi.model.VehicleSocketDataCacheQueueModel; import com.ssi.service.VmsChargingEquipmentInfoService; import com.ssi.service.VmsTosOrdersService; import com.ssi.service.platform.WebSocketDataService; import com.ssi.utils.RestTemplateUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; /** * @author SunnyHotz * @PackageName:com.ssi.task * @ClassName:ChargingManageTask * @Description: * @date 2022/7/18 11:43 */ @Slf4j @Component public class ChargingManageTask { @Value("${spring.websocket.pushInPool.enable:false}") private boolean pushInPool; @Value("${harbor.command.info_key:harbor:command:vin:info}") private String infoKey; @Value("${command-url}") private String odbuUrl; @Value("${order.latestOrderKeyPrefix:harbor:command:status}") private String latestOrderKeyPrefix; @Value("${ivccs.vehicle.latestData.redis.prefix:ivccs:vms:vehicle:latest:}") private String lastVehicleKeyPrefix; @Autowired private RedisDataModel redisDataModel; @Autowired private WebSocketDataService webSocketDataService; @Autowired private VmsTosOrdersService vmsTosOrdersService; @Autowired(required = false) private VehicleSocketDataCacheQueueModel vehicleSocketDataCacheQueueModel; @Autowired private VmsChargingEquipmentInfoService chargingEquipmentInfoService; private AtomicInteger threadNum = new AtomicInteger(0); //前往充电车辆 private final static List chargingVehicleList = new CopyOnWriteArrayList<>(); //充电中车辆 private final static List onChargingVehicleList = new CopyOnWriteArrayList<>(); //需紧急充电 private final static ArrayList> chargingE1VehicleList = new ArrayList<>(); //非紧急充电 private final static ArrayList> chargingE2VehicleList = new ArrayList<>(); //可执行车辆 private final static ArrayList usualE3VehicleList = new ArrayList<>(); //用车需求队列 private final static Deque waitTaskDeque = new ArrayDeque<>(); //锁定充电桩 private final static ArrayList lockedChargingEquipments = new ArrayList<>(); // @Scheduled(cron = "") public void invokeForCharging() throws Exception { //获取空闲的充电枪 List chargingEquipmentInfos = chargingEquipmentInfoService.qryFreeEquipment(1); if(CollectionUtils.isEmpty(chargingEquipmentInfos)){ return; } //过滤已锁定充电桩 chargingEquipmentInfos = chargingEquipmentInfos.stream().filter(e -> !lockedChargingEquipments.contains(e.getEquipmentId())).distinct().collect(Collectors.toList()); //待充电车辆优先级排序,获取匹配车辆 List> aimToChargingList = getAdapterVehicle(chargingEquipmentInfos.size()); if(CollectionUtils.isEmpty(aimToChargingList)){ return; } for (int i = 0; i < aimToChargingList.size(); i++) { //下发调度去充电站指令 JSONObject jsonObject = sendTaskOrder(aimToChargingList.get(i), chargingEquipmentInfos.get(i)); if(1 == jsonObject.getIntValue("code")){ chargingVehicleList.add(jsonObject); lockedChargingEquipments.add(chargingEquipmentInfos.get(i).getEquipmentId()); } } } /** * 定时检测需充电车辆,其实这样并不友好, 因为电量是动态变化 */ @Scheduled(cron="0 0/1 * * * ?") private synchronized void needChargingVehicle() { //获取需加入充电队列的在线托盘 List> onlineAutoVehicles = getOnlineAutoVehicle(); if (onlineAutoVehicles.isEmpty()) return; onlineAutoVehicles.sort((o1, o2) -> { Integer soc1 = Objects.isNull(o1.get("soc"))?Integer.valueOf(100):(Integer)o1.get("soc"); Integer soc2 = Objects.isNull(o2.get("soc"))?Integer.valueOf(100):(Integer)o2.get("soc"); return (soc1-soc2); }); //清空缓存,重新填装 chargingE1VehicleList.clear(); chargingE2VehicleList.clear(); onlineAutoVehicles.stream().forEach(e->{ if((Integer)e.get("soc")0){ vin = usualE3VehicleList.remove(0); }else if(chargingE2VehicleList.size()>0){ Map map = chargingE2VehicleList.remove(chargingE2VehicleList.size() - 1); vin = Objects.nonNull(map.get("vin"))?String.valueOf(map.get("vin")):""; }else if(onChargingVehicleList.size()>0){ //查询充电桩充电量接口,获取当前电量》40 且当前电量最多的一个 vin = getMaxSocVehicle(vin); } //调用下电接口,并下发任务信息 return vin; } /** *正式充电回调 */ public void invokeForCharged(){ //获取当前充电车辆 Iterator iterator = chargingVehicleList.iterator(); while (iterator.hasNext()){ JSONObject next = iterator.next(); //调用充电桩接口判断是否充电完成 //调用车辆远程启动 //离开充电区 } } private String getMaxSocVehicle(String vin) { TreeMap socMap = new TreeMap<>(); for (int i = 0; i < onChargingVehicleList.size(); i++) { Map vehicleStatus = redisDataModel.getJson2Map(String.format("%s:%s-%s", lastVehicleKeyPrefix, onChargingVehicleList.get(i), "harbor_D00A")); socMap.put((Integer) vehicleStatus.get("soc"),i); } Map.Entry socEntry = socMap.firstEntry(); if(socEntry.getKey()>=40){ int index = socEntry.getValue(); vin = onChargingVehicleList.remove(index); } return vin; } private List> getAdapterVehicle(Integer avaliable) { List> result = new ArrayList<>(); for(int i=0; i obj = null; if(chargingE1VehicleList.size()>0){ obj = chargingE1VehicleList.remove(0); }else if(chargingE2VehicleList.size()>0){ obj = chargingE2VehicleList.remove(0); } if(obj!=null){ result.add(obj); } } return result; } private JSONObject sendTaskOrder(Map v, VmsChargingEquipmentInfo equipmentInfo) { JSONObject param = new JSONObject(); String temp = URL.To_ODBU_URL; param.put("vin", v.get("vin"));// 车辆编号 param.put("taskSource", 2);// 1-TOS下发;2-手动下发;3-VMS下发 param.put("taskNo", UUID.randomUUID().toString().replace("-", ""));// 任务编号 param.put("seq", v.get("seq"));// 序号 param.put("taskType", 3);// 任务编号 6 停车 3 充电 param.put("vehicleTaskLabel", 5); //车辆任务标签,1:装船;2:卸船;3:堆场间搬移;4:停车,5:充电,6:临时停车 param.put("taskLocationType", 6);// "任务类型, 1-去堆场(装箱或卸箱);2-去停车点(上扭锁,解扭锁,停车);3-去固定停车区;4-去临时停车区;5-去桥吊(装箱或卸箱);6-去充电" param.put("taskOperation", 0); // 任务操作:0-开始 1-取消 2-强制取消 // param.put("parkingAreaNo", equipmentInfo.getEquipmentId());// 停车区编号,缓冲区编号,充电位编号 param.put("latitude", equipmentInfo.getEquipmentLat());// 目的地维度 param.put("longitude", equipmentInfo.getEquipmentLng());// 目的地经度 String result = RestTemplateUtil.post(String.format("%s%s", odbuUrl, temp), param.toString(), null); JSONObject jsonObject = JSONObject.parseObject(result); jsonObject.put("taskNo",param.getString("taskNo")); jsonObject.put("vin", v.get("vin")); return jsonObject; } private List> getOnlineAutoVehicle() { List> resultList= new ArrayList<>(); Map> messages;//全部 //获取在线车辆 messages = webSocketDataService.realTimeDataAll(); if (messages.isEmpty()) return Collections.EMPTY_LIST; //清空非充电车辆重新填充 usualE3VehicleList.clear(); messages.entrySet().stream().filter(entry->{ if(Objects.isNull(entry.getValue())) return false; return "1".equals(String.valueOf(entry.getValue().get("isOnline"))); }).forEach(entry -> { String keys = String.format("%s:%s", infoKey, entry.getKey()); String vehicleMap = redisDataModel.get(keys); if(vehicleMap != null) { //判断redis是否存在 JSONObject obj = JSONObject.parseObject(vehicleMap); Integer vehicleType =(Integer) obj.get("vehicleType");//1:X69B ,2:X69C,3:有人集卡两秒 if (vehicleType != 3){ //判断是否符合充电条件 if(needCharging(entry.getValue())) { resultList.add(entry.getValue()); }else { usualE3VehicleList.add(entry.getKey()); } } } }) ; return resultList; } private boolean needCharging(Map value) { //当前是否安排任务 Map taskStatus = vmsTosOrdersService.getOrdersByVin(String.valueOf(value.get("vin"))); if(String.valueOf(taskStatus.get("workStatus")).equals("0")){ //正在执行任务,逻辑暂不处理 return false; } //当前是否在充电中 List vins = chargingVehicleList.stream().map(e -> e.getString("vin")).collect(Collectors.toList()); if(vins.contains(String.valueOf(value.get("vin")))){ return false; } //电量判断 Integer powerReserve = Objects.nonNull(value.get("soc")) ? (Integer) value.get("soc") : Integer.valueOf(100); if(powerReserve<= ElecLevelEnum.LEVEL_E2.getValue()){ return true; } return false; } class TaskInnvoker implements Runnable{ @Override public void run() { threadNum.incrementAndGet(); long begin = System.currentTimeMillis(); while (chargingVehicleList.size()>0){ Iterator iterator = chargingVehicleList.iterator(); while (iterator.hasNext()){ JSONObject next = iterator.next(); //判断是否到达充电站 List orders = vmsTosOrdersService.lambdaQuery().eq(VmsTosOrders::getTaskNo, next.getString("taskNo")).list(); if(CollectionUtils.isEmpty(orders)){ continue; } Integer status = orders.get(0).getStatus(); //到达充电站调用充电接口 if(3==status){ //调用充电接口 //列表移除 iterator.remove(); onChargingVehicleList.add(next.getString("vin")); } } if((System.currentTimeMillis() - begin) > 60*60*1000){ //超时没有达到充电桩 } //wait try { Thread.currentThread().wait(30000); }catch (Exception e){ log.error("调用充电接口出错====>",e); } } threadNum.decrementAndGet(); } } }