#
Junjie
2025-04-15 d56b8093dc9e3e75f8efe1a0f1aa6d821c9c3dfb
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/thread/impl/NyShuttleThread.java
@@ -9,6 +9,7 @@
import com.zy.asrs.framework.common.SpringUtils;
import com.zy.asrs.framework.exception.CoolException;
import com.zy.asrs.wcs.common.ExecuteSupport;
import com.zy.asrs.wcs.core.action.ShuttleAction;
import com.zy.asrs.wcs.core.domain.param.ShuttleMoveLocParam;
import com.zy.asrs.wcs.core.entity.BasShuttle;
import com.zy.asrs.wcs.core.entity.Loc;
@@ -30,6 +31,7 @@
import com.zy.asrs.wcs.rcs.constant.DeviceRedisConstant;
import com.zy.asrs.wcs.rcs.entity.Device;
import com.zy.asrs.wcs.rcs.entity.DeviceDataLog;
import com.zy.asrs.wcs.rcs.model.CommandResponse;
import com.zy.asrs.wcs.rcs.model.command.NyShuttleHttpCommand;
import com.zy.asrs.wcs.rcs.model.enums.ShuttleProtocolStatusType;
import com.zy.asrs.wcs.rcs.model.enums.SlaveType;
@@ -60,7 +62,11 @@
    private static final boolean DEBUG = false;//调试模式
    private List<JSONObject> socketReadResults = new ArrayList<>();
    private List<JSONObject> socketResults = new ArrayList<>();
    //原始设备数据
    private Object originDeviceData;
    public NyShuttleThread(Device device, RedisUtil redisUtil) {
        this.device = device;
@@ -75,18 +81,125 @@
        //监听消息并存储
        Thread innerThread = new Thread(() -> {
            while (true) {
                listenSocketMessage();
                try {
                    listenSocketMessage();
                    listenInit();//监听初始化事件
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        innerThread.start();
        while (true) {
            try {
                read();
                Thread.sleep(500);
            } catch (Exception e) {
                log.error("ShuttleThread Fail", e);
        //设备读取
        Thread readThread = new Thread(() -> {
            while (true) {
                try {
                    read();
                    Thread.sleep(50);
                } catch (Exception e) {
                    log.error("ShuttleThread Fail", e);
                }
            }
        });
        readThread.start();
        //设备执行
        Thread executeThread = new Thread(() -> {
            while (true) {
                try {
                    ShuttleAction shuttleAction = SpringUtils.getBean(ShuttleAction.class);
                    if (shuttleAction == null) {
                        continue;
                    }
                    Object object = redisUtil.get(DeviceRedisConstant.SHUTTLE_FLAG + device.getDeviceNo());
                    if (object == null) {
                        continue;
                    }
                    Integer taskNo = Integer.valueOf(String.valueOf(object));
                    if (taskNo != 0) {
                        //存在任务需要执行
                        boolean result = shuttleAction.executeWork(device, taskNo);
                    }
                    //小车空闲且有跑库程序
                    shuttleAction.moveLoc(device);
                    Thread.sleep(200);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        executeThread.start();
        //其他任务
        Thread otherThread = new Thread(() -> {
            while (true) {
                try {
                    saveLog();//保存数据
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        otherThread.start();
    }
    private void saveLog() {
        if (shuttleProtocol == null) {
            return;
        }
        if (System.currentTimeMillis() - shuttleProtocol.getDeviceDataLog() > 1000 * 5) {
            if (this.originDeviceData != null) {
                //采集时间超过5s,保存一次数据记录
                //保存数据记录
                DeviceDataLogService deviceDataLogService = SpringUtils.getBean(DeviceDataLogService.class);
                DeviceDataLog deviceDataLog = new DeviceDataLog();
                deviceDataLog.setOriginData(JSON.toJSONString(this.originDeviceData));
                deviceDataLog.setWcsData(JSON.toJSONString(shuttleProtocol));
                deviceDataLog.setType(String.valueOf(SlaveType.Shuttle));
                deviceDataLog.setDeviceNo(String.valueOf(shuttleProtocol.getShuttleNo()));
                deviceDataLog.setCreateTime(new Date());
                deviceDataLog.setHostId(device.getHostId());
                deviceDataLogService.save(deviceDataLog);
                //更新采集时间
                shuttleProtocol.setDeviceDataLog(System.currentTimeMillis());
            }
        }
        //将四向穿梭车状态保存至数据库
        BasShuttleService shuttleService = SpringUtils.getBean(BasShuttleService.class);
        BasShuttle basShuttle = shuttleService.getOne(new LambdaQueryWrapper<BasShuttle>()
                .eq(BasShuttle::getShuttleNo, device.getDeviceNo())
                .eq(BasShuttle::getHostId, device.getHostId()));
        if (basShuttle == null) {
            basShuttle = new BasShuttle();
            //四向穿梭车号
            basShuttle.setShuttleNo(Integer.valueOf(device.getDeviceNo()));
            basShuttle.setStatus(1);
            basShuttle.setDeleted(0);
            basShuttle.setHostId(device.getHostId());
            basShuttle.setDeviceId(device.getId().intValue());
            shuttleService.save(basShuttle);
        }else {
            Integer shuttleId = basShuttle.getId();
            basShuttle = new BasShuttle();
            basShuttle.setId(shuttleId);
        }
        //任务号
        basShuttle.setTaskNo(shuttleProtocol.getTaskNo().intValue());
        //修改时间
        basShuttle.setUpdateTime(new Date());
        //设备状态
        basShuttle.setProtocol(JSON.toJSONString(shuttleProtocol));
        if (shuttleService.updateById(basShuttle)) {
            OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), device.getDeviceNo()));
        }
    }
@@ -111,7 +224,19 @@
            }
            JSONObject result = JSON.parseObject(sb.toString());//得到响应结果集
            if (!socketResults.isEmpty() && socketResults.size() >= 5) {
            String msgType = result.getString("msgType");
            if ("responseMsg".equals(msgType)) {
                JSONObject response = result.getJSONObject("response");
                JSONObject body = response.getJSONObject("body");
                if (body.containsKey("workingMode")) {
                    //read
                    socketReadResults.add(body);
                    return;
                }
            }
            if (!socketResults.isEmpty() && socketResults.size() >= 20) {
                socketResults.remove(0);//清理头节点
            }
            socketResults.add(result);//添加数据
@@ -120,7 +245,7 @@
        }
    }
    public JSONObject getRequestBody(String type) {
    public JSONObject getRequestBody(String type, String taskId) {
        try {
            // 获取服务器响应
            JSONObject result = null;
@@ -143,7 +268,14 @@
                }
                if (!responseType.equals(type)) {
                    continue;//响应ID与请求ID不一致,不在调试模式下
                    continue;//响应类型与请求类型不一致,不在调试模式下
                }
                if (taskId != null) {
                    String responseTaskId = resultBody.get("taskId").toString();
                    if (!responseTaskId.equals(taskId)) {
                        continue;//响应ID与请求ID不一致,不在调试模式下
                    }
                }
                result = socketResult;
@@ -167,7 +299,7 @@
                this.connect();
            }
            readStatus();
            listenInit();//监听初始化事件
            Thread.sleep(200);
        } catch (Exception e) {
            e.printStackTrace();
            OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】读取四向穿梭车状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), device.getId(), device.getIp(), device.getPort()));
@@ -188,7 +320,18 @@
            //----------读取四向穿梭车状态-----------
            NyShuttleHttpCommand readStatusCommand = getReadStatusCommand(Integer.parseInt(device.getDeviceNo()));
            JSONObject data = requestCommand(readStatusCommand);
            requestCommandAsync(readStatusCommand);//请求状态
            if (this.socketReadResults.isEmpty()) {
                if (System.currentTimeMillis() - shuttleProtocol.getLastOnlineTime() > 1000 * 60) {
                    //最后一次上线时间超过60s,认定离线
                    this.shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.OFFLINE);
                }
                return;
            }
            JSONObject data = this.socketReadResults.get(0);
            this.socketReadResults.remove(0);
            if (data == null) {
                if (System.currentTimeMillis() - shuttleProtocol.getLastOnlineTime() > 1000 * 60) {
                    //最后一次上线时间超过60s,认定离线
@@ -237,56 +380,22 @@
                ///读取四向穿梭车状态-end
                //小车处于运行中,将标记置为true
                if (shuttleProtocol.getDeviceStatus() == 1) {
                if (shuttleProtocol.getDeviceStatus() == 0) {
                    shuttleProtocol.setPakMk(true);
                }
                if (shuttleProtocol.getProtocolStatusType() == null && shuttleProtocol.getDeviceStatus().intValue() == 0) {
                if (shuttleProtocol.getProtocolStatusType() == null && shuttleProtocol.getDeviceStatus().intValue() == 1) {
                    //小车空闲状态、小车任务状态为未知,认定曾离线过,需要复位成空闲
                    shuttleProtocol.setProtocolStatusType(ShuttleProtocolStatusType.IDLE);
                }
                if (System.currentTimeMillis() - shuttleProtocol.getDeviceDataLog() > 1000 * 5) {
                    //采集时间超过5s,保存一次数据记录
                    //保存数据记录
                    DeviceDataLogService deviceDataLogService = SpringUtils.getBean(DeviceDataLogService.class);
                    DeviceDataLog deviceDataLog = new DeviceDataLog();
                    deviceDataLog.setOriginData(JSON.toJSONString(data));
                    deviceDataLog.setWcsData(JSON.toJSONString(shuttleProtocol));
                    deviceDataLog.setType(String.valueOf(SlaveType.Shuttle));
                    deviceDataLog.setDeviceNo(String.valueOf(shuttleProtocol.getShuttleNo()));
                    deviceDataLog.setCreateTime(new Date());
                    deviceDataLog.setHostId(device.getHostId());
                    deviceDataLogService.save(deviceDataLog);
                    //更新采集时间
                    shuttleProtocol.setDeviceDataLog(System.currentTimeMillis());
                if (shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.OFFLINE) && shuttleProtocol.getDeviceStatus().intValue() == 1) {
                    this.shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.IDLE);
                }
                //将四向穿梭车状态保存至数据库
                BasShuttleService shuttleService = SpringUtils.getBean(BasShuttleService.class);
                BasShuttle basShuttle = shuttleService.getOne(new LambdaQueryWrapper<BasShuttle>()
                        .eq(BasShuttle::getShuttleNo, device.getDeviceNo())
                        .eq(BasShuttle::getHostId, device.getHostId()));
                if (basShuttle == null) {
                    basShuttle = new BasShuttle();
                    //四向穿梭车号
                    basShuttle.setShuttleNo(Integer.valueOf(device.getDeviceNo()));
                    basShuttle.setStatus(1);
                    basShuttle.setDeleted(0);
                    basShuttle.setHostId(device.getHostId());
                    basShuttle.setDeviceId(device.getId().intValue());
                    shuttleService.save(basShuttle);
                }
                //任务号
                basShuttle.setTaskNo(shuttleProtocol.getTaskNo().intValue());
                //修改时间
                basShuttle.setUpdateTime(new Date());
                //设备状态
                basShuttle.setProtocol(JSON.toJSONString(shuttleProtocol));
                if (shuttleService.updateById(basShuttle)) {
                    OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), device.getDeviceNo()));
                }
                this.originDeviceData = data;
                OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), device.getDeviceNo()));
            }
        } catch (Exception e) {
            e.printStackTrace();
@@ -322,21 +431,21 @@
                String requestType = resultBody.getString("requestType");
                Integer requestId = resultHeader.getInteger("requestId");
                if (requestType.equals("init")) {
                    removeIdx = i;//此数据已经处理,从结果集中剔除
                    socketResults.remove(removeIdx);
                    Integer code = resultBody.getInteger("code");
                    OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】四向车复位上报 ===>> [code:{1}] [ip:{2}] [port:{3}]", code, device.getId(), device.getIp(), device.getPort()));
                    //小车复位请求
                    ShuttleCommand initCommand = getInitCommand(requestId, code);
                    //发出请求
                    NyShuttleHttpCommand httpCommand = JSON.parseObject(initCommand.getBody(), NyShuttleHttpCommand.class);
                    JSONObject requestResult = requestCommand(httpCommand);
                    removeIdx = i;//此数据已经处理,从结果集中剔除
                    log.info(MessageFormat.format("【{0}】四向车复位上报 ===>> [code:{1}] [ip:{2}] [port:{3}]", device.getId(), code, device.getIp(), device.getPort()));
                    OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】四向车复位上报 ===>> [code:{1}] [ip:{2}] [port:{3}]", device.getId(), code, device.getIp(), device.getPort()));
                    break;
                }
            }
            if (removeIdx != -1) {
                socketResults.remove(removeIdx);
            }
        } catch (Exception e) {
            e.printStackTrace();
@@ -362,12 +471,14 @@
    }
    @Override
    public boolean movePath(List<NavigateNode> nodes, Integer taskNo) {
        return true;
    public CommandResponse movePath(List<NavigateNode> nodes, Integer taskNo) {
        CommandResponse response = new CommandResponse(true);
        return response;
    }
    @Override
    public boolean move(ShuttleCommand command) {
    public CommandResponse move(ShuttleCommand command) {
        CommandResponse response = new CommandResponse(false);
        try {
            //发出请求
            NyShuttleHttpCommand httpCommand = JSON.parseObject(command.getBody(), NyShuttleHttpCommand.class);
@@ -406,70 +517,86 @@
            for (NyShuttleHttpCommand requestCommand : commandList) {
                JSONObject result = requestCommand(requestCommand);
//                if (result == null) {
//                    return false;//请求失败
//                }
                if (result == null) {
                    return response;//请求失败
                }
                this.shuttleProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
                response.setMessage(JSON.toJSONString(result));
                response.setResult(true);
            }
            return true;
        } catch (IOException e) {
            return false;
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            response.setMessage(e.getMessage());
            return response;
        }
    }
    @Override
    public boolean lift(ShuttleCommand command) {
    public CommandResponse lift(ShuttleCommand command) {
        CommandResponse response = new CommandResponse(false);
        try {
            //发出请求
            NyShuttleHttpCommand httpCommand = JSON.parseObject(command.getBody(), NyShuttleHttpCommand.class);
            JSONObject result = requestCommand(httpCommand);
            if (result == null) {
                return false;//请求失败
                return response;//请求失败
            }
            this.shuttleProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            return true;
        } catch (IOException e) {
            return false;
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return response;
        }
    }
    @Override
    public boolean charge(ShuttleCommand command) {
    public CommandResponse charge(ShuttleCommand command) {
        CommandResponse response = new CommandResponse(false);
        try {
            //发出请求
            NyShuttleHttpCommand httpCommand = JSON.parseObject(command.getBody(), NyShuttleHttpCommand.class);
            JSONObject result = requestCommand(httpCommand);
            if (result == null) {
                return false;//请求失败
                return response;//请求失败
            }
            this.shuttleProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            return true;
        } catch (IOException e) {
            return false;
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return response;
        }
    }
    @Override
    public boolean reset(ShuttleCommand command) {
    public CommandResponse reset(ShuttleCommand command) {
        setSyncTaskNo(0);
        setProtocolStatus(ShuttleProtocolStatusType.IDLE);
        enableMoveLoc(null, false);
        return true;
        return new CommandResponse(true, JSON.toJSONString(command));
    }
    @Override
    public boolean updateLocation(ShuttleCommand command) {
    public CommandResponse updateLocation(ShuttleCommand command) {
        CommandResponse response = new CommandResponse(false);
        try {
            //发出请求
            NyShuttleHttpCommand httpCommand = JSON.parseObject(command.getBody(), NyShuttleHttpCommand.class);
            JSONObject result = requestCommand(httpCommand);
            if (result == null) {
                return false;//请求失败
                return response;//请求失败
            }
            this.shuttleProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            return true;
        } catch (IOException e) {
            return false;
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return response;
        }
    }
@@ -595,7 +722,7 @@
            return false;
        }
        if (this.shuttleProtocol.getDeviceStatus() == 1 && this.shuttleProtocol.getHasCharge()) {
        if (this.shuttleProtocol.getDeviceStatus() == 0 && this.shuttleProtocol.getHasCharge()) {
            //运行中 && 充电中
            return true;
        }
@@ -720,6 +847,15 @@
    }
    @Override
    public boolean requestWaiting() {
        if (this.shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.IDLE)) {
            this.shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.WAITING);
            return true;
        }
        return false;
    }
    @Override
    public ShuttleCommand getMoveCommand(Integer taskNo, String startCodeNum, String distCodeNum, Integer allDistance, Integer runDirection, Integer runSpeed, List<NavigateNode> nodes) {
        NavigateMapData navigateMapData = SpringUtils.getBean(NavigateMapData.class);
        NyShuttleHttpCommand httpStandard = getHttpStandard(Integer.parseInt(device.getDeviceNo()), taskNo);
@@ -727,9 +863,10 @@
        ArrayList<HashMap<String, Object>> path = new ArrayList<>();
        Integer taskId = getTaskId();
        HashMap<String, Object> body = new HashMap<>();
        body.put("requestType", "move");//移动命令
        body.put("taskId", getTaskId());//TaskID需要随机
        body.put("taskId", taskId);//TaskID需要随机
//        body.put("start", navigateNodeToNyPointNode(NavigatePositionConvert.codeToNode(startCodeNum, device.getHostId())));//起点
//        body.put("target", navigateNodeToNyPointNode(NavigatePositionConvert.codeToNode(distCodeNum, device.getHostId())));//终点
        body.put("path", path);
@@ -772,6 +909,7 @@
        command.setBody(JSON.toJSONString(httpStandard));
        command.setMode(ShuttleCommandModeType.MOVE.id);
        command.setTargetLocNo(loc.getLocNo());
        command.setTaskNo(taskId);
        return command;
    }
@@ -780,9 +918,10 @@
        NyShuttleHttpCommand httpStandard = getHttpStandard(Integer.parseInt(device.getDeviceNo()), taskNo);
        NyShuttleHttpCommand.NyRequest request = httpStandard.getRequest();
        Integer taskId = getTaskId();//TaskID需要随机
        HashMap<String, Object> body = new HashMap<>();
        body.put("requestType", lift ? "liftUp" : "liftDown");//顶升或下降命令
        body.put("taskId", getTaskId());//TaskID需要随机
        body.put("taskId", taskId);
        request.setBody(body);
        httpStandard.setRequest(request);
@@ -791,6 +930,7 @@
        command.setShuttleNo(Integer.parseInt(this.device.getDeviceNo()));
        command.setBody(JSON.toJSONString(httpStandard));
        command.setMode(lift ? ShuttleCommandModeType.PALLET_LIFT.id : ShuttleCommandModeType.PALLET_DOWN.id);
        command.setTaskNo(taskId);
        return command;
    }
@@ -799,9 +939,10 @@
        NyShuttleHttpCommand httpStandard = getHttpStandard(Integer.parseInt(device.getDeviceNo()), taskNo);
        NyShuttleHttpCommand.NyRequest request = httpStandard.getRequest();
        Integer taskId = getTaskId();//TaskID需要随机
        HashMap<String, Object> body = new HashMap<>();
        body.put("requestType", charge ? "charge" : "stopCharge");//充电或停止充电
        body.put("taskId", getTaskId());//TaskID需要随机
        body.put("taskId", taskId);
        request.setBody(body);
        httpStandard.setRequest(request);
@@ -810,6 +951,7 @@
        command.setShuttleNo(Integer.parseInt(this.device.getDeviceNo()));
        command.setBody(JSON.toJSONString(httpStandard));
        command.setMode(charge ? ShuttleCommandModeType.CHARGE_OPEN.id : ShuttleCommandModeType.CHARGE_CLOSE.id);
        command.setTaskNo(taskId);
        return command;
    }
@@ -829,6 +971,7 @@
        command.setShuttleNo(Integer.parseInt(this.device.getDeviceNo()));
        command.setBody(JSON.toJSONString(httpStandard));
        command.setMode(ShuttleCommandModeType.UPDATE_LOCATION.id);
        command.setTaskNo(taskNo);
        return command;
    }
@@ -883,6 +1026,7 @@
        command.setShuttleNo(Integer.parseInt(this.device.getDeviceNo()));
        command.setBody(JSON.toJSONString(httpStandard));
        command.setMode(ShuttleCommandModeType.RESET.id);
        command.setTaskNo(taskNo);
        return command;
    }
@@ -966,29 +1110,49 @@
//            System.out.println("Sent message to server: " + JSON.toJSONString(httpCommand));
        String requestType = null;
        String taskId = null;
        try {
            requestType = httpCommand.getRequest().getBody().get("requestType").toString();
            taskId = httpCommand.getRequest().getBody().get("taskId").toString();
        } catch (Exception e) {
            return null;
//            return null;
            //taskId可能取空,不报错,正常情况
        }
        // 获取服务器响应
        // 尝试10次
        JSONObject result = null;
        for (int i = 0; i < 10; i++) {
            result = getRequestBody(requestType);
            result = getRequestBody(requestType,taskId);
            if (result == null) {
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else {
                break;
            }
            break;
        }
        return result;//返回Body结果集
    }
    private void requestCommandAsync(NyShuttleHttpCommand httpCommand) throws IOException {
        if (this.socket == null) {
            return;
        }
        //压缩数据包
        JSONObject data = JSON.parseObject(JSON.toJSONString(httpCommand));
        data.remove("nodes");
        // 获取输出流
        OutputStreamWriter writer = new OutputStreamWriter(this.socket.getOutputStream());
        writer.write(JSON.toJSONString(data) + "\r\n");
        writer.flush();
//            System.out.println("Sent message to server: " + JSON.toJSONString(httpCommand));
    }
    private JSONObject filterBodyData(JSONObject data) {
        Object response = data.get("response");
        if (response == null) {