hangzhoumesParent/common/servicebase/src/main/java/com/mes/common/config/Const.java
@@ -33,4 +33,12 @@ public static final Integer GLASS_STATE_TAKE = 200; public static final Integer A10_OUT_TARGET_DAMAGE = 201; /** * 卧式理片笼详情表玻璃状态 * 进片任务1 * 出片任务2 */ public static final Integer GLASS_CACHE_TYPE_IN = 1; public static final Integer GLASS_CACHE_TYPE_OUT = 2; } hangzhoumesParent/moduleService/CacheGlassModule/src/main/java/com/mes/edgstoragecage/entity/EdgStorageCageDetails.java
@@ -1,6 +1,7 @@ package com.mes.edgstoragecage.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import lombok.Data; import lombok.EqualsAndHashCode; @@ -106,6 +107,11 @@ * 玻璃间隙 */ private Integer gap; /** * 玻璃间隙 */ @TableField(exist = false) private Integer count; } hangzhoumesParent/moduleService/CacheGlassModule/src/main/java/com/mes/edgstoragecage/service/EdgStorageCageDetailsService.java
@@ -40,16 +40,16 @@ /** * 查询笼内版图差值范围内的 此尺寸玻璃 如无则按照 钢化版图序号 以及玻璃序号 * @param glassId * @param poor * @param threshold * @return */ EdgStorageCageDetails selectConformGlass(String glassId, int poor); EdgStorageCageDetails selectConformGlass(String glassId, int threshold); /** * 获取出片信息数据 * @param glassId * @param poor * @param threshold * @return */ EdgStorageCageDetails selectOutGlass(String glassId, int poor); EdgStorageCageDetails selectOutGlass(String glassId, int threshold); } hangzhoumesParent/moduleService/CacheGlassModule/src/main/java/com/mes/edgstoragecage/service/impl/EdgStorageCageDetailsServiceImpl.java
@@ -143,51 +143,52 @@ /** * 查询笼内版图差值范围内的 此尺寸玻璃 如无则按照 钢化版图序号 以及玻璃序号 * * @param glassId * @param poor * @param threshold * @return */ @Override public EdgStorageCageDetails selectConformGlass(String glassId, int poor){ public EdgStorageCageDetails selectConformGlass(String glassId, int threshold) { //1.去笼内查询此尺寸的玻璃 目前版图差值内的玻璃 是否有同尺寸的 //1.1 有同尺寸的 则生成同尺寸的任务 //1.2 无同尺寸的 则生成版图顺序最小的出片 EdgStorageCageDetails edgStorageCageDetails= baseMapper.selectOne(new MPJLambdaQueryWrapper<EdgStorageCageDetails>() EdgStorageCageDetails edgStorageCageDetails = baseMapper.selectOne(new MPJLambdaQueryWrapper<EdgStorageCageDetails>() .selectAll(EdgStorageCageDetails.class) .eq(EdgStorageCageDetails::getGlassId,glassId) .eq(EdgStorageCageDetails::getGlassId, glassId) ); List<EdgStorageCageDetails> listEdgStorageCageDetails= baseMapper.selectList(new LambdaQueryWrapper<EdgStorageCageDetails>() .lt(EdgStorageCageDetails::getState,200) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId,EdgStorageCageDetails::getTemperingFeedSequence) List<EdgStorageCageDetails> listEdgStorageCageDetails = baseMapper.selectList(new LambdaQueryWrapper<EdgStorageCageDetails>() .lt(EdgStorageCageDetails::getState, 200) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId, EdgStorageCageDetails::getTemperingFeedSequence) ); EdgStorageCageDetails minTemperingLayoutId=new EdgStorageCageDetails(); if(!listEdgStorageCageDetails.isEmpty()){ minTemperingLayoutId=listEdgStorageCageDetails.get(0); EdgStorageCageDetails minTemperingLayoutId = new EdgStorageCageDetails(); if (!listEdgStorageCageDetails.isEmpty()) { minTemperingLayoutId = listEdgStorageCageDetails.get(0); } EdgStorageCageDetails result=new EdgStorageCageDetails(); if(edgStorageCageDetails!=null&&minTemperingLayoutId!=null){ result=edgStorageCageMapper.selectJoinOne(EdgStorageCageDetails.class,new MPJLambdaWrapper<EdgStorageCage>() EdgStorageCageDetails result = new EdgStorageCageDetails(); if (edgStorageCageDetails != null && minTemperingLayoutId != null) { result = edgStorageCageMapper.selectJoinOne(EdgStorageCageDetails.class, new MPJLambdaWrapper<EdgStorageCage>() .selectAll(EdgStorageCageDetails.class) .leftJoin(EdgStorageCageDetails.class,on->on .eq(EdgStorageCageDetails::getDeviceId,EdgStorageCage::getDeviceId) .eq(EdgStorageCageDetails::getSlot,EdgStorageCage::getSlot)) .leftJoin(EdgStorageCageDetails.class, on -> on .eq(EdgStorageCageDetails::getDeviceId, EdgStorageCage::getDeviceId) .eq(EdgStorageCageDetails::getSlot, EdgStorageCage::getSlot)) .isNotNull(EdgStorageCageDetails::getSlot) .eq(EdgStorageCageDetails::getWidth,edgStorageCageDetails.getWidth()) .eq(EdgStorageCageDetails::getHeight,edgStorageCageDetails.getHeight()) .ge(EdgStorageCageDetails::getTemperingLayoutId,minTemperingLayoutId.getTemperingLayoutId()) .le(EdgStorageCageDetails::getTemperingLayoutId,minTemperingLayoutId.getTemperingLayoutId()+poor) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId,EdgStorageCageDetails::getTemperingFeedSequence) .eq(EdgStorageCageDetails::getWidth, edgStorageCageDetails.getWidth()) .eq(EdgStorageCageDetails::getHeight, edgStorageCageDetails.getHeight()) .ge(EdgStorageCageDetails::getTemperingLayoutId, minTemperingLayoutId.getTemperingLayoutId()) .le(EdgStorageCageDetails::getTemperingLayoutId, minTemperingLayoutId.getTemperingLayoutId() + threshold) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId, EdgStorageCageDetails::getTemperingFeedSequence) ); } if (result==null){ result=edgStorageCageMapper.selectJoinOne(EdgStorageCageDetails.class,new MPJLambdaWrapper<EdgStorageCage>() if (result == null) { result = edgStorageCageMapper.selectJoinOne(EdgStorageCageDetails.class, new MPJLambdaWrapper<EdgStorageCage>() .selectAll(EdgStorageCageDetails.class) .leftJoin(EdgStorageCageDetails.class,on->on .eq(EdgStorageCageDetails::getDeviceId,EdgStorageCage::getDeviceId) .eq(EdgStorageCageDetails::getSlot,EdgStorageCage::getSlot)) .leftJoin(EdgStorageCageDetails.class, on -> on .eq(EdgStorageCageDetails::getDeviceId, EdgStorageCage::getDeviceId) .eq(EdgStorageCageDetails::getSlot, EdgStorageCage::getSlot)) .isNotNull(EdgStorageCageDetails::getSlot) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId,EdgStorageCageDetails::getTemperingFeedSequence) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId, EdgStorageCageDetails::getTemperingFeedSequence) ); } return result; @@ -197,11 +198,11 @@ * 查询笼内版图差值范围内的 此尺寸玻璃 如无则按照 钢化版图序号 以及玻璃序号 * * @param glassId * @param poor * @param threshold * @return */ @Override public EdgStorageCageDetails selectOutGlass(String glassId, int poor) { public EdgStorageCageDetails selectOutGlass(String glassId, int threshold) { EdgStorageCageDetails oldEdgStorageCageDetails = null; if (StringUtils.isNotEmpty(glassId)) { oldEdgStorageCageDetails = baseMapper.selectOne(new MPJLambdaQueryWrapper<EdgStorageCageDetails>() @@ -227,25 +228,23 @@ EdgStorageCageDetails outEdgStorageCageDetails = null; //todo:获取笼子内最大版图id和最小版图id插值,判断是否大于阈值,大于阈值直接出最小版图玻璃 //todo:逻辑1:获取两条线已出最后一块玻璃在笼内相同尺寸所剩数量,优先走数量少的线 //todo:逻辑2:优先走空闲的线 //todo:需要在卧式理片笼详情表中新增状态,用来表示玻璃进出理片笼情况 if (oldEdgStorageCageDetails != null && minTemperingLayoutId != null) { log.info("按照上一片已出玻璃宽度{},高度{},及版图id区间{}到{}获取出片任务玻璃信息", oldEdgStorageCageDetails.getWidth() , oldEdgStorageCageDetails.getHeight(), minTemperingLayoutId.getTemperingLayoutId(), minTemperingLayoutId.getTemperingLayoutId() + poor); outEdgStorageCageDetails = this.getOne(new LambdaQueryWrapper<EdgStorageCageDetails>() .notIn(CollectionUtils.isNotEmpty(glassIds), EdgStorageCageDetails::getGlassId, glassIds) .eq(EdgStorageCageDetails::getWidth, oldEdgStorageCageDetails.getWidth()) .eq(EdgStorageCageDetails::getHeight, oldEdgStorageCageDetails.getHeight()) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId, EdgStorageCageDetails::getTemperingFeedSequence) .last("limit 1")); log.info("出片任务的玻璃信息:{}", outEdgStorageCageDetails); } // if (queryMaxMinDiff(threshold)) //todo:逻辑1:获取两条线已出最后一块玻璃在笼内相同尺寸所剩数量,优先走数量少的线 //todo:需要在卧式理片笼详情表中新增状态,用来表示玻璃进出理片笼情况 if (oldEdgStorageCageDetails != null && minTemperingLayoutId != null) { log.info("按照上一片已出玻璃宽度{},高度{},及版图id区间{}到{}获取出片任务玻璃信息", oldEdgStorageCageDetails.getWidth() , oldEdgStorageCageDetails.getHeight(), minTemperingLayoutId.getTemperingLayoutId(), minTemperingLayoutId.getTemperingLayoutId() + threshold); outEdgStorageCageDetails = this.getOne(new LambdaQueryWrapper<EdgStorageCageDetails>() .notIn(CollectionUtils.isNotEmpty(glassIds), EdgStorageCageDetails::getGlassId, glassIds) .eq(EdgStorageCageDetails::getWidth, oldEdgStorageCageDetails.getWidth()) .eq(EdgStorageCageDetails::getHeight, oldEdgStorageCageDetails.getHeight()) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId, EdgStorageCageDetails::getTemperingFeedSequence) .last("limit 1")); log.info("出片任务的玻璃信息:{}", outEdgStorageCageDetails); } if (outEdgStorageCageDetails == null) { outEdgStorageCageDetails = minTemperingLayoutId; } return outEdgStorageCageDetails; } } hangzhoumesParent/moduleService/CacheGlassModule/src/main/java/com/mes/job/CacheGlassTask.java
@@ -3,6 +3,9 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.yulichang.query.MPJQueryWrapper; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.mes.common.S7object; import com.mes.common.config.Const; import com.mes.device.PlcParameterObject; @@ -21,6 +24,7 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -51,12 +55,13 @@ String taskRequestTypeValue = plcParameterObject.getPlcParameter("A06_request_word").getValue(); String glassIdeValue = plcParameterObject.getPlcParameter("A05_scanning_ID").getValue(); String confirmationWrodValue = plcParameterObject.getPlcParameter("MES_confirmation_word").getValue(); // 1为A09空闲,2为A10空闲,3为A09A10都空闲,0为A09A10都有玻璃 String outGlassstate = plcParameterObject.getPlcParameter("A09_glass_status").getValue(); //A08 A09表示线路相同 可做等价 String out08Glassstate = plcParameterObject.getPlcParameter("A08_glass_status").getValue(); String out10Glassstate = plcParameterObject.getPlcParameter("A10_glass_status").getValue(); String confirmationWrodAddress = plcParameterObject.getPlcParameter("MES_confirmation_word").getAddress(); String currentSlot = plcParameterObject.getPlcParameter("Current_slot").getValue(); log.info("1、获取到的请求字为:{},获取到的扫描ID为:{},获取到的确认字为:{},获取到的出片状态为:{},当前格子号为:{}", taskRequestTypeValue, glassIdeValue, confirmationWrodValue, outGlassstate, currentSlot); log.info("1、获取到的请求字为:{},获取到的扫描ID为:{},获取到的确认字为:{},获取到的出片状态分别为:A09{}、A10{},当前格子号为:{}", taskRequestTypeValue, glassIdeValue, confirmationWrodValue, out08Glassstate, out10Glassstate, currentSlot); if ("0".equals(taskRequestTypeValue)) { if ("0".equals(confirmationWrodValue)) { @@ -79,19 +84,22 @@ } else if ("2".equals(taskRequestTypeValue)) { //09空闲 :1 10空闲 :2 都空闲:3 其他0 log.info("3、出片请求,且确认字为0,执行进片任务"); outTo(Integer.parseInt(outGlassstate), confirmationWrodAddress, currentSlot); outTo(Integer.parseInt(out08Glassstate), confirmationWrodAddress); } else if ("3".equals(taskRequestTypeValue)) { log.info("3、进片和出片都空闲,执行出片任务"); if ("0".equals(outGlassstate)) { //加笼子里面是否有玻璃,有先出,无玻璃先进 int count = edgStorageCageDetailsService.count(new LambdaQueryWrapper<EdgStorageCageDetails>().eq(EdgStorageCageDetails::getState, Const.GLASS_STATE_IN)); if ("0".equals(out08Glassstate) || count > 0) { inTo(glassIdeValue, confirmationWrodAddress, currentSlot); } else { outTo(Integer.parseInt(outGlassstate), confirmationWrodAddress, currentSlot); outTo(Integer.parseInt(out08Glassstate), confirmationWrodAddress); } } } /** * 进片任务 * * @param glassId * @param confirmationWrodAddress * @param currentSlot @@ -137,31 +145,58 @@ /** * 出片任务 * * @param line * @param confirmationWrodAddress * @param currentSlot */ private void outTo(int line, String confirmationWrodAddress, String currentSlot) { private void outTo(int line, String confirmationWrodAddress) { //逻辑步骤: // 0、A09、A10是否空闲,是否可以执行出片任务 // 1、获取钢化版图是否超过阈值 // 1.1、超过阈值:获取当前最小版图需要出片的玻璃信息 // 1.1.1、获取两条线最后一次出片的任务信息 // 1.1.2、按照出片信息去详情表查询格子在笼子里面剩余相同尺寸的玻璃数据 // 1.1.3、判断哪条线玻璃数量在理片笼内的数据最少,决定最小版图走该条线(问题:如果这条线非空闲,直接结束) // 1.2、未超过阈值: // 1.2.1、获取程序那条线空闲 // 1.2.2、获取该条线最后一次出片的任务信息 // 1.2.3、按照出片信息去详情表查询格子在笼子里面剩余相同尺寸的玻璃数据且以版图id、版序升序排序 取第一块玻璃出片 // 2、如果没有历史出片任务 // 2.1、出当前版图id最小版序最小的玻璃(问题:两条线都没有历史任务,出片时两条线的玻璃尺寸相同,是否找尺寸不同的) Assert.isTrue(line != 0, "A09、A10都有玻璃,无法出片"); log.info("1、出片任务出【{}】号线,备注(09空闲:1;10空闲:2;都空闲:3)", line); log.info("0、出片任务出【{}】号线,备注(09空闲:1;10空闲:2;都空闲:3)", line); //定义出片玻璃信息 EdgStorageCageDetails glassInfo = null; int endcell = 0; List<TaskCache> oldTaskCacheList; if (line == 2) { endcell = Const.A10_OUT_TARGET_POSITION; oldTaskCacheList = taskCacheService.selectLastOutCacheInfos(Const.A10_OUT_TARGET_POSITION); boolean flag = queryMaxMinDiff(threshold); log.info("1、获取钢化版图是否超过阈值:{}", flag); if (flag) { glassInfo = queryMinGlass(0.0, 0.0); log.info("1.1、超过阈值:获取当前最小版图需要出片的玻璃信息:{}", glassInfo); Integer a09Count = queryCountByTaskLine(Const.A09_OUT_TARGET_POSITION).size(); Integer a10Count = queryCountByTaskLine(Const.A10_OUT_TARGET_POSITION).size(); log.info("1.2、获取笼子剩余数量A09为{},A10为{}", a09Count, a10Count); if (a10Count <= a09Count && line != 2) { log.info("1.2.1、A09线出片"); endcell = Const.A09_OUT_TARGET_POSITION; } else { log.info("1.2.2、A10线出片"); endcell = Const.A09_OUT_TARGET_POSITION; } } else { endcell = Const.A09_OUT_TARGET_POSITION; oldTaskCacheList = taskCacheService.selectLastOutCacheInfos(Const.A09_OUT_TARGET_POSITION); } log.info("2、判断出片线路{},获取最后该条线已出片的任务信息{}(备注:0待执行,1已执行).都空闲优先出A09线", endcell, oldTaskCacheList); //获取指定线路将要出的玻璃信息 endcell = line == 2 ? Const.A10_OUT_TARGET_POSITION : Const.A09_OUT_TARGET_POSITION; //当前任务出完无玻璃 更换玻璃 int othercell = endcell == Const.A10_OUT_TARGET_POSITION ? Const.A09_OUT_TARGET_POSITION : Const.A10_OUT_TARGET_POSITION; List<EdgStorageCageDetails> details = queryCountByTaskLine(endcell); if (details.size() > 0) { glassInfo = details.get(0); } else { //todo:去理片笼里面查 glassInfo = queryChangeGlassInfo(othercell); } String glassId = ""; if (CollectionUtil.isNotEmpty(oldTaskCacheList)) { glassId = oldTaskCacheList.get(0).getGlassId(); } EdgStorageCageDetails glassInfo = edgStorageCageDetailsService.selectOutGlass(glassId, threshold); log.info("3、按照历史已出玻璃id{}和阈值{},拿出理片笼内的出片信息{}", glassId, threshold, glassInfo); if (glassInfo != null) { log.info("4、添加出片任务,玻璃id:{},任务类型:{},起始位置:{},结束位置:{}", glassInfo.getGlassId(), @@ -176,9 +211,121 @@ taskCacheService.insertTaskCache(taskCache); S7object.getinstance().plccontrol.WriteWord(confirmationWrodAddress, (short) 1); } } /** * 获取详情表内最大最小版图id的差值,判断是否出最小版图玻璃 * * @return */ private boolean queryMaxMinDiff(int threshold) { //todo:获取笼子内最大版图id和最小版图id插值,判断是否大于阈值,大于阈值直接出最小版图玻璃 QueryWrapper<EdgStorageCageDetails> queryWrapper = new QueryWrapper<>(); queryWrapper.select("max(tempering_layout_id)-min(tempering_layout_id) as diff") .eq("state", Const.GLASS_STATE_IN); Integer diff = (Integer) edgStorageCageDetailsService.listObjs(queryWrapper).get(0); return diff > threshold; } /** * 获取当前最小版图需要出片的玻璃信息 * * @param width * @param height */ private EdgStorageCageDetails queryMinGlass(Double width, Double height) { return edgStorageCageDetailsService.getOne(new LambdaQueryWrapper<EdgStorageCageDetails>() .eq(EdgStorageCageDetails::getState, 100) .eq(width != 0, EdgStorageCageDetails::getWidth, width) .eq(height != 0, EdgStorageCageDetails::getHeight, height) .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId, EdgStorageCageDetails::getTemperingFeedSequence) .last("limit 1")); } /** * 获取任务表中指定线路笼子内还剩余的玻璃数量 */ private List<EdgStorageCageDetails> queryCountByTaskLine(int line) { //获取任务表中最后一次出片的玻璃id LambdaQueryWrapper<TaskCache> queryWrapper = new LambdaQueryWrapper<TaskCache>().eq(TaskCache::getTaskType, Const.GLASS_CACHE_TYPE_OUT) .eq(TaskCache::getEndCell, line).orderByDesc(TaskCache::getCreateTime); List<TaskCache> taskCacheList = taskCacheService.list(queryWrapper); if (CollectionUtil.isEmpty(taskCacheList)) { return new ArrayList<>(); } TaskCache taskCache = taskCacheList.get(0); MPJQueryWrapper<EdgStorageCageDetails> mpjLambdaWrapper = new MPJQueryWrapper<>(); mpjLambdaWrapper.select("a.*") .innerJoin("edg_storage_cage_details t1 on t.width = t1.width and t.height = t1.height") .eq("t.glass_id", taskCache.getGlassId()) .ne("t1.glass_id", taskCache.getGlassId()) .orderByAsc("t1.tempering_layout_id", "t1.tempering_feed_sequence"); List<EdgStorageCageDetails> details = edgStorageCageDetailsService.selectJoinList(EdgStorageCageDetails.class, mpjLambdaWrapper); if (CollectionUtil.isEmpty(details)) { return new ArrayList<>(); } return details; } /** * 更换出片玻璃 * * @param othercell * @return */ private EdgStorageCageDetails queryChangeGlassInfo(int othercell) { //获取笼子内数量前二的玻璃数量 MPJLambdaWrapper<EdgStorageCageDetails> wrapper = new MPJLambdaWrapper<>(); wrapper.select(EdgStorageCageDetails::getWidth, EdgStorageCageDetails::getHeight) .selectCount("*", EdgStorageCageDetails::getCount) .groupBy(EdgStorageCageDetails::getWidth, EdgStorageCageDetails::getHeight) .last("order by count(*) desc limit 2"); List<EdgStorageCageDetails> list = edgStorageCageDetailsService.list(wrapper); log.info("获取笼子内数量前二的玻璃数量:{}", list); Assert.notEmpty(list, "笼子里没有玻璃"); //一片玻璃直接出 if (list.size() == 1) { return list.get(0); } //分别获取宽高的玻璃数量 EdgStorageCageDetails firstSize = list.get(0); EdgStorageCageDetails secondSize = list.get(1); //获取任务表中最后一次出片的玻璃id LambdaQueryWrapper<TaskCache> queryWrapper = new LambdaQueryWrapper<TaskCache>().eq(TaskCache::getTaskType, Const.GLASS_CACHE_TYPE_OUT) .eq(TaskCache::getEndCell, othercell).orderByDesc(TaskCache::getCreateTime); List<TaskCache> taskCacheList = taskCacheService.list(queryWrapper); log.info("获取任务表中{}线最后一次出片的玻璃任务信息:{}", othercell, taskCacheList); if (CollectionUtil.isEmpty(taskCacheList)) { log.info("{}线没有出片任务信息,直接出片", othercell); return queryMinGlass(firstSize.getWidth(), firstSize.getHeight()); } Integer firstCount = firstSize.getCount(); Double firstWidth = firstSize.getWidth(); Double firstHeight = firstSize.getHeight(); Integer secondCount = secondSize.getCount(); Double secondWidth = secondSize.getWidth(); Double secondHeight = secondSize.getHeight(); //获取数量前2的玻璃数量比例 Integer mix = firstCount / secondCount; log.info("获取玻璃数量前2的玻璃占比为:{}", mix); if (mix >= 2) { log.info("获取玻璃数量前2的玻璃占比为{},大于2,直接出玻璃数据的最多的,宽:{},高:{}", mix, firstWidth, firstHeight); return queryMinGlass(firstWidth, firstHeight); } else { log.info("获取玻璃数量前2的玻璃占比为{},小于2", mix); TaskCache taskCache = taskCacheList.get(0); EdgStorageCageDetails outGlassInfo = edgStorageCageDetailsService.getOne(new LambdaQueryWrapper<EdgStorageCageDetails>().eq(EdgStorageCageDetails::getGlassId, taskCache.getGlassId())); log.info("{}线有出片任务信息,任务信息为{},玻璃信息为{}", othercell, taskCache, outGlassInfo); if (outGlassInfo.getWidth().equals(firstWidth) && outGlassInfo.getHeight().equals(firstHeight)) { log.info("数量最多的宽{}高{}和{}线任务的宽{}高{}相同,出数量排第二的玻璃,宽{}高{}", firstWidth, firstHeight, othercell, outGlassInfo.getWidth(), outGlassInfo.getHeight(), secondWidth, secondHeight); return queryMinGlass(secondWidth, secondHeight); } else { log.info("数量第二多的宽{}高{}和{}线任务的宽{}高{}相同,出数量排第二的玻璃,宽{}高{}", secondWidth, secondHeight, othercell, outGlassInfo.getWidth(), outGlassInfo.getHeight(), firstWidth, firstHeight); return queryMinGlass(firstWidth, firstHeight); } } } } hangzhoumesParent/moduleService/CacheGlassModule/src/main/resources/JsonFile/PlcCacheGlass.json
@@ -32,7 +32,7 @@ "unit":"" }, { "codeId": "A09_glass_status", "codeId": "A08_glass_status", "addressIndex":"68", "addressLenght":"2", "ratio":"1", hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/AppRunnerConfig.java
New file @@ -0,0 +1,29 @@ package com.mes; import com.mes.common.S7object; import com.mes.job.PlcStorageCageTask; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Slf4j @Component @Order(1) public class AppRunnerConfig implements ApplicationRunner { private final PlcStorageCageTask plcStorageCageTask; public AppRunnerConfig(PlcStorageCageTask plcStorageCageTask) { this.plcStorageCageTask = plcStorageCageTask; } @Override public void run(ApplicationArguments args) throws Exception { log.info("启动完成"); S7object.getinstance().start(); } } hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/bigstorage/service/BigStorageCageService.java
@@ -18,7 +18,7 @@ */ public interface BigStorageCageService extends IService<BigStorageCage> { void updateRemainWidth(int Slot); void updateRemainWidth(int slot); BigStorageCageDetails feedGlass(GlassInfo glassInfo, BigStorageCageDetails bigStorageCageDetails); hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/bigstorage/service/impl/BigStorageCageServiceImpl.java
@@ -61,10 +61,10 @@ bigStorageCageDetails.setSlot(layoutSlotInfo.getSlot()); } else { log.info("3、查询理片笼内片序+1等于当前玻璃片序的玻璃的结果为空时获取当前玻璃版图id是否存在理片笼内"); LambdaQueryWrapper<BigStorageCageDetails> BigStorageCageDetailslambdaQueryWrapper = new LambdaQueryWrapper<>(); BigStorageCageDetailslambdaQueryWrapper LambdaQueryWrapper<BigStorageCageDetails> bigStorageCageDetailslambdaQueryWrapper = new LambdaQueryWrapper<>(); bigStorageCageDetailslambdaQueryWrapper .select(BigStorageCageDetails::getTemperingLayoutId); layoutSlotInfo = bigStorageCageDetailsMapper.selectOne(BigStorageCageDetailslambdaQueryWrapper); layoutSlotInfo = bigStorageCageDetailsMapper.selectOne(bigStorageCageDetailslambdaQueryWrapper); if(layoutSlotInfo != null){ log.info("4、获取笼子内适合的格子"); @@ -78,10 +78,10 @@ .apply("LEFT JOIN (SELECT device_id, tempering_layout_id FROM big_storage_cage_details) b ON a.device_id = b.device_id AND a.slot = b.slot") .orderByAsc("layoutCount") .orderByAsc("a.device_id"); List<Map<String, Object>> BigStorageCageDetailsCount= bigStorageCageDetailsMapper.selectMaps(queryWrapper); List<Map<String, Object>> bigStorageCageDetailsCount= bigStorageCageDetailsMapper.selectMaps(queryWrapper); log.info("5、查询笼子内是否有合适的格子"); for (Map<String, Object> map : BigStorageCageDetailsCount) { for (Map<String, Object> map : bigStorageCageDetailsCount) { for (Map.Entry<String, Object> entry : map.entrySet()) { int deviceId = Integer.parseInt(entry.getKey()); BigStorageCage bigStorageCage=bigStorageCageSlot(deviceId); @@ -92,8 +92,9 @@ } } } log.info("6、当找到合适的格子时添加玻璃到笼子表"); if (bigStorageCageDetails.getSlot() != null) { log.info("6、当找到合适的格子时添加玻璃到笼子表"); bigStorageCageDetails.setState(0); bigStorageCageDetailsMapper.insert(bigStorageCageDetails); updateRemainWidth(bigStorageCageDetails.getSlot()) ; hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/common/S7object.java
New file @@ -0,0 +1,61 @@ package com.mes.common; import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType; import com.mes.device.PlcParameterObject; import com.mes.tools.InitUtil; import com.mes.tools.S7control; /** * @Author : zhoush * @Date: 2024/4/9 15:13 * @Description: */ public class S7object extends Thread { public S7control plccontrol; // PLC通讯类实例 private EPlcType plcType = EPlcType.S1200; // 西门子PLC类型 private String ip = "192.168.10.1"; // plc ip地址 private int port = 102; // plc 端口号 public PlcParameterObject PlcMesObject; private static volatile S7object instance = null; private S7object() { if (plccontrol == null) { plccontrol = new S7control(plcType, ip, port, 0, 0); String PlcLoadGlass=S7object.class.getResource("/JsonFile/PlcCacheVerticalGlass.json").getPath(); //log.info(PLCAutoMes.class.getResource("").getPath()); PlcMesObject = InitUtil.initword(PlcLoadGlass); } } // 单例模式 获取类的唯一实例 public static S7object getinstance() { if (instance == null) { synchronized (S7object.class) { if (instance == null) { instance = new S7object(); } } } return instance; } @Override public void run() { while (this != null) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } byte[] getplcvlues= plccontrol.ReadByte(PlcMesObject.getPlcAddressBegin(),PlcMesObject.getPlcAddressLength()); PlcMesObject.setPlcParameterList(getplcvlues); } } } hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/common/WebSocketServer.java
New file @@ -0,0 +1,160 @@ package com.mes.common; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint(value = "/api/talk/{username}") @Component("webSocketServer") public class WebSocketServer { public static ConfigurableApplicationContext applicationContext; // 解决无法注入mapper问题 //使用方法 // homeMapper=WebSocketServer.applicationContext.getBean(HomeMapper.class); public static void setApplicationContext(ConfigurableApplicationContext configurableApplicationContext) { WebSocketServer.applicationContext = configurableApplicationContext; } private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class); private List<String> messages; /** * 记录当前在线连接数 */ public static final Map<String, ArrayList<WebSocketServer>> sessionMap = new ConcurrentHashMap<>(); String username; Session session; public WebSocketServer() { this.messages = new ArrayList<>(); } /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session, @PathParam("username") String username) { this.username = username; this.session = session; List<WebSocketServer> webSocketServers = sessionMap.get(username); if (webSocketServers == null) { ArrayList<WebSocketServer> arrayListwebserver = new ArrayList<WebSocketServer>(); arrayListwebserver.add(this); sessionMap.put(username, arrayListwebserver); } else { webSocketServers.add(this); } log.info("有新用户加入,username={}, 当前在线人数为:{}", username, sessionMap.get(username).size()); // JSONObject result = new JSONObject(); // JSONArray array = new JSONArray(); // result.set("users", array); // for (Object key : sessionMap.keySet()) { // JSONObject jsonObject = new JSONObject(); // jsonObject.set("username", key); // array.add(jsonObject); // } // sendAllMessage(JSONUtil.toJsonStr(result)); // 后台发送消息给所有的客户端 } /** * 连接关闭调用的方法 */ @OnClose public void onClose(Session session, @PathParam("username") String username) { List<WebSocketServer> webSocketServers = sessionMap.get(username); ArrayList<WebSocketServer> arrayListwebserver = new ArrayList<WebSocketServer>(); if (webSocketServers.size() > 1) { for (WebSocketServer webSocketServer : webSocketServers) { if (webSocketServer != this) { arrayListwebserver.add(webSocketServer); } } sessionMap.put(username, arrayListwebserver); log.info("移除username={}一名用户session, {}的当前在线人数为:{}", username, username, sessionMap.get(username).size()); } else { sessionMap.remove(username); log.info("移除username={}一名用户session, {}连接关闭, 当前连接数为:{}", username, username, sessionMap.size()); } } /** * 收到客户端消息后调用的方法 * 后台收到客户端发送过来的消息 * onMessage 是一个消息的中转站 * 接受 浏览器端 socket.send 发送过来的 json数据 * * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session, @PathParam("username") String username) { log.info("服务端收到用户username={}的消息:{}", username, message); JSONObject obj = JSONUtil.parseObj(message); String text = obj.getStr("data"); JSONObject jsonObject = new JSONObject(); jsonObject.set("message", text); this.messages.add(text); this.sendMessage(jsonObject.toString()); // JSONUtil.toJsonStr(jsonObject) } @OnError public void onError(Session session, Throwable error) { log.error("发生错误"); error.printStackTrace(); } /** * 服务端发送消息给客户端 */ public void sendMessage(String message) { try { // log.info("服务端给客户端[{}]发送消息{}", this.session.getId(), message); this.session.getBasicRemote().sendText(message); } catch (Exception e) { log.error("服务端发送消息给客户端失败", e); } } // /** // * 服务端发送消息给所有客户端 // */ // public void sendAllMessage(String message) { // try { // for (WebSocketServer webSocketServer : sessionMap.values()) { // // log.info("服务端给客户端[{}]发送消息{}", this.session.getId(), message); // webSocketServer.sendMessage(message); // } // } catch (Exception e) { // log.error("服务端发送消息给客户端失败", e); // } // } public List<String> getMessages() { return messages; } public void clearMessages() { messages.clear(); } } hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/java/com/mes/job/PlcStorageCageTask.java
@@ -5,8 +5,12 @@ import com.mes.bigstorage.service.BigStorageCageDetailsService; import com.mes.bigstorage.service.BigStorageCageService; import com.mes.bigstoragetask.entity.BigStorageCageFeedTask; import com.mes.bigstoragetask.entity.BigStorageCageOutTask; import com.mes.bigstoragetask.service.BigStorageCageFeedTaskService; import com.mes.bigstoragetask.service.BigStorageCageOutTaskService; import com.mes.common.S7object; import com.mes.common.WebSocketServer; import com.mes.device.PlcParameterObject; import com.mes.edgstoragetask.service.TaskCacheService; import com.mes.glassinfo.entity.GlassInfo; import com.mes.glassinfo.service.GlassInfoService; @@ -16,28 +20,31 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; @Component @Slf4j public class PlcStorageCageTask { @Autowired @Resource private BigStorageCageService bigStorageCageService; @Autowired @Resource private BigStorageCageDetailsService bigStorageCageDetailsService; @Autowired @Resource private GlassInfoService glassInfoService; @Autowired @Resource private BigStorageCageFeedTaskService bigStorageCageFeedTaskService; @Autowired @Resource private BigStorageCageOutTaskService bigStorageCageOutTaskService; @Autowired @Resource private TaskCacheService taskCacheService; @Autowired @Resource private SysMenuService sysMenuService; PlcParameterObject plcParameterObject = S7object.getinstance().PlcMesObject; /** * fixedRate : 上一个调用开始后再次调用的延时(不用等待上一次调用完成) * fixedDelay : 上一个调用结束后再次调用的延时 @@ -46,22 +53,18 @@ public void plcStorageCageTask() throws InterruptedException { JSONObject jsonObject = new JSONObject(); try { Thread.sleep(300); // 爆笼报警 boolean bigStorageCageFullAlarm = false; String plcD01FeedReq = "0"; String plcD04FeedReq = "0"; String plcFeedGlassid = "111"; String plcFeedGlassid = ""; String plcFeedReqLine = "0"; if ("1".equals(plcD01FeedReq)) { if ("1".equals(plcParameterObject.getPlcParameter("D01Request").getValue())) { plcFeedReqLine = "1"; } else { //plc任务发送字0 plcFeedGlassid=plcParameterObject.getPlcParameter("D01ID1").getValue(); } if ("1".equals(plcD04FeedReq)) { if ("1".equals(plcParameterObject.getPlcParameter("D04Request").getValue())) { plcFeedReqLine = "2"; } else { //plc任务发送字0 plcFeedGlassid=plcParameterObject.getPlcParameter("D04ID1").getValue(); } if (!("0".equals(plcFeedReqLine))) { @@ -75,10 +78,8 @@ log.info("3、查询任务表判断当前任务类型为上车等到还是上车启动" + taskType); bigStorageCageFeedTaskService.addFeedTask(slotInfo, Integer.parseInt(plcFeedReqLine), taskType); log.info("4、添加任务到任务表"); //plc任务发送字1 bigStorageCageFullAlarm = false; } else { //理片笼爆笼报警 bigStorageCageFullAlarm = true; } } else { @@ -96,24 +97,33 @@ } } //出片请求 String plcOutReq = "0"; boolean result = false; if ("1".equals(plcOutReq)) { result = bigStorageCageService.outGlass(); log.info("8、出片请求时调用出片接口" + result); if (result) { //plc任务发送字1 } } else { bigStorageCageOutTaskService.updateOutTask(); //plc任务发送字0 //查询出片表是否有任务未完成的任务 List<BigStorageCageOutTask> bigStorageCageOutTask=bigStorageCageOutTaskService.querybigStorageCageOutTask(0); if(bigStorageCageOutTask.size()==0){ bigStorageCageService.outGlass(); log.info("8、没有未完成任务时调用出片接口"); } //显示剩余空格子 bigStorageCageOutTaskService.updateOutTask(); log.info("9、根据任务表状态修改钢化小片表任务状态"); //报警信息 jsonObject.append("bigStorageCageFullAlarm", bigStorageCageFullAlarm); ArrayList<WebSocketServer> sendwServer = WebSocketServer.sessionMap.get("Home"); if (sendwServer != null) { for (WebSocketServer webserver : sendwServer) { if (webserver != null) { webserver.sendMessage(jsonObject.toString()); List<String> messages = webserver.getMessages(); if (!messages.isEmpty()) { // // 将最后一个消息转换为整数类型的列表 webserver.clearMessages(); } } else { log.info("Home is closed"); } } } } catch (Exception e) { e.printStackTrace(); } hangzhoumesParent/moduleService/CacheVerticalGlassModule/src/main/resources/JsonFile/PlcCacheVerticalGlass.json
New file @@ -0,0 +1,57 @@ { "plcAddressBegin":"DB.0", "plcAddressLenght":"72", "dataType":"word", "parameteInfor":[ { "codeId": "D01Request", "addressIndex":"0", "addressLenght":"2", "ratio":"1", "unit":"m/min" }, { "codeId": "D01ID1", "addressIndex":"2", "addressLenght":"6", "ratio":"1", "unit":"" }, { "codeId": "D04Request", "addressIndex":"8", "addressLenght":"2", "ratio":"1", "unit":"" }, { "codeId": "D04ID1", "addressIndex":"10", "addressLenght":"6", "ratio":"1", "unit":"" }, { "codeId": "D02Go", "addressIndex":"20", "addressLenght":"2", "ratio":"1", "unit":"" }, { "codeId": "D05Go", "addressIndex":"22", "addressLenght":"2", "ratio":"1", "unit":"" } , { "codeId": "DeviceStatus", "addressIndex":"70", "addressLenght":"2", "ratio":"1", "unit":"" } ] }