PlcSignalMonitor.java 11 KB

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