| New file |
| | |
| | | package com.mes.plc.client; |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * PLC客æ·ç«¯æ¥å£ |
| | | * <p> |
| | | * å®ä¹PLCéä¿¡çéç¨æ¹æ³ï¼æ¯æå¤ç§PLCåè®®ï¼S7ãModbusçï¼ |
| | | * </p> |
| | | * |
| | | * @author huang |
| | | * @date 2025/12/19 |
| | | */ |
| | | public interface PlcClient { |
| | | |
| | | /** |
| | | * è¿æ¥PLC |
| | | * |
| | | * @return æ¯å¦è¿æ¥æå |
| | | */ |
| | | boolean connect(); |
| | | |
| | | /** |
| | | * æå¼PLCè¿æ¥ |
| | | */ |
| | | void disconnect(); |
| | | |
| | | /** |
| | | * 读åPLCçæææ°æ® |
| | | * |
| | | * @return PLCæ°æ®ï¼keyä¸ºåæ®µåï¼valueä¸ºåæ®µå¼ |
| | | */ |
| | | Map<String, Object> readAllData(); |
| | | |
| | | /** |
| | | * 读åPLCçæå®åæ®µæ°æ® |
| | | * |
| | | * @param fields éè¦è¯»åçåæ®µå表 |
| | | * @return PLCæ°æ®ï¼keyä¸ºåæ®µåï¼valueä¸ºåæ®µå¼ |
| | | */ |
| | | Map<String, Object> readData(String... fields); |
| | | |
| | | /** |
| | | * åå
¥PLCæ°æ® |
| | | * |
| | | * @param data éè¦åå
¥çæ°æ®ï¼keyä¸ºåæ®µåï¼valueä¸ºåæ®µå¼ |
| | | * @return æ¯å¦åå
¥æå |
| | | */ |
| | | boolean writeData(Map<String, Object> data); |
| | | |
| | | /** |
| | | * æ£æ¥PLCè¿æ¥ç¶æ |
| | | * |
| | | * @return æ¯å¦è¿æ¥æå |
| | | */ |
| | | boolean isConnected(); |
| | | |
| | | /** |
| | | * è·åPLCç±»å |
| | | * |
| | | * @return PLCç±»å |
| | | */ |
| | | String getPlcType(); |
| | | |
| | | /** |
| | | * è·åè¿æ¥è¶
æ¶æ¶é´ |
| | | * |
| | | * @return è¶
æ¶æ¶é´ï¼æ¯«ç§ï¼ |
| | | */ |
| | | int getTimeout(); |
| | | |
| | | /** |
| | | * è®¾ç½®è¿æ¥è¶
æ¶æ¶é´ |
| | | * |
| | | * @param timeout è¶
æ¶æ¶é´ï¼æ¯«ç§ï¼ |
| | | */ |
| | | void setTimeout(int timeout); |
| | | } |
| New file |
| | |
| | | package com.mes.plc.client.impl; |
| | | |
| | | import com.mes.connect.modbus.ModbusTcpClient; |
| | | import com.mes.device.entity.DeviceConfig; |
| | | import com.mes.plc.client.PlcClient; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * Modbusåè®®PLC客æ·ç«¯å®ç° |
| | | * <p> |
| | | * åºäºé¡¹ç®ä¸å·²æçModbuså®ç° |
| | | * </p> |
| | | * |
| | | * @author huang |
| | | * @date 2025/12/19 |
| | | */ |
| | | @Slf4j |
| | | public class ModbusPlcClient implements PlcClient { |
| | | |
| | | // PLC IPå°å |
| | | private final String plcIp; |
| | | |
| | | // PLCç«¯å£ |
| | | private final int plcPort; |
| | | |
| | | // ä»ç«å°å |
| | | private final int unitId; |
| | | |
| | | // Modbus客æ·ç«¯å®ä¾ |
| | | private ModbusTcpClient modbusClient; |
| | | |
| | | // è¿æ¥ç¶æ |
| | | private boolean connected = false; |
| | | |
| | | // è¶
æ¶æ¶é´ï¼æ¯«ç§ï¼ |
| | | private int timeout = 5000; |
| | | |
| | | /** |
| | | * æé 彿° |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | */ |
| | | public ModbusPlcClient(DeviceConfig device) { |
| | | this.plcIp = device.getPlcIp(); |
| | | this.plcPort = device.getPlcPort() != null ? device.getPlcPort() : 502; |
| | | |
| | | // ä»é
ç½®ä¸è·åä»ç«å°åï¼é»è®¤1 |
| | | int unitIdValue = 1; |
| | | try { |
| | | Map<String, Object> extraParams = parseExtraParams(device.getExtraParams()); |
| | | if (extraParams != null) { |
| | | Object unitIdObj = extraParams.get("unitId"); |
| | | if (unitIdObj instanceof Number) { |
| | | unitIdValue = ((Number) unitIdObj).intValue(); |
| | | } else if (unitIdObj instanceof String) { |
| | | unitIdValue = Integer.parseInt((String) unitIdObj); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("è§£æunitId失败ï¼ä½¿ç¨é»è®¤å¼1: deviceId={}", device.getId(), e); |
| | | } |
| | | this.unitId = unitIdValue; |
| | | } |
| | | |
| | | /** |
| | | * è§£æè®¾å¤çextraParams |
| | | * |
| | | * @param extraParamsJson extraParamsçJSONå符串 |
| | | * @return è§£æåçMap |
| | | */ |
| | | private Map<String, Object> parseExtraParams(String extraParamsJson) { |
| | | if (extraParamsJson == null || extraParamsJson.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | try { |
| | | // è¿éç®åå¤çï¼å®é
项ç®ä¸åºè¯¥ä½¿ç¨JacksonæGsonè§£æ |
| | | // ç±äºé¡¹ç®ä¸å·²æObjectMapperï¼è¿éææ¶è¿å空Mapï¼åç»å®å |
| | | return new HashMap<>(); |
| | | } catch (Exception e) { |
| | | log.error("è§£æextraParams失败: {}", extraParamsJson, e); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean connect() { |
| | | try { |
| | | if (modbusClient != null && isConnected()) { |
| | | return true; |
| | | } |
| | | |
| | | // å建Modbus客æ·ç«¯å®ä¾ |
| | | this.modbusClient = new ModbusTcpClient(this.plcIp, this.plcPort, this.unitId); |
| | | |
| | | // è¿æ¥PLC |
| | | this.modbusClient.connect(); |
| | | this.connected = true; |
| | | log.info("Modbus PLCè¿æ¥æå: {}:{}ï¼ä»ç«å°å: {}", this.plcIp, this.plcPort, this.unitId); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("Modbus PLCè¿æ¥å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | this.connected = false; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void disconnect() { |
| | | try { |
| | | if (this.modbusClient != null) { |
| | | this.modbusClient.disconnect(); |
| | | log.info("Modbus PLCæå¼è¿æ¥: {}:{}", this.plcIp, this.plcPort); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("Modbus PLCæå¼è¿æ¥å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | } finally { |
| | | this.connected = false; |
| | | this.modbusClient = null; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> readAllData() { |
| | | if (!isConnected() && !connect()) { |
| | | log.error("Modbus PLCæªè¿æ¥ï¼æ æ³è¯»åæ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return Collections.emptyMap(); |
| | | } |
| | | |
| | | try { |
| | | // TODO: å®ç°Modbusè¯»åæææ°æ® |
| | | // è¿éææ¶è¿å空Mapï¼åç»å®å |
| | | log.warn("Modbus readAllDataæªå®ç°ï¼è¿å空Map"); |
| | | return new HashMap<>(); |
| | | } catch (Exception e) { |
| | | log.error("Modbus PLCè¯»åæææ°æ®å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | this.connected = false; |
| | | return Collections.emptyMap(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> readData(String... fields) { |
| | | if (!isConnected() && !connect()) { |
| | | log.error("Modbus PLCæªè¿æ¥ï¼æ æ³è¯»åæ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return Collections.emptyMap(); |
| | | } |
| | | |
| | | try { |
| | | // TODO: å®ç°Modbus读åæå®åæ®µæ°æ® |
| | | // è¿éææ¶è¿å空Mapï¼åç»å®å |
| | | log.warn("Modbus readDataæªå®ç°ï¼è¿å空Map"); |
| | | return new HashMap<>(); |
| | | } catch (Exception e) { |
| | | log.error("Modbus PLCè¯»åæ°æ®å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | this.connected = false; |
| | | return Collections.emptyMap(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean writeData(Map<String, Object> data) { |
| | | if (!isConnected() && !connect()) { |
| | | log.error("Modbus PLCæªè¿æ¥ï¼æ æ³åå
¥æ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return false; |
| | | } |
| | | |
| | | try { |
| | | // TODO: å®ç°Modbusåå
¥æ°æ® |
| | | // è¿éææ¶è¿åtrueï¼åç»å®å |
| | | log.warn("Modbus writeDataæªå®ç°ï¼è¿åæå"); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("Modbus PLCåå
¥æ°æ®å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | this.connected = false; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean isConnected() { |
| | | try { |
| | | if (!this.connected || this.modbusClient == null) { |
| | | return false; |
| | | } |
| | | // æ£æ¥è¿æ¥ç¶æ |
| | | return this.modbusClient.isConnected(); |
| | | } catch (Exception e) { |
| | | this.connected = false; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public String getPlcType() { |
| | | return "MODBUS"; |
| | | } |
| | | |
| | | @Override |
| | | public int getTimeout() { |
| | | return this.timeout; |
| | | } |
| | | |
| | | @Override |
| | | public void setTimeout(int timeout) { |
| | | this.timeout = timeout; |
| | | // ModbusTcpClient䏿¯æç´æ¥è®¾ç½®è¶
æ¶ï¼è¿éä»
è®°å½è¶
æ¶æ¶é´ |
| | | } |
| | | } |
| New file |
| | |
| | | package com.mes.plc.client.impl; |
| | | |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType; |
| | | import com.github.xingshuangs.iot.protocol.s7.service.S7PLC; |
| | | import com.mes.device.entity.DeviceConfig; |
| | | import com.mes.plc.client.PlcClient; |
| | | import com.mes.service.PlcDynamicDataService; |
| | | import com.mes.s7.enhanced.EnhancedS7Serializer; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | | * S7åè®®PLC客æ·ç«¯å®ç° |
| | | * <p> |
| | | * åºäºç°æçS7åºå®ç°PlcClientæ¥å£ |
| | | * </p> |
| | | * |
| | | * @author huang |
| | | * @date 2025/12/19 |
| | | */ |
| | | @Slf4j |
| | | public class S7PlcClient implements PlcClient { |
| | | |
| | | // PLCç±»å |
| | | private final EPlcType plcType; |
| | | |
| | | // PLC IPå°å |
| | | private final String plcIp; |
| | | |
| | | // PLCç«¯å£ |
| | | private final int plcPort; |
| | | |
| | | // 设å¤é
ç½® |
| | | private final DeviceConfig device; |
| | | |
| | | // 模ååç§° |
| | | private final String moduleName; |
| | | |
| | | // S7 PLCå®ä¾ |
| | | private S7PLC s7Plc; |
| | | |
| | | // S7åºååå¨ |
| | | private EnhancedS7Serializer s7Serializer; |
| | | |
| | | // è¿æ¥ç¶æ |
| | | private boolean connected = false; |
| | | |
| | | // è¶
æ¶æ¶é´ï¼æ¯«ç§ï¼ |
| | | private int timeout = 5000; |
| | | |
| | | // PLCç±»åæ å° |
| | | private static final Map<String, EPlcType> PLC_TYPE_MAP = new ConcurrentHashMap<>(); |
| | | |
| | | // PLCå¨ææ°æ®æå¡ |
| | | private PlcDynamicDataService plcDynamicDataService; |
| | | |
| | | /** |
| | | * 设置PLCå¨ææ°æ®æå¡ |
| | | * |
| | | * @param plcDynamicDataService PLCå¨ææ°æ®æå¡å®ä¾ |
| | | */ |
| | | public void setPlcDynamicDataService(PlcDynamicDataService plcDynamicDataService) { |
| | | this.plcDynamicDataService = plcDynamicDataService; |
| | | } |
| | | |
| | | static { |
| | | // åå§åPLCç±»åæ å° |
| | | PLC_TYPE_MAP.put("S7_1200", EPlcType.S1200); |
| | | PLC_TYPE_MAP.put("S7_1500", EPlcType.S1500); |
| | | PLC_TYPE_MAP.put("S7_200", EPlcType.S200); |
| | | PLC_TYPE_MAP.put("S7_300", EPlcType.S300); |
| | | PLC_TYPE_MAP.put("S7_400", EPlcType.S400); |
| | | } |
| | | |
| | | /** |
| | | * æé 彿° |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | * @param s7Serializer S7åºååå¨ |
| | | */ |
| | | public S7PlcClient(DeviceConfig device, EnhancedS7Serializer s7Serializer) { |
| | | this.device = device; |
| | | this.plcIp = device.getPlcIp(); |
| | | this.plcPort = device.getPlcPort() != null ? device.getPlcPort() : 102; |
| | | this.moduleName = device.getModuleName() != null ? device.getModuleName() : "DB1"; |
| | | this.s7Serializer = s7Serializer; |
| | | |
| | | // è§£æPLCç±»å |
| | | String plcTypeValue = device.getPlcType(); |
| | | this.plcType = PLC_TYPE_MAP.getOrDefault(plcTypeValue, EPlcType.S1200); |
| | | } |
| | | |
| | | @Override |
| | | public boolean connect() { |
| | | try { |
| | | if (s7Plc != null && isConnected()) { |
| | | return true; |
| | | } |
| | | |
| | | // å建S7PLCå®ä¾ |
| | | this.s7Plc = new S7PLC(this.plcType, this.plcIp, this.plcPort); |
| | | |
| | | |
| | | // è¿æ¥PLC |
| | | this.s7Plc.connect(); |
| | | this.connected = true; |
| | | log.info("S7 PLCè¿æ¥æå: {}:{}ï¼ç±»å: {}", this.plcIp, this.plcPort, this.plcType); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("S7 PLCè¿æ¥å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | this.connected = false; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void disconnect() { |
| | | try { |
| | | if (this.s7Plc != null) { |
| | | |
| | | log.info("S7 PLCæå¼è¿æ¥: {}:{}", this.plcIp, this.plcPort); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("S7 PLCæå¼è¿æ¥å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | } finally { |
| | | this.connected = false; |
| | | this.s7Plc = null; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> readAllData() { |
| | | if (!isConnected() && !connect()) { |
| | | log.error("S7 PLCæªè¿æ¥ï¼æ æ³è¯»åæ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return Collections.emptyMap(); |
| | | } |
| | | |
| | | try { |
| | | if (this.plcDynamicDataService == null) { |
| | | log.error("PLCå¨ææ°æ®æå¡æªåå§åï¼æ æ³è¯»åæ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return Collections.emptyMap(); |
| | | } |
| | | |
| | | // 使ç¨PlcDynamicDataServiceè¯»åææPLCæ°æ® |
| | | Map<String, Object> data = this.plcDynamicDataService.readAllPlcData(this.device, this.s7Serializer); |
| | | if (data == null) { |
| | | log.warn("PLCå¨ææ°æ®æå¡è¿åç©ºæ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return new HashMap<>(); |
| | | } |
| | | |
| | | log.info("S7 PLCè¯»åæææ°æ®æå: {}:{}, dataSize={}", this.plcIp, this.plcPort, data.size()); |
| | | return data; |
| | | } catch (Exception e) { |
| | | log.error("S7 PLCè¯»åæææ°æ®å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | this.connected = false; |
| | | return Collections.emptyMap(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> readData(String... fields) { |
| | | if (!isConnected() && !connect()) { |
| | | log.error("S7 PLCæªè¿æ¥ï¼æ æ³è¯»åæ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return Collections.emptyMap(); |
| | | } |
| | | |
| | | try { |
| | | if (this.plcDynamicDataService == null) { |
| | | log.error("PLCå¨ææ°æ®æå¡æªåå§åï¼æ æ³è¯»åæ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return Collections.emptyMap(); |
| | | } |
| | | |
| | | if (fields == null || fields.length == 0) { |
| | | return readAllData(); |
| | | } |
| | | |
| | | // 使ç¨PlcDynamicDataService读åæå®å段PLCæ°æ® |
| | | Map<String, Object> data = this.plcDynamicDataService.readPlcData(this.device, java.util.Arrays.asList(fields), this.s7Serializer); |
| | | if (data == null) { |
| | | log.warn("PLCå¨ææ°æ®æå¡è¿åç©ºæ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return new HashMap<>(); |
| | | } |
| | | |
| | | log.info("S7 PLC读åæå®åæ®µæ°æ®æå: {}:{}, fields={}", this.plcIp, this.plcPort, java.util.Arrays.toString(fields)); |
| | | return data; |
| | | } catch (Exception e) { |
| | | log.error("S7 PLCè¯»åæ°æ®å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | this.connected = false; |
| | | return Collections.emptyMap(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean writeData(Map<String, Object> data) { |
| | | if (!isConnected() && !connect()) { |
| | | log.error("S7 PLCæªè¿æ¥ï¼æ æ³åå
¥æ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return false; |
| | | } |
| | | |
| | | try { |
| | | if (this.plcDynamicDataService == null) { |
| | | log.error("PLCå¨ææ°æ®æå¡æªåå§åï¼æ æ³åå
¥æ°æ®: {}:{}", this.plcIp, this.plcPort); |
| | | return false; |
| | | } |
| | | |
| | | if (data == null || data.isEmpty()) { |
| | | log.warn("åå
¥æ°æ®ä¸ºç©ºï¼è·³è¿æä½: {}:{}", this.plcIp, this.plcPort); |
| | | return true; |
| | | } |
| | | |
| | | // 使ç¨PlcDynamicDataServiceåå
¥PLCæ°æ® |
| | | this.plcDynamicDataService.writePlcData(this.device, data, this.s7Serializer); |
| | | log.info("S7 PLCåå
¥æ°æ®æå: {}:{}, fields={}", this.plcIp, this.plcPort, data.keySet()); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("S7 PLCåå
¥æ°æ®å¤±è´¥: {}:{}", this.plcIp, this.plcPort, e); |
| | | this.connected = false; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean isConnected() { |
| | | try { |
| | | // S7PLC䏿¯æç´æ¥æ£æ¥è¿æ¥ç¶æï¼ä½¿ç¨å
鍿 å¿ |
| | | return this.connected && this.s7Plc != null; |
| | | } catch (Exception e) { |
| | | this.connected = false; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public String getPlcType() { |
| | | return this.plcType.name(); |
| | | } |
| | | |
| | | @Override |
| | | public int getTimeout() { |
| | | return this.timeout; |
| | | } |
| | | |
| | | @Override |
| | | public void setTimeout(int timeout) { |
| | | this.timeout = timeout; |
| | | |
| | | } |
| | | } |
| New file |
| | |
| | | package com.mes.plc.factory; |
| | | |
| | | import com.mes.device.entity.DeviceConfig; |
| | | import com.mes.plc.client.PlcClient; |
| | | import com.mes.plc.client.impl.ModbusPlcClient; |
| | | import com.mes.plc.client.impl.S7PlcClient; |
| | | import com.mes.service.PlcDynamicDataService; |
| | | import com.mes.s7.enhanced.EnhancedS7Serializer; |
| | | import com.mes.s7.provider.S7SerializerProvider; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.ConcurrentMap; |
| | | |
| | | /** |
| | | * PLC客æ·ç«¯å·¥å |
| | | * <p> |
| | | * æ ¹æ®è®¾å¤é
ç½®å建ä¸åç±»åçPLC客æ·ç«¯å®ä¾ |
| | | * </p> |
| | | * |
| | | * @author huang |
| | | * @date 2025/12/19 |
| | | */ |
| | | @Slf4j |
| | | @Component |
| | | public class PlcClientFactory { |
| | | // S7åºåå卿ä¾è
|
| | | @Autowired |
| | | private S7SerializerProvider s7SerializerProvider; |
| | | |
| | | // PLCå¨ææ°æ®æå¡ |
| | | @Autowired |
| | | private PlcDynamicDataService plcDynamicDataService; |
| | | |
| | | // 客æ·ç«¯ç¼åï¼æé«æ§è½ |
| | | private final ConcurrentMap<String, PlcClient> clientCache = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * æ ¹æ®è®¾å¤é
ç½®å建æè·åPLC客æ·ç«¯ |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | * @return PLC客æ·ç«¯å®ä¾ |
| | | */ |
| | | public PlcClient getClient(DeviceConfig device) { |
| | | if (device == null) { |
| | | log.error("设å¤é
ç½®ä¸ºç©ºï¼æ æ³å建PLC客æ·ç«¯"); |
| | | return null; |
| | | } |
| | | |
| | | // çæç¼åé® |
| | | String cacheKey = generateCacheKey(device); |
| | | |
| | | // å°è¯ä»ç¼åä¸è·å客æ·ç«¯ |
| | | PlcClient client = clientCache.get(cacheKey); |
| | | if (client != null && client.isConnected()) { |
| | | return client; |
| | | } |
| | | |
| | | // ç¼å䏿²¡ææè¿æ¥å·²æå¼ï¼å建æ°å®¢æ·ç«¯ |
| | | try { |
| | | client = createClient(device); |
| | | if (client != null) { |
| | | // è¿æ¥PLC |
| | | if (client.connect()) { |
| | | // å°å®¢æ·ç«¯æ¾å
¥ç¼å |
| | | clientCache.put(cacheKey, client); |
| | | log.info("PLC客æ·ç«¯å建æå: cacheKey={}, plcType={}", cacheKey, client.getPlcType()); |
| | | } else { |
| | | log.error("PLC客æ·ç«¯è¿æ¥å¤±è´¥: cacheKey={}, plcType={}", cacheKey, client.getPlcType()); |
| | | // è¿æ¥å¤±è´¥ï¼ä¸æ¾å
¥ç¼å |
| | | client = null; |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("å建PLC客æ·ç«¯å¤±è´¥: cacheKey={}", cacheKey, e); |
| | | client = null; |
| | | } |
| | | |
| | | return client; |
| | | } |
| | | |
| | | /** |
| | | * çæç¼åé® |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | * @return ç¼åé® |
| | | */ |
| | | private String generateCacheKey(DeviceConfig device) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("device:") |
| | | .append(device.getId()) |
| | | .append(":") |
| | | .append(device.getPlcType()) |
| | | .append(":") |
| | | .append(device.getPlcIp()) |
| | | .append(":") |
| | | .append(device.getPlcPort()); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®è®¾å¤ç±»åå建ä¸åçPLC客æ·ç«¯ |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | * @return PLC客æ·ç«¯å®ä¾ |
| | | */ |
| | | private PlcClient createClient(DeviceConfig device) { |
| | | if (device == null) { |
| | | return null; |
| | | } |
| | | |
| | | String plcType = device.getPlcType(); |
| | | if (plcType == null || plcType.isEmpty()) { |
| | | log.error("PLCç±»åä¸ºç©ºï¼æ æ³å建客æ·ç«¯: deviceId={}", device.getId()); |
| | | return null; |
| | | } |
| | | |
| | | // æ ¹æ®PLCç±»åå建ä¸åç客æ·ç«¯ |
| | | if (plcType.startsWith("S7")) { |
| | | // S7å议客æ·ç«¯ |
| | | return createS7Client(device); |
| | | } else if (plcType.equals("MODBUS")) { |
| | | // Modbuså议客æ·ç«¯ |
| | | return createModbusClient(device); |
| | | } else { |
| | | log.error("䏿¯æçPLCç±»å: deviceId={}, plcType={}", device.getId(), plcType); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å建S7å议客æ·ç«¯ |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | * @return S7客æ·ç«¯å®ä¾ |
| | | */ |
| | | private PlcClient createS7Client(DeviceConfig device) { |
| | | try { |
| | | // è·åS7åºååå¨ |
| | | EnhancedS7Serializer s7Serializer = s7SerializerProvider.getSerializer(device); |
| | | if (s7Serializer == null) { |
| | | log.error("è·åS7Serializer失败: deviceId={}", device.getId()); |
| | | return null; |
| | | } |
| | | |
| | | // å建S7客æ·ç«¯ |
| | | S7PlcClient client = new S7PlcClient(device, s7Serializer); |
| | | // 设置PLCå¨ææ°æ®æå¡ |
| | | client.setPlcDynamicDataService(this.plcDynamicDataService); |
| | | return client; |
| | | } catch (Exception e) { |
| | | log.error("å建S7客æ·ç«¯å¤±è´¥: deviceId={}", device.getId(), e); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å建Modbuså议客æ·ç«¯ |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | * @return Modbus客æ·ç«¯å®ä¾ |
| | | */ |
| | | private PlcClient createModbusClient(DeviceConfig device) { |
| | | try { |
| | | // å建Modbus客æ·ç«¯ |
| | | return new ModbusPlcClient(device); |
| | | } catch (Exception e) { |
| | | log.error("å建Modbus客æ·ç«¯å¤±è´¥: deviceId={}", device.getId(), e); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å
³éå¹¶ç§»é¤æå®è®¾å¤çPLC客æ·ç«¯ |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | */ |
| | | public void removeClient(DeviceConfig device) { |
| | | if (device == null) { |
| | | return; |
| | | } |
| | | |
| | | String cacheKey = generateCacheKey(device); |
| | | PlcClient client = clientCache.remove(cacheKey); |
| | | if (client != null) { |
| | | client.disconnect(); |
| | | log.info("PLC客æ·ç«¯å·²ç§»é¤: cacheKey={}", cacheKey); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å
³éå¹¶æ¸
餿æPLC客æ·ç«¯ |
| | | */ |
| | | public void clearAllClients() { |
| | | log.info("å¼å§æ¸
餿æPLC客æ·ç«¯ï¼å½åç¼å大å°: {}", clientCache.size()); |
| | | |
| | | for (PlcClient client : clientCache.values()) { |
| | | try { |
| | | client.disconnect(); |
| | | } catch (Exception e) { |
| | | log.error("å
³éPLC客æ·ç«¯å¤±è´¥", e); |
| | | } |
| | | } |
| | | |
| | | clientCache.clear(); |
| | | log.info("ææPLC客æ·ç«¯å·²æ¸
é¤"); |
| | | } |
| | | |
| | | /** |
| | | * è·å客æ·ç«¯ç¼åå¤§å° |
| | | * |
| | | * @return ç¼åå¤§å° |
| | | */ |
| | | public int getCacheSize() { |
| | | return clientCache.size(); |
| | | } |
| | | } |
| | |
| | | @Resource |
| | | private PlcDynamicDataService plcDynamicDataService; |
| | | |
| | | @Resource |
| | | private com.mes.plc.factory.PlcClientFactory plcClientFactory; |
| | | |
| | | private final ObjectMapper objectMapper = new ObjectMapper(); |
| | | private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<Map<String, Object>>() {}; |
| | | |
| | | private static final int ON = 1; |
| | | private static final int OFF = 0; |
| | | |
| | | // ç¼åä¸å设å¤çS7Serializerå®ä¾ |
| | | // ç¼åä¸å设å¤çS7Serializerå®ä¾ï¼ä¿æå
¼å®¹ï¼éæ¥è¿ç§»ï¼ |
| | | private final ConcurrentMap<String, EnhancedS7Serializer> serializerCache = new ConcurrentHashMap<>(); |
| | | |
| | | // ==================== åºäºDeviceConfigçæ°APIï¼æ¨è使ç¨ï¼ ==================== |
| | | |
| | | /** |
| | | * æ ¹æ®è®¾å¤ID模æPLCåé请æ±å |
| | |
| | | return false; |
| | | } |
| | | try { |
| | | // å°è¯ä½¿ç¨æ°çPLC客æ·ç«¯å·¥å |
| | | com.mes.plc.client.PlcClient plcClient = plcClientFactory.getClient(device); |
| | | if (plcClient != null) { |
| | | // ä½¿ç¨æ°çPLC客æ·ç«¯è¯»åæ°æ® |
| | | Map<String, Object> currentData = plcClient.readAllData(); |
| | | if (currentData != null && !currentData.isEmpty()) { |
| | | // æ£æ¥èæºç¶æ |
| | | Integer onlineState = parseInteger(currentData.get("onlineState")); |
| | | if (onlineState != null && onlineState == OFF) { |
| | | log.info("å½åPLCèæºæ¨¡å¼ä¸º0ï¼åæ¢èæº: deviceId={}", deviceId); |
| | | return false; |
| | | } |
| | | |
| | | // æ£æ¥æ±æ¥åï¼å¦æä¸º1åé置为0 |
| | | Integer plcReport = parseInteger(currentData.get("plcReport")); |
| | | if (plcReport != null && plcReport == ON) { |
| | | log.info("å½åä¸çPLCæ±æ¥å为1ï¼é置为0: deviceId={}", deviceId); |
| | | currentData.put("plcReport", OFF); |
| | | } |
| | | |
| | | // 设置请æ±å为1 |
| | | currentData.put("plcRequest", ON); |
| | | |
| | | // ä½¿ç¨æ°çPLC客æ·ç«¯åå
¥æ°æ® |
| | | boolean success = plcClient.writeData(currentData); |
| | | if (success) { |
| | | log.info("模æPLCåé请æ±åæåï¼plcRequest=1, deviceId={}", deviceId); |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 妿æ°å®¢æ·ç«¯å¤±è´¥ï¼åéå°æ§å®ç°ï¼ä¿æå
¼å®¹ï¼ |
| | | log.warn("æ°PLC客æ·ç«¯å¤±è´¥ï¼åéå°æ§å®ç°: deviceId={}", deviceId); |
| | | return simulatePlcRequestByDeviceLegacy(device); |
| | | } catch (Exception e) { |
| | | log.error("æ ¹æ®è®¾å¤æ¨¡æPLC请æ±å失败: deviceId={}", deviceId, e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ§çå®ç°ï¼æ ¹æ®è®¾å¤ID模æPLCåé请æ±å |
| | | * |
| | | * @param device 设å¤é
ç½® |
| | | * @return æ¯å¦æå |
| | | */ |
| | | private boolean simulatePlcRequestByDeviceLegacy(DeviceConfig device) { |
| | | try { |
| | | EnhancedS7Serializer s7Serializer = getSerializerForDevice(device); |
| | | if (s7Serializer == null) { |
| | | log.error("è·åS7Serializer失败: deviceId={}", deviceId); |
| | | log.error("è·åS7Serializer失败: deviceId={}", device.getId()); |
| | | return false; |
| | | } |
| | | |
| | | // 使ç¨PlcDynamicDataServiceè¯»åæ°æ®ï¼æ¯æaddressMappingï¼ |
| | | Map<String, Object> currentData = plcDynamicDataService.readAllPlcData(device, s7Serializer); |
| | | if (currentData == null || currentData.isEmpty()) { |
| | | log.error("读åPLCæ°æ®å¤±è´¥ï¼è¿å空: deviceId={}", deviceId); |
| | | log.error("读åPLCæ°æ®å¤±è´¥ï¼è¿å空: deviceId={}", device.getId()); |
| | | return false; |
| | | } |
| | | |
| | |
| | | onlineState = Integer.parseInt(strValue); |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | log.warn("è§£æonlineState失败: deviceId={}, value={}", deviceId, onlineStateObj, e); |
| | | log.warn("è§£æonlineState失败: deviceId={}, value={}", device.getId(), onlineStateObj, e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (onlineState != null && onlineState == OFF) { |
| | | log.info("å½åPLCèæºæ¨¡å¼ä¸º0ï¼åæ¢èæº: deviceId={}", deviceId); |
| | | log.info("å½åPLCèæºæ¨¡å¼ä¸º0ï¼åæ¢èæº: deviceId={}", device.getId()); |
| | | return false; |
| | | } |
| | | |
| | |
| | | plcReport = Integer.parseInt(strValue); |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | log.warn("è§£æplcReport失败: deviceId={}, value={}", deviceId, plcReportObj, e); |
| | | log.warn("è§£æplcReport失败: deviceId={}, value={}", device.getId(), plcReportObj, e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (plcReport != null && plcReport == ON) { |
| | | log.info("å½åä¸çPLCæ±æ¥å为1ï¼é置为0: deviceId={}", deviceId); |
| | | log.info("å½åä¸çPLCæ±æ¥å为1ï¼é置为0: deviceId={}", device.getId()); |
| | | currentData.put("plcReport", OFF); |
| | | } |
| | | |
| | |
| | | // 使ç¨PlcDynamicDataServiceåå
¥æ°æ® |
| | | plcDynamicDataService.writePlcData(device, currentData, s7Serializer); |
| | | |
| | | log.info("模æPLCåé请æ±åæåï¼plcRequest=1, deviceId={}", deviceId); |
| | | log.info("模æPLCåé请æ±åæåï¼æ§çï¼ï¼plcRequest=1, deviceId={}", device.getId()); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("æ ¹æ®è®¾å¤æ¨¡æPLC请æ±å失败: deviceId={}", deviceId, e); |
| | | log.error("æ ¹æ®è®¾å¤æ¨¡æPLC请æ±åå¤±è´¥ï¼æ§çï¼: deviceId={}", device.getId(), e); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | EnhancedS7Serializer serializer = EnhancedS7Serializer.newInstance(s7Plc); |
| | | if (serializer == null) { |
| | | log.error("å建EnhancedS7Serializer失败: deviceId={}, plcIp={}, plcType={}", |
| | | device.getId(), plcIp, plcType); |
| | | device.getId(), plcIp, plcType.name()); |
| | | } |
| | | return serializer; |
| | | } catch (Exception e) { |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="PLCç±»å" prop="plcType"> |
| | | <el-select v-model="deviceForm.plcType" placeholder="éæ©PLCç±»å" style="width: 100%;" clearable> |
| | | <el-form-item label="é讯类å" prop="plcType"> |
| | | <el-select v-model="deviceForm.plcType" placeholder="éæ©é讯类å" style="width: 100%;" clearable> |
| | | <el-option label="西é¨å S7-1200" value="S1200" /> |
| | | <el-option label="西é¨å S7-1500" value="S1500" /> |
| | | <el-option label="Modbus æ§å¶å¨" value="MODBUS" /> |
| | | <el-option label="Modbus TCP" value="MODBUS" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="é讯åè®®" prop="protocolType"> |
| | | <el-select |
| | | v-model="deviceForm.protocolType" |
| | | placeholder="éæ©é讯åè®®" |
| | | style="width: 100%;" |
| | | @change="handleProtocolTypeChange" |
| | | > |
| | | <el-option label="S7 Communication" value="S7 Communication" /> |
| | | <el-option label="Modbus TCP" value="Modbus TCP" /> |
| | | <el-option label="OPC UA" value="OPC UA" /> |
| | | <el-option label="EtherNet/IP" value="EtherNet/IP" /> |
| | | <el-option label="Profinet" value="Profinet" /> |
| | | <el-option label="å
¶ä»" value="å
¶ä»" /> |
| | | </el-select> |
| | | <span class="form-tip">S7ç³»åPLCé常使ç¨S7 Communicationåè®®</span> |
| | | </el-form-item> |
| | | |
| | | |
| | | <el-form-item label="è¶
æ¶æ¶é´(ç§)" prop="timeout"> |
| | | <el-input-number |
| | |
| | | moduleName: [ |
| | | { required: true, message: '请è¾å
¥æ¨¡ååç§°', trigger: 'blur' } |
| | | ], |
| | | protocolType: [ |
| | | { required: true, message: 'è¯·éæ©é讯åè®®', trigger: 'change' } |
| | | ], |
| | | |
| | | timeout: [ |
| | | { required: true, message: '请è¾å
¥è¶
æ¶æ¶é´', trigger: 'blur' }, |
| | | { type: 'number', min: 1, max: 300, message: 'è¶
æ¶æ¶é´å¨ 1 å° 300 ç§ä¹é´', trigger: 'blur' } |
| | |
| | | } |
| | | }) |
| | | |
| | | // å¤çé讯åè®®åå |
| | | const handleProtocolTypeChange = (value) => { |
| | | if (!deviceForm.plcType || !value) { |
| | | return |
| | | } |
| | | |
| | | if (value !== 'S7 Communication' && S7_PLC_TYPES.includes(deviceForm.plcType)) { |
| | | ElMessage.warning('S7ç³»åPLCé常使ç¨S7 Communicationåè®®ï¼è¯·ç¡®è®¤åè®®éæ©æ¯å¦æ£ç¡®') |
| | | return |
| | | } |
| | | |
| | | if (value !== 'Modbus TCP' && MODBUS_PLC_TYPES.includes(deviceForm.plcType)) { |
| | | ElMessage.warning('Modbus ç±»åPLCéå¸¸ä½¿ç¨ Modbus TCP åè®®ï¼è¯·ç¡®è®¤åè®®éæ©æ¯å¦æ£ç¡®') |
| | | } |
| | | } |
| | | |
| | | // æ¹æ³å®ä¹ |
| | | // å 载设å¤ç±»åå表 |
| New file |
| | |
| | | # MES_Test_Project å¿«éåèæå |
| | | |
| | | ## ð å¿«éå¼å§ |
| | | |
| | | ### å端å¯å¨ |
| | | ```bash |
| | | # å¯å¨ç½å
³ |
| | | cd gateway |
| | | mvn spring-boot:run |
| | | |
| | | # å¯å¨PLCæå¡ï¼ç«¯å£10018ï¼ |
| | | cd mes-processes/mes-plcSend |
| | | mvn spring-boot:run |
| | | ``` |
| | | |
| | | ### å端å¯å¨ |
| | | ```bash |
| | | cd mes-web |
| | | npm install |
| | | npm run dev |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## ð æ ¸å¿ç®å½éæ¥ |
| | | |
| | | ### åç«¯æ ¸å¿ç®å½ |
| | | |
| | | | è·¯å¾ | 说æ | |
| | | |------|------| |
| | | | `mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java` | **任塿§è¡å¼æï¼æ ¸å¿ï¼** | |
| | | | `mes-processes/mes-plcSend/src/main/java/com/mes/interaction/vehicle/handler/LoadVehicleLogicHandler.java` | 大车设å¤é»è¾å¤çå¨ | |
| | | | `mes-processes/mes-plcSend/src/main/java/com/mes/device/service/DeviceCoordinationService.java` | 设å¤åè°æå¡ | |
| | | | `mes-common/serverBase/src/main/java/com/mes/exception/GlobalExceptionHandler.java` | å
¨å±å¼å¸¸å¤ç | |
| | | |
| | | ### åç«¯æ ¸å¿ç®å½ |
| | | |
| | | | è·¯å¾ | 说æ | |
| | | |------|------| |
| | | | `mes-web/src/main.js` | åºç¨å
¥å£ | |
| | | | `mes-web/src/router/index.js` | è·¯ç±é
ç½® | |
| | | | `mes-web/src/utils/request.js` | HTTP请æ±å°è£
| |
| | | | `mes-web/public/config.js` | æå¡å¨å°åé
ç½® | |
| | | |
| | | --- |
| | | |
| | | ## ð§ å¸¸ç¨æä½ |
| | | |
| | | ### æ·»å æ°è®¾å¤ç±»å |
| | | |
| | | 1. **å®ä¹è®¾å¤ç±»å常é** |
| | | ```java |
| | | // DeviceConfig.DeviceType |
| | | public static final String NEW_DEVICE = "æ°è®¾å¤ç±»å"; |
| | | ``` |
| | | |
| | | 2. **å建设å¤é»è¾å¤çå¨** |
| | | ```java |
| | | @Component |
| | | public class NewDeviceLogicHandler extends BaseDeviceLogicHandler { |
| | | @Override |
| | | public String getDeviceType() { |
| | | return DeviceConfig.DeviceType.NEW_DEVICE; |
| | | } |
| | | |
| | | @Override |
| | | protected DevicePlcVO.OperationResult doExecute(...) { |
| | | // å®ç°é»è¾ |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | 3. **é
置设å¤é»è¾åæ°**ï¼åç«¯ï¼ |
| | | ```json |
| | | { |
| | | "deviceLogic": { |
| | | "timeout": 5000, |
| | | "customParam": "value" |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### æ·»å æ°é¡µé¢ |
| | | |
| | | 1. **å建Vueç»ä»¶** |
| | | ```vue |
| | | <!-- mes-web/src/views/newModule/NewPage.vue --> |
| | | <template> |
| | | <div>æ°é¡µé¢</div> |
| | | </template> |
| | | ``` |
| | | |
| | | 2. **æ·»å è·¯ç±** |
| | | ```javascript |
| | | // mes-web/src/router/index.js |
| | | { |
| | | path: '/newModule/newPage', |
| | | name: 'newPage', |
| | | component: () => import('../views/newModule/NewPage.vue') |
| | | } |
| | | ``` |
| | | |
| | | 3. **æ·»å APIæ¥å£** |
| | | ```javascript |
| | | // mes-web/src/api/newModule.js |
| | | export function getNewData() { |
| | | return request.get('/api/newModule/data') |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## ð 设å¤ç±»å鿥 |
| | | |
| | | | 设å¤ç±»å | 常é | å¤çå¨ | 说æ | |
| | | |---------|------|--------|------| |
| | | | å¤§è½¦è®¾å¤ | `LOAD_VEHICLE` | `LoadVehicleLogicHandler` | å¤å®ä¾åè°ï¼MESä»»å¡å¤ç | |
| | | | 大çç笼 | `LARGE_GLASS` | `LargeGlassLogicHandler` | æ ¼åèå´é
ç½® | |
| | | | å§è½¬ç«æ«ç | `WORKSTATION_SCANNER` | `HorizontalScannerLogicHandler` | 宿¶æ«æï¼æ°æ®è½åº | |
| | | | å§è½¬ç« | `WORKSTATION_TRANSFER` | `HorizontalTransferLogicHandler` | 30sç¼å²ï¼æ¹éå¤ç | |
| | | | å§å¼ç¼å | `GLASS_STORAGE` | `GlassStorageLogicHandler` | å·²å®ç°ï¼å½åä¸ä½¿ç¨ | |
| | | |
| | | --- |
| | | |
| | | ## ð æ§è¡æµç¨éæ¥ |
| | | |
| | | ### 任塿§è¡æµç¨ |
| | | ``` |
| | | Controller â Service â TaskExecutionEngine â DeviceInteraction/Handler â PLC |
| | | ``` |
| | | |
| | | ### 设å¤åè°æµç¨ |
| | | ``` |
| | | 设å¤A宿 â æ°æ®ä¼ é â 设å¤B读å â 设å¤Bæ§è¡ â ç¶æåæ¥ |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## ð API端ç¹éæ¥ |
| | | |
| | | ### 设å¤ç®¡ç |
| | | - `GET /device/config/list` - 设å¤å表 |
| | | - `POST /device/config/create` - åå»ºè®¾å¤ |
| | | - `PUT /device/config/update` - æ´æ°è®¾å¤ |
| | | - `DELETE /device/config/delete/{id}` - å é¤è®¾å¤ |
| | | |
| | | ### 设å¤ç»ç®¡ç |
| | | - `GET /device/group/list` - 设å¤ç»å表 |
| | | - `POST /device/group/create` - å建设å¤ç» |
| | | - `POST /device/group/{groupId}/devices` - æ·»å 设å¤å°ç» |
| | | |
| | | ### ä»»å¡ç®¡ç |
| | | - `POST /device/task/start` - å¯å¨ä»»å¡ |
| | | - `GET /device/task/list` - ä»»å¡å表 |
| | | - `GET /device/task/{taskId}` - ä»»å¡è¯¦æ
|
| | | - `POST /device/task/{taskId}/cancel` - åæ¶ä»»å¡ |
| | | |
| | | ### 宿¶çæ§ï¼SSEï¼ |
| | | - `GET /task/notification/sse?taskId=xxx` - ç嬿å®ä»»å¡ |
| | | - `GET /task/notification/sse/all` - ç嬿æä»»å¡ |
| | | |
| | | --- |
| | | |
| | | ## ð 常è§é®é¢ |
| | | |
| | | ### 1. 设å¤ç¶æä¸¢å¤± |
| | | **åå **ï¼å¤§è½¦è®¾å¤ç¶æåå¨å¨å
åä¸ï¼æå¡éå¯å丢失 |
| | | **è§£å³**ï¼æ©å±æ¯ææ°æ®åºæä¹
å |
| | | |
| | | ### 2. 任塿§è¡å¤±è´¥ |
| | | **æ£æ¥**ï¼ |
| | | - 设å¤ç¶æï¼å¨çº¿/ç¦»çº¿ï¼ |
| | | - PLCè¿æ¥ç¶æ |
| | | - 设å¤åè°æ£æ¥ |
| | | - æ¥ç任塿¥éª¤è¯¦æ
|
| | | |
| | | ### 3. SSEè¿æ¥æå¼ |
| | | **åå **ï¼è¿æ¥è¶
æ¶ï¼30åéï¼ |
| | | **è§£å³**ï¼åç«¯éæ°è¿æ¥ |
| | | |
| | | ### 4. 设å¤é»è¾ä¸çæ |
| | | **æ£æ¥**ï¼ |
| | | - 设å¤ç±»åæ¯å¦æ£ç¡® |
| | | - `extraParams.deviceLogic` é
ç½®æ¯å¦æ£ç¡® |
| | | - Handleræ¯å¦å·²æ³¨åï¼æ¥çæ¥å¿ï¼ |
| | | |
| | | --- |
| | | |
| | | ## ð è°è¯æå·§ |
| | | |
| | | ### æ¥ç注åç设å¤å¤çå¨ |
| | | ```java |
| | | @Autowired |
| | | private DeviceLogicHandlerFactory factory; |
| | | Set<String> types = factory.getSupportedDeviceTypes(); |
| | | ``` |
| | | |
| | | ### æ¥çæ¥å¿ |
| | | - 任塿§è¡ï¼`TaskExecutionEngine` æ¥å¿ |
| | | - è®¾å¤æ§è¡ï¼å
·ä½ Handler æ¥å¿ |
| | | - åè°æå¡ï¼`DeviceCoordinationService` æ¥å¿ |
| | | |
| | | ### å端è°è¯ |
| | | - æå¼æµè§å¨å¼åè
å·¥å
· |
| | | - æ¥ç Network æ ç¾ï¼API请æ±ï¼ |
| | | - æ¥ç Console æ ç¾ï¼é误信æ¯ï¼ |
| | | |
| | | --- |
| | | |
| | | ## ð¦ æ¨¡åä¾èµå
³ç³» |
| | | |
| | | ``` |
| | | mes-parent (ç¶æ¨¡å) |
| | | âââ mes-common (å
Œ
±æ¨¡å) |
| | | â âââ springSecurity (å®å
¨) |
| | | â âââ serverBase (åºç¡æå¡) |
| | | â âââ communication (éä¿¡) |
| | | â âââ model (æ°æ®æ¨¡å) |
| | | âââ mes-processes (ä¸å¡æµç¨) |
| | | â âââ mes-plcSend (PLCæå¡) |
| | | âââ gateway (APIç½å
³) |
| | | ``` |
| | | |
| | | **ä¾èµå
³ç³»**ï¼ |
| | | - `mes-plcSend` ä¾èµ `springSecurity` å `serverBase` |
| | | - `serverBase` ä¾èµ `model` |
| | | - `gateway` ç¬ç«è¿è¡ |
| | | |
| | | --- |
| | | |
| | | ## âï¸ é
ç½®æä»¶ä½ç½® |
| | | |
| | | | é
ç½®æä»¶ | ä½ç½® | 说æ | |
| | | |---------|------|------| |
| | | | å端主é
ç½® | `mes-processes/mes-plcSend/src/main/resources/application.yml` | PLCæå¡é
ç½® | |
| | | | å端é
ç½® | `mes-web/public/config.js` | æå¡å¨å°å | |
| | | | è·¯ç±é
ç½® | `mes-web/src/router/index.js` | åç«¯è·¯ç± | |
| | | | æ°æ®åºè¿ç§» | `mes-processes/mes-plcSend/src/main/resources/db/migration/` | æ°æ®åºèæ¬ | |
| | | |
| | | --- |
| | | |
| | | ## ð¯ å¼åè§è |
| | | |
| | | ### å½åè§è |
| | | - **ç±»å**ï¼å¤§é©¼å³°ï¼PascalCaseï¼ |
| | | - **æ¹æ³å**ï¼å°é©¼å³°ï¼camelCaseï¼ |
| | | - **常é**ï¼å
¨å¤§åä¸å线ï¼UPPER_SNAKE_CASEï¼ |
| | | - **å
å**ï¼å
¨å°å |
| | | |
| | | ### 代ç ç»ç» |
| | | - **ç®å设å¤**ï¼æ¾å¨ `interaction/impl/` |
| | | - **å¤æè®¾å¤**ï¼å建ç¬ç«å
ï¼å¦ `interaction/vehicle/`ï¼ |
| | | - **éè¦åè°ç设å¤**ï¼å建 `coordination/` åå
|
| | | |
| | | ### 注éè§è |
| | | - ç±»åæ¹æ³å¿
é¡»æJavaDoc注é |
| | | - 夿é»è¾éè¦è¡å
注é |
| | | - TODOæ è®°å¾
宿åè½ |
| | | |
| | | --- |
| | | |
| | | ## ð ç¸å
³ææ¡£ |
| | | |
| | | - **è¯¦ç»æ¥å**ï¼`项ç®è¯¦ç»æ¥å.md` |
| | | - **PLCæå¡README**ï¼`mes-processes/mes-plcSend/README.md` |
| | | - **æ¶æææ¡£**ï¼`mes-processes/mes-plcSend/ARCHITECTURE.md` |
| | | |
| | | --- |
| | | |
| | | **æåæ´æ°**ï¼2025å¹´ |
| | | |