PlcSignalMonitor.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package com.mes.component;
  2. import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
  3. import com.mes.ui.MesClient;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import javax.swing.*;
  7. import java.awt.*;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. /**
  11. * PLC信号监控组件
  12. * 可复用的信号监控面板,支持显示PLC信号状态和详细对话框
  13. */
  14. public class PlcSignalMonitor {
  15. private static final Logger log = LoggerFactory.getLogger(PlcSignalMonitor.class);
  16. private S7PLC s7PLC;
  17. private String plcDb;
  18. private String stationName;
  19. private JFrame parentFrame;
  20. // 信号标签(用于对话框中的实时更新)
  21. private JLabel signal_feeding;
  22. private JLabel signal_blanking;
  23. private JLabel signal_running;
  24. private JLabel signal_deviceStatus;
  25. private JLabel signal_allowFeeding;
  26. private JLabel signal_allowBlanking;
  27. private JLabel signal_heart;
  28. private JLabel signal_toDevice;
  29. private JLabel signal_toTransfer;
  30. private JLabel signal_transferToDevice;
  31. /**
  32. * 构造函数
  33. * @param s7PLC PLC连接对象
  34. * @param plcDb DB块名称(如 DB7000)
  35. * @param stationName 工位名称(如 OP040A)
  36. * @param parentFrame 父窗口
  37. */
  38. public PlcSignalMonitor(S7PLC s7PLC, String plcDb, String stationName, JFrame parentFrame) {
  39. this.s7PLC = s7PLC;
  40. this.plcDb = plcDb;
  41. this.stationName = stationName;
  42. this.parentFrame = parentFrame;
  43. }
  44. /**
  45. * 创建信号监控按钮(放在工位面板中)
  46. * @return 信号监控按钮
  47. */
  48. public JButton createSignalButton() {
  49. JButton signalBtn = new JButton("PLC信号");
  50. signalBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
  51. signalBtn.setForeground(new Color(0, 102, 204));
  52. signalBtn.setToolTipText("点击查看PLC信号详情");
  53. signalBtn.addActionListener(e -> showSignalDialog());
  54. return signalBtn;
  55. }
  56. /**
  57. * 创建信号标签
  58. */
  59. private JLabel createSignalLabel(String text, boolean active) {
  60. JLabel label = new JLabel(text);
  61. label.setOpaque(true);
  62. label.setFont(new Font("微软雅黑", Font.PLAIN, 11));
  63. label.setHorizontalAlignment(SwingConstants.CENTER);
  64. label.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
  65. label.setPreferredSize(new Dimension(50, 18));
  66. updateSignalLabel(label, active);
  67. return label;
  68. }
  69. /**
  70. * 更新信号标签状态
  71. */
  72. private void updateSignalLabel(JLabel label, boolean active) {
  73. if (active) {
  74. label.setBackground(new Color(0, 200, 0));
  75. label.setForeground(Color.WHITE);
  76. } else {
  77. label.setBackground(new Color(200, 200, 200));
  78. label.setForeground(Color.DARK_GRAY);
  79. }
  80. }
  81. /**
  82. * 显示信号监控对话框
  83. */
  84. public void showSignalDialog() {
  85. JDialog dialog = new JDialog(parentFrame, stationName + " - PLC信号监控", false);
  86. dialog.setSize(550, 400);
  87. dialog.setLocationRelativeTo(parentFrame);
  88. JPanel panel = new JPanel();
  89. panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
  90. panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  91. // 标题
  92. JLabel title = new JLabel("PLC信号实时监控");
  93. title.setFont(new Font("微软雅黑", Font.BOLD, 16));
  94. title.setAlignmentX(Component.CENTER_ALIGNMENT);
  95. panel.add(title);
  96. panel.add(Box.createVerticalStrut(10));
  97. // 工位信息
  98. JLabel stationInfo = new JLabel("工位: " + stationName + " | DB块: " + plcDb);
  99. stationInfo.setFont(new Font("微软雅黑", Font.PLAIN, 12));
  100. stationInfo.setForeground(Color.GRAY);
  101. stationInfo.setAlignmentX(Component.CENTER_ALIGNMENT);
  102. panel.add(stationInfo);
  103. panel.add(Box.createVerticalStrut(15));
  104. // 信号详情面板
  105. JPanel signalPanel = createSignalDetailPanel();
  106. panel.add(signalPanel);
  107. panel.add(Box.createVerticalStrut(15));
  108. // 刷新按钮
  109. JButton refreshBtn = new JButton("刷新信号");
  110. refreshBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
  111. refreshBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
  112. refreshBtn.addActionListener(e -> updateSignalDisplay());
  113. panel.add(refreshBtn);
  114. dialog.add(panel);
  115. // 首次显示时更新信号
  116. updateSignalDisplay();
  117. dialog.setVisible(true);
  118. }
  119. /**
  120. * 创建信号详情面板
  121. */
  122. private JPanel createSignalDetailPanel() {
  123. List<String[]> signalList = new ArrayList<>();
  124. signalList.add(new String[]{"请求上料", plcDb + ".0.0", "PLC→MES"});
  125. signalList.add(new String[]{"下料信号", plcDb + ".0.1", "PLC→MES"});
  126. signalList.add(new String[]{"设备运行", plcDb + ".0.2", "PLC→MES"});
  127. signalList.add(new String[]{"设备通讯", plcDb + ".0.3", "PLC状态"});
  128. signalList.add(new String[]{"MES允许上料", plcDb + ".0.4", "MES→PLC"});
  129. signalList.add(new String[]{"MES允许下料", plcDb + ".0.5", "MES→PLC"});
  130. signalList.add(new String[]{"心跳信号", plcDb + ".0.6", "MES→PLC"});
  131. signalList.add(new String[]{"上料到设备", plcDb + ".0.7", "PLC→MES"});
  132. if (MesClient.transferEnabled) {
  133. signalList.add(new String[]{"上料到中转车", plcDb + ".1.0", "PLC→MES"});
  134. signalList.add(new String[]{"中转车上料到设备", plcDb + ".1.1", "PLC→MES"});
  135. }
  136. JPanel panel = new JPanel(new GridLayout(signalList.size() + 1, 4, 5, 5));
  137. panel.setBorder(BorderFactory.createTitledBorder(stationName + " 信号状态"));
  138. // 表头
  139. panel.add(createHeaderLabel("信号名称"));
  140. panel.add(createHeaderLabel("地址"));
  141. panel.add(createHeaderLabel("方向"));
  142. panel.add(createHeaderLabel("状态"));
  143. // 初始化信号标签
  144. signal_feeding = createStatusLabel();
  145. signal_blanking = createStatusLabel();
  146. signal_running = createStatusLabel();
  147. signal_deviceStatus = createStatusLabel();
  148. signal_allowFeeding = createStatusLabel();
  149. signal_allowBlanking = createStatusLabel();
  150. signal_heart = createStatusLabel();
  151. signal_toDevice = createStatusLabel();
  152. signal_toTransfer = createStatusLabel();
  153. signal_transferToDevice = createStatusLabel();
  154. List<JLabel> statusLabels = new ArrayList<>();
  155. statusLabels.add(signal_feeding);
  156. statusLabels.add(signal_blanking);
  157. statusLabels.add(signal_running);
  158. statusLabels.add(signal_deviceStatus);
  159. statusLabels.add(signal_allowFeeding);
  160. statusLabels.add(signal_allowBlanking);
  161. statusLabels.add(signal_heart);
  162. statusLabels.add(signal_toDevice);
  163. if (MesClient.transferEnabled) {
  164. statusLabels.add(signal_toTransfer);
  165. statusLabels.add(signal_transferToDevice);
  166. }
  167. // 添加信号行
  168. for (int i = 0; i < signalList.size(); i++) {
  169. String[] signals = signalList.get(i);
  170. panel.add(new JLabel(signals[0], SwingConstants.CENTER));
  171. panel.add(new JLabel(signals[1], SwingConstants.CENTER));
  172. panel.add(new JLabel(signals[2], SwingConstants.CENTER));
  173. panel.add(statusLabels.get(i));
  174. }
  175. return panel;
  176. }
  177. /**
  178. * 创建表头标签
  179. */
  180. private JLabel createHeaderLabel(String text) {
  181. JLabel label = new JLabel(text, SwingConstants.CENTER);
  182. label.setFont(new Font("微软雅黑", Font.BOLD, 12));
  183. return label;
  184. }
  185. /**
  186. * 创建状态标签
  187. */
  188. private JLabel createStatusLabel() {
  189. JLabel label = new JLabel("--", SwingConstants.CENTER);
  190. label.setOpaque(true);
  191. label.setBackground(Color.LIGHT_GRAY);
  192. label.setFont(new Font("微软雅黑", Font.PLAIN, 11));
  193. return label;
  194. }
  195. /**
  196. * 更新信号显示
  197. */
  198. private void updateSignalDisplay() {
  199. try {
  200. if (s7PLC == null) {
  201. log.warn("[{}] PLC连接为空,无法读取信号", stationName);
  202. showConnectionError();
  203. return;
  204. }
  205. // 读取所有信号
  206. boolean feeding = s7PLC.readBoolean(plcDb + ".0.0");
  207. boolean blanking = s7PLC.readBoolean(plcDb + ".0.1");
  208. boolean running = s7PLC.readBoolean(plcDb + ".0.2");
  209. boolean deviceStatus = s7PLC.readBoolean(plcDb + ".0.3");
  210. boolean allowFeeding = s7PLC.readBoolean(plcDb + ".0.4");
  211. boolean allowBlanking = s7PLC.readBoolean(plcDb + ".0.5");
  212. boolean heart = s7PLC.readBoolean(plcDb + ".0.6");
  213. boolean toDevice = s7PLC.readBoolean(plcDb + ".0.7");
  214. boolean toTransfer = MesClient.transferEnabled && s7PLC.readBoolean(plcDb + ".1.0");
  215. boolean transferToDevice = MesClient.transferEnabled && s7PLC.readBoolean(plcDb + ".1.1");
  216. // 在EDT线程中更新UI
  217. SwingUtilities.invokeLater(() -> {
  218. updateStatusLabel(signal_feeding, feeding);
  219. updateStatusLabel(signal_blanking, blanking);
  220. updateStatusLabel(signal_running, running);
  221. updateStatusLabel(signal_deviceStatus, deviceStatus);
  222. updateStatusLabel(signal_allowFeeding, allowFeeding);
  223. updateStatusLabel(signal_allowBlanking, allowBlanking);
  224. updateStatusLabel(signal_heart, heart);
  225. updateStatusLabel(signal_toDevice, toDevice);
  226. if (MesClient.transferEnabled) {
  227. updateStatusLabel(signal_toTransfer, toTransfer);
  228. updateStatusLabel(signal_transferToDevice, transferToDevice);
  229. }
  230. });
  231. } catch (Exception e) {
  232. String errorMsg = e.getMessage();
  233. if (errorMsg != null && errorMsg.contains("connect timed out")) {
  234. log.warn("[{}] PLC连接超时,请检查网络连接", stationName);
  235. } else {
  236. log.error("[{}] 读取PLC信号异常: {}", stationName, errorMsg);
  237. }
  238. // 在UI上显示错误提示
  239. SwingUtilities.invokeLater(this::showConnectionError);
  240. }
  241. }
  242. /**
  243. * 显示连接错误提示
  244. */
  245. private void showConnectionError() {
  246. JLabel[] labels = {
  247. signal_feeding, signal_blanking, signal_running, signal_deviceStatus,
  248. signal_allowFeeding, signal_allowBlanking, signal_heart,
  249. signal_toDevice, signal_toTransfer, signal_transferToDevice
  250. };
  251. for (JLabel label : labels) {
  252. if (label != null && label.getParent() != null) {
  253. label.setText("ERR");
  254. label.setBackground(Color.ORANGE);
  255. label.setForeground(Color.WHITE);
  256. }
  257. }
  258. }
  259. /**
  260. * 更新状态标签
  261. */
  262. private void updateStatusLabel(JLabel label, boolean active) {
  263. if (label != null) {
  264. if (active) {
  265. label.setText("1");
  266. label.setBackground(new Color(0, 200, 0));
  267. label.setForeground(Color.WHITE);
  268. } else {
  269. label.setText("0");
  270. label.setBackground(new Color(200, 200, 200));
  271. label.setForeground(Color.DARK_GRAY);
  272. }
  273. }
  274. }
  275. }