| | |
| | | import com.mes.device.entity.DeviceConfig; |
| | | import com.mes.device.service.DeviceConfigService; |
| | | import com.mes.device.util.ConfigJsonHelper; |
| | | import com.mes.service.PlcDynamicDataService; |
| | | import com.mes.plc.client.PlcClient; |
| | | import com.mes.plc.factory.PlcClientFactory; |
| | | import com.mes.s7.enhanced.EnhancedS7Serializer; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | |
| | | /** |
| | | * PLC测试写入服务 |
| | | * |
| | | * |
| | | * 基于DeviceConfig的新API,用于模拟PLC行为进行测试 |
| | | * |
| | | * 推荐使用:DevicePlcOperationService(生产环境) |
| | | * |
| | | * |
| | | * @author huang |
| | | * @date 2025/10/29 |
| | | */ |
| | |
| | | |
| | | @Resource |
| | | private DeviceConfigService deviceConfigService; |
| | | |
| | | |
| | | @Resource |
| | | private PlcDynamicDataService plcDynamicDataService; |
| | | |
| | | |
| | | @Resource |
| | | private 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发送请求字 |
| | | * |
| | | * |
| | | * @param deviceId 设备ID |
| | | * @return 是否成功 |
| | | */ |
| | |
| | | return false; |
| | | } |
| | | try { |
| | | // 尝试使用新的PLC客户端工厂 |
| | | 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; |
| | | } |
| | | |
| | | |
| | | // 检查联机状态 |
| | | Object onlineStateObj = currentData.get("onlineState"); |
| | | Integer onlineState = null; |
| | |
| | | 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; |
| | | } |
| | | |
| | | |
| | | // 检查汇报字,如果为1则重置为0 |
| | | Object plcReportObj = currentData.get("plcReport"); |
| | | Integer plcReport = null; |
| | |
| | | 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); |
| | | } |
| | | |
| | | |
| | | // 设置请求字为1 |
| | | currentData.put("plcRequest", ON); |
| | | |
| | | |
| | | // 使用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; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 根据设备ID模拟PLC任务完成汇报 |
| | | * |
| | | * |
| | | * @param deviceId 设备ID |
| | | * @return 是否成功 |
| | | */ |
| | |
| | | return false; |
| | | } |
| | | try { |
| | | EnhancedS7Serializer s7Serializer = getSerializerForDevice(device); |
| | | if (s7Serializer == null) { |
| | | log.error("获取S7Serializer失败: deviceId={}", deviceId); |
| | | return false; |
| | | // 尝试使用新的PLC客户端工厂 |
| | | PlcClient plcClient = plcClientFactory.getClient(device); |
| | | if (plcClient != null) { |
| | | // 使用新的PLC客户端读取数据 |
| | | Map<String, Object> currentData = plcClient.readAllData(); |
| | | if (currentData == null) { |
| | | currentData = new HashMap<>(); |
| | | } |
| | | |
| | | // 设置汇报字为1,请求字清0 |
| | | currentData.put("plcReport", ON); |
| | | currentData.put("plcRequest", OFF); |
| | | |
| | | // 使用新的PLC客户端写入数据 |
| | | boolean success = plcClient.writeData(currentData); |
| | | if (success) { |
| | | log.info("模拟PLC任务完成汇报:plcReport=1, deviceId={}", deviceId); |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | // 使用PlcDynamicDataService读取数据 |
| | | Map<String, Object> currentData = plcDynamicDataService.readAllPlcData(device, s7Serializer); |
| | | if (currentData == null || currentData.isEmpty()) { |
| | | log.error("读取PLC数据失败,返回空: deviceId={}", deviceId); |
| | | return false; |
| | | } |
| | | |
| | | // 设置汇报字为1,请求字清0 |
| | | currentData.put("plcReport", ON); |
| | | currentData.put("plcRequest", OFF); |
| | | currentData.put("mesGlassCount", 10); |
| | | |
| | | // 使用PlcDynamicDataService写入数据 |
| | | plcDynamicDataService.writePlcData(device, currentData, s7Serializer); |
| | | |
| | | log.info("模拟PLC任务完成汇报:plcReport=1, mesGlassCount=10, deviceId={}", deviceId); |
| | | return true; |
| | | |
| | | // 如果新客户端失败,回退到旧实现(保持兼容) |
| | | log.warn("新PLC客户端失败,回退到旧实现: deviceId={}", deviceId); |
| | | return simulatePlcReportByDeviceLegacy(device); |
| | | } catch (Exception e) { |
| | | log.error("根据设备模拟PLC汇报失败: deviceId={}", deviceId, e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 旧版实现:根据设备模拟PLC任务完成汇报 |
| | | * |
| | | * @param device 设备配置 |
| | | * @return 是否成功 |
| | | */ |
| | | private boolean simulatePlcReportByDeviceLegacy(DeviceConfig device) { |
| | | try { |
| | | EnhancedS7Serializer s7Serializer = getSerializerForDevice(device); |
| | | if (s7Serializer == null) { |
| | | log.error("获取S7Serializer失败: deviceId={}", device.getId()); |
| | | return false; |
| | | } |
| | | |
| | | // 使用PlcDynamicDataService读取数据 |
| | | Map<String, Object> currentData = plcDynamicDataService.readAllPlcData(device, s7Serializer); |
| | | if (currentData == null || currentData.isEmpty()) { |
| | | log.error("读取PLC数据失败,返回空: deviceId={}", device.getId()); |
| | | return false; |
| | | } |
| | | |
| | | // 设置汇报字为1,请求字清0 |
| | | currentData.put("plcReport", ON); |
| | | currentData.put("plcRequest", OFF); |
| | | |
| | | // 使用PlcDynamicDataService写入数据 |
| | | plcDynamicDataService.writePlcData(device, currentData, s7Serializer); |
| | | |
| | | log.info("模拟PLC任务完成汇报(旧版):plcReport=1, deviceId={}", device.getId()); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("根据设备模拟PLC汇报失败(旧版): deviceId={}", device.getId(), e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 根据设备ID重置PLC所有状态 |
| | | * |
| | | * |
| | | * @param deviceId 设备ID |
| | | * @return 是否成功 |
| | | */ |
| | |
| | | return false; |
| | | } |
| | | try { |
| | | // 尝试使用新的PLC客户端工厂 |
| | | PlcClient plcClient = plcClientFactory.getClient(device); |
| | | if (plcClient != null) { |
| | | // 构建重置数据 |
| | | Map<String, Object> resetData = new HashMap<>(); |
| | | resetData.put("plcRequest", OFF); |
| | | resetData.put("plcReport", OFF); |
| | | resetData.put("mesSend", OFF); |
| | | resetData.put("mesConfirm", OFF); |
| | | resetData.put("onlineState", ON); |
| | | resetData.put("alarmInfo", OFF); |
| | | |
| | | // 使用新的PLC客户端写入数据 |
| | | boolean success = plcClient.writeData(resetData); |
| | | if (success) { |
| | | log.info("PLC状态已重置, deviceId={}", deviceId); |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | // 如果新客户端失败,回退到旧实现(保持兼容) |
| | | log.warn("新PLC客户端失败,回退到旧实现: deviceId={}", deviceId); |
| | | return resetPlcByDeviceLegacy(device); |
| | | } catch (Exception e) { |
| | | log.error("根据设备重置PLC状态失败: deviceId={}", deviceId, e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 旧版实现:根据设备重置PLC所有状态 |
| | | * |
| | | * @param device 设备配置 |
| | | * @return 是否成功 |
| | | */ |
| | | private boolean resetPlcByDeviceLegacy(DeviceConfig device) { |
| | | try { |
| | | EnhancedS7Serializer s7Serializer = getSerializerForDevice(device); |
| | | if (s7Serializer == null) { |
| | | log.error("获取S7Serializer失败: deviceId={}", deviceId); |
| | | log.error("获取S7Serializer失败: deviceId={}", device.getId()); |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // 构建重置数据 |
| | | Map<String, Object> resetData = new HashMap<>(); |
| | | resetData.put("plcRequest", OFF); |
| | |
| | | resetData.put("mesSend", OFF); |
| | | resetData.put("mesConfirm", OFF); |
| | | resetData.put("onlineState", ON); |
| | | resetData.put("mesGlassCount", 0); |
| | | resetData.put("alarmInfo", OFF); |
| | | |
| | | |
| | | // 使用PlcDynamicDataService写入数据 |
| | | plcDynamicDataService.writePlcData(device, resetData, s7Serializer); |
| | | |
| | | log.info("PLC状态已重置, deviceId={}", deviceId); |
| | | |
| | | log.info("PLC状态已重置(旧版): deviceId={}", device.getId()); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("根据设备重置PLC状态失败: deviceId={}", deviceId, e); |
| | | log.error("根据设备重置PLC状态失败(旧版): deviceId={}", device.getId(), e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 根据设备ID读取PLC当前状态 |
| | | * |
| | | * |
| | | * @param deviceId 设备ID |
| | | * @return PLC状态数据 |
| | | */ |
| | |
| | | return null; |
| | | } |
| | | try { |
| | | // 尝试使用新的PLC客户端工厂 |
| | | PlcClient plcClient = plcClientFactory.getClient(device); |
| | | if (plcClient != null) { |
| | | // 使用新的PLC客户端读取所有数据 |
| | | Map<String, Object> data = plcClient.readAllData(); |
| | | log.info("读取PLC状态成功: deviceId={}, dataSize={}", deviceId, data != null ? data.size() : 0); |
| | | return data; |
| | | } |
| | | |
| | | // 如果新客户端失败,回退到旧实现(保持兼容) |
| | | log.warn("新PLC客户端失败,回退到旧实现: deviceId={}", deviceId); |
| | | |
| | | EnhancedS7Serializer s7Serializer = getSerializerForDevice(device); |
| | | if (s7Serializer == null) { |
| | | log.error("获取S7Serializer失败: deviceId={}", deviceId); |
| | |
| | | } |
| | | // 使用PlcDynamicDataService读取所有数据(支持addressMapping) |
| | | Map<String, Object> data = plcDynamicDataService.readAllPlcData(device, s7Serializer); |
| | | log.info("读取PLC状态成功(旧版): deviceId={}, dataSize={}", deviceId, data != null ? data.size() : 0); |
| | | return data; |
| | | } catch (Exception e) { |
| | | log.error("读取设备PLC状态失败: deviceId={}", deviceId, e); |
| | |
| | | } |
| | | |
| | | try { |
| | | // 尝试使用新的PLC客户端工厂 |
| | | PlcClient plcClient = plcClientFactory.getClient(device); |
| | | if (plcClient != null) { |
| | | // 使用新的PLC客户端写入数据 |
| | | boolean success = plcClient.writeData(fieldValues); |
| | | if (success) { |
| | | log.info("写入PLC字段成功: deviceId={}, fields={}", deviceId, fieldValues.keySet()); |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | // 如果新客户端失败,回退到旧实现(保持兼容) |
| | | log.warn("新PLC客户端失败,回退到旧实现: deviceId={}", deviceId); |
| | | |
| | | // 获取对应的S7Serializer(使用设备配置) |
| | | EnhancedS7Serializer s7Serializer = getSerializerForDevice(device); |
| | | if (s7Serializer == null) { |
| | |
| | | // 使用动态数据服务写入字段(基于DeviceConfig) |
| | | plcDynamicDataService.writePlcData(device, fieldValues, s7Serializer); |
| | | |
| | | log.info("写入PLC字段成功: deviceId={}, fields={}", deviceId, fieldValues.keySet()); |
| | | log.info("写入PLC字段成功(旧版): deviceId={}, fields={}", deviceId, fieldValues.keySet()); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("写入PLC字段失败: deviceId={}", deviceId, e); |
| | |
| | | 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) { |