mes-processes/mes-plcSend/src/main/java/com/mes/service/PlcTestWriteService.java
@@ -7,7 +7,8 @@
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;
@@ -21,11 +22,9 @@
/**
 * PLC测试写入服务
 *
 *
 * 基于DeviceConfig的新API,用于模拟PLC行为进行测试
 *
 * 推荐使用:DevicePlcOperationService(生产环境)
 *
 *
 * @author huang
 * @date 2025/10/29
 */
@@ -35,24 +34,26 @@
    @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 是否成功
     */
@@ -63,42 +64,98 @@
            return false;
        }
        try {
            EnhancedS7Serializer s7Serializer = getSerializerForDevice(device);
            if (s7Serializer == null) {
                log.error("获取S7Serializer失败: deviceId={}", deviceId);
                return false;
            }
            // 使用PlcDynamicDataService读取数据(支持addressMapping)
            Map<String, Object> currentData = plcDynamicDataService.readAllPlcData(device, s7Serializer);
            if (currentData == null || currentData.isEmpty()) {
                log.error("读取PLC数据失败,返回空: deviceId={}", deviceId);
                return false;
            }
            // 检查联机状态
            Object onlineStateObj = currentData.get("onlineState");
            Integer onlineState = null;
            if (onlineStateObj != null) {
                if (onlineStateObj instanceof Number) {
                    onlineState = ((Number) onlineStateObj).intValue();
                } else {
                    try {
                        String strValue = String.valueOf(onlineStateObj);
                        if (!strValue.isEmpty() && !"null".equalsIgnoreCase(strValue)) {
                            onlineState = Integer.parseInt(strValue);
            // 尝试使用新的PLC客户端工厂
            PlcClient plcClient = plcClientFactory.getClient(device);
            if (plcClient != null) {
                // 使用新的PLC客户端读取数据
                Map<String, Object> currentData = plcClient.readAllData();
                if (currentData != null && !currentData.isEmpty()) {
                    // 检查联机状态(仅当配置中存在该字段时)
                    if (hasFieldInConfig(device, "onlineState")) {
                        Object onlineStateObj = currentData.get("onlineState");
                        if (onlineStateObj != null) {
                            Integer onlineState = parseInteger(onlineStateObj);
                            if (onlineState == OFF) {
                                log.info("当前PLC联机模式为0,停止联机: deviceId={}", deviceId);
                                return false;
                            }
                        }
                    } catch (NumberFormatException e) {
                        log.warn("解析onlineState失败: deviceId={}, value={}", deviceId, onlineStateObj, e);
                    }
                    // 检查汇报字,如果为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;
                    }
                }
            }
            if (onlineState != null && onlineState == OFF) {
                log.info("当前PLC联机模式为0,停止联机: deviceId={}", deviceId);
            // 如果新客户端失败,回退到旧实现(保持兼容)
            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={}", device.getId());
                return false;
            }
            // 使用PlcDynamicDataService读取数据(支持addressMapping)
            Map<String, Object> currentData = plcDynamicDataService.readAllPlcData(device, s7Serializer);
            if (currentData == null || currentData.isEmpty()) {
                log.error("读取PLC数据失败,返回空: deviceId={}", device.getId());
                return false;
            }
            // 检查联机状态(仅当配置中存在该字段时)
            if (hasFieldInConfig(device, "onlineState")) {
                Object onlineStateObj = currentData.get("onlineState");
                Integer onlineState = null;
                if (onlineStateObj != null) {
                    if (onlineStateObj instanceof Number) {
                        onlineState = ((Number) onlineStateObj).intValue();
                    } else {
                        try {
                            String strValue = String.valueOf(onlineStateObj);
                            if (!strValue.isEmpty() && !"null".equalsIgnoreCase(strValue)) {
                                onlineState = Integer.parseInt(strValue);
                            }
                        } catch (NumberFormatException e) {
                            log.warn("解析onlineState失败: deviceId={}, value={}", device.getId(), onlineStateObj, e);
                        }
                    }
                }
                if (onlineState != null && onlineState == OFF) {
                    log.info("当前PLC联机模式为0,停止联机: deviceId={}", device.getId());
                    return false;
                }
            }
            // 检查汇报字,如果为1则重置为0
            Object plcReportObj = currentData.get("plcReport");
            Integer plcReport = null;
@@ -112,33 +169,33 @@
                            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 是否成功
     */
@@ -149,38 +206,75 @@
            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 是否成功
     */
@@ -191,36 +285,108 @@
            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) {
                // 构建重置数据(只添加配置中存在的字段)
                Map<String, Object> resetData = new HashMap<>();
                if (hasFieldInConfig(device, "plcRequest")) {
                    resetData.put("plcRequest", OFF);
                }
                if (hasFieldInConfig(device, "plcReport")) {
                    resetData.put("plcReport", OFF);
                }
                if (hasFieldInConfig(device, "mesSend")) {
                    resetData.put("mesSend", OFF);
                }
                if (hasFieldInConfig(device, "mesConfirm")) {
                    resetData.put("mesConfirm", OFF);
                }
                if (hasFieldInConfig(device, "onlineState")) {
                    resetData.put("onlineState", ON);
                }
                if (hasFieldInConfig(device, "alarmInfo")) {
                    resetData.put("alarmInfo", OFF);
                }
                // 检查是否有字段需要重置
                if (resetData.isEmpty()) {
                    log.warn("设备配置中未找到任何可重置的字段: deviceId={}", deviceId);
                    return false;
                }
                // 使用新的PLC客户端写入数据
                boolean success = plcClient.writeData(resetData);
                if (success) {
                    log.info("PLC状态已重置, deviceId={}", deviceId);
                    return true;
                }
            }
            // 构建重置数据
            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("mesGlassCount", 0);
            resetData.put("alarmInfo", OFF);
            // 使用PlcDynamicDataService写入数据
            plcDynamicDataService.writePlcData(device, resetData, s7Serializer);
            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={}", device.getId());
                return false;
            }
            // 构建重置数据(只添加配置中存在的字段)
            Map<String, Object> resetData = new HashMap<>();
            if (hasFieldInConfig(device, "plcRequest")) {
                resetData.put("plcRequest", OFF);
            }
            if (hasFieldInConfig(device, "plcReport")) {
                resetData.put("plcReport", OFF);
            }
            if (hasFieldInConfig(device, "mesSend")) {
                resetData.put("mesSend", OFF);
            }
            if (hasFieldInConfig(device, "mesConfirm")) {
                resetData.put("mesConfirm", OFF);
            }
            if (hasFieldInConfig(device, "onlineState")) {
                resetData.put("onlineState", ON);
            }
            if (hasFieldInConfig(device, "alarmInfo")) {
                resetData.put("alarmInfo", OFF);
            }
            // 检查是否有字段需要重置
            if (resetData.isEmpty()) {
                log.warn("设备配置中未找到任何可重置的字段: deviceId={}", device.getId());
                return false;
            }
            // 使用PlcDynamicDataService写入数据
            plcDynamicDataService.writePlcData(device, resetData, s7Serializer);
            log.info("PLC状态已重置(旧版): deviceId={}", device.getId());
            return true;
        } catch (Exception e) {
            log.error("根据设备重置PLC状态失败(旧版): deviceId={}", device.getId(), e);
            return false;
        }
    }
    /**
     * 根据设备ID读取PLC当前状态
     *
     *
     * @param deviceId 设备ID
     * @return PLC状态数据
     */
@@ -231,6 +397,18 @@
            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);
@@ -238,6 +416,7 @@
            }
            // 使用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);
@@ -260,6 +439,20 @@
        }
        
        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) {
@@ -270,7 +463,7 @@
            // 使用动态数据服务写入字段(基于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);
@@ -329,7 +522,7 @@
                    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) {
@@ -422,4 +615,44 @@
        
        throw new IllegalStateException("无法解析设备的PLC项目标识, deviceId=" + device.getId());
    }
    /**
     * 检查设备配置中是否存在指定字段
     *
     * @param device 设备配置
     * @param fieldName 字段名
     * @return 是否存在
     */
    private boolean hasFieldInConfig(DeviceConfig device, String fieldName) {
        if (device == null || fieldName == null || fieldName.isEmpty()) {
            return false;
        }
        try {
            // 从 configJson 中检查(新结构)
            Map<String, Object> configParams = ConfigJsonHelper.parseToMap(device.getConfigJson(), objectMapper);
            if (configParams.containsKey(fieldName)) {
                return true;
            }
            // 从 extraParams.addressMapping 中检查(兼容旧结构)
            Map<String, Object> extraParams = parseExtraParams(device);
            Object addressMapping = extraParams.get("addressMapping");
            if (addressMapping != null) {
                Map<String, Object> addressMappingMap;
                if (addressMapping instanceof Map) {
                    addressMappingMap = (Map<String, Object>) addressMapping;
                } else if (addressMapping instanceof String) {
                    addressMappingMap = objectMapper.readValue((String) addressMapping, MAP_TYPE);
                } else {
                    return false;
                }
                return addressMappingMap.containsKey(fieldName);
            }
        } catch (Exception e) {
            log.warn("检查字段是否存在时出错: deviceId={}, fieldName={}", device.getId(), fieldName, e);
        }
        return false;
    }
}