package com.zy.acs.manager.core.scheduler; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.github.xingshuangs.iot.protocol.modbus.service.ModbusRtuOverTcp; import com.zy.acs.charge.ChargeCoreService; import com.zy.acs.common.constant.RedisConstant; import com.zy.acs.common.enums.AgvStatusType; import com.zy.acs.common.utils.RedisSupport; import com.zy.acs.framework.common.Cools; import com.zy.acs.framework.common.DateUtils; import com.zy.acs.manager.common.config.UplinkProperties; import com.zy.acs.manager.core.integrate.wms.FaultReportService; import com.zy.acs.manager.core.integrate.wms.TaskReportService; import com.zy.acs.manager.core.service.ChargeService; import com.zy.acs.manager.core.service.MainLockWrapService; import com.zy.acs.manager.manager.entity.*; import com.zy.acs.manager.manager.enums.*; import com.zy.acs.manager.manager.service.*; import com.zy.acs.manager.system.service.ConfigService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.Instant; import java.time.ZoneId; import java.util.Date; import java.util.List; import java.util.Optional; import java.util.Set; /** * judge whether agv go to funcSta which be charging or standby * Created by vincent on 2023/9/9 */ @Slf4j @Component public class MaintainScheduler { private final RedisSupport redis = RedisSupport.defaultRedisSupport; @Autowired private AgvService agvService; @Autowired private AgvDetailService agvDetailService; @Autowired private FuncStaService funcStaService; @Autowired private UplinkProperties uplinkProperties; @Autowired private MainLockWrapService mainLockWrapService; @Autowired private TaskService taskService; @Autowired private ConfigService configService; @Autowired private AgvModelService agvModelService; @Autowired private SegmentService segmentService; @Autowired private TaskReportService taskReportService; @Autowired private VehFaultRecService vehFaultRecService; @Autowired private FaultReportService faultReportService; @Autowired private ChargeService chargeService; @Autowired private ChargeCoreService chargeCoreService; @Scheduled(cron = "0/5 * * * * ? ") private synchronized void autoCharge() { if (!configService.getVal("TaskAssignMode", Boolean.class)) { return; } List agvList = agvService.list(new LambdaQueryWrapper().eq(Agv::getStatus, StatusType.ENABLE.val)); for (Agv agv : agvList) { AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId()); AgvModel agvModel = agvModelService.getByAgvId(agv.getId()); if (null == agvDetail || null == agvDetail.getSoc() || null == agvDetail.getAgvStatus()) { continue; } if (agvDetail.getAgvStatus().equals(AgvStatusType.CHARGE)) { continue; } if (agvDetailService.isPowerLoss(agv, agvDetail, agvModel)) { if (0 < taskService.count(new LambdaQueryWrapper() .eq(Task::getAgvId, agv.getId()) .and(i -> { i.eq(Task::getTaskSts, TaskStsType.WAITING.val()) .or().eq(Task::getTaskSts, TaskStsType.ASSIGN.val()) .or().eq(Task::getTaskSts, TaskStsType.PROGRESS.val()); }) )) { continue; } if (0 < segmentService.count(new LambdaQueryWrapper() .eq(Segment::getAgvId, agv.getId()) .and(i -> { // i.eq(Segment::getState, SegmentStateType.WAITING.toString()).or() i.eq(Segment::getState, SegmentStateType.RUNNING.toString()); }) )) { continue; } mainLockWrapService.buildMinorTask(agv.getId(), TaskTypeType.TO_CHARGE, null, null); } } } @Scheduled(cron = "0/1 * * * * ? ") // @Scheduled(cron = "0 */2 * * * ? ") private synchronized void autoStandby() { if (!configService.getVal("TaskAssignMode", Boolean.class)) { return; } if (!configService.getVal("automaticStandbyPosition", Boolean.class)) { return; } List agvList = agvService.list(new LambdaQueryWrapper().eq(Agv::getStatus, StatusType.ENABLE.val)); for (Agv agv : agvList) { AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId()); AgvModel agvModel = agvModelService.getByAgvId(agv.getId()); if (null == agvDetail || null == agvDetail.getSoc() || null == agvDetail.getAgvStatus() || null == agvDetail.getRecentCode()) { continue; } // low battery status, that need to go to charge // if (agvDetailService.isPowerLoss(agv, agvDetail, agvModel)) { // continue; // } // 存在充电标记,跳过 if (redis.getMap(RedisConstant.AGV_CHARGE_FLAG, agv.getUuid()) != null) { continue; } // is charging ? if (agvDetail.getAgvStatus().equals(AgvStatusType.CHARGE)) { if (agvDetail.getSoc() < agvModel.getQuaBattery()) { continue; } } // already on standby code ? if (0 < funcStaService.count(new LambdaQueryWrapper() .eq(FuncSta::getType, FuncStaType.STANDBY.toString()) .eq(FuncSta::getCode, agvDetail.getRecentCode()) )) { continue; } // has running tasks ? if (0 < taskService.count(new LambdaQueryWrapper() .eq(Task::getAgvId, agv.getId()) .and(i -> { i.eq(Task::getTaskSts, TaskStsType.WAITING.val()) .or().eq(Task::getTaskSts, TaskStsType.ASSIGN.val()) .or().eq(Task::getTaskSts, TaskStsType.PROGRESS.val()); }) )) { continue; } // the time between the latest task and now that be must more that @{param} seconds // if (!Optional.ofNullable((Boolean) redis.getObject(RedisConstant.AGV_TO_STANDBY_FLAG, agv.getUuid())).orElse(false)) { Integer intervalOfAutoStandby = configService.getVal("intervalOfAutoStandby", Integer.class); if (null != intervalOfAutoStandby && intervalOfAutoStandby > 0) { Task latestTask = taskService.findLatestTask(agv.getId(), null); if (null != latestTask) { long seconds = DateUtils.diffToSeconds( Optional.ofNullable(latestTask.getEndTime()).orElse(latestTask.getUpdateTime()) , new Date() ); if (seconds < intervalOfAutoStandby) { continue; } } } else { continue; } // } mainLockWrapService.buildMinorTask(agv.getId(), TaskTypeType.TO_STANDBY, null, null); } } @Scheduled(cron = "0/3 * * * * ? ") private void reportTaskToUplink() { if (!uplinkProperties.getEnabled()) { return; } List taskList = taskService.list(new LambdaQueryWrapper() .in(Task::getUplinkSts, TaskUplinkStateType.PENDING.toString(), TaskUplinkStateType.FAILED.toString()) .eq(Task::getTaskSts, TaskStsType.COMPLETE.val()) .isNotNull(Task::getBusId) ); if (Cools.isEmpty(taskList)) { return; } for (Task task : taskList) { boolean finished = taskReportService.reportFinished(task); if (finished) { task.setUplinkSts(TaskUplinkStateType.SUCCESS.toString()); } else { log.error("failed to report task to uplink: {}", task.getSeqNum()); task.setUplinkSts(TaskUplinkStateType.FAILED.toString()); } taskService.updateById(task); } } @Scheduled(cron = "0/5 * * * * ? ") private synchronized void releaseFuncSta() { List funcStaList = funcStaService.list(new LambdaQueryWrapper().eq(FuncSta::getState, FuncStaStateType.OCCUPIED.toString())); for (FuncSta funcSta : funcStaList) { boolean beIdle = funcStaService.isCanBeIdle(funcSta); if (beIdle) { funcSta.setState(FuncStaStateType.IDLE.toString()); funcSta.setUpdateTime(new Date()); if (!funcStaService.updateById(funcSta)) { log.error("FuncSta [{}] failed to be idle !!!", funcSta.getName()); } } } } @Scheduled(cron = "0/3 * * * * ? ") private void reportFault() { String reportFaultUrl = configService.getVal("reportFaultUrl", String.class); if (Cools.isEmpty(reportFaultUrl)) { return; } List vehFaultRecList = vehFaultRecService.list((new LambdaQueryWrapper().eq(VehFaultRec::getState, VehFaultRecStateType.PENDING).ge(VehFaultRec::getHappenTime, Instant.now().minusSeconds(3).atZone(ZoneId.systemDefault()).toLocalDateTime()))); if (Cools.isEmpty(vehFaultRecList)) { return; } for (VehFaultRec vehFaultRec : vehFaultRecList) { boolean finished = faultReportService.reportFinished(vehFaultRec, reportFaultUrl); if (finished) { vehFaultRec.setState(VehFaultRecStateType.REPORT_SUCCESS.name()); } else { log.error("failed to report vehFaultRec to uplink"); vehFaultRec.setState(VehFaultRecStateType.REPORT_FAILED.name()); } vehFaultRecService.updateById(vehFaultRec); } } /** * 调度对接充电桩 */ @Scheduled(cron = "0/5 * * * * ? ") private synchronized void startCharge() { Set mapKeys = redis.getMapKeys(RedisConstant.AGV_CHARGE_FLAG); for (String key : mapKeys) { Integer status = redis.getMap(RedisConstant.AGV_CHARGE_FLAG, key); if (null == status) { continue; } AgvDetail agvDetail = agvDetailService.selectByAgvNo(key); FuncSta funcSta = funcStaService.getByCodeAndType(agvDetail.getCode(), FuncStaType.CHARGE.toString()); ModbusRtuOverTcp modbusTcp = chargeService.get(funcSta.getUuid()); if (null == agvDetail || null == agvDetail.getSoc() || null == agvDetail.getAgvStatus() || funcSta == null || null == modbusTcp) { continue; } switch (status) { case 1: // 后退信号消失,说明马达正在前进 if (chargeCoreService.checkBackwardRelayOffline(modbusTcp)) { chargeCoreService.startCharging(modbusTcp); } if (chargeCoreService.checkForwardRelayOnline(modbusTcp)) { double current = chargeCoreService.getCurrent(modbusTcp); double voltage = chargeCoreService.getVoltage(modbusTcp); if (current > 0 && voltage > 0) { redis.setMap(RedisConstant.AGV_CHARGE_FLAG, key, 2); log.info("charge complete"); } else { log.info("read charge current and voltage: {},{}", current, voltage); } } break; case 2: AgvModel agvModel = agvModelService.getByAgvId(agvDetail.getAgvId()); if (agvDetail.getSoc() >= agvModel.getQuaBattery()) { // 前进信号存在,说明机械臂未伸回 if (chargeCoreService.checkForwardRelayOnline(modbusTcp)) { chargeCoreService.stopCharging(modbusTcp); } if (chargeCoreService.checkBackwardRelayOffline(modbusTcp)) { redis.deleteMap(RedisConstant.AGV_CHARGE_FLAG, key); log.info("charge over"); } } break; default: log.error("charge status error: {}", status); break; } } } }