diff --git a/backend/script_groups/ObtainIOFromProjectTia/scripts_description.json b/backend/script_groups/ObtainIOFromProjectTia/scripts_description.json index 188256c..05a5720 100644 --- a/backend/script_groups/ObtainIOFromProjectTia/scripts_description.json +++ b/backend/script_groups/ObtainIOFromProjectTia/scripts_description.json @@ -1,8 +1,8 @@ { "x1.py": { - "display_name": "1: Exportar Lógica desde TIA Portal v18,v19,v20 en XML", - "short_description": "Exporta la lógica del PLC desde TIA Portal en archivos XML y SCL.", - "long_description": "Este script utiliza TIA Portal Openness para exportar la lógica de un PLC en formato XML y SCL. Permite seleccionar un proyecto de TIA Portal y genera los archivos de exportación en el directorio configurado.\n***\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, versión de TIA Portal).\n2. **Selección de Proyecto:** Abre un cuadro de diálogo para seleccionar el archivo del proyecto de TIA Portal.\n3. **Conexión a TIA Portal:** Utiliza la API de TIA Openness para conectarse al portal y abrir el proyecto seleccionado.\n4. **Exportación:** Exporta la lógica del PLC en archivos XML y SCL al directorio configurado.\n5. **Cierre:** Cierra la conexión con TIA Portal al finalizar.", + "display_name": "1: Exportar Lógica desde TIA Portal v15,v16,v17,v18,v19,v20 en XML", + "short_description": "Exporta la lógica del PLC desde TIA Portal (V15 a V20) en archivos XML y SCL.", + "long_description": "Este script utiliza TIA Portal Openness para exportar la lógica de un PLC en formato XML y SCL. Permite seleccionar un proyecto de TIA Portal (V15, V16, V17, V18, V19, V20) y genera los archivos de exportación en el directorio configurado.\n***\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, versión de TIA Portal).\n2. **Selección de Proyecto:** Abre un cuadro de diálogo para seleccionar el archivo del proyecto de TIA Portal (V15 a V20).\n3. **Conexión a TIA Portal:** Utiliza la API de TIA Openness para conectarse al portal y abrir el proyecto seleccionado.\n4. **Exportación:** Exporta la lógica del PLC en archivos XML y SCL al directorio configurado.\n5. **Cierre:** Cierra la conexión con TIA Portal al finalizar.", "hidden": false }, "x2.py": { @@ -12,9 +12,9 @@ "hidden": false }, "x4.py": { - "display_name": "3: Exportar Referencias Cruzadas desde TIA Portal", - "short_description": "Script para exportar las referencias cruzadas de un proyecto TIA Portal", - "long_description": "Este script exporta las referencias cruzadas (cross-references) de un proyecto TIA Portal, proporcionando información detallada sobre las interconexiones entre variables, bloques y componentes del sistema.\n***\n**Funcionalidad:**\n\n1. **Referencias cruzadas:** Extrae información sobre dónde se utilizan las variables y bloques\n2. **Análisis de dependencias:** Identifica relaciones entre componentes del proyecto\n3. **Documentación:** Genera reportes útiles para mantenimiento y debugging\n4. **Formato estructurado:** Exporta en formato legible para análisis posterior\n\n**Casos de uso:**\n- Documentación de proyecto\n- Análisis de impacto de cambios\n- Debugging y mantenimiento\n- Auditorías de código", + "display_name": "3: Exportar Referencias Cruzadas desde TIA Portal v17,v18,v19,v20", + "short_description": "Script para exportar las referencias cruzadas de un proyecto TIA Portal (V17 a V20)", + "long_description": "Este script exporta las referencias cruzadas (cross-references) de un proyecto TIA Portal (V17, V18, V19, V20), proporcionando información detallada sobre las interconexiones entre variables, bloques y componentes del sistema.\n***\n**Funcionalidad:**\n\n1. **Referencias cruzadas:** Extrae información sobre dónde se utilizan las variables y bloques\n2. **Análisis de dependencias:** Identifica relaciones entre componentes del proyecto\n3. **Documentación:** Genera reportes útiles para mantenimiento y debugging\n4. **Formato estructurado:** Exporta en formato legible para análisis posterior\n\n**Casos de uso:**\n- Documentación de proyecto\n- Análisis de impacto de cambios\n- Debugging y mantenimiento\n- Auditorías de código\n\n**NOTA:** La exportación de referencias cruzadas requiere TIA Portal V17.0 o superior. Las versiones V15 y V16 no soportan esta funcionalidad en la API de Openness.", "hidden": false }, "xTest.py": { @@ -28,5 +28,23 @@ "short_description": "Test script to verify SIMATIC SD compatibility detection", "long_description": "", "hidden": false + }, + "test_path_validation.py": { + "display_name": "test_path_validation", + "short_description": "Test script for path validation and sanitization functions", + "long_description": "", + "hidden": false + }, + "test_sanitization.py": { + "display_name": "test_sanitization", + "short_description": "Test script for updated sanitization function", + "long_description": "", + "hidden": false + }, + "test_block_validation.py": { + "display_name": "test_block_validation", + "short_description": "Test script para verificar la función is_block_exportable", + "long_description": "", + "hidden": false } } \ No newline at end of file diff --git a/backend/script_groups/ObtainIOFromProjectTia/test_block_validation.py b/backend/script_groups/ObtainIOFromProjectTia/test_block_validation.py new file mode 100644 index 0000000..23f74ea --- /dev/null +++ b/backend/script_groups/ObtainIOFromProjectTia/test_block_validation.py @@ -0,0 +1,56 @@ +""" +Test script para verificar la función is_block_exportable +""" + + +# Mock class para simular un bloque de TIA Portal +class MockBlock: + def __init__(self, programming_language): + self.programming_language = programming_language + + def get_property(self, name): + if name == "ProgrammingLanguage": + return self.programming_language + raise Exception(f"Property {name} not found") + + +# Importar la función desde x1.py +import sys +import os + +sys.path.append(os.path.dirname(__file__)) +from x1 import is_block_exportable + +# Testear diferentes tipos de bloques +test_cases = [ + ("LAD", True, "LAD blocks should be exportable"), + ("FBD", True, "FBD blocks should be exportable"), + ("STL", True, "STL blocks should be exportable"), + ("SCL", True, "SCL blocks should be exportable"), + ("ProDiag_OB", False, "ProDiag_OB blocks should not be exportable"), + ("ProDiag", False, "ProDiag blocks should not be exportable"), + ("GRAPH", False, "GRAPH blocks should not be exportable"), +] + +print("=== Test de validación de bloques ===") +for prog_lang, expected_exportable, description in test_cases: + block = MockBlock(prog_lang) + is_exportable, detected_lang, reason = is_block_exportable(block) + + status = "✓ PASS" if is_exportable == expected_exportable else "✗ FAIL" + print(f"{status} - {description}") + print(f" Lenguaje: {detected_lang}, Exportable: {is_exportable}, Razón: {reason}") + print() + + +# Test con bloque que genera excepción +class MockBlockError: + def get_property(self, name): + raise Exception("Cannot access property") + + +print("=== Test de manejo de errores ===") +error_block = MockBlockError() +is_exportable, detected_lang, reason = is_block_exportable(error_block) +print(f"Bloque con error - Exportable: {is_exportable}, Lenguaje: {detected_lang}") +print(f"Razón: {reason}") diff --git a/backend/script_groups/ObtainIOFromProjectTia/test_path_validation.py b/backend/script_groups/ObtainIOFromProjectTia/test_path_validation.py deleted file mode 100644 index b8a9246..0000000 --- a/backend/script_groups/ObtainIOFromProjectTia/test_path_validation.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Test script for path validation and sanitization functions -""" - -import os -import re - - -def sanitize_filename(name): - """Sanitizes a filename by removing/replacing invalid characters and whitespace.""" - # Replace spaces and other problematic characters with underscores - sanitized = re.sub(r'[<>:"/\\|?*\s]+', "_", name) - # Remove leading/trailing underscores and dots - sanitized = sanitized.strip("_.") - # Ensure it's not empty - if not sanitized: - sanitized = "unknown" - return sanitized - - -def sanitize_path(path): - """Sanitizes a path by ensuring it doesn't contain problematic whitespace.""" - # Normalize the path and remove any trailing/leading whitespace - normalized = os.path.normpath(path.strip()) - return normalized - - -def validate_export_path(path): - """Validates that an export path is suitable for TIA Portal.""" - if not path: - return False, "La ruta está vacía" - - # Check for problematic characters or patterns - if any(char in path for char in '<>"|?*'): - return False, f"La ruta contiene caracteres no válidos: {path}" - - # Check for excessive whitespace - if path != path.strip(): - return False, f"La ruta contiene espacios al inicio o final: '{path}'" - - # Check for multiple consecutive spaces - if " " in path: - return False, f"La ruta contiene espacios múltiples consecutivos: '{path}'" - - # Check path length (Windows limitation) - if len(path) > 250: - return False, f"La ruta es demasiado larga ({len(path)} caracteres): {path}" - - return True, "OK" - - -# Test cases -test_names = [ - "IO access error", - "CreatesAnyPointer", - "WriteMemArea_G", - "Block with spaces", - "Block<>with:invalid|chars", - " Block with leading and trailing spaces ", - "Block with multiple spaces", - "", -] - -test_paths = [ - "C:\\normal\\path", - "C:\\path with spaces\\subdir", - " C:\\path with leading space", - "C:\\path with trailing space ", - "C:\\path with multiple spaces\\subdir", - "C:\\pathinvalid:chars|in\\subdir", - "", -] - -print("=== Testing sanitize_filename ===") -for name in test_names: - sanitized = sanitize_filename(name) - print(f"'{name}' -> '{sanitized}'") - -print("\n=== Testing sanitize_path ===") -for path in test_paths: - sanitized = sanitize_path(path) - print(f"'{path}' -> '{sanitized}'") - -print("\n=== Testing validate_export_path ===") -for path in test_paths: - sanitized = sanitize_path(path) - is_valid, msg = validate_export_path(sanitized) - print(f"'{sanitized}' -> Valid: {is_valid}, Message: {msg}") - -print("\n=== Test specific problematic block names ===") -problematic_blocks = ["IO access error", "CreatesAnyPointer", "WriteMemArea_G"] -base_path = "D:\\Export\\Test" - -for block_name in problematic_blocks: - sanitized_name = sanitize_filename(block_name) - full_path = sanitize_path( - os.path.join(base_path, sanitized_name, "ProgramBlocks_XML") - ) - is_valid, msg = validate_export_path(full_path) - print(f"Block: '{block_name}' -> '{sanitized_name}'") - print(f" Full path: '{full_path}'") - print(f" Valid: {is_valid}, Message: {msg}") - print() diff --git a/backend/script_groups/ObtainIOFromProjectTia/test_sanitization.py b/backend/script_groups/ObtainIOFromProjectTia/test_sanitization.py deleted file mode 100644 index 6276b7a..0000000 --- a/backend/script_groups/ObtainIOFromProjectTia/test_sanitization.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Test script for updated sanitization function -""" - -import re - - -def sanitize_filename(name): - """Sanitizes a filename by removing/replacing invalid characters and whitespace.""" - # Handle specific problematic cases first - if name == "I/O access error": - return "IO_access_error" - elif name == "Time error interrupt": - return "Time_error_interrupt" - elif name.startswith("I/O_"): - return name.replace("I/O_", "IO_").replace("/", "_") - - # Replace spaces and other problematic characters with underscores - sanitized = re.sub(r'[<>:"/\\|?*\s]+', "_", name) - # Remove leading/trailing underscores and dots - sanitized = sanitized.strip("_.") - # Ensure it's not empty - if not sanitized: - sanitized = "unknown" - return sanitized - - -# Test the problematic block names from the log -problematic_blocks = [ - "IO access error", - "Time error interrupt", - "I/O_FLT1", - "I/O_FLT2", - "CreatesAnyPointer", - "WriteMemArea_G", - "ComGetPut_G", - "Sys_Plc_G", - "Sys_PLC_D", - "RACK_FLT", - "Startup", - "PROG_ERR", -] - -print("=== Testing updated sanitize_filename function ===") -for block_name in problematic_blocks: - sanitized = sanitize_filename(block_name) - has_spaces = " " in block_name - has_slash = "/" in block_name - print(f"'{block_name}' -> '{sanitized}' [Spaces: {has_spaces}, Slash: {has_slash}]") diff --git a/backend/script_groups/ObtainIOFromProjectTia/x1.py b/backend/script_groups/ObtainIOFromProjectTia/x1.py index cddc90f..ad57913 100644 --- a/backend/script_groups/ObtainIOFromProjectTia/x1.py +++ b/backend/script_groups/ObtainIOFromProjectTia/x1.py @@ -19,7 +19,14 @@ from backend.script_utils import load_configuration # --- Configuration --- # Supported TIA Portal versions mapping (extension -> version) -SUPPORTED_TIA_VERSIONS = {".ap18": "18.0", ".ap19": "19.0", ".ap20": "20.0"} +SUPPORTED_TIA_VERSIONS = { + ".ap15": "15.0", + ".ap16": "16.0", + ".ap17": "17.0", + ".ap18": "18.0", + ".ap19": "19.0", + ".ap20": "20.0", +} EXPORT_OPTIONS = None # Use default export options KEEP_FOLDER_STRUCTURE = ( @@ -65,6 +72,36 @@ except Exception as e: # --- Functions --- +def is_block_exportable(block): + """ + Checks if a block can be exported based on its programming language. + Returns (is_exportable, programming_language, reason) + """ + try: + prog_language = block.get_property(name="ProgrammingLanguage") + + # List of known unsupported programming languages + unsupported_languages = [ + "ProDiag_OB", # ProDiag Organization Blocks + "ProDiag", # ProDiag Function Blocks + "GRAPH", # GRAPH (Sequential Control) + ] + + if prog_language in unsupported_languages: + return ( + False, + prog_language, + f"Programming language '{prog_language}' is not supported for export", + ) + + return True, prog_language, "OK" + + except Exception as e: + # If we can't determine the programming language, assume it might be exportable + # but warn about it + return True, "Unknown", f"Could not determine programming language: {e}" + + def sanitize_filename(name): """Sanitizes a filename by removing/replacing invalid characters and whitespace.""" import re @@ -188,6 +225,17 @@ def get_supported_filetypes(): return filetypes +def normalize_project_path(project_path): + """Normalizes a TIA Portal project path to avoid path-related issues.""" + # Convert forward slashes to backslashes for Windows + normalized = project_path.replace("/", "\\") + # Use os.path.normpath to clean up the path + normalized = os.path.normpath(normalized) + # Ensure it's an absolute path + normalized = os.path.abspath(normalized) + return normalized + + def detect_tia_version(project_file_path): """Detects TIA Portal version based on file extension.""" file_path = Path(project_file_path) @@ -203,9 +251,9 @@ def detect_tia_version(project_file_path): print( f"ADVERTENCIA: Extensión de archivo no reconocida '{file_extension}'. Extensiones soportadas: {list(SUPPORTED_TIA_VERSIONS.keys())}" ) - # Default to version 18.0 for backward compatibility - print("Usando por defecto TIA Portal V18.0") - return "18.0" + # Default to version 15.0 for backward compatibility + print("Usando por defecto TIA Portal V15.0") + return "15.0" def select_project_file(): @@ -282,6 +330,18 @@ def export_plc_data(plc, export_base_dir): for block in program_blocks: block_name = block.get_name() print(f" Procesando bloque: {block_name}...") + + # Check if block is exportable + is_exportable, prog_language, reason = is_block_exportable(block) + + if not is_exportable: + print(f" ADVERTENCIA: {reason}. Omitiendo bloque {block_name}.") + blocks_skipped += 1 + continue + + if prog_language == "Unknown": + print(f" ADVERTENCIA: {reason}") + try: if not block.is_consistent(): print(f" Compilando bloque {block_name}...") @@ -364,6 +424,15 @@ def export_plc_data(plc, export_base_dir): ) print(f" Ruta problemática: '{xml_blocks_path}'") print(f" Tipo de bloque: {type(block).__name__}") + print(f" Lenguaje de programación: {prog_language}") + + # Check if it's a ProDiag related error + if "ProDiag" in str( + xml_ex + ) or "not supported during import and export" in str(xml_ex): + print( + f" Este bloque usa un lenguaje no soportado para exportación. Omitiendo." + ) # Skip this block and continue with others blocks_skipped += 1 @@ -372,7 +441,6 @@ def export_plc_data(plc, export_base_dir): # If we get here, XML export was successful # Now try SCL export if applicable try: - prog_language = block.get_property(name="ProgrammingLanguage") if prog_language == "SCL": print(f" Exportando {block_name} como SCL...") try: @@ -440,9 +508,13 @@ def export_plc_data(plc, export_base_dir): ) print(f" Ruta problemática: '{scl_blocks_path}'") # Don't raise, just continue - except Exception as prop_ex: + else: + print( + f" Bloque {block_name} no es SCL (lenguaje: {prog_language}). Omitiendo exportación SCL." + ) + except Exception as scl_check_ex: print( - f" No se pudo obtener el lenguaje de programación para {block_name}. Omitiendo SCL. Error: {prop_ex}" + f" Error verificando lenguaje para exportación SCL: {scl_check_ex}" ) blocks_exported += 1 @@ -584,6 +656,8 @@ if __name__ == "__main__": # 1. Select Project File, Export Directory comes from config project_file = select_project_file() + # Normalize the project file path to avoid TIA Portal path issues + project_file = normalize_project_path(project_file) export_dir = sanitize_path( working_directory ) # Use working directory from config with sanitization @@ -615,7 +689,17 @@ if __name__ == "__main__": # 4. Open Project print(f"Abriendo proyecto: {os.path.basename(project_file)}...") - project_object = portal_instance.open_project(project_file_path=project_file) + print(f"Ruta completa del proyecto: {project_file}") + + try: + project_object = portal_instance.open_project( + project_file_path=project_file + ) + except Exception as open_ex: + print(f"Error al abrir el proyecto: {open_ex}") + print("Intentando obtener proyecto ya abierto...") + project_object = None + if project_object is None: print( "El proyecto podría estar ya abierto, intentando obtener el manejador..." @@ -640,8 +724,21 @@ if __name__ == "__main__": print("\nProceso de exportación completado.") - except ts.TiaException as tia_ex: - print(f"\nError de TIA Portal Openness: {tia_ex}") + except ValueError as val_ex: + # Handle TIA Portal Openness exceptions (they come as ValueError) + if "OpennessAccessException" in str(val_ex): + print(f"\nError de TIA Portal Openness: {val_ex}") + print("Posibles causas:") + print("- El proyecto puede estar corrupto o en un formato incompatible") + print( + "- El proyecto puede requerir actualización a una versión más reciente" + ) + print( + "- Verificar que la ruta del proyecto no contenga caracteres especiales" + ) + print("- Asegurarse de que TIA Portal esté instalado correctamente") + else: + print(f"\nError de valor: {val_ex}") traceback.print_exc() except FileNotFoundError: print(f"\nERROR: Archivo de proyecto no encontrado en {project_file}") diff --git a/backend/script_groups/ObtainIOFromProjectTia/x4.py b/backend/script_groups/ObtainIOFromProjectTia/x4.py index a6cfcb4..cf9acf3 100644 --- a/backend/script_groups/ObtainIOFromProjectTia/x4.py +++ b/backend/script_groups/ObtainIOFromProjectTia/x4.py @@ -19,7 +19,18 @@ from backend.script_utils import load_configuration # --- Configuration --- # Supported TIA Portal versions mapping (extension -> version) -SUPPORTED_TIA_VERSIONS = {".ap18": "18.0", ".ap19": "19.0", ".ap20": "20.0"} +SUPPORTED_TIA_VERSIONS = { + ".ap15": "15.0", + ".ap16": "16.0", + ".ap17": "17.0", + ".ap18": "18.0", + ".ap19": "19.0", + ".ap20": "20.0", +} + +# Cross-references export support was introduced in TIA Portal V17+ +# Earlier versions don't support the export_cross_references() method +CROSS_REFERENCES_SUPPORTED_VERSIONS = ["17.0", "18.0", "19.0", "20.0"] # Filter for cross-references. Based on documentation: # 1: 'AllObjects', 2: 'ObjectsWithReferences', 3: 'ObjectsWithoutReferences', 4: 'UnusedObjects' @@ -83,6 +94,34 @@ except Exception as e: # --- Functions --- +def normalize_project_path(project_path): + """Normalizes a project path to ensure it's compatible with TIA Portal.""" + if not project_path: + return project_path + + # Convert to Path object for easier manipulation + path_obj = Path(project_path) + + # Resolve to absolute path and normalize + try: + normalized = path_obj.resolve() + # Convert back to string with Windows-style separators + normalized_str = str(normalized).replace("/", "\\") + + print(f" Ruta original: {project_path}") + print(f" Ruta normalizada: {normalized_str}") + + return normalized_str + except Exception as e: + print(f" ADVERTENCIA: Error al normalizar ruta: {e}") + return str(project_path) + + +def is_cross_references_supported(tia_version): + """Check if cross-references export is supported in the given TIA Portal version.""" + return tia_version in CROSS_REFERENCES_SUPPORTED_VERSIONS + + def get_supported_filetypes(): """Returns the supported file types for TIA Portal projects.""" filetypes = [] @@ -112,9 +151,9 @@ def detect_tia_version(project_file_path): print( f"ADVERTENCIA: Extensión de archivo no reconocida '{file_extension}'. Extensiones soportadas: {list(SUPPORTED_TIA_VERSIONS.keys())}" ) - # Default to version 18.0 for backward compatibility - print("Usando por defecto TIA Portal V18.0") - return "18.0" + # Default to version 15.0 for backward compatibility + print("Usando por defecto TIA Portal V15.0") + return "15.0" def select_project_file(): @@ -249,19 +288,31 @@ def export_plc_cross_references( print(f" Exportación completada en {elapsed_time:.2f} segundos") blocks_cr_exported += 1 exported_blocks.add(norm_block) - except RuntimeError as block_ex: - print( - f" ERROR TIA al exportar referencias cruzadas para el bloque {block_name}: {block_ex}" - ) + except Exception as block_ex: + error_msg = str(block_ex) + if ( + "NotSupportedException" in error_msg + and "not supported in this API version" in error_msg + ): + print( + f" ERROR: Método export_cross_references() no soportado en esta versión de TIA Portal para el bloque {block_name}" + ) + print( + f" Esta funcionalidad requiere TIA Portal V17.0 o superior." + ) + elif "RuntimeError" in str(type(block_ex)): + print( + f" ERROR TIA al exportar referencias cruzadas para el bloque {block_name}: {block_ex}" + ) + else: + print( + f" ERROR GENERAL al exportar referencias cruzadas para el bloque {block_name}: {block_ex}" + ) + traceback.print_exc() + problematic_blocks.add(norm_block) blocks_cr_skipped += 1 - except Exception as block_ex: - print( - f" ERROR GENERAL al exportar referencias cruzadas para el bloque {block_name}: {block_ex}" - ) - traceback.print_exc() - problematic_blocks.add(norm_block) # Always mark as problematic - blocks_cr_skipped += 1 + if _is_disposed_exception(block_ex): # Escalamos para que el script pueda re-abrir el Portal y omitir el bloque raise PortalDisposedException(block_ex, failed_block=block_name) @@ -496,13 +547,39 @@ def open_portal_and_project(tia_version: str, project_file_path: str): print("Conectado a TIA Portal.") print(f"ID del proceso del Portal: {portal.get_process_id()}") - project_obj = portal.open_project(project_file_path=str(project_file_path)) - if project_obj is None: - project_obj = portal.get_project() - if project_obj is None: - raise Exception( - "No se pudo abrir u obtener el proyecto especificado tras la reapertura." - ) + # Normalize the project path + normalized_path = normalize_project_path(project_file_path) + + print(f"Abriendo proyecto: {Path(normalized_path).name}...") + + try: + project_obj = portal.open_project(project_file_path=normalized_path) + if project_obj is None: + print( + "El proyecto podría estar ya abierto, intentando obtener el manejador..." + ) + project_obj = portal.get_project() + if project_obj is None: + raise Exception( + "No se pudo abrir u obtener el proyecto especificado tras la reapertura." + ) + + print("Proyecto abierto exitosamente.") + return portal, project_obj + + except Exception as e: + error_msg = str(e) + print(f"ERROR al abrir proyecto: {error_msg}") + + if "path" in error_msg.lower() and "cannot be" in error_msg.lower(): + print( + f" Problema con formato de ruta. Ruta utilizada: '{normalized_path}'" + ) + print(f" Ruta original: '{project_file_path}'") + + # Re-raise with more context + raise Exception(f"Error al abrir proyecto TIA Portal: {error_msg}") + return portal, project_obj @@ -535,6 +612,23 @@ if __name__ == "__main__": # 2. Detect TIA Portal version from project file tia_version = detect_tia_version(project_file) + # Check if cross-references export is supported in this version + if not is_cross_references_supported(tia_version): + print( + f"\nADVERTENCIA: La exportación de referencias cruzadas no está soportada en TIA Portal V{tia_version}" + ) + print( + f"Las referencias cruzadas están soportadas desde TIA Portal V17.0 en adelante." + ) + print( + "Versiones soportadas para referencias cruzadas:", + ", ".join([f"V{v}" for v in CROSS_REFERENCES_SUPPORTED_VERSIONS]), + ) + print( + "\nEl script se cerrará. Por favor use TIA Portal V17.0 o superior para exportar referencias cruzadas." + ) + sys.exit(1) + # 3. Define Export Directory using working_directory and subfolder export_base_dir = Path(working_directory) try: @@ -640,7 +734,7 @@ if __name__ == "__main__": print("\nProceso de exportación de referencias cruzadas completado.") - except RuntimeError as tia_ex: + except Exception as tia_ex: print(f"\nError de TIA Portal Openness: {tia_ex}") traceback.print_exc() except FileNotFoundError: diff --git a/data/log.txt b/data/log.txt index e2e95a5..58eb772 100644 --- a/data/log.txt +++ b/data/log.txt @@ -1,5 +1,13 @@ -[16:23:41] Iniciando ejecución de x1.py en D:\Trabajo\VM\45 - HENKEL - VM Auto Changeover\ExportTia... -[16:23:41] --- Exportador de datos TIA Portal (Bloques, UDTs, Variables) --- -[16:24:03] No se seleccionó ningún archivo de proyecto. Saliendo. -[16:24:04] Ejecución de x1.py finalizada (success). Duración: 0:00:22.833498. -[16:24:04] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\.log\log_x1.txt +[16:48:57] Iniciando ejecución de x4.py en D:\Trabajo\VM\45 - HENKEL - VM Auto Changeover\ExportTia... +[16:48:57] --- Exportador de Referencias Cruzadas de TIA Portal --- +[16:48:57] Configuración: +[16:48:57] - Tiempo esperado por bloque: 120 segundos (para logging) +[16:48:57] - Máximo intentos de reapertura: 5 +[16:48:57] - Filtro de referencias cruzadas: 1 +[16:49:01] Versión de TIA Portal detectada: 16.0 (de la extensión .ap16) +[16:49:01] ADVERTENCIA: La exportación de referencias cruzadas no está soportada en TIA Portal V16.0 +[16:49:01] Las referencias cruzadas están soportadas desde TIA Portal V17.0 en adelante. +[16:49:01] Versiones soportadas para referencias cruzadas: V17.0, V18.0, V19.0, V20.0 +[16:49:01] El script se cerrará. Por favor use TIA Portal V17.0 o superior para exportar referencias cruzadas. +[16:49:02] Ejecución de x4.py finalizada (error). Duración: 0:00:05.217693. +[16:49:02] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\.log\log_x4.txt