| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- package com.mes.component;
- import com.alibaba.fastjson2.JSONObject;
- import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
- import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
- import com.mes.ui.DataUtil;
- import com.mes.ui.MesClient;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import javax.swing.*;
- import java.awt.*;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.awt.event.MouseAdapter;
- import java.awt.event.MouseEvent;
- import java.util.Timer;
- import java.util.TimerTask;
- public class WorkJPanelOP40Transfer extends JPanel {
- public static final Logger log = LoggerFactory.getLogger(WorkJPanelOP40Transfer.class);
- public String oprno = "OP040";
- public String pos = "A";
- public String lastSn = ""; // 最近的码
- public String lineSn = "XT";
- public JLabel feedinglabel; // 请求扫码信号
- public JLabel feedingmeslabel; // MES扫码反馈
- public JLabel feedingtotransferlabel; // 去中转台信号
- public JTextField productSnFeeding; // 工件码显示
- public JButton status_menu; // 状态显示
- public JButton resetFeedingBtn; // 刷新按钮
-
- public JButton signalBtn; // 信号监控按钮
-
- public PlcSignalMonitor signalMonitor; // 信号监控组件
- public ImageIcon imageGreen;
- public ImageIcon imageGray;
- public String plcIp1 = "192.168.90.83"; // PLC3 西侧
- public String plcIp2 = "192.168.90.84"; // PLC4 东侧
- // 只连接一个PLC
- public S7PLC s7PLC = null;
- public Integer workWidth = 470;
- public Integer workHeight = 300;
- public String plcDb = "DB7005"; // 共用工位6的DB块
- public Integer tjFeedingFlag = 0; // 上料状态标识: 0=等待请求, 1=已获取工件码等待清空
- public Boolean toTransfer = false; // 去中转台信号(用于触发清空)
-
- public int scanRetryCount = 0; // 扫码重试计数器,最多重试1次(共2次扫码机会)
- public static final int MAX_SCAN_RETRY = 1; // 最大重试次数
- public Boolean plcHeart = false;
-
- // 用于检测状态变化的上一次值(减少日志输出)
- private java.util.Map<String, Boolean> lastReadValues = new java.util.HashMap<>();
- private java.util.Map<String, Boolean> lastWriteValues = new java.util.HashMap<>();
- public Integer isLocal = 0; // 0=正式 1=本地
- public WorkJPanelOP40Transfer(String position) {
- this.setLayout(null);
- this.setBackground(Color.WHITE);
- this.pos = position;
- // 根据位置选择连接的PLC,DB块都是DB7005(共用工位6的DB块)
- if (pos.equals("A")) {
- // 中转车1 连接 PLC3(西侧)
- s7PLC = new S7PLC(EPlcType.S1500, plcIp1);
- } else if (pos.equals("B")) {
- // 中转车2 连接 PLC4(东侧)
- s7PLC = new S7PLC(EPlcType.S1500, plcIp2);
- }
- JLabel oprnoLabel = new JLabel("中转车" + (pos.equals("A") ? "1" : "2"));
- oprnoLabel.setHorizontalAlignment(SwingConstants.CENTER);
- oprnoLabel.setForeground(Color.BLACK);
- oprnoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20));
- oprnoLabel.setBounds(0, 0, workWidth / 5, 40);
- this.add(oprnoLabel);
- status_menu = new JButton("等待请求");
- status_menu.setBounds(workWidth / 5, 0, workWidth * 4 / 5, 40);
- status_menu.setForeground(Color.GREEN);
- status_menu.setFont(new Font("微软雅黑", Font.PLAIN, 16));
- status_menu.setBackground(Color.BLACK);
- this.add(status_menu);
- JLabel oprnoLabelFeeding = new JLabel("上料");
- oprnoLabelFeeding.setHorizontalAlignment(SwingConstants.CENTER);
- oprnoLabelFeeding.setForeground(Color.BLACK);
- oprnoLabelFeeding.setFont(new Font("微软雅黑", Font.PLAIN, 20));
- oprnoLabelFeeding.setBounds(0, 50, workWidth / 5, 40);
- this.add(oprnoLabelFeeding);
- productSnFeeding = new JTextField("");
- productSnFeeding.setHorizontalAlignment(SwingConstants.CENTER);
- productSnFeeding.setForeground(Color.BLACK);
- productSnFeeding.setFont(new Font("微软雅黑", Font.PLAIN, 16));
- productSnFeeding.setEditable(false);
- productSnFeeding.setBounds(workWidth / 5, 50, workWidth * 3 / 5, 40);
- productSnFeeding.addMouseListener(new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- String sn = productSnFeeding.getText().trim();
- if (!sn.isEmpty()) {
- MesClient.createQRCode(productSnFeeding.getText(), oprno + pos);
- }
- }
- });
- this.add(productSnFeeding);
- resetFeedingBtn = new JButton("刷新");
- resetFeedingBtn.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- int choice = JOptionPane.showConfirmDialog(null, "确定刷新工件吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
- if (choice == JOptionPane.YES_OPTION) {
- resetFeeding();
- }
- }
- });
- resetFeedingBtn.setFont(new Font("微软雅黑", Font.PLAIN, 22));
- resetFeedingBtn.setBounds(workWidth * 4 / 5 + 10, 50, workWidth / 5 - 10, 40);
- this.add(resetFeedingBtn);
- imageGreen = new ImageIcon(MesClient.class.getResource("/bg/green_dot.png"));
- imageGreen.setImage(imageGreen.getImage().getScaledInstance(20, 20, Image.SCALE_SMOOTH));
- imageGray = new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png"));
- imageGray.setImage(imageGray.getImage().getScaledInstance(20, 20, Image.SCALE_SMOOTH));
- feedinglabel = new JLabel("请求扫码");
- feedinglabel.setHorizontalAlignment(SwingConstants.LEFT);
- feedinglabel.setIcon(imageGreen);
- feedinglabel.setForeground(Color.BLACK);
- feedinglabel.setBounds(0, 150, workWidth / 3, 30);
- this.add(feedinglabel);
- feedingmeslabel = new JLabel("MES扫码反馈");
- feedingmeslabel.setHorizontalAlignment(SwingConstants.LEFT);
- feedingmeslabel.setIcon(imageGreen);
- feedingmeslabel.setForeground(Color.BLACK);
- feedingmeslabel.setBounds(workWidth / 3, 150, workWidth / 3, 30);
- feedingmeslabel.addMouseListener(new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- boolean ret = readAllowFeeding();
- int choice = JOptionPane.showConfirmDialog(null, "确定修改MES扫码反馈结果为" + (ret ? "false" : "true") + "吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
- if (choice == JOptionPane.YES_OPTION) {
- writeAllowFeeding(!ret);
- }
- }
- });
- this.add(feedingmeslabel);
- feedingtotransferlabel = new JLabel("去中转台");
- feedingtotransferlabel.setHorizontalAlignment(SwingConstants.LEFT);
- feedingtotransferlabel.setIcon(imageGray);
- feedingtotransferlabel.setForeground(Color.BLACK);
- feedingtotransferlabel.setBounds(workWidth * 2 / 3, 150, workWidth / 3, 30);
- this.add(feedingtotransferlabel);
-
- // 信号监控按钮
- String stationName = "中转车" + (pos.equals("A") ? "1(西侧)" : "2(东侧)");
- signalMonitor = new PlcSignalMonitor(s7PLC, plcDb, stationName, MesClient.mesClientFrame);
- signalBtn = signalMonitor.createSignalButton();
- signalBtn.setBounds(4, 190, 90, 26);
- this.add(signalBtn);
- startOprnoTimer();
- heartData();
- resetScanA();
- }
- public void setMenuStatus(String msg, int error) {
- if (error == 0) {
- this.status_menu.setForeground(Color.GREEN);
- } else {
- this.status_menu.setForeground(Color.RED);
- }
- this.status_menu.setText(msg);
- }
- // 定时任务 -----------------------------------------------------------------------------------------------------
- public Timer cjTimerText2;
- public void heartData() {
- // 中转车不写心跳,由工位F/L (DB7005) 统一写入
- // 避免同一个地址被多个组件写入导致冲突
- //
- // 原代码(已禁用):
- // if (cjTimerText2 != null) {
- // cjTimerText2.cancel();
- // }
- // cjTimerText2 = new Timer();
- // cjTimerText2.schedule(new TimerTask() {
- // public void run() {
- // if (MesClient.isLogin == 1 && isLocal == 0) {
- // plcHeart = !plcHeart;
- // writeBoolean(plcDb + ".0.6", plcHeart);
- // }
- // }
- // }, 1000, 1000);
- }
- public Timer oprnoTimer;
- public void startOprnoTimer() {
- //心跳显示图标
- if (oprnoTimer != null) {
- oprnoTimer.cancel();
- }
- oprnoTimer = new Timer();
- oprnoTimer.schedule(new TimerTask() {
- public void run() {
- try {
- if (MesClient.isLogin == 1) {
- // 读取PLC信号并更新UI
- Boolean retFeeding = readFeeding();
- feedinglabel.setIcon(retFeeding ? imageGreen : imageGray);
- Boolean retFeedingAllow = readAllowFeeding();
- feedingmeslabel.setIcon(retFeedingAllow ? imageGreen : imageGray);
- toTransfer = readFeedingToTransfer();
- feedingtotransferlabel.setIcon(toTransfer ? imageGreen : imageGray);
- // 请求信号消失时,清除MES反馈
- if (!retFeeding && retFeedingAllow) {
- writeAllowFeeding(false);
- }
- // 状态机逻辑(简化版)
- // 扫码和saveSn由工位6(F/L)的barCodeForTransfer()方法处理
- // 中转车面板只负责显示和重置
- if (tjFeedingFlag == 1) {
- // 状态1:已获取工件码,等待toTransfer信号变为false后清空
- if (!toTransfer) {
- log.info("[" + oprno + pos + "]toTransfer变为false,清空工件码");
- resetFeeding();
- }
- }
- }
- } catch (Exception e) {
- log.error(e.getMessage());
- }
- }
- }, 100, 3000);
- }
- public void barCode() {
- if (!productSnFeeding.getText().isEmpty()) {
- return;
- }
- String sn = readQrcode();
- if (sn.equals("")) {
- if (productSnFeeding.getText().isEmpty()) {
- productSnFeeding.setText("空结果");
- this.setMenuStatus("获取工件码为空", -1);
- }
- } else {
- productSnFeeding.setText(sn);
- lastSn = sn;
- // 查询工件质量
- JSONObject retObj = DataUtil.checkQuality(sn, oprno + pos, MesClient.user_menu.getText());
- if (retObj.get("result") != null && retObj.get("result").toString().equalsIgnoreCase("true")) {
- tjFeedingFlag = 1;//可加工
- setMenuStatus("工件可以加工", 0);
- writeAllowFeeding(true);
- resetFeedingBtn.setEnabled(false);
- } else {
- writeAllowFeeding(false);
- resetFeedingBtn.setEnabled(true);
- if (retObj.get("result") == null) {
- setMenuStatus("请求失败,请重试", -1);
- } else {
- if (retObj.get("result").toString().equalsIgnoreCase("false")) {
- setMenuStatus(retObj.getString("message"), -1);
- }
- }
- }
- }
- }
- public void resetFeeding() {
- productSnFeeding.setText("");
- tjFeedingFlag = 0;
- scanRetryCount = 0; // 重置重试计数器
- setMenuStatus("等待请求", 0);
- resetFeedingBtn.setEnabled(true);
- writeAllowFeeding(false);
- }
- public void resetScanA() {
- tjFeedingFlag = 0;
- scanRetryCount = 0; // 重置重试计数器
- productSnFeeding.setText("");
- setMenuStatus("等待请求", 0);
- resetFeedingBtn.setEnabled(true);
- // 延迟写入PLC,避免初始化时连接超时
- if(MesClient.isLogin == 1) {
- writeAllowFeeding(false);
- }
- }
- // 与设备交互-----------------------------------------------------------------------------------------
- // 请求扫码信号 (DB7005.0.0)
- public boolean readFeeding() {
- if (isLocal == 1) {
- return false;
- } else {
- return readBoolean(plcDb + ".0.0");
- }
- }
- // 读取去中转台信号 (DB7005.1.0)
- public boolean readFeedingToTransfer() {
- if (isLocal == 1) {
- return false;
- } else {
- return readBoolean(plcDb + ".1.0");
- }
- }
- // 读取MES允许上料信号 (DB7005.0.4)
- public boolean readAllowFeeding() {
- if (isLocal == 1) {
- return false;
- } else {
- return readBoolean(plcDb + ".0.4");
- }
- }
- // 写入MES允许上料信号 (DB7005.0.4)
- public boolean writeAllowFeeding(Boolean b) {
- if (isLocal == 1) {
- return true;
- } else {
- return writeBoolean(plcDb + ".0.4", b);
- }
- }
- // 读取中转车号 (DB7005.2.0)
- public int readTransferNo() {
- if (isLocal == 1) {
- return 1;
- } else {
- return s7PLC.readInt16(plcDb + ".2.0");
- }
- }
- // 读取中转车层数 (DB7005.4.0)
- public int readTransferFloor() {
- if (isLocal == 1) {
- return 1;
- } else {
- return s7PLC.readInt16(plcDb + ".4.0");
- }
- }
- // 中转车不扫码,直接从数据库获取工件码
- public String readQrcode() {
- String sn = "";
- if (isLocal == 1) {
- return "";
- } else {
- try {
- // if(this.pos.equals("A")){
- // sn = MesClient.scanQrcode1();
- // }else{
- // sn = MesClient.scanQrcode2();
- // }
- if(pos.equals("A")){
- log.info("[{}]触发西侧摄像头扫码", oprno+pos);
- // sn = MesClient.scanQrcode1();
- sn = MesClient.scanSnA;
- }else{
- log.info("[{}]触发东侧摄像头扫码", oprno+pos);
- sn = MesClient.scanSnB;
- // sn = MesClient.scanQrcode2();
- }
- } catch (Exception e) {
- log.error("[" + oprno + pos + "]获取工件码异常: " + e.getMessage(), e);
- }
- }
- return sn;
- }
- // 读取布尔值(只在值变化时打印日志)
- public boolean readBoolean(String db) {
- boolean permit;
- try {
- // 检查PLC连接是否可用
- if(s7PLC == null) {
- return false;
- }
- permit = s7PLC.readBoolean(db);
- // 只在值变化时打印日志
- Boolean lastValue = lastReadValues.get(db);
- if (lastValue == null || lastValue != permit) {
- log.info("<" + this.oprno + this.pos + ">读取" + db + "-->成功,结果:{}", permit ? "true" : "false");
- lastReadValues.put(db, permit);
- }
- } catch (Exception e) {
- // 连接超时时不打印完整堆栈
- if(e.getMessage() != null && e.getMessage().contains("connect timed out")) {
- // 连接超时是常见情况,降低日志级别
- } else {
- log.error("<" + this.oprno + this.pos + ">读取" + db + "-->失败: {}", e.getMessage());
- }
- return false;
- }
- return permit;
- }
- // 写入布尔值(只在值变化时打印日志)
- public boolean writeBoolean(String db, boolean permit) {
- try {
- // 检查PLC连接是否可用
- if(s7PLC == null) {
- log.warn("<" + this.oprno + this.pos + ">PLC未初始化,跳过写入" + db);
- return false;
- }
- // 只在值变化时打印日志
- Boolean lastValue = lastWriteValues.get(db);
- if (lastValue == null || lastValue != permit) {
- s7PLC.writeBoolean(db, permit);
- log.info("<" + this.oprno + this.pos + ">写入" + db + "-->成功,写入内容:{}", permit ? "true" : "false");
- lastWriteValues.put(db, permit);
- } else {
- // 值未变化,仍然执行写入但不打印日志
- s7PLC.writeBoolean(db, permit);
- }
- } catch (Exception e) {
- // 连接超时时不打印完整堆栈
- if(e.getMessage() != null && e.getMessage().contains("connect timed out")) {
- log.warn("<" + this.oprno + this.pos + ">写入" + db + "-->连接超时(PLC未连接)");
- } else {
- log.error("<" + this.oprno + this.pos + ">写入" + db + "-->失败,写入内容:{}", permit ? "true" : "false");
- log.error(e.getMessage());
- }
- return false;
- }
- return true;
- }
- }
|