| | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.*; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | this.api = api; |
| | | this.logicConfig = JsonConversion.jsonToObjectByJackson(ReadFile.readJson(machine.getLogicFile()).toString(), LogicConfig.class); |
| | | this.plcParameters = JsonConversion.jsonToObjectByJackson(ReadFile.readJson(machine.getMachineFile()).toString(), PlcParameters.class); |
| | | this.logicConfig.getLogics(); |
| | | this.plcParameters.Initialization(); |
| | | for (LogicItem logicItem : logicConfig.getLogics()) { |
| | | if (logicItem.getLogicInterval()==0){ |
| | | //默认1000毫秒 |
| | | logicItem.setLogicInterval(1000); |
| | | } |
| | | for (Logic logic : logicItem.getLogic()) { |
| | | logic.setAddress(this.plcParameters.getMap().get(logic.getCodeId()).getAddress()); |
| | | logic.setPlcDataType(this.plcParameters.getMap().get(logic.getCodeId()).getPlcDataType()); |
| | | } |
| | | for (ReturnValue returnValue : logicItem.getReturnValue()) { |
| | | returnValue.setAddress(this.plcParameters.getMap().get(returnValue.getCodeId()).getAddress()); |
| | | returnValue.setPlcDataType(this.plcParameters.getMap().get(returnValue.getCodeId()).getPlcDataType()); |
| | | } |
| | | } |
| | | |
| | | |
| | | switch (machine.getProtocolType().getName()) { |
| | | case "ModbusTcp": |
| | | client = new ModbusTcpClient(machine.getIp(), machine.getPort(), 1); |
| | |
| | | log.error("无效的协议类型: {}", protocolType); |
| | | throw new IllegalArgumentException("无效的协议类型: " + protocolType); |
| | | } |
| | | if (client != null) { |
| | | client.connect(); |
| | | boolean connected = client.isConnected(); |
| | | if (!connected) { |
| | | log.error("连接PLC失败: {}", machine.getIp()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void run() { |
| | | log.info("MachineThread启动,设备IP: {}", machine.getIp()); |
| | | if (client == null || !client.isConnected()) { |
| | | log.error("PLC客户端未连接,线程退出"); |
| | | return; |
| | | } |
| | | |
| | | plcParameters.Initialization(); |
| | | |
| | | try { |
| | | // 初始化读取PLC参数 |
| | | readPlcParameter(); |
| | | } catch (Exception e) { |
| | | log.error("初始化读取PLC参数失败: {}", e.getMessage(), e); |
| | | return; |
| | | } |
| | | // 为每个逻辑项创建并启动子线程 |
| | | //startLogicThread(logicConfig.getLogics().get(0)); |
| | | for (LogicItem logicItem : logicConfig.getLogics()) { |
| | | startLogicThread(logicItem); |
| | | //startLogicThread(logicConfig.getLogics().get(0)); |
| | | } |
| | | |
| | | // 主线程持续运行,定期读取PLC参数并监控连接状态 |
| | | while (running) { |
| | | try { |
| | | // 读取PLC参数,为逻辑处理提供最新数据 |
| | | readPlcParameter(); |
| | | |
| | | // 检查PLC连接状态 |
| | | if (!client.isConnected()) { |
| | | log.warn("PLC连接断开,尝试重新连接"); |
| | | log.info("PLC尝试连接... 设备IP: {}", machine.getIp()); |
| | | tryReconnect(); |
| | | } |
| | | |
| | | // 检查逻辑线程状态,重启已终止的线程 |
| | | // 读取PLC参数,为逻辑处理提供最新数据 |
| | | this.readPlcParameter(); |
| | | plcParameters.Initialization(); |
| | | // 检查逻辑线程状态,开启/重启 线程 |
| | | checkLogicThreadsStatus(); |
| | | |
| | | // 等待下一个执行周期 |
| | | Thread.sleep(mainThreadInterval); |
| | | } catch (InterruptedException e) { |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 线程退出前关闭所有资源 |
| | | shutdown(); |
| | | log.info("MachineThread已退出,设备IP: {}", machine.getIp()); |
| | |
| | | |
| | | // 为指定逻辑项创建并启动子线程 |
| | | private void startLogicThread(LogicItem logicItem) { |
| | | String logicId = logicItem.getName(); // 假设每个LogicItem有唯一ID |
| | | String logicId = this.machine.getId()+" - "+this.machine.getName()+" - "+ logicItem.getName(); // 假设每个LogicItem有唯一ID |
| | | if (logicThreads.containsKey(logicId) && logicThreads.get(logicId).isAlive()) { |
| | | log.warn("逻辑项线程已在运行: {}", logicId); |
| | | return; |
| | | } |
| | | |
| | | // 设置运行标志 |
| | | logicRunningFlags.put(logicId, true); |
| | | |
| | | // 创建并启动线程 |
| | | Thread thread = new Thread(() -> { |
| | | log.info("逻辑项线程启动: {}", logicId); |
| | | |
| | | // 逻辑项子线程持续运行的循环 |
| | | while (logicRunningFlags.getOrDefault(logicId, false)) { |
| | | try { |
| | | // 执行实际业务逻辑 |
| | | basicsLogic(logicItem); |
| | | |
| | | // 根据逻辑项的执行频率设置等待时间,默认1000ms |
| | | int logicInterval = 1000; |
| | | Thread.sleep(logicInterval); |
| | | Thread.sleep(logicItem.getLogicInterval()); |
| | | } catch (InterruptedException e) { |
| | | log.info("逻辑项线程被中断,准备退出: {}", logicId); |
| | | logicRunningFlags.put(logicId, false); |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | log.info("逻辑项线程已退出: {}", logicId); |
| | | }); |
| | | |
| | | // 设置线程名称 |
| | | thread.setName("Logic-" + logicId); |
| | | |
| | | thread.setName(logicId); |
| | | // 存储线程引用 |
| | | logicThreads.put(logicId, thread); |
| | | |
| | | // 启动线程 |
| | | thread.start(); |
| | | log.info("已启动逻辑项线程: {}", logicId); |
| | | //log.info("已启动逻辑项线程: {}", logicId); |
| | | } |
| | | |
| | | // 检查逻辑线程状态,重启已终止的线程 |
| | | private void checkLogicThreadsStatus() { |
| | | for (LogicItem logicItem : logicConfig.getLogics()) { |
| | | String logicId = logicItem.getName(); |
| | | String logicId = this.machine.getId()+" - "+this.machine.getName()+" - "+ logicItem.getName(); |
| | | Thread thread = logicThreads.get(logicId); |
| | | |
| | | // 如果线程不存在或已终止且运行标志为true,则重启线程 |
| | | if ((thread == null || !thread.isAlive()) && |
| | | logicRunningFlags.getOrDefault(logicId, false)) { |
| | | log.warn("逻辑项线程已终止,准备重启: {}", logicId); |
| | | if ((thread == null || !thread.isAlive()) &&!logicRunningFlags.getOrDefault(logicId, false)) { |
| | | startLogicThread(logicItem); |
| | | } |
| | | } |
| | |
| | | private void tryReconnect() { |
| | | if (client != null) { |
| | | try { |
| | | log.info("尝试重新连接PLC: {}", machine.getIp()); |
| | | client.disconnect(); |
| | | Thread.sleep(2000); |
| | | client.connect(); |
| | | boolean reconnected = client.isConnected(); |
| | | if (reconnected) { |
| | | log.info("PLC重新连接成功: {}", machine.getIp()); |
| | |
| | | // 关闭线程前的清理工作 |
| | | public void shutdown() { |
| | | running = false; |
| | | |
| | | // 停止所有逻辑线程 |
| | | for (String logicId : logicRunningFlags.keySet()) { |
| | | logicRunningFlags.put(logicId, false); |
| | |
| | | thread.interrupt(); |
| | | } |
| | | } |
| | | |
| | | // 等待所有逻辑线程结束 |
| | | for (String logicId : logicThreads.keySet()) { |
| | | Thread thread = logicThreads.get(logicId); |
| | |
| | | } |
| | | } |
| | | if (isEqual){ |
| | | List<String> result=new ArrayList<>(); |
| | | log.info("满足条件:{}",logicItem.getName()); |
| | | //3.查询此逻辑下需要返回给PLC的数据 result可接收 HTTP接口,视图,存储过程 等 如下 |
| | | try{ |
| | | String connectType=logicItem.getConnectType(); |
| | | String connectAddress=logicItem.getConnectAddress(); |
| | | Map map=new HashMap(); |
| | | switch (connectType) { |
| | | case "Http": |
| | | map.put("method","POST"); |
| | | map.put("plcParameter",plcParameters); |
| | | result= api.httpApi(connectAddress,map); |
| | | log.info("接口返回内容:{}",result); |
| | | break; |
| | | case "View": // 视图/表 |
| | | result= api.viewApi(connectAddress,map); |
| | | break; |
| | | case "Procedure": // 存储过程 |
| | | //result= api.procedureAPI(connectAddress,plcParameter); |
| | | break; |
| | | default: |
| | | log.warn("不支持的连接类型: {}", connectType); |
| | | return; // 不支持的方式 |
| | | List<String> resultWrite=null; |
| | | if (logicItem.getApiConfigBefore()!=null){ |
| | | ApiConfig apiConfig=logicItem.getApiConfigBefore(); |
| | | resultWrite=api.callApi(apiConfig,plcParameters); |
| | | log.info("ApiConfigBefore 外置接口[{}:{}]返回的内容:{}",apiConfig.getType(),apiConfig.getAddress(),resultWrite); |
| | | } |
| | | //写入PLC返回值成功时调用接口 |
| | | if (basicsResult(resultWrite,logicItem.getReturnValue())){ |
| | | ApiConfig apiConfig=logicItem.getApiConfigAfter(); |
| | | if (logicItem.getApiConfigAfter()!=null){ |
| | | List<String> result=api.callApi(apiConfig,plcParameters); |
| | | log.info("ApiConfigAfter 外置接口[{}:{}]返回的内容:{}",apiConfig.getType(),apiConfig.getAddress(),result); |
| | | } |
| | | } |
| | | |
| | | }catch (Exception e){ |
| | | log.error("调用接口失败: {}", e.getMessage(), e); |
| | | } |
| | | //4.返回PLC内容 |
| | | if (result != null&&!result.isEmpty()) { |
| | | basicsResult(result,logicItem.getReturnValue()); |
| | | } |
| | | |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("执行basicsLogic失败: {}", e.getMessage(), e); |
| | |
| | | if (values!=null && !values.equals("")){ |
| | | //还需增添 不同类型调用不同方法 |
| | | switch (itemReturnValue.getPlcDataType()) { |
| | | case "int": |
| | | case "Word": |
| | | client.writeRegister(itemReturnValue.getAddress(),(int)Double.parseDouble(values)); |
| | | break; |
| | | case "string": |
| | | case "String": |
| | | client.writeString(itemReturnValue.getAddress(),values); |
| | | break; |
| | | case "float": |
| | | case "Float": |
| | | client.writeFloat(itemReturnValue.getAddress(),Float.valueOf(values)); |
| | | break; |
| | | case "bit": |
| | | client.writeBit(itemReturnValue.getAddress(),Boolean.valueOf(values)); |
| | | break; |
| | | default: |
| | | log.error("不支持的数据类型: {}", itemReturnValue.getPlcDataType()); |
| | | return false; |
| | | } |
| | | |
| | | } |
| | | } |
| | | return true; |