package com.zy.asrs.service.impl; import com.alibaba.excel.util.StringUtils; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.zy.asrs.entity.*; import com.zy.asrs.entity.mes.TransArrivalStation; import com.zy.asrs.entity.mes.TransParent; import com.zy.asrs.entity.rcs.*; import com.zy.asrs.enums.RcsRetMethodEnum; import com.zy.asrs.mapper.BlockStationMapper; import com.zy.asrs.mapper.BlockTaskMapper; import com.zy.asrs.service.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.*; import java.net.ConnectException; import java.net.SocketTimeoutException; import java.net.URL; import java.net.URLConnection; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @Slf4j @Service public class RcsServiceImpl implements RcsService { // 海康RCS地址 @Value("${hik.url}") private String HIK_URL; // 华晓RCS地址 @Value("${hx.url}") private String HX_URL; @Value("${mes.defaultUserId}") public long defaultUserId; @Resource private MesService mesService; @Resource private TaskService taskService; @Resource private BlockStationMapper blockStationMapper; @Resource private BlockTaskMapper blockTaskMapper; @Resource private TaskDetlServiceImpl taskDetlService; @Resource private WrkMastService wrkMastService; // region 封锁区逻辑,目前只有一个大封锁区,任务全部转到滑块库处理,或直接写到滑块库 /** * 申请封锁区请求 * * @param apply * @return */ private int applyBlock(RcsReporterEqpt apply) { BlockTask blockTask = new BlockTask(); blockTask.setTaskCode(apply.getTaskCode()); blockTask.setApplyTime(new Date()); blockTask.setBlockNo(apply.getEqptCode()); blockTask.setBlockName(apply.getEqptName()); blockTask.setMethod(apply.getMethod()); blockTask.setCompleted(0); return blockTaskMapper.insert(blockTask); } /** * 管理封锁区进入 * TODO:增加锁防冲突,可能为分布式锁,定期5秒循环调用 * */ public void managerBlock() { try { BlockTask firstTask = blockTaskMapper.findTop(); if (firstTask == null) { return; } EntityWrapper wrapper = new EntityWrapper<>(); wrapper.eq("block_no", firstTask.getBlockNo()); List stations = blockStationMapper.selectList(wrapper); if (!stations.isEmpty()) { boolean locked = false; for (BlockStation station : stations) { // 只允许1个厂家设备进入封锁区,status状态:0 空闲;1 海康封锁中;2 华晓封锁中;-1 异常; if (station.getStatus() > 0 && !station.getStatus().equals(firstTask.getAgvFactory())) { locked = true; break; } } if (!locked) { // 封锁状态 int success = blockStationMapper.addByBlockNo(firstTask.getBlockNo(), firstTask.getAgvFactory()); if (success > 0) { // 通知RCS RcsEqptNotify notify = new RcsEqptNotify(); notify.setEqptCode(firstTask.getBlockNo()); notify.setTaskCode(firstTask.getTaskCode()); notify.setActionStatus("1"); notifyEqpt(notify, firstTask.getAgvFactory()); } } } } catch (Exception e) { log.error("管理封锁区异常", e); } } /** * 离开释放封锁区请求 * TODO:增加锁防冲突,可能为分布式锁 * * @param apply * @return */ private int releaseBlock(RcsReporterEqpt apply) { BlockTask task = blockTaskMapper.findByTaskCode(apply.getTaskCode()); EntityWrapper wrapper = new EntityWrapper<>(); wrapper.eq("block_no", task.getBlockNo()); List stations = blockStationMapper.selectList(wrapper); if (!stations.isEmpty()) { // 先完成任务 task.setCompleted(1); task.setCompletedTime(new Date()); int updateTask = blockTaskMapper.updateById(task); // 再更新封锁区数量 for (BlockStation station : stations) { if (station.getAgvNum() - 1 == 0) { station.setStatus(0); } station.setAgvNum(station.getAgvNum() - 1); int updateBlock = blockStationMapper.updateById(station); } } return 1; } // endregion // region 海康RCS,AGV /** * 2.1.2任务下发接口 * 厂家:海量、华晓 * * @param rcsTaskSubmit * @param rcsFactory 1 海康;2 华晓; * @return */ public int submitTask(RcsTaskSubmit rcsTaskSubmit, int rcsFactory){ String url = rcsFactory == 2 ? HIK_URL : HX_URL + "api/robot/controller/task/submit"; String response = sendPost(url, rcsTaskSubmit.toString()); if (!StringUtils.isEmpty(response) && response.contains("code")){ RcsReturn rcsReturn = JSONObject.parseObject(response, RcsReturn.class); if("SUCCESS".equals(rcsReturn.getCode())) { JSONObject data = rcsReturn.getData(); String robotTaskCode = data.getString("robotTaskCode"); if (robotTaskCode.equals(rcsTaskSubmit.getRobotTaskCode())){ return 1; } } } return 0; } /** * 2.1.3任务继续执行接口 * * @param rcsTaskContinue * @param rcsFactory * @return */ public int continueTask(RcsTaskContinue rcsTaskContinue, int rcsFactory){ String url = rcsFactory == 2 ? HIK_URL : HX_URL + "api/robot/controller/task/extend/continue"; String response = sendPost(url, rcsTaskContinue.toString()); if (!StringUtils.isEmpty(response) && response.contains("code")){ RcsReturn rcsReturn = JSONObject.parseObject(response, RcsReturn.class); if("SUCCESS".equals(rcsReturn.getCode())) { JSONObject data = rcsReturn.getData(); String robotTaskCode = data.getString("robotTaskCode"); if (robotTaskCode.equals(rcsTaskContinue.getRobotTaskCode())) { return 1; } } } return 0; } /** * 2.1.4任务取消接口 * * @param rcsTaskCancel * @param rcsFactory * @return */ public int cancelTask(RcsTaskCancel rcsTaskCancel, int rcsFactory){ String url = rcsFactory == 2 ? HIK_URL : HX_URL + "api/robot/controller/task/cancel"; String response = sendPost(url, rcsTaskCancel.toString()); if (!StringUtils.isEmpty(response) && response.contains("code")){ RcsReturn rcsReturn = JSONObject.parseObject(response, RcsReturn.class); if("SUCCESS".equals(rcsReturn.getCode())) { JSONObject data = rcsReturn.getData(); String robotTaskCode = data.getString("robotTaskCode"); if (robotTaskCode.equals(rcsTaskCancel.getRobotTaskCode())) { return 1; } } } return 0; } /** * 2.1.15外设执行通知接口,通知进入封锁区 * * @param rcsEqptNotify * @param rcsFactory * @return */ private int notifyEqpt(RcsEqptNotify rcsEqptNotify, int rcsFactory){ String url = rcsFactory == 2 ? HIK_URL : HX_URL + "api/wcs/robot/eqpt/notify"; String response = sendPost(url, rcsEqptNotify.toString()); if (!StringUtils.isEmpty(response) && response.contains("code")){ RcsReturn rcsReturn = JSONObject.parseObject(response, RcsReturn.class); if("SUCCESS".equals(rcsReturn.getCode())) { JSONObject data = rcsReturn.getData(); String applyCode = data.getString("taskCode"); //申请请求编号,非任务编号 if (applyCode.equals(rcsEqptNotify.getTaskCode())) { return 1; } } } return 0; } /** * 2.2.1任务执行回馈 * 厂家:海量、华晓 * * @param rcsReporterTask * @return */ public RcsReturn reporterTask(RcsReporterTask rcsReporterTask) { RcsReturn rcsReturn = new RcsReturn(); String robotTaskCode = rcsReporterTask.getRobotTaskCode(); String singleRobotCode = rcsReporterTask.getSingleRobotCode(); JSONObject values = rcsReporterTask.getExtra().getJSONObject("values"); // start : 任务开始;outbin : 走出储位;end : 任务完成 String method = values.getString("method"); String carrierType = values.getString("carrierType"); String slotCategory = values.getString("slotCategory"); String slotCode = values.getString("slotCode"); try { if ("Q3".equals(carrierType) || "Q8".equals(carrierType)) { //AGV EntityWrapper wrapper = new EntityWrapper<>(); wrapper.eq("task_no", robotTaskCode); Task task = taskService.selectOne(wrapper); if (task == null || !task.getTaskNo().equals(robotTaskCode)) { rcsReturn.setCode("Err_RobotCodeNotMatch"); rcsReturn.setMessage(""); JSONObject data = new JSONObject(); data.put("robotTaskCode", robotTaskCode); rcsReturn.setData(data); return rcsReturn; } JSONObject memo = JSONObject.parseObject(task.getMemo()); switch (Objects.requireNonNull(RcsRetMethodEnum.getEnum(method))) { case TASK_START: { task.setWrkSts(302L); // 301 任务下发、302 任务执行、303 任务中断、304 任务结束 task.setModiTime(new Date()); task.setModiUser(defaultUserId); taskService.updateById(task); } break; case TASK_OUT_BIN: { // TODO:立库出库一托,AGV开始运输后,给MES发送出库完成(一托发一次) JSONObject taskMemo = JSONObject.parseObject(task.getMemo()); mesService.outFeedbackByTuo(taskMemo.getString("OrderNo"), task); } break; case TASK_END: { // 更新任务状态等内部逻辑 task.setWrkSts(304L); // 301 任务下发、302 任务执行、303 任务中断、304 任务结束 task.setModiTime(new Date()); task.setModiUser(defaultUserId); taskService.updateById(task); // 任务完成 // mesService.reporterTask(rcsReporterTask); // EntityWrapper wapper2 = new EntityWrapper<>(); // wapper2.eq("wrk_no", task.getWrkNo()) // .eq("matnr", memo.getString("ItemNo")) // .eq("order_no", memo.getString("OrderNo")); // TaskDetl taskDetl = taskDetlService.selectOne(wapper2); // taskDetl.setAnfme() // taskDetlService.updateById(); // // 301 任务下发、302 任务执行、303 任务中断、304 任务结束 // taskService.completeWrkMast(); // taskDetlService. } break; case APPLY_IN_STATION: case APPLY_OFF_STATION: case ARRIVE_OFF_STATION: { TransParent apply = new TransParent(); apply.setTaskno(robotTaskCode); apply.setTaskname(memo.getString("taskName")); apply.setAgvCode(singleRobotCode); String transType = memo.getString("TransType"); apply.setTransType(transType); apply.setProductLineId(memo.getString("ProductLineId")); if(transType.equals("02") || transType.equals("04") || transType.equals("06")) { apply.setStationId(task.getSourceStaNo()); } else { apply.setStationId(task.getStaNo()); } if (RcsRetMethodEnum.APPLY_IN_STATION.getCode().equals(method)) { mesService.applyInStation(apply); } else if (RcsRetMethodEnum.APPLY_OFF_STATION.getCode().equals(method)) { mesService.applyOutStation(apply); } else if (RcsRetMethodEnum.ARRIVE_OFF_STATION.getCode().equals(method)) { mesService.outStation(apply); } } break; case ARRIVE_ON_STATION: { // TODO: 如果产线是运输起点,则不发送到站完成,暂时调试使用lG,未实现判断 if (rcsReporterTask.getCurrentSeq() == 0 && task.getSourceStaNo().startsWith("LG")) { break; } EntityWrapper wapper2 = new EntityWrapper<>(); wapper2.eq("wrk_no", task.getWrkNo()) .eq("matnr", memo.getString("Itemno")) .eq("order_no", memo.getString("OrderNo")); TaskDetl taskDetl = taskDetlService.selectOne(wapper2); TransArrivalStation arrivalStation = new TransArrivalStation(); arrivalStation.setTaskno(robotTaskCode); arrivalStation.setTaskname(memo.getString("taskName")); arrivalStation.setTuoPanId(taskDetl.getZpallet()); // memo.getString("TuoPanId") arrivalStation.setProductLineId(memo.getString("ProductLineId")); String transType = memo.getString("TransType"); arrivalStation.setDaotype(transType); if(transType.equals("02") || transType.equals("04") || transType.equals("06")) { arrivalStation.setStationID(task.getSourceStaNo()); } else { arrivalStation.setStationID(task.getStaNo()); } arrivalStation.setOrderNo(memo.getString("OrderNo")); arrivalStation.setAgvCode(singleRobotCode); arrivalStation.setItemno(memo.getString("Itemno")); String memo2 = taskDetl.getMemo(); List itemBarCode = new ArrayList<>(); Matcher matcher = Pattern.compile("\"([^\"]*)\"").matcher(memo2); while (matcher.find()) { itemBarCode.add(matcher.group(1)); } arrivalStation.setItemBarcode(itemBarCode); mesService.arriveOnStation(arrivalStation); } break; default: {} break; } } else if ("CTU".equals(carrierType)) { //CTU EntityWrapper wrapper = new EntityWrapper<>(); wrapper.eq("task_no", robotTaskCode); WrkMast task = wrkMastService.selectOne(wrapper); if (task == null || !task.getTaskNo().equals(robotTaskCode)) { rcsReturn.setCode("Err_RobotCodeNotMatch"); rcsReturn.setMessage(""); JSONObject data = new JSONObject(); data.put("robotTaskCode", robotTaskCode); rcsReturn.setData(data); return rcsReturn; } // JSONObject memo = JSONObject.parseObject(task.getMemo()); switch (Objects.requireNonNull(RcsRetMethodEnum.getEnum(method))) { case TASK_START: { // task.setWrkSts(302L); // 301 任务下发、302 任务执行、303 任务中断、304 任务结束 // task.setModiTime(new Date()); // task.setModiUser(defaultUserId); // taskService.updateById(task); } break; // case TASK_OUT_BIN: {} break; case TASK_END: { // 更新任务状态等内部逻辑 long wrkSts = task.getWrkSts(); // 1.入库;101.出库; if (task.getIoType() == 1) { wrkSts = 4L; } else if (task.getIoType() == 101) { wrkSts = 14L; } task.setWrkSts(wrkSts); // 4.入库完成;14.已出库未确认; task.setModiTime(new Date()); task.setModiUser(defaultUserId); wrkMastService.updateById(task); // TODO:任务完成触发出入库变更操作 // // 入库完成 // mesService.inFeedback(memo.getString("OrderNo")); // // 出库完成 // mesService.outFeedback(memo.getString("OrderNo")); } break; default: {} break; } } // 返回RCS rcsReturn.setCode("SUCCESS"); rcsReturn.setMessage(""); JSONObject data = new JSONObject(); data.put("robotTaskCode", robotTaskCode); rcsReturn.setData(data); } catch (Exception e) { log.error("RCS反馈任务进度处理异常 - {}", rcsReporterTask, e); rcsReturn.setCode("Err_Internal"); rcsReturn.setMessage("内部处理异常"); JSONObject data = new JSONObject(); data.put("robotTaskCode", robotTaskCode); rcsReturn.setData(data); } return rcsReturn; } /** * 2.2.4请求外设接口(请求封锁区) * 厂家:海量、华晓 * * @param rcsReporterEqpt * @return */ public RcsReturn reporterEqpt(RcsReporterEqpt rcsReporterEqpt){ int success = 0; if ("APPLY_LOCK".equals(rcsReporterEqpt.getMethod())) { //申请 success = applyBlock(rcsReporterEqpt); } else if ("RELEASE_EQPT".equals(rcsReporterEqpt.getMethod())) { //释放 success = releaseBlock(rcsReporterEqpt); } // 返回RCS RcsReturn rcsReturn = new RcsReturn(); rcsReturn.setCode(success > 0 ? "SUCCESS" : "Err_Internal"); rcsReturn.setMessage(success > 0 ? "" : "内部错误"); JSONObject data = new JSONObject(); data.put("extra", null); rcsReturn.setData(data); return rcsReturn; } // endregion // region 海康CTU 刀具库 // TODO: CTU上层组参引用, // 2.1.2任务下发接口 // 2.1.3任务继续执行接口 // 2.1.4任务取消接口 // 2.2.1任务执行回馈 //// @Transactional(rollbackFor = Exception.class) // public void receiveTaskStatus(RcsReporterTask callbackParam, String method, String stockType, Long hostId) { // // JSONObject values = callbackParam.getExtra().getJSONObject("values"); // EntityWrapper wapper = new EntityWrapper<>(); // wapper.eq("task_no", callbackParam.getRobotTaskCode()); // Task task = taskService.selectOne(wapper); // if (task == null && !StringUtils.isEmpty(task.getWrkNo())) { // if (1 == task.getIoType()) { // 入库 // // 更新库存 // // // 更新任务状态 // } else if (101 == task.getIoType()) { // 出库 // // 更新库存 // // // 更新任务状态 // // // 货物和托盘解绑 // } // } // } // endregion // region 华晓RCS /** * 9.7申请进入生产线 * * @param apply * @return */ public JSONObject hxApplyInLine(TransParent apply) { String status = mesService.applyInLine(apply); JSONObject result = new JSONObject(); result.put("Success", 1); result.put("Message", status); JSONObject data = new JSONObject(); data.put("status", status); result.put("Data", data); return result; } // endregion // region httpUtil /** * 向指定 URL 发送POST方法的请求 * * @param url 发送请求的 URL * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return 所代表远程资源的响应结果 */ public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; StringBuilder result = new StringBuilder(); try { log.info("sendPost - {} - {}", url, param); URL realUrl = new URL(url); URLConnection conn = realUrl.openConnection(); conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("Accept-Charset", "utf-8"); conn.setRequestProperty("Content-Type", "application/json;charset=utf-8"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); conn.setDoOutput(true); conn.setDoInput(true); out = new PrintWriter(conn.getOutputStream()); out.print(param); out.flush(); in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); String line; while ((line = in.readLine()) != null) { result.append(line); } log.info("recv - {}", result); } catch (ConnectException e) { log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e); } catch (SocketTimeoutException e) { log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); } catch (IOException e) { log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e); } catch (Exception e) { log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e); } finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); } } return result.toString(); } // endregion }