自动化立体仓库 - WCS系统
1
zhangc
2025-04-10 697af1096e89e54d473874179a704719fb184df2
1
4个文件已添加
1个文件已删除
8个文件已修改
1263 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java 288 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/MainProcess.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/ServerBootstrap.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/cache/MessageQueue.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SlaveType.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/command/LedCommand.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/protocol/StaProtocol.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/properties/SlaveProperties.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/LedThread.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/FyDevpThread.java 319 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/NormalLedThread.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/SiemensDevpThread.java 399 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java
@@ -1,24 +1,33 @@
package com.zy.asrs.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
import com.zy.asrs.domain.enums.NotifyMsgType;
import com.zy.asrs.entity.*;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.NotifyUtils;
import com.zy.asrs.utils.Utils;
import com.zy.common.model.*;
import com.zy.common.model.MapNode;
import com.zy.common.model.NavigateNode;
import com.zy.common.model.SearchLocParam;
import com.zy.common.model.StartupDto;
import com.zy.common.model.enums.NavigationMapType;
import com.zy.common.service.CommonService;
import com.zy.common.utils.*;
import com.zy.core.News;
import com.zy.core.action.LiftAction;
import com.zy.core.action.ShuttleAction;
import com.zy.core.cache.MessageQueue;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.dispatcher.ShuttleDispatchUtils;
import com.zy.core.enums.*;
import com.zy.core.model.*;
import com.zy.core.model.command.*;
import com.zy.core.model.command.LiftAssignCommand;
import com.zy.core.model.command.LiftCommand;
import com.zy.core.model.command.ShuttleAssignCommand;
import com.zy.core.model.command.ShuttleCommand;
import com.zy.core.model.protocol.*;
import com.zy.core.properties.SlaveProperties;
import com.zy.core.thread.*;
@@ -28,7 +37,10 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
 * 立体仓库WCS系统主流程业务
@@ -78,6 +90,250 @@
    private BasLiftOptService basLiftOptService;
    @Autowired
    private LiftAction liftAction;
    //入库站点
    public static final ArrayList<Integer> inSta = new ArrayList<Integer>() {{
        add(1012);
        add(1014);
        add(1022);
        add(1025);
        add(1032);
    }};
    //出库站点
    public static final ArrayList<Integer> outSta = new ArrayList<Integer>() {{
        add(1012);
        add(1014);
        add(1022);
        add(1025);
        add(1032);
    }};
    private boolean isInEnable(DevpThread devpThread, Integer staNo) {
        if (staNo == null) {
            return false;
        }
        // 获取入库站信息
        switch (staNo) {
            case 1011:
            case 1012:
                devpThread.getStation().get(1012).isInEnable();
                break;
            case 1021:
            case 1022:
            case 1023:
                devpThread.getStation().get(1022).isInEnable();
                break;
            case 1031:
            case 1032:
                devpThread.getStation().get(1032).isInEnable();
                break;
            case 1025:
            case 1026:
                devpThread.getStation().get(1025).isInEnable();
                break;
            case 1013:
            case 1014:
            case 1015:
                devpThread.getStation().get(1014).isInEnable();
                break;
        }
        return false;
    }
    private boolean isOutEnable(DevpThread devpThread, Integer staNo) {
        if (staNo == null) {
            return false;
        }
        // 获取入库站信息
        switch (staNo) {
            case 1011:
            case 1012:
                devpThread.getStation().get(1012).isOutEnable();
                break;
            case 1021:
            case 1022:
            case 1023:
                devpThread.getStation().get(1022).isOutEnable();
                break;
            case 1031:
            case 1032:
                devpThread.getStation().get(1032).isOutEnable();
                break;
            case 1025:
            case 1026:
                devpThread.getStation().get(1025).isOutEnable();
                break;
            case 1013:
            case 1014:
            case 1015:
                devpThread.getStation().get(1014).isOutEnable();
                break;
        }
        return false;
    }
    /**
     * 组托
     * 入库站,根据条码扫描生成入库工作档,工作状态 2
     */
    public synchronized void generateInboundWrk() {
        try {
            DevpSlave devpSlave = slaveProperties.getDevpSlave().get(0);
            // 遍历入库口
            for (DevpSlave.Sta inSta : devpSlave.getInSta()) {
                // 获取入库站信息
                DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, devpSlave.getId());
                StaProtocol staProtocol = devpThread.getStation().get(inSta.getStaNo());
                if (staProtocol == null) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                Short workNo = staProtocol.getWorkNo();
                // 尺寸检测异常
                boolean back = false;
                String errMsg = "异常:";
                if (staProtocol.isFrontErr()) {
                    errMsg = errMsg + "前超限;";
                    back = true;
                }
                if (staProtocol.isBackErr()) {
                    errMsg = errMsg + "后超限";
                    back = true;
                }
                if (staProtocol.isHighErr()) {
                    errMsg = errMsg + "高超限";
                    back = true;
                }
                if (staProtocol.isLeftErr()) {
                    errMsg = errMsg + "左超限";
                    back = true;
                }
                if (staProtocol.isRightErr()) {
                    errMsg = errMsg + "右超限";
                    back = true;
                }
                if (staProtocol.isWeightErr()) {
                    errMsg = errMsg + "超重";
                    back = true;
                }
                if (staProtocol.isBarcodeErr()) {
                    errMsg = errMsg + "扫码失败";
                    back = true;
                }
                // 退回
                if (back) {
                    // led 异常显示
                    LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                    if (ledThread != null) {
                        ledThread.error(errMsg);
                    }
                    continue;
                }
                // 判断是否满足入库条件
                if (staProtocol.isAutoing() && staProtocol.isLoading()
                        && isInEnable(devpThread, inSta.getStaNo())
                        && !staProtocol.isEmptyMk() && (workNo == 0 || (workNo >= 9990 && workNo <= 9999))
                        && staProtocol.isPakMk()
                ) {
                    String barcode = staProtocol.getBarcode();
                    if (!Cools.isEmpty(barcode)) {
                        News.info("条码扫描器检测条码信息:{}", barcode);
                    }
                    // 判断重复工作档
                    WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>()
                            .eq("source_sta_no", inSta.getStaNo())
                            .eq("wrk_sts", WrkStsType.NEW_INBOUND)
                            .eq("barcode", barcode));
                    if (wrkMast != null) {
                        News.error("工作档已存在,工作号={}", wrkMast.getWrkNo());
                        if (staProtocol.getWorkNo().intValue() != wrkMast.getWrkNo()) {
                            MessageQueue.offer(SlaveType.Devp, devpSlave.getId(), new Task(2, staProtocol));
                            devpThread.setPakMk(staProtocol.getSiteId(), false);
                            News.info("输送线入库命令下发,任务数据={}", JSON.toJSON(wrkMast));
                        }
                        continue;
                    }
                    try {
                        String wmsUrl = "127.0.0.1:8080/fyxcwms";
                        SearchLocParam param = new SearchLocParam();
                        param.setBarcode(barcode);
                        param.setIoType(1);
                        param.setSourceStaNo(inSta.getStaNo());
                        param.setLocType1(staProtocol.getLocType1().shortValue());
                        String response = new HttpHandler.Builder()
                                .setUri(wmsUrl)
                                .setPath("/rpc/pakin/loc/v1")
                                .setJson(JSON.toJSONString(param))
                                .build()
                                .doPost();
                        JSONObject jsonObject = JSON.parseObject(response);
                        Integer code = jsonObject.getInteger("code");
                        if (code.equals(200)) {
                            MessageQueue.offer(SlaveType.Devp, devpSlave.getId(), new Task(2, staProtocol));
                            devpThread.setPakMk(staProtocol.getSiteId(), false);
                            News.info("输送线入库命令下发,任务数据={}", JSON.toJSON(wrkMast));
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
//                                String wmsLocNo = dto.getLocNo();
//                                int row = Integer.parseInt(wmsLocNo.substring(0, 2));
//                                int bay = Integer.parseInt(wmsLocNo.substring(2, 5));
//                                int lev = Integer.parseInt(wmsLocNo.substring(5, 7));
//                                String wcsLocNo = Utils.getLocNo(row, bay, lev);
//
//                                CreateInTaskParam createInTaskParam = new CreateInTaskParam();
//                                createInTaskParam.setTaskNo(String.valueOf(dto.getWorkNo()));
//                                createInTaskParam.setDestLoc(wcsLocNo);
//                                createInTaskParam.setOriginSite(dto.getSourceStaNo().toString());
//                                createInTaskParam.setDestSite(dto.getStaNo().toString());
//                                createInTaskParam.setPriority(11);
//                                createInTaskParam.setBarcode(barcode);
//
//                                R result = openUtils.createInTask(createInTaskParam);
//                                News.info("创建入库任务,任务数据={},WMS响应={},请求响应={}", JSON.toJSON(param), JSON.toJSON(jsonObject), JSON.toJSON(result));
//                                try{
//                                    String msg = "";
//                                    HashMap<String, String> hashMap = new HashMap<>();
//                                    hashMap.put("msg", msg);
//                                    hashMap.put("sta", inSta.getStaNo().toString());
//                                    new HttpHandler.Builder()
//                                            .setUri(wmsUrl)
//                                            .setPath("/rpc/led/getError")
//                                            .setJson(JSON.toJSONString(hashMap))
//                                            .build()
//                                            .doPost();
//                                }catch (Exception e){
//
//                                }
                        } else {
                            String msg = jsonObject.getString("msg");
                            HashMap<String, String> hashMap = new HashMap<>();
                            hashMap.put("msg", msg);
                            hashMap.put("sta", inSta.getStaNo().toString());
                            new HttpHandler.Builder()
                                    .setUri(wmsUrl)
                                    .setPath("/rpc/led/getError")
                                    .setJson(JSON.toJSONString(hashMap))
                                    .build()
                                    .doPost();
                            News.error("入库申请失败,任务数据={},请求响应={}", JSON.toJSON(param), JSON.toJSON(jsonObject));
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 初始化实时地图
@@ -494,7 +750,7 @@
                        }
                    } else {
                        Object object = redisUtil.get(RedisKeyType.SHUTTLE_WORK_FLAG.key + shuttleProtocol.getTaskNo());
                        if(object != null){
                        if (object != null) {
                            ShuttleAssignCommand assignCommand = JSON.parseObject(object.toString(), ShuttleAssignCommand.class);
                            if (!assignCommand.getAuto()) {
                                //手动模式
@@ -1191,7 +1447,7 @@
                        }
                        int errorCode = Integer.parseInt(shuttleProtocol.getErrorCode());
                        BasShuttleErr basShuttleErr = basShuttleErrService.queryByCode(errorCode);
                        String errName = basShuttleErr==null? "未知异常":basShuttleErr.getErrName();
                        String errName = basShuttleErr == null ? "未知异常" : basShuttleErr.getErrName();
                        BasShuttleErrLog basShuttleErrLog = new BasShuttleErrLog(
                                null,    // 编号
                                wrkMast.getWrkNo(),    // 工作号
@@ -1263,7 +1519,7 @@
                        }
                        BasLiftErr basLiftErr = basLiftErrService.queryByCode(Integer.parseInt(liftProtocol.getErrorCode()));
                        String errName = basLiftErr==null? "未知异常":basLiftErr.getErrName();
                        String errName = basLiftErr == null ? "未知异常" : basLiftErr.getErrName();
                        BasLiftErrLog basLiftErrLog = new BasLiftErrLog(
                                null,    // 编号
@@ -1367,7 +1623,7 @@
                            ArrayList<String> locs = new ArrayList<>();
                            locs.add(charge.getLocNo());
                            Integer checkHasShuttle = Utils.checkGroupLocHasShuttle(locs);
                            if(checkHasShuttle != null) {
                            if (checkHasShuttle != null) {
                                //当前充电桩有穿梭车,不分配该充电桩
                                continue;
                            }
@@ -1417,7 +1673,7 @@
            //查询小车充电任务
            for (ShuttleSlave shuttle : slaveProperties.getShuttle()) {
                WrkMast wrkMast = wrkMastService.selectChargeWorking(shuttle.getId());
                if(wrkMast == null) {
                if (wrkMast == null) {
                    continue;
                }
@@ -1503,7 +1759,7 @@
            //判断是否存在未完成的移动任务
            WrkMast moveWrk = wrkMastService.selectShuttleHasMoveWorking(wrkMast.getShuttleNo());
            if(moveWrk != null) {
            if (moveWrk != null) {
                return false;
            }
@@ -1604,7 +1860,7 @@
            }
            BasShuttleCharge basShuttleCharge = basShuttleChargeService.selectOne(new EntityWrapper<BasShuttleCharge>().eq("charge_id", wrkMast.getMk()));
            if(basShuttleCharge == null) {
            if (basShuttleCharge == null) {
                return false;
            }
@@ -1636,7 +1892,7 @@
                    this.shuttleMoveExecuteTransportLift(wrkMast);
                } else if ("TRANSPORT_DEVP".equals(wrkMast.getMk())) {
                }else {
                } else {
                    this.shuttleMoveExecuteMove(wrkMast);
                }
            }
@@ -1682,7 +1938,7 @@
        if (Utils.getRow(liftLocNo) == Utils.getRow(wrkMast.getSourceLocNo()) && Utils.getBay(liftLocNo) == Utils.getBay(wrkMast.getSourceLocNo())) {
            //取货位置是提升机
            this.shuttleMoveExecuteTransportLiftTake(wrkMast);
        }else {
        } else {
            //放货位置是提升机
            this.shuttleMoveExecuteTransportLiftPut(wrkMast);
        }
@@ -1907,7 +2163,7 @@
                wrkMast.setSystemMsg("");//清空消息
                wrkMastService.updateById(wrkMast);
                return false;
            }else {
            } else {
                liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, wrkMast.getLiftNo());
                if (liftThread == null) {
                    News.info("{}号提升机不存在", wrkMast.getLiftNo());
@@ -2371,7 +2627,7 @@
                wrkMast.setSystemMsg("");//清空消息
                wrkMastService.updateById(wrkMast);
                return false;
            }else {
            } else {
                liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, wrkMast.getLiftNo());
                if (liftThread == null) {
                    News.info("{}号提升机不存在", wrkMast.getLiftNo());
@@ -2934,7 +3190,7 @@
                    return false;//路径解锁失败
                }
                commands.addAll(moveCommands);
            }else {
            } else {
                //小车在待机位,直接移动完成
                wrkMast.setWrkSts(WrkStsType.MOVE_SITE_COMPLETE.sts);//  302.小车移动至站点 ==> 303.小车移动至站点完成
                wrkMast.setModiTime(now);
@@ -3134,7 +3390,7 @@
                wrkMast.setSystemMsg("");//清空消息
                wrkMastService.updateById(wrkMast);
                return false;
            }else {
            } else {
                liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, wrkMast.getLiftNo());
                if (liftThread == null) {
                    News.info("{}号提升机不存在", wrkMast.getLiftNo());
src/main/java/com/zy/core/MainProcess.java
@@ -40,6 +40,12 @@
                    if (!SystemProperties.WCS_RUNNING_STATUS.get()) {
                        continue;
                    }
                    //zhangc
                    //输送线
                    // 入库  ===>> 入库站到堆垛机站,根据条码扫描生成入库工作档
                    mainService.generateInboundWrk(); // 组托
                    //初始化实时地图
                    mainService.initRealtimeBasMap();
src/main/java/com/zy/core/ServerBootstrap.java
@@ -5,9 +5,11 @@
import com.zy.core.cache.MessageQueue;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.SlaveType;
import com.zy.core.model.*;
import com.zy.core.model.DevpSlave;
import com.zy.core.model.ForkLiftSlave;
import com.zy.core.model.LiftSlave;
import com.zy.core.model.ShuttleSlave;
import com.zy.core.properties.SlaveProperties;
import com.zy.core.thread.*;
import com.zy.core.thread.impl.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -46,7 +48,7 @@
        News.info("核心控制层已启动...............................................");
    }
    private void initMq(){
    private void initMq() {
        // 初始化货叉提升机mq
        for (Slave forkLift : slaveProperties.getForkLift()) {
            MessageQueue.init(SlaveType.ForkLift, forkLift);
@@ -61,7 +63,7 @@
        }
    }
    private void initThread(){
    private void initThread() {
        // 初始化货叉提升机
        for (ForkLiftSlave forkLiftSlave : slaveProperties.getForkLift()) {
            News.info("初始化货叉提升机........................................................");
@@ -119,6 +121,33 @@
            new Thread(thread).start();
            SlaveConnection.put(SlaveType.Shuttle, shuttleSlave.getId(), thread);
        }
        // 初始化输送线
        for (DevpSlave devpSlave : slaveProperties.getDevpSlave()) {
            News.info("初始化输送线......................................................");
            ThreadHandler thread = null;
            if (devpSlave.getThreadImpl().equals("FyDevpThread")) {
                thread = new FyDevpThread(devpSlave);
            } else {
                throw new CoolException("未知的线程实现");
            }
            new Thread(thread).start();
            SlaveConnection.put(SlaveType.Shuttle, devpSlave.getId(), thread);
        }
        // 初始化电视机
        for (DevpSlave devpSlave : slaveProperties.getL()) {
            News.info("初始化电视机......................................................");
            ThreadHandler thread = null;
            if (devpSlave.getThreadImpl().equals("FyDevpThread")) {
                thread = new FyDevpThread(devpSlave);
            } else {
                throw new CoolException("未知的线程实现");
            }
            new Thread(thread).start();
            SlaveConnection.put(SlaveType.Shuttle, devpSlave.getId(), thread);
        }
    }
src/main/java/com/zy/core/cache/MessageQueue.java
@@ -24,6 +24,8 @@
    private static final Map<Integer, ConcurrentLinkedQueue<Task>> FORK_LIFT_EXCHANGE = new ConcurrentHashMap<>();
    //货叉提升机Master mq交换机
    private static final Map<Integer, ConcurrentLinkedQueue<Task>> FORK_LIFT_MASTER_EXCHANGE = new ConcurrentHashMap<>();
    //显示屏mq交换机
    private static final Map<Integer, ConcurrentLinkedQueue<Task>> LED_EXCHANGE = new ConcurrentHashMap<>();
    /**
     * mq 交换机初始化
@@ -44,6 +46,9 @@
                break;
            case Devp:
                DEVP_EXCHANGE.put(slave.getId(), new ConcurrentLinkedQueue<>());
                break;
            case Led:
                LED_EXCHANGE.put(slave.getId(), new ConcurrentLinkedQueue<>());
                break;
            default:
                break;
@@ -66,6 +71,8 @@
                return LIFT_EXCHANGE.get(id).offer(task);
            case Devp:
                return DEVP_EXCHANGE.get(id).offer(task);
            case Led:
                return LED_EXCHANGE.get(id).offer(task);
            default:
                return false;
        }
@@ -87,6 +94,8 @@
                return LIFT_EXCHANGE.get(id).poll();
            case Devp:
                return DEVP_EXCHANGE.get(id).poll();
            case Led:
                return LED_EXCHANGE.get(id).poll();
            default:
                return null;
        }
@@ -107,12 +116,14 @@
                return LIFT_EXCHANGE.get(id).peek();
            case Devp:
                return DEVP_EXCHANGE.get(id).peek();
            case Led:
                return LED_EXCHANGE.get(id).peek();
            default:
                return null;
        }
    }
    public static void clear(SlaveType type, Integer id){
    public static void clear(SlaveType type, Integer id) {
        switch (type) {
            case Shuttle:
                SHUTTLE_EXCHANGE.get(id).clear();
@@ -129,6 +140,9 @@
            case Devp:
                DEVP_EXCHANGE.get(id).clear();
                break;
            case Led:
                LED_EXCHANGE.get(id).clear();
                break;
            default:
                break;
        }
src/main/java/com/zy/core/enums/SlaveType.java
@@ -7,6 +7,7 @@
    Lift,
    ForkLift,
    ForkLiftMaster,
    Led
    ;
    public static SlaveType findInstance(String s){
src/main/java/com/zy/core/model/command/LedCommand.java
New file
@@ -0,0 +1,36 @@
package com.zy.core.model.command;
import com.zy.common.model.MatDto;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
 * led命令报文
 * Created by vincent on 2020/8/11
 */
@Data
public class LedCommand extends Object {
    private String title;
    private String workNo;
    private Integer staNo;
    private Integer sourceStaNo;
    private String locNo;
    private String sourceLocNo;
    private List<MatDto> matDtos = new ArrayList<>();
    private boolean emptyMk = false;
    private Integer ioType;
    private String barcode;
}
src/main/java/com/zy/core/model/protocol/StaProtocol.java
@@ -20,13 +20,29 @@
    // 目标站
    private Short staNo;
    // 完结工作号
    private Short  finishWorkNo;
    // ----------------------------------------------------------------
    // 自动
    private boolean autoing;
    //空闲
    private boolean idle;
    // 条码
    private String    barcode;
    //重量
    private Integer weight;
    // 有物
    private boolean loading;
    // 库位号
    private String locNo;
    // 可入
    private boolean inEnable;
src/main/java/com/zy/core/properties/SlaveProperties.java
@@ -23,6 +23,10 @@
    private int groupCount;
    private List<LedS> Led = new ArrayList<>();
    private List<DevpSlave> devpSlave = new ArrayList<>();
    private List<ShuttleSlave> shuttle = new ArrayList<>();
    private List<LiftSlave> lift = new ArrayList<>();
src/main/java/com/zy/core/thread/LedThread.java
New file
@@ -0,0 +1,23 @@
package com.zy.core.thread;
import com.zy.core.ThreadHandler;
import com.zy.core.model.command.LedCommand;
import java.util.List;
public interface LedThread extends ThreadHandler {
    void write(List<LedCommand> commands);
    void reset();
    void error(String error);
    void errorReset();
    void setLedMk(boolean mk);
    boolean isLedMk();
}
src/main/java/com/zy/core/thread/impl/FyDevpThread.java
New file
@@ -0,0 +1,319 @@
package com.zy.core.thread.impl;
import HslCommunication.Core.Types.OperateResult;
import HslCommunication.Core.Types.OperateResultExOne;
import HslCommunication.Profinet.Siemens.SiemensPLCS;
import HslCommunication.Profinet.Siemens.SiemensS7Net;
import com.alibaba.fastjson.JSON;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.common.SpringUtils;
import com.zy.asrs.entity.BasDevp;
import com.zy.asrs.service.BasDevpService;
import com.zy.core.News;
import com.zy.core.cache.MessageQueue;
import com.zy.core.cache.OutputQueue;
import com.zy.core.enums.SlaveType;
import com.zy.core.model.DevpSlave;
import com.zy.core.model.Task;
import com.zy.core.model.protocol.StaProtocol;
import com.zy.core.thread.DevpThread;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 输送线线程
 * Created by vincent on 2020/8/4
 */
@Data
@Slf4j
public class FyDevpThread implements Runnable, DevpThread {
    private DevpSlave slave;
    private SiemensS7Net siemensS7Net;
    private Map<Integer, StaProtocol> station = new ConcurrentHashMap<>();
    private short heartBeatVal = 1;
    private int barcodeSize = 10;
    //写
    public static final ArrayList<Integer> staNos1 = new ArrayList<Integer>() {{
        add(1012);
        add(1014);
        add(1015);
        add(1022);
        add(1023);
        add(1025);
        add(1026);
        add(1031);
        add(1032);
    }};
    //读
    public static final ArrayList<Integer> staNos2 = new ArrayList<Integer>() {{
        add(1011);
        add(1012);
        add(1013);
        add(1014);
        add(1015);
        add(1021);
        add(1022);
        add(1023);
        add(1024);
        add(1025);
        add(1026);
        add(1031);
        add(1032);
    }};
    public FyDevpThread(DevpSlave slave) {
        this.slave = slave;
    }
    @Override
    @SuppressWarnings("InfiniteLoopStatement")
    public void run() {
        connect();
        while (true) {
            try {
                int step = 1;
                Task task = MessageQueue.poll(SlaveType.Devp, slave.getId());
                if (task != null) {
                    step = task.getStep();
                }
                switch (step) {
                    // 读数据
                    case 1:
                        read();
                        break;
                    // 写数据 ID+目标站
                    case 2:
                        write((StaProtocol) task.getData());
                        read();
                        break;
                    default:
                        break;
                }
                // 心跳
//                heartbeat();
                Thread.sleep(400);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public boolean connect() {
        boolean result = false;
        siemensS7Net = new SiemensS7Net(SiemensPLCS.S1500, slave.getIp());
        siemensS7Net.setRack(slave.getRack().byteValue());
        siemensS7Net.setSlot(slave.getSlot().byteValue());
        OperateResult connect = siemensS7Net.ConnectServer();
        if (connect.IsSuccess) {
            result = true;
            OutputQueue.DEVP.offer(MessageFormat.format("【{0}】输送线plc连接成功 ===>> [id:{1}] [ip:{2}] [port:{3}] [rack:{4}] [slot:{5}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort(), slave.getRack(), slave.getSlot()));
            News.info("输送线plc连接成功 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
        } else {
            OutputQueue.DEVP.offer(MessageFormat.format("【{0}】输送线plc连接失败!!! ===>> [id:{1}] [ip:{2}] [port:{3}]  [rack:{4}] [slot:{5}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort(), slave.getRack(), slave.getSlot()));
            News.error("输送线plc连接失败!!! ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
        }
        // siemensS7Net.ConnectClose();
        return result;
    }
    /**
     * 读取状态 ====> 整块plc
     */
    private void read() throws InterruptedException {
        int staNoSize = staNos2.size();
        OperateResultExOne<byte[]> result = siemensS7Net.Read("DB82.14", (short) (staNoSize * 26));
        if (result.IsSuccess) {
            for (int i = 0; i < staNoSize; i++) {
                Integer siteId = staNos2.get(i);
                StaProtocol staProtocol = station.get(staNos2.get(i));
                if (null == staProtocol) {
                    staProtocol = new StaProtocol();
                    staProtocol.setSiteId(siteId);
                    if (siteId == 1015) {
                        staProtocol.setLocNo("1200301");
                    } else if (siteId == 1026) {
                        staProtocol.setLocNo("1200305");
                    }
                    station.put(siteId, staProtocol);
                }
                Thread.sleep(300);
                boolean[] status = siemensS7Net.getByteTransform().TransBool(result.Content, i * 26, 2);
                staProtocol.setAutoing(status[0]);  // 自动
                staProtocol.setIdle(status[1]); //空闲
                staProtocol.setLoading(status[2]);  // 有物
                staProtocol.setBackErr(status[5]);
                staProtocol.setLeftErr(status[6]);
                staProtocol.setRightErr(status[7]);
                staProtocol.setHighErr(status[8]);
                staProtocol.setWeightErr(status[9]);
                staProtocol.setLow(status[10]);
                staProtocol.setHigh(status[11]);
                staProtocol.setInEnable(status[13]); // 可入
                staProtocol.setOutEnable(status[14]);// 可出
                staProtocol.setWorkNo(siemensS7Net.getByteTransform().TransInt16(result.Content, i * 26 + 2));     // 工作号
                staProtocol.setStaNo((short) siemensS7Net.getByteTransform().TransInt16(result.Content, i * 26 + 4));   // 目标站
                staProtocol.setFinishWorkNo(siemensS7Net.getByteTransform().TransInt16(result.Content, i * 26 + 6)); //已完成工作号
                staProtocol.setBarcode(siemensS7Net.getByteTransform().TransString(result.Content, i * 26 + 10, 12, "UTF-8").trim()); //条码
                staProtocol.setWeight(siemensS7Net.getByteTransform().TransInt32(result.Content, i * 26 + 22)); //重量
                if (!staProtocol.isPakMk() && !staProtocol.isLoading()) {
                    staProtocol.setPakMk(true);
                }
            }
        }
        if (!Cools.isEmpty(result) && result.IsSuccess) {
            OutputQueue.DEVP.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功", DateUtils.convert(new Date()), slave.getId()));
            // 根据实时信息更新数据库
            try {
                List<BasDevp> stations = new ArrayList<>();
                for (Integer sta : staNos2) {
                    StaProtocol staProtocol = station.get(sta);
                    BasDevp sqlModel = staProtocol.toSqlModel();
                    stations.add(sqlModel);
                }
                if (!stations.isEmpty()) {
                    BasDevpService basConveyorStaService = SpringUtils.getBean(BasDevpService.class);
                    if (null != basConveyorStaService && !basConveyorStaService.updateBatchById(stations)) {
                        throw new Exception("更新数据库数据失败");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                OutputQueue.DEVP.offer(MessageFormat.format("【{0}】更新数据库数据失败 ===>> [id:{1}] [ip:{2}] [port:{3}] [rack:{4}] [slot:{5}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort(), slave.getRack(), slave.getSlot()));
                News.error("更新数据库数据失败 ===>> [id:{}] [ip:{}] [port:{}] [rack:{}] [slot:{}]", slave.getId(), slave.getIp(), slave.getPort(), slave.getRack(), slave.getSlot());
            }
        } else {
            OutputQueue.DEVP.offer(MessageFormat.format("【{0}】读取输送线plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}] [rack:{4}] [slot:{5}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort(), slave.getRack(), slave.getSlot()));
//            log.error("读取输送线plc状态信息失败 ===>> [id:{}] [ip:{}] [port:{}] [rack:{}] [slot:{}]", device.getId(), device.getIp(), device.getPort(), device.getRack(), device.getSlot());
        }
    }
    /**
     * 写入 ID+目标站 =====> 单站点写入
     */
    private void write(StaProtocol staProtocol) throws InterruptedException {
        if (null == staProtocol) {
            return;
        }
        int index = staNos1.indexOf(staProtocol.getSiteId());
        index += 1;
        short[] array = new short[2];
        array[0] = staProtocol.getWorkNo();
        array[1] = staProtocol.getStaNo();
        String staNoAddress = "DB83." + (index * 8 + 4);
        String workNoAddress = "DB83." + (index * 8 + 6);
        OperateResult write1 = null;    // 工作号
        OperateResult write2 = null;     // 目标站
        //任务下发次数
        int writeCount = 0;
        do {
            write1 = siemensS7Net.Write(workNoAddress, array[0]);    // 工作号
            write2 = siemensS7Net.Write(staNoAddress, array[1]);
            if ((write1.IsSuccess && write2.IsSuccess)) {
                log.info("写入输送线命令后返回成功,并且回读成功。输送线plc编号={},{},{},写入次数={}", staProtocol.getSiteId(), JSON.toJSON(staProtocol.getWorkNo()), JSON.toJSON(staProtocol.getStaNo()), writeCount);
//                OperateResultExOne<byte[]> readResult = siemensS7Net.Read("DB82.14", (short) (staNos2.indexOf(siteId) * 26));
//                //OperateResultExOne<byte[]> readResult = siemensS7Net.Read(staNoAddress, (short) 8);
//                if (readResult.IsSuccess) {
//                    int workNo2 = siemensS7Net.getByteTransform().TransInt16(readResult.Content, 2);     // 工作号
//                    int staNo2 = siemensS7Net.getByteTransform().TransInt16(readResult.Content, 4);   // 目标站
//                    // int staNo2 = siemensS7Net.getByteTransform().TransInt16(readResult.Content, 0);
//                    //int workNo2 = siemensS7Net.getByteTransform().TransInt16(readResult.Content, 0);
//                    if (workNo == workNo2 && staNo == staNo2) {
//                        //任务命令写入成功
//                        log.info("写入输送线命令后返回成功,并且回读成功。输送线plc编号={},{},{},写入次数={}", siteId, JSON.toJSON(workNo), JSON.toJSON(staNo), writeCount);
//                        return true;
//                    } else {//返回结果是成功了,但是真实值不相同
//                        writeCount++;
//                        log.error("写入输送线命令后返回成功,但是读取任务值不一致。输送线plc编号={},{},{},写入次数={}", siteId, JSON.toJSON(workNo), JSON.toJSON(staNo), writeCount);
//                    }
//                } else {
//                    writeCount++;
//                    log.error("写入输送线命令后读取失败。输送线plc编号={},站点数据={},{},写入次数={}", siteId, JSON.toJSON(workNo), JSON.toJSON(staNo), writeCount);
//                }
            } else {
                writeCount++;
            }
        } while (writeCount < 5);
//        StaProtocol staProtocol = station.get(siteId);
//        if (staProtocol.getWorkNo() == 0 && staProtocol.getStaNo() ==0) {
//            staProtocol.setPakMk(true);
//        }
        OutputQueue.DEVP.offer(MessageFormat.format("【{0}】写入输送线站点数据失败。输送线plc编号={1},站点数据={2}", slave.getId(), JSON.toJSON(array)));
        log.error("写入输送线站点数据失败。输送线plc编号={},站点数据={}", slave.getId(), JSON.toJSON(array));
    }
    /**
     * 心跳
     */
    private void heartbeat() {
        if (heartBeatVal == 1) {
            heartBeatVal = 2;
        } else {
            heartBeatVal = 1;
        }
        OperateResult write = siemensS7Net.Write("DB100.50", heartBeatVal);
        if (!write.IsSuccess) {
            News.error("输送线plc编号={} 心跳失败", slave.getId());
        }
    }
    /**
     * 设置入库标记
     */
    @Override
    public void setPakMk(Integer siteId, boolean pakMk) {
        StaProtocol staProtocol = station.get(siteId);
        if (null != staProtocol) {
            staProtocol.setPakMk(pakMk);
        }
    }
    public synchronized void setOutInModel(Short staNo, Short outInModel) {
        String dbAddress = "DB51.4";
        if (staNo == 105) {
            dbAddress = "DB51.4";
        } else if (staNo == 205) {
            dbAddress = "DB51.10";
        } else if (staNo == 346) {
            dbAddress = "DB51.12";
        } else {
            News.error("模式切换失败,地址错误={},model={}", staNo, outInModel);
            return;
        }
        OperateResult write = siemensS7Net.Write(dbAddress, outInModel);
        if (!write.IsSuccess) {
            News.error("模式切换失败={},model={}", staNo, outInModel);
        }
    }
    @Override
    public void close() {
        siemensS7Net.ConnectClose();
    }
}
src/main/java/com/zy/core/thread/impl/NormalLedThread.java
New file
@@ -0,0 +1,88 @@
package com.zy.core.thread.impl;
import com.zy.common.model.MatDto;
import com.zy.core.model.command.LedCommand;
import com.zy.core.thread.LedThread;
import lombok.extern.slf4j.Slf4j;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Slf4j
@SuppressWarnings("all")
public class NormalLedThread implements LedThread, Runnable {
    private Set<Integer> workNos = new HashSet<>();
    private boolean ledMk = false;
    private boolean resetStatus = false;    // 复位状态
    // 显示器
    private StringBuffer stringBuffer = new StringBuffer();
    private List<LedCommand> commandList;
    private StringBuffer errorMsg = new StringBuffer();
    @Override
    public void run() {
    }
    public void write(List<LedCommand> list) {
        commandList = list;
        StringBuilder sb = new StringBuilder();
        for (LedCommand command : list) {
            sb.append(command.getTitle()).append("(").append(command.getWorkNo()).append(")").append("\n");
            sb.append("源库位:").append(command.getSourceLocNo()).append("\n");
            sb.append("目标站:").append(command.getStaNo()).append("\n");
            if (!command.isEmptyMk()) {
                for (MatDto matDto : command.getMatDtos()) {
                    sb.append("物料编码:").append(matDto.getMatNo()).append("\n");
                    sb.append("名称:").append(matDto.getMaknx()).append("\n");
                    sb.append("数量:").append(matDto.getCount()).append("\n");
                    sb.append("规格:").append(matDto.getSpecs()).append("\n");
                }
            }
            sb.append("\n");
        }
        stringBuffer.delete(0, stringBuffer.length());
        stringBuffer.append(sb.toString());
        errorReset();
    }
    public void reset() {
        commandList = null;
        stringBuffer.delete(0, stringBuffer.length());
        errorMsg.delete(0, errorMsg.length());
    }
    public void error(String msg) {
        errorMsg.delete(0, errorMsg.length());
        errorMsg.append(msg);
    }
    public void errorReset() {
        this.errorMsg.delete(0, errorMsg.length());
    }
    @Override
    public boolean connect() {
        return true;
    }
    @Override
    public void close() {
    }
    @Override
    public void setLedMk(boolean mk) {
        this.ledMk = mk;
    }
    @Override
    public boolean isLedMk() {
        return this.ledMk;
    }
}
src/main/java/com/zy/core/thread/impl/SiemensDevpThread.java
File was deleted
src/main/resources/application.yml
@@ -13,7 +13,7 @@
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/fyxc_shuttle?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root
    password: zhangchao
  mvc:
    static-path-pattern: /**
  redis:
@@ -44,14 +44,14 @@
# 下位机配置
wcs-slave:
#  # 四向穿梭车1
#  shuttle[0]:
#    id: 1
#    ip: 192.168.10.81
#    port: 8888
#    rack: 0
#    slot: 0
#    threadImpl: NyShuttleThread
  #  # 四向穿梭车1
  #  shuttle[0]:
  #    id: 1
  #    ip: 192.168.10.81
  #    port: 8888
  #    rack: 0
  #    slot: 0
  #    threadImpl: NyShuttleThread
  # 四向穿梭车2
  shuttle[0]:
    id: 2
@@ -72,3 +72,15 @@
    standByBay: 1
    staRow: 2
    staBay: 1
  devpSlave[0]:
    id:
    inSta[0]:
      staNo:
      backSta:
    inSta[1]:
      staNo:
      backSta: