Actualización de scripts de exportación y mejora en la gestión de versiones de TIA Portal

- Se modificó el script x1.py para soportar múltiples versiones de TIA Portal (18, 19 y 20) y se mejoró la detección de la versión a partir de la extensión del archivo del proyecto.
- Se actualizó la descripción del script en scripts_description.json para reflejar las nuevas versiones soportadas.
- Se realizaron ajustes en los logs de ejecución para reflejar las nuevas fechas y duraciones en el script x1.
- Se mejoró la gestión de directorios de exportación y se añadieron mensajes en español para una mejor comprensión del proceso de exportación.
This commit is contained in:
Miguel 2025-06-12 20:17:36 +02:00
parent be3b333491
commit 04084e7289
7 changed files with 2470 additions and 247 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"x1.py": { "x1.py": {
"display_name": "1: Exportar Lógica desde TIA Portal v18 en XML", "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.", "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.", "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.",
"hidden": false "hidden": false

View File

@ -7,6 +7,7 @@ from tkinter import filedialog
import os import os
import sys import sys
import traceback import traceback
from pathlib import Path # Import Path
script_root = os.path.dirname( script_root = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.dirname(__file__))) os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
@ -15,11 +16,15 @@ sys.path.append(script_root)
from backend.script_utils import load_configuration from backend.script_utils import load_configuration
# --- Configuration --- # --- Configuration ---
TIA_PORTAL_VERSION = "18.0" # Target TIA Portal version (e.g., "18.0") # Supported TIA Portal versions mapping (extension -> version)
SUPPORTED_TIA_VERSIONS = {
".ap18": "18.0",
".ap19": "19.0",
".ap20": "20.0"
}
EXPORT_OPTIONS = None # Use default export options EXPORT_OPTIONS = None # Use default export options
KEEP_FOLDER_STRUCTURE = ( KEEP_FOLDER_STRUCTURE = True # Replicate TIA project folder structure in export directory
True # Replicate TIA project folder structure in export directory
)
# --- TIA Scripting Import Handling --- # --- TIA Scripting Import Handling ---
# Check if the TIA_SCRIPTING environment variable is set # Check if the TIA_SCRIPTING environment variable is set
@ -59,6 +64,33 @@ except Exception as e:
# --- Functions --- # --- Functions ---
def get_supported_filetypes():
"""Returns the supported file types for TIA Portal projects."""
filetypes = []
for ext, version in SUPPORTED_TIA_VERSIONS.items():
version_major = version.split('.')[0]
filetypes.append((f"TIA Portal V{version_major} Projects", f"*{ext}"))
# Add option to show all supported files
all_extensions = " ".join([f"*{ext}" for ext in SUPPORTED_TIA_VERSIONS.keys()])
filetypes.insert(0, ("All TIA Portal Projects", all_extensions))
return filetypes
def detect_tia_version(project_file_path):
"""Detects TIA Portal version based on file extension."""
file_path = Path(project_file_path)
file_extension = file_path.suffix.lower()
if file_extension in SUPPORTED_TIA_VERSIONS:
detected_version = SUPPORTED_TIA_VERSIONS[file_extension]
print(f"Versión de TIA Portal detectada: {detected_version} (de la extensión {file_extension})")
return detected_version
else:
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"
def select_project_file(): def select_project_file():
"""Opens a dialog to select a TIA Portal project file.""" """Opens a dialog to select a TIA Portal project file."""
@ -66,16 +98,11 @@ def select_project_file():
root.withdraw() # Hide the main tkinter window root.withdraw() # Hide the main tkinter window
file_path = filedialog.askopenfilename( file_path = filedialog.askopenfilename(
title="Select TIA Portal Project File", title="Select TIA Portal Project File",
filetypes=[ filetypes=get_supported_filetypes()
(
f"TIA Portal V{TIA_PORTAL_VERSION} Projects",
f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}",
)
], # e.g. *.ap18
) )
root.destroy() root.destroy()
if not file_path: if not file_path:
print("No project file selected. Exiting.") print("No se seleccionó ningún archivo de proyecto. Saliendo.")
sys.exit(0) sys.exit(0)
return file_path return file_path
@ -95,7 +122,7 @@ def select_export_directory():
def export_plc_data(plc, export_base_dir): def export_plc_data(plc, export_base_dir):
"""Exports Blocks, UDTs, and Tag Tables from a given PLC.""" """Exports Blocks, UDTs, and Tag Tables from a given PLC."""
plc_name = plc.get_name() plc_name = plc.get_name()
print(f"\n--- Processing PLC: {plc_name} ---") print(f"\n--- Procesando PLC: {plc_name} ---")
# Define base export path for this PLC # Define base export path for this PLC
plc_export_dir = os.path.join(export_base_dir, plc_name) plc_export_dir = os.path.join(export_base_dir, plc_name)
@ -104,143 +131,140 @@ def export_plc_data(plc, export_base_dir):
# --- Export Program Blocks --- # --- Export Program Blocks ---
blocks_exported = 0 blocks_exported = 0
blocks_skipped = 0 blocks_skipped = 0
print(f"\n[PLC: {plc_name}] Exporting Program Blocks...") print(f"\n[PLC: {plc_name}] Exportando bloques de programa...")
xml_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_XML") xml_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_XML")
scl_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_SCL") scl_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_SCL")
os.makedirs(xml_blocks_path, exist_ok=True) os.makedirs(xml_blocks_path, exist_ok=True)
os.makedirs(scl_blocks_path, exist_ok=True) os.makedirs(scl_blocks_path, exist_ok=True)
print(f" XML Target: {xml_blocks_path}") print(f" Destino XML: {xml_blocks_path}")
print(f" SCL Target: {scl_blocks_path}") print(f" Destino SCL: {scl_blocks_path}")
try: try:
program_blocks = plc.get_program_blocks() # program_blocks = plc.get_program_blocks()
print(f" Found {len(program_blocks)} program blocks.") print(f" Se encontraron {len(program_blocks)} bloques de programa.")
for block in program_blocks: for block in program_blocks:
block_name = block.get_name() # Assuming get_name() exists block_name = block.get_name()
print(f" Processing block: {block_name}...") print(f" Procesando bloque: {block_name}...")
try: try:
if not block.is_consistent(): # if not block.is_consistent():
print(f" Compiling block {block_name}...") print(f" Compilando bloque {block_name}...")
block.compile() # block.compile()
if not block.is_consistent(): if not block.is_consistent():
print( print(
f" WARNING: Block {block_name} inconsistent after compile. Skipping." f" ADVERTENCIA: Bloque {block_name} inconsistente después de compilar. Omitiendo."
) )
blocks_skipped += 1 blocks_skipped += 1
continue continue
print(f" Exporting {block_name} as XML...") print(f" Exportando {block_name} como XML...")
block.export( block.export(
target_directory_path=xml_blocks_path, # target_directory_path=xml_blocks_path,
export_options=EXPORT_OPTIONS, # export_options=EXPORT_OPTIONS,
export_format=ts.Enums.ExportFormats.SimaticML, # export_format=ts.Enums.ExportFormats.SimaticML,
keep_folder_structure=KEEP_FOLDER_STRUCTURE, keep_folder_structure=KEEP_FOLDER_STRUCTURE,
) # )
try: try:
prog_language = block.get_property(name="ProgrammingLanguage") prog_language = block.get_property(name="ProgrammingLanguage")
if prog_language == "SCL": if prog_language == "SCL":
print(f" Exporting {block_name} as SCL...") print(f" Exportando {block_name} como SCL...")
block.export( block.export(
target_directory_path=scl_blocks_path, target_directory_path=scl_blocks_path,
export_options=EXPORT_OPTIONS, export_options=EXPORT_OPTIONS,
export_format=ts.Enums.ExportFormats.ExternalSource, # export_format=ts.Enums.ExportFormats.ExternalSource,
keep_folder_structure=KEEP_FOLDER_STRUCTURE, keep_folder_structure=KEEP_FOLDER_STRUCTURE,
) )
except Exception as prop_ex: except Exception as prop_ex:
print( print(
f" Could not get ProgrammingLanguage for {block_name}. Skipping SCL. Error: {prop_ex}" f" No se pudo obtener el lenguaje de programación para {block_name}. Omitiendo SCL. Error: {prop_ex}"
) )
blocks_exported += 1 blocks_exported += 1
except Exception as block_ex: except Exception as block_ex:
print(f" ERROR exporting block {block_name}: {block_ex}") print(f" ERROR exportando bloque {block_name}: {block_ex}")
blocks_skipped += 1 blocks_skipped += 1
print( print(
f" Program Blocks Export Summary: Exported={blocks_exported}, Skipped/Errors={blocks_skipped}" f" Resumen de exportación de bloques: Exportados={blocks_exported}, Omitidos/Errores={blocks_skipped}"
) )
except Exception as e: except Exception as e:
print(f" ERROR processing Program Blocks: {e}") print(f" ERROR procesando bloques de programa: {e}")
traceback.print_exc() traceback.print_exc()
# --- Export PLC Data Types (UDTs) --- # --- Export PLC Data Types (UDTs) ---
udts_exported = 0 udts_exported = 0
udts_skipped = 0 udts_skipped = 0
print(f"\n[PLC: {plc_name}] Exporting PLC Data Types (UDTs)...") print(f"\n[PLC: {plc_name}] Exportando tipos de datos PLC (UDTs)...")
udt_export_path = os.path.join(plc_export_dir, "PlcDataTypes") udt_export_path = os.path.join(plc_export_dir, "PlcDataTypes")
os.makedirs(udt_export_path, exist_ok=True) os.makedirs(udt_export_path, exist_ok=True)
print(f" Target: {udt_export_path}") print(f" Destino: {udt_export_path}")
try: try:
udts = plc.get_user_data_types() # udts = plc.get_user_data_types()
print(f" Found {len(udts)} UDTs.") print(f" Se encontraron {len(udts)} UDTs.")
for udt in udts: for udt in udts:
udt_name = udt.get_name() # udt_name = udt.get_name()
print(f" Processing UDT: {udt_name}...") print(f" Procesando UDT: {udt_name}...")
try: try:
if not udt.is_consistent(): # if not udt.is_consistent():
print(f" Compiling UDT {udt_name}...") print(f" Compilando UDT {udt_name}...")
udt.compile() # udt.compile()
if not udt.is_consistent(): if not udt.is_consistent():
print( print(
f" WARNING: UDT {udt_name} inconsistent after compile. Skipping." f" ADVERTENCIA: UDT {udt_name} inconsistente después de compilar. Omitiendo."
) )
udts_skipped += 1 udts_skipped += 1
continue continue
print(f" Exporting {udt_name}...") print(f" Exportando {udt_name}...")
udt.export( udt.export(
target_directory_path=udt_export_path, # target_directory_path=udt_export_path,
export_options=EXPORT_OPTIONS, # export_options=EXPORT_OPTIONS,
# export_format defaults to SimaticML for UDTs
keep_folder_structure=KEEP_FOLDER_STRUCTURE, keep_folder_structure=KEEP_FOLDER_STRUCTURE,
) # )
udts_exported += 1 udts_exported += 1
except Exception as udt_ex: except Exception as udt_ex:
print(f" ERROR exporting UDT {udt_name}: {udt_ex}") print(f" ERROR exportando UDT {udt_name}: {udt_ex}")
udts_skipped += 1 udts_skipped += 1
print( print(
f" UDT Export Summary: Exported={udts_exported}, Skipped/Errors={udts_skipped}" f" Resumen de exportación de UDTs: Exportados={udts_exported}, Omitidos/Errores={udts_skipped}"
) )
except Exception as e: except Exception as e:
print(f" ERROR processing UDTs: {e}") print(f" ERROR procesando UDTs: {e}")
traceback.print_exc() traceback.print_exc()
# --- Export PLC Tag Tables --- # --- Export PLC Tag Tables ---
tags_exported = 0 tags_exported = 0
tags_skipped = 0 tags_skipped = 0
print(f"\n[PLC: {plc_name}] Exporting PLC Tag Tables...") print(f"\n[PLC: {plc_name}] Exportando tablas de variables PLC...")
tags_export_path = os.path.join(plc_export_dir, "PlcTags") tags_export_path = os.path.join(plc_export_dir, "PlcTags")
os.makedirs(tags_export_path, exist_ok=True) os.makedirs(tags_export_path, exist_ok=True)
print(f" Target: {tags_export_path}") print(f" Destino: {tags_export_path}")
try: try:
tag_tables = plc.get_plc_tag_tables() # tag_tables = plc.get_plc_tag_tables()
print(f" Found {len(tag_tables)} Tag Tables.") print(f" Se encontraron {len(tag_tables)} tablas de variables.")
for table in tag_tables: for table in tag_tables:
table_name = table.get_name() # table_name = table.get_name()
print(f" Processing Tag Table: {table_name}...") print(f" Procesando tabla de variables: {table_name}...")
try: try:
# Note: Consistency check might not be available/needed for tag tables like blocks/UDTs print(f" Exportando {table_name}...")
print(f" Exporting {table_name}...")
table.export( table.export(
target_directory_path=tags_export_path, # target_directory_path=tags_export_path,
export_options=EXPORT_OPTIONS, # export_options=EXPORT_OPTIONS,
# export_format defaults to SimaticML for Tag Tables
keep_folder_structure=KEEP_FOLDER_STRUCTURE, keep_folder_structure=KEEP_FOLDER_STRUCTURE,
) # )
tags_exported += 1 tags_exported += 1
except Exception as table_ex: except Exception as table_ex:
print(f" ERROR exporting Tag Table {table_name}: {table_ex}") print(f" ERROR exportando tabla de variables {table_name}: {table_ex}")
tags_skipped += 1 tags_skipped += 1
print( print(
f" Tag Table Export Summary: Exported={tags_exported}, Skipped/Errors={tags_skipped}" f" Resumen de exportación de tablas de variables: Exportados={tags_exported}, Omitidos/Errores={tags_skipped}"
) )
except Exception as e: except Exception as e:
print(f" ERROR processing Tag Tables: {e}") print(f" ERROR procesando tablas de variables: {e}")
traceback.print_exc() traceback.print_exc()
print(f"\n--- Finished processing PLC: {plc_name} ---") print(f"\n--- Finalizado el procesamiento del PLC: {plc_name} ---")
# --- Main Script --- # --- Main Script ---
@ -250,75 +274,76 @@ if __name__ == "__main__":
configs = load_configuration() configs = load_configuration()
working_directory = configs.get("working_directory") working_directory = configs.get("working_directory")
print("--- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---") print("--- Exportador de datos TIA Portal (Bloques, UDTs, Variables) ---")
# Validate working directory # Validate working directory
if not working_directory or not os.path.isdir(working_directory): if not working_directory or not os.path.isdir(working_directory):
print("ERROR: Working directory not set or invalid in configuration.") print("ERROR: Directorio de trabajo no configurado o inválido.")
print("Please configure the working directory using the main application.") print("Por favor configure el directorio de trabajo usando la aplicación principal.")
sys.exit(1) sys.exit(1)
# 1. Select Project File, Export Directory comes from config # 1. Select Project File, Export Directory comes from config
project_file = select_project_file() project_file = select_project_file()
export_dir = working_directory # Use working directory from config export_dir = working_directory # Use working directory from config
print(f"\nSelected Project: {project_file}") # 2. Detect TIA Portal version from project file
print(f"Using Export Directory (Working Directory): {export_dir}") tia_version = detect_tia_version(project_file)
print(f"\nProyecto seleccionado: {project_file}")
print(f"Usando directorio de exportación (Directorio de trabajo): {export_dir}")
portal_instance = None portal_instance = None
project_object = None project_object = None
try: try:
# 2. Connect to TIA Portal # 3. Connect to TIA Portal with detected version
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...") print(f"\nConectando a TIA Portal V{tia_version}...")
portal_instance = ts.open_portal( portal_instance = ts.open_portal(
version=TIA_PORTAL_VERSION, version=tia_version,
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface, portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
) )
print("Connected to TIA Portal.") print("Conectado a TIA Portal.")
print(f"Portal Process ID: {portal_instance.get_process_id()}") # print(f"ID del proceso del Portal: {portal_instance.get_process_id()}")
# 3. Open Project # 4. Open Project
print(f"Opening project: {os.path.basename(project_file)}...") print(f"Abriendo proyecto: {os.path.basename(project_file)}...")
project_object = portal_instance.open_project(project_file_path=project_file) # project_object = portal_instance.open_project(project_file_path=project_file)
if project_object is None: if project_object is None:
print("Project might already be open, attempting to get handle...") print("El proyecto podría estar ya abierto, intentando obtener el manejador...")
project_object = portal_instance.get_project() # project_object = portal_instance.get_project()
if project_object is None: if project_object is None:
raise Exception("Failed to open or get the specified project.") raise Exception("No se pudo abrir u obtener el proyecto especificado.")
print("Project opened successfully.") print("Proyecto abierto exitosamente.")
# 4. Get PLCs # 5. Get PLCs
plcs = project_object.get_plcs() # plcs = project_object.get_plcs()
if not plcs: if not plcs:
print("No PLC devices found in the project.") print("No se encontraron dispositivos PLC en el proyecto.")
else: else:
print(f"Found {len(plcs)} PLC(s). Starting export process...") print(f"Se encontraron {len(plcs)} PLC(s). Iniciando proceso de exportación...")
# 5. Iterate and Export Data for each PLC # 6. Iterate and Export Data for each PLC
for plc_device in plcs: for plc_device in plcs:
export_plc_data( export_plc_data(plc=plc_device, export_base_dir=export_dir)
plc=plc_device, export_base_dir=export_dir
) # Pass export_dir
print("\nExport process completed.") print("\nProceso de exportación completado.")
except ts.TiaException as tia_ex: except ts.TiaException as tia_ex:
print(f"\nTIA Portal Openness Error: {tia_ex}") print(f"\nError de TIA Portal Openness: {tia_ex}")
traceback.print_exc() traceback.print_exc()
except FileNotFoundError: except FileNotFoundError:
print(f"\nERROR: Project file not found at {project_file}") print(f"\nERROR: Archivo de proyecto no encontrado en {project_file}")
except Exception as e: except Exception as e:
print(f"\nAn unexpected error occurred: {e}") print(f"\nOcurrió un error inesperado: {e}")
traceback.print_exc() traceback.print_exc()
finally: finally:
# 6. Cleanup # 7. Cleanup
if portal_instance: if portal_instance:
try: try:
print("\nClosing TIA Portal...") print("\nCerrando TIA Portal...")
portal_instance.close_portal() # portal_instance.close_portal()
print("TIA Portal closed.") print("TIA Portal cerrado.")
except Exception as close_ex: except Exception as close_ex:
print(f"Error during TIA Portal cleanup: {close_ex}") print(f"Error durante la limpieza de TIA Portal: {close_ex}")
print("\nScript finished.") print("\nScript finalizado.")

View File

@ -8,7 +8,7 @@ from tkinter import filedialog
import os import os
import sys import sys
import traceback import traceback
from pathlib import Path # Import Path for easier path manipulation from pathlib import Path
script_root = os.path.dirname( script_root = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.dirname(__file__))) os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
@ -17,14 +17,19 @@ sys.path.append(script_root)
from backend.script_utils import load_configuration from backend.script_utils import load_configuration
# --- Configuration --- # --- Configuration ---
TIA_PORTAL_VERSION = "18.0" # Target TIA Portal version (e.g., "18.0") # Supported TIA Portal versions mapping (extension -> version)
SUPPORTED_TIA_VERSIONS = {
".ap18": "18.0",
".ap19": "19.0",
".ap20": "20.0"
}
# Filter for cross-references. Based on documentation: # Filter for cross-references. Based on documentation:
# 1: 'AllObjects', 2: 'ObjectsWithReferences', 3: 'ObjectsWithoutReferences', 4: 'UnusedObjects' # 1: 'AllObjects', 2: 'ObjectsWithReferences', 3: 'ObjectsWithoutReferences', 4: 'UnusedObjects'
# Using 1 to export all. 0 might also work as a default in some API versions. # Using 1 to export all. 0 might also work as a default in some API versions.
CROSS_REF_FILTER = 1 CROSS_REF_FILTER = 1
# --- TIA Scripting Import Handling --- # --- TIA Scripting Import Handling ---
# (Same import handling as x1.py)
if os.getenv("TIA_SCRIPTING"): if os.getenv("TIA_SCRIPTING"):
sys.path.append(os.getenv("TIA_SCRIPTING")) sys.path.append(os.getenv("TIA_SCRIPTING"))
else: else:
@ -33,209 +38,225 @@ else:
try: try:
import siemens_tia_scripting as ts import siemens_tia_scripting as ts
except ImportError: except ImportError:
print("ERROR: Failed to import 'siemens_tia_scripting'.") print("ERROR: Error al importar 'siemens_tia_scripting'.")
print("Ensure:") print("Asegúrese de que:")
print(f"1. TIA Portal Openness for V{TIA_PORTAL_VERSION} is installed.") print("1. TIA Portal Openness está instalado.")
print( print(
"2. The 'siemens_tia_scripting' Python module is installed (pip install ...) or" "2. El módulo 'siemens_tia_scripting' de Python está instalado (pip install ...) o"
) )
print( print(
" the path to its binaries is set in the 'TIA_SCRIPTING' environment variable." " la ruta a sus binarios está configurada en la variable de entorno 'TIA_SCRIPTING'."
) )
print( print(
"3. You are using a compatible Python version (e.g., 3.12.X as per documentation)." "3. Está usando una versión compatible de Python (ej. 3.12.X según la documentación)."
) )
sys.exit(1) sys.exit(1)
except Exception as e: except Exception as e:
print(f"An unexpected error occurred during import: {e}") print(f"Ocurrió un error inesperado durante la importación: {e}")
traceback.print_exc() traceback.print_exc()
sys.exit(1) sys.exit(1)
# --- Functions --- # --- Functions ---
def get_supported_filetypes():
"""Returns the supported file types for TIA Portal projects."""
filetypes = []
for ext, version in SUPPORTED_TIA_VERSIONS.items():
version_major = version.split('.')[0]
filetypes.append((f"TIA Portal V{version_major} Projects", f"*{ext}"))
# Add option to show all supported files
all_extensions = " ".join([f"*{ext}" for ext in SUPPORTED_TIA_VERSIONS.keys()])
filetypes.insert(0, ("All TIA Portal Projects", all_extensions))
return filetypes
def detect_tia_version(project_file_path):
"""Detects TIA Portal version based on file extension."""
file_path = Path(project_file_path)
file_extension = file_path.suffix.lower()
if file_extension in SUPPORTED_TIA_VERSIONS:
detected_version = SUPPORTED_TIA_VERSIONS[file_extension]
print(f"Versión de TIA Portal detectada: {detected_version} (de la extensión {file_extension})")
return detected_version
else:
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"
def select_project_file(): def select_project_file():
"""Opens a dialog to select a TIA Portal project file.""" """Opens a dialog to select a TIA Portal project file."""
root = tk.Tk() root = tk.Tk()
root.withdraw() # Hide the main tkinter window root.withdraw()
file_path = filedialog.askopenfilename( file_path = filedialog.askopenfilename(
title="Select TIA Portal Project File", title="Seleccionar archivo de proyecto TIA Portal",
filetypes=[ filetypes=get_supported_filetypes()
(
f"TIA Portal V{TIA_PORTAL_VERSION} Projects",
f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}",
)
], # e.g. *.ap18
) )
root.destroy() root.destroy()
if not file_path: if not file_path:
print("No project file selected. Exiting.") print("No se seleccionó ningún archivo de proyecto. Saliendo.")
sys.exit(0) sys.exit(0)
return file_path return file_path
def export_plc_cross_references(plc, export_base_dir): def export_plc_cross_references(plc, export_base_dir):
"""Exports cross-references for various elements from a given PLC.""" """Exports cross-references for various elements from a given PLC."""
plc_name = plc.get_name() plc_name = plc.get_name()
print(f"\n--- Processing PLC: {plc_name} ---") print(f"\n--- Procesando PLC: {plc_name} ---")
# Define base export path for this PLC's cross-references # Define base export path for this PLC's cross-references
plc_export_dir = export_base_dir / plc_name plc_export_dir = export_base_dir / plc_name
plc_export_dir.mkdir(parents=True, exist_ok=True) # Use pathlib's mkdir plc_export_dir.mkdir(parents=True, exist_ok=True)
# --- Export Program Block Cross-References --- # --- Export Program Block Cross-References ---
blocks_cr_exported = 0 blocks_cr_exported = 0
blocks_cr_skipped = 0 blocks_cr_skipped = 0
print(f"\n[PLC: {plc_name}] Exporting Program Block Cross-References...") print(f"\n[PLC: {plc_name}] Exportando referencias cruzadas de bloques de programa...")
blocks_cr_path = plc_export_dir / "ProgramBlocks_CR" blocks_cr_path = plc_export_dir / "ProgramBlocks_CR"
blocks_cr_path.mkdir(exist_ok=True) blocks_cr_path.mkdir(exist_ok=True)
print(f" Target: {blocks_cr_path}") print(f" Destino: {blocks_cr_path}")
try: try:
# Assuming get_program_blocks() doesn't need folder_path to get all blocks
program_blocks = plc.get_program_blocks() program_blocks = plc.get_program_blocks()
print(f" Found {len(program_blocks)} program blocks.") print(f" Se encontraron {len(program_blocks)} bloques de programa.")
for block in program_blocks: for block in program_blocks:
block_name = block.get_name() block_name = block.get_name()
print(f" Processing block: {block_name}...") print(f" Procesando bloque: {block_name}...")
try: try:
# Note: Consistency check might not be needed/available before cross-ref export print(f" Exportando referencias cruzadas para {block_name}...")
print(f" Exporting cross-references for {block_name}...")
block.export_cross_references( block.export_cross_references(
target_directorypath=str( target_directorypath=str(blocks_cr_path),
blocks_cr_path
), # API likely needs string path
filter=CROSS_REF_FILTER, filter=CROSS_REF_FILTER,
) )
blocks_cr_exported += 1 blocks_cr_exported += 1
except RuntimeError as block_ex: except RuntimeError as block_ex:
print( print(
f" TIA ERROR exporting cross-references for block {block_name}: {block_ex}" f" ERROR TIA al exportar referencias cruzadas para el bloque {block_name}: {block_ex}"
) )
blocks_cr_skipped += 1 blocks_cr_skipped += 1
except Exception as block_ex: except Exception as block_ex:
print( print(
f" GENERAL ERROR exporting cross-references for block {block_name}: {block_ex}" f" ERROR GENERAL al exportar referencias cruzadas para el bloque {block_name}: {block_ex}"
) )
traceback.print_exc() # Print stack trace for general errors traceback.print_exc()
blocks_cr_skipped += 1 blocks_cr_skipped += 1
print( print(
f" Program Block CR Export Summary: Exported={blocks_cr_exported}, Skipped/Errors={blocks_cr_skipped}" f" Resumen de exportación de referencias cruzadas de bloques: Exportados={blocks_cr_exported}, Omitidos/Errores={blocks_cr_skipped}"
) )
except AttributeError: except AttributeError:
print( print(
" AttributeError: Could not find 'get_program_blocks' on PLC object. Skipping Program Blocks." " Error de atributo: No se pudo encontrar 'get_program_blocks' en el objeto PLC. Omitiendo bloques de programa."
) )
except Exception as e: except Exception as e:
print(f" ERROR accessing Program Blocks for cross-reference export: {e}") print(f" ERROR al acceder a los bloques de programa para exportar referencias cruzadas: {e}")
traceback.print_exc() traceback.print_exc()
# --- Export PLC Tag Table Cross-References --- # --- Export PLC Tag Table Cross-References ---
tags_cr_exported = 0 tags_cr_exported = 0
tags_cr_skipped = 0 tags_cr_skipped = 0
print(f"\n[PLC: {plc_name}] Exporting PLC Tag Table Cross-References...") print(f"\n[PLC: {plc_name}] Exportando referencias cruzadas de tablas de variables...")
tags_cr_path = plc_export_dir / "PlcTags_CR" tags_cr_path = plc_export_dir / "PlcTags_CR"
tags_cr_path.mkdir(exist_ok=True) tags_cr_path.mkdir(exist_ok=True)
print(f" Target: {tags_cr_path}") print(f" Destino: {tags_cr_path}")
try: try:
# Assuming get_plc_tag_tables() doesn't need folder_path to get all tables
tag_tables = plc.get_plc_tag_tables() tag_tables = plc.get_plc_tag_tables()
print(f" Found {len(tag_tables)} Tag Tables.") print(f" Se encontraron {len(tag_tables)} tablas de variables.")
for table in tag_tables: for table in tag_tables:
table_name = table.get_name() table_name = table.get_name()
print(f" Processing Tag Table: {table_name}...") print(f" Procesando tabla de variables: {table_name}...")
try: try:
print(f" Exporting cross-references for {table_name}...") print(f" Exportando referencias cruzadas para {table_name}...")
table.export_cross_references( table.export_cross_references(
target_directorypath=str(tags_cr_path), filter=CROSS_REF_FILTER target_directorypath=str(tags_cr_path),
filter=CROSS_REF_FILTER
) )
tags_cr_exported += 1 tags_cr_exported += 1
except RuntimeError as table_ex: except RuntimeError as table_ex:
print( print(
f" TIA ERROR exporting cross-references for Tag Table {table_name}: {table_ex}" f" ERROR TIA al exportar referencias cruzadas para la tabla {table_name}: {table_ex}"
) )
tags_cr_skipped += 1 tags_cr_skipped += 1
except Exception as table_ex: except Exception as table_ex:
print( print(
f" GENERAL ERROR exporting cross-references for Tag Table {table_name}: {table_ex}" f" ERROR GENERAL al exportar referencias cruzadas para la tabla {table_name}: {table_ex}"
) )
traceback.print_exc() traceback.print_exc()
tags_cr_skipped += 1 tags_cr_skipped += 1
print( print(
f" Tag Table CR Export Summary: Exported={tags_cr_exported}, Skipped/Errors={tags_cr_skipped}" f" Resumen de exportación de referencias cruzadas de tablas: Exportados={tags_cr_exported}, Omitidos/Errores={tags_cr_skipped}"
) )
except AttributeError: except AttributeError:
print( print(
" AttributeError: Could not find 'get_plc_tag_tables' on PLC object. Skipping Tag Tables." " Error de atributo: No se pudo encontrar 'get_plc_tag_tables' en el objeto PLC. Omitiendo tablas de variables."
) )
except Exception as e: except Exception as e:
print(f" ERROR accessing Tag Tables for cross-reference export: {e}") print(f" ERROR al acceder a las tablas de variables para exportar referencias cruzadas: {e}")
traceback.print_exc() traceback.print_exc()
# --- Export PLC Data Type (UDT) Cross-References --- # --- Export PLC Data Type (UDT) Cross-References ---
udts_cr_exported = 0 udts_cr_exported = 0
udts_cr_skipped = 0 udts_cr_skipped = 0
print(f"\n[PLC: {plc_name}] Exporting PLC Data Type (UDT) Cross-References...") print(f"\n[PLC: {plc_name}] Exportando referencias cruzadas de tipos de datos PLC (UDTs)...")
udts_cr_path = plc_export_dir / "PlcDataTypes_CR" udts_cr_path = plc_export_dir / "PlcDataTypes_CR"
udts_cr_path.mkdir(exist_ok=True) udts_cr_path.mkdir(exist_ok=True)
print(f" Target: {udts_cr_path}") print(f" Destino: {udts_cr_path}")
try: try:
# Assuming get_user_data_types() doesn't need folder_path to get all UDTs
udts = plc.get_user_data_types() udts = plc.get_user_data_types()
print(f" Found {len(udts)} UDTs.") print(f" Se encontraron {len(udts)} UDTs.")
for udt in udts: for udt in udts:
udt_name = udt.get_name() udt_name = udt.get_name()
print(f" Processing UDT: {udt_name}...") print(f" Procesando UDT: {udt_name}...")
try: try:
print(f" Exporting cross-references for {udt_name}...") print(f" Exportando referencias cruzadas para {udt_name}...")
udt.export_cross_references( udt.export_cross_references(
target_directorypath=str(udts_cr_path), filter=CROSS_REF_FILTER target_directorypath=str(udts_cr_path),
filter=CROSS_REF_FILTER
) )
udts_cr_exported += 1 udts_cr_exported += 1
except RuntimeError as udt_ex: except RuntimeError as udt_ex:
print( print(
f" TIA ERROR exporting cross-references for UDT {udt_name}: {udt_ex}" f" ERROR TIA al exportar referencias cruzadas para el UDT {udt_name}: {udt_ex}"
) )
udts_cr_skipped += 1 udts_cr_skipped += 1
except Exception as udt_ex: except Exception as udt_ex:
print( print(
f" GENERAL ERROR exporting cross-references for UDT {udt_name}: {udt_ex}" f" ERROR GENERAL al exportar referencias cruzadas para el UDT {udt_name}: {udt_ex}"
) )
traceback.print_exc() traceback.print_exc()
udts_cr_skipped += 1 udts_cr_skipped += 1
print( print(
f" UDT CR Export Summary: Exported={udts_cr_exported}, Skipped/Errors={udts_cr_skipped}" f" Resumen de exportación de referencias cruzadas de UDTs: Exportados={udts_cr_exported}, Omitidos/Errores={udts_cr_skipped}"
) )
except AttributeError: except AttributeError:
print( print(
" AttributeError: Could not find 'get_user_data_types' on PLC object. Skipping UDTs." " Error de atributo: No se pudo encontrar 'get_user_data_types' en el objeto PLC. Omitiendo UDTs."
) )
except Exception as e: except Exception as e:
print(f" ERROR accessing UDTs for cross-reference export: {e}") print(f" ERROR al acceder a los UDTs para exportar referencias cruzadas: {e}")
traceback.print_exc() traceback.print_exc()
# --- Export System Block Cross-References --- # --- Export System Block Cross-References ---
sys_blocks_cr_exported = 0 sys_blocks_cr_exported = 0
sys_blocks_cr_skipped = 0 sys_blocks_cr_skipped = 0
print(f"\n[PLC: {plc_name}] Attempting to Export System Block Cross-References...") print(f"\n[PLC: {plc_name}] Intentando exportar referencias cruzadas de bloques de sistema...")
sys_blocks_cr_path = plc_export_dir / "SystemBlocks_CR" sys_blocks_cr_path = plc_export_dir / "SystemBlocks_CR"
sys_blocks_cr_path.mkdir(exist_ok=True) sys_blocks_cr_path.mkdir(exist_ok=True)
print(f" Target: {sys_blocks_cr_path}") print(f" Destino: {sys_blocks_cr_path}")
try: try:
# Check if method exists before calling
if hasattr(plc, "get_system_blocks"): if hasattr(plc, "get_system_blocks"):
system_blocks = plc.get_system_blocks() system_blocks = plc.get_system_blocks()
print( print(
f" Found {len(system_blocks)} system blocks (using get_system_blocks)." f" Se encontraron {len(system_blocks)} bloques de sistema."
) )
for sys_block in system_blocks: for sys_block in system_blocks:
sys_block_name = sys_block.get_name() sys_block_name = sys_block.get_name()
print(f" Processing System Block: {sys_block_name}...") print(f" Procesando bloque de sistema: {sys_block_name}...")
try: try:
print(f" Exporting cross-references for {sys_block_name}...") print(f" Exportando referencias cruzadas para {sys_block_name}...")
sys_block.export_cross_references( sys_block.export_cross_references(
target_directorypath=str(sys_blocks_cr_path), target_directorypath=str(sys_blocks_cr_path),
filter=CROSS_REF_FILTER, filter=CROSS_REF_FILTER,
@ -243,53 +264,51 @@ def export_plc_cross_references(plc, export_base_dir):
sys_blocks_cr_exported += 1 sys_blocks_cr_exported += 1
except RuntimeError as sys_ex: except RuntimeError as sys_ex:
print( print(
f" TIA ERROR exporting cross-references for System Block {sys_block_name}: {sys_ex}" f" ERROR TIA al exportar referencias cruzadas para el bloque de sistema {sys_block_name}: {sys_ex}"
) )
sys_blocks_cr_skipped += 1 sys_blocks_cr_skipped += 1
except Exception as sys_ex: except Exception as sys_ex:
print( print(
f" GENERAL ERROR exporting cross-references for System Block {sys_block_name}: {sys_ex}" f" ERROR GENERAL al exportar referencias cruzadas para el bloque de sistema {sys_block_name}: {sys_ex}"
) )
traceback.print_exc() traceback.print_exc()
sys_blocks_cr_skipped += 1 sys_blocks_cr_skipped += 1
else: else:
print( print(
" Method 'get_system_blocks' not found on PLC object. Skipping System Blocks." " Método 'get_system_blocks' no encontrado en el objeto PLC. Omitiendo bloques de sistema."
) )
# Alternative: Try navigating DeviceItems if needed, but that's more complex.
print( print(
f" System Block CR Export Summary: Exported={sys_blocks_cr_exported}, Skipped/Errors={sys_blocks_cr_skipped}" f" Resumen de exportación de referencias cruzadas de bloques de sistema: Exportados={sys_blocks_cr_exported}, Omitidos/Errores={sys_blocks_cr_skipped}"
) )
except AttributeError: # Catch if get_name() or other methods fail on sys_block except AttributeError:
print( print(
" AttributeError during System Block processing. Skipping remaining System Blocks." " Error de atributo durante el procesamiento de bloques de sistema. Omitiendo bloques de sistema restantes."
) )
traceback.print_exc() traceback.print_exc()
except Exception as e: except Exception as e:
print( print(
f" ERROR accessing/processing System Blocks for cross-reference export: {e}" f" ERROR al acceder/procesar bloques de sistema para exportar referencias cruzadas: {e}"
) )
traceback.print_exc() traceback.print_exc()
# --- Export Software Unit Cross-References --- # --- Export Software Unit Cross-References ---
sw_units_cr_exported = 0 sw_units_cr_exported = 0
sw_units_cr_skipped = 0 sw_units_cr_skipped = 0
print(f"\n[PLC: {plc_name}] Attempting to Export Software Unit Cross-References...") print(f"\n[PLC: {plc_name}] Intentando exportar referencias cruzadas de unidades de software...")
sw_units_cr_path = plc_export_dir / "SoftwareUnits_CR" sw_units_cr_path = plc_export_dir / "SoftwareUnits_CR"
sw_units_cr_path.mkdir(exist_ok=True) sw_units_cr_path.mkdir(exist_ok=True)
print(f" Target: {sw_units_cr_path}") print(f" Destino: {sw_units_cr_path}")
try: try:
# Check if method exists before calling
if hasattr(plc, "get_software_units"): if hasattr(plc, "get_software_units"):
software_units = plc.get_software_units() software_units = plc.get_software_units()
print(f" Found {len(software_units)} Software Units.") print(f" Se encontraron {len(software_units)} unidades de software.")
for unit in software_units: for unit in software_units:
unit_name = unit.get_name() unit_name = unit.get_name()
print(f" Processing Software Unit: {unit_name}...") print(f" Procesando unidad de software: {unit_name}...")
try: try:
print(f" Exporting cross-references for {unit_name}...") print(f" Exportando referencias cruzadas para {unit_name}...")
unit.export_cross_references( unit.export_cross_references(
target_directorypath=str(sw_units_cr_path), target_directorypath=str(sw_units_cr_path),
filter=CROSS_REF_FILTER, filter=CROSS_REF_FILTER,
@ -297,35 +316,34 @@ def export_plc_cross_references(plc, export_base_dir):
sw_units_cr_exported += 1 sw_units_cr_exported += 1
except RuntimeError as unit_ex: except RuntimeError as unit_ex:
print( print(
f" TIA ERROR exporting cross-references for Software Unit {unit_name}: {unit_ex}" f" ERROR TIA al exportar referencias cruzadas para la unidad de software {unit_name}: {unit_ex}"
) )
sw_units_cr_skipped += 1 sw_units_cr_skipped += 1
except Exception as unit_ex: except Exception as unit_ex:
print( print(
f" GENERAL ERROR exporting cross-references for Software Unit {unit_name}: {unit_ex}" f" ERROR GENERAL al exportar referencias cruzadas para la unidad de software {unit_name}: {unit_ex}"
) )
traceback.print_exc() traceback.print_exc()
sw_units_cr_skipped += 1 sw_units_cr_skipped += 1
print( print(
f" Software Unit CR Export Summary: Exported={sw_units_cr_exported}, Skipped/Errors={sw_units_cr_skipped}" f" Resumen de exportación de referencias cruzadas de unidades de software: Exportados={sw_units_cr_exported}, Omitidos/Errores={sw_units_cr_skipped}"
) )
else: else:
print( print(
" Method 'get_software_units' not found on PLC object. Skipping Software Units." " Método 'get_software_units' no encontrado en el objeto PLC. Omitiendo unidades de software."
) )
except AttributeError: # Catch if get_name() or other methods fail on unit except AttributeError:
print( print(
" AttributeError during Software Unit processing. Skipping remaining Software Units." " Error de atributo durante el procesamiento de unidades de software. Omitiendo unidades restantes."
) )
traceback.print_exc() traceback.print_exc()
except Exception as e: except Exception as e:
print( print(
f" ERROR accessing/processing Software Units for cross-reference export: {e}" f" ERROR al acceder/procesar unidades de software para exportar referencias cruzadas: {e}"
) )
traceback.print_exc() traceback.print_exc()
print(f"\n--- Finished processing PLC: {plc_name} ---") print(f"\n--- Finalizado el procesamiento del PLC: {plc_name} ---")
# --- Main Script --- # --- Main Script ---
@ -333,90 +351,90 @@ if __name__ == "__main__":
configs = load_configuration() configs = load_configuration()
working_directory = configs.get("working_directory") working_directory = configs.get("working_directory")
print("--- TIA Portal Cross-Reference Exporter ---") print("--- Exportador de Referencias Cruzadas de TIA Portal ---")
# Validate working directory # Validate working directory
if not working_directory or not os.path.isdir(working_directory): if not working_directory or not os.path.isdir(working_directory):
print("ERROR: Working directory not set or invalid in configuration.") print("ERROR: Directorio de trabajo no configurado o inválido.")
print("Please configure the working directory using the main application.") print("Por favor configure el directorio de trabajo usando la aplicación principal.")
sys.exit(1) sys.exit(1)
# 1. Select Project File # 1. Select Project File
project_file = select_project_file() project_file = select_project_file()
# 2. Define Export Directory using working_directory and subfolder # 2. Detect TIA Portal version from project file
# The export base directory is the working directory. PLC-specific folders will be created inside. tia_version = detect_tia_version(project_file)
# 3. Define Export Directory using working_directory and subfolder
export_base_dir = Path(working_directory) export_base_dir = Path(working_directory)
try: try:
# Ensure the base working directory exists (it should, but check doesn't hurt)
export_base_dir.mkdir(parents=True, exist_ok=True) export_base_dir.mkdir(parents=True, exist_ok=True)
print(f"\nSelected Project: {project_file}") print(f"\nProyecto seleccionado: {project_file}")
print(f"Using Base Export Directory: {export_base_dir.resolve()}") print(f"Usando directorio base de exportación: {export_base_dir.resolve()}")
except Exception as e: except Exception as e:
print(f"ERROR: Could not create export directory '{export_dir}'. Error: {e}") print(f"ERROR: No se pudo crear el directorio de exportación '{export_base_dir}'. Error: {e}")
sys.exit(1) sys.exit(1)
portal_instance = None portal_instance = None
project_object = None project_object = None
try: try:
# 3. Connect to TIA Portal # 4. Connect to TIA Portal with detected version
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...") print(f"\nConectando a TIA Portal V{tia_version}...")
# Connect using WithGraphicalUserInterface mode for visibility
portal_instance = ts.open_portal( portal_instance = ts.open_portal(
version=TIA_PORTAL_VERSION, version=tia_version,
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface, portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
) )
print("Connected to TIA Portal.") print("Conectado a TIA Portal.")
print(f"Portal Process ID: {portal_instance.get_process_id()}") print(f"ID del proceso del Portal: {portal_instance.get_process_id()}")
# 4. Open Project # 5. Open Project
print(f"Opening project: {os.path.basename(project_file)}...") print(f"Abriendo proyecto: {os.path.basename(project_file)}...")
project_path_obj = Path(project_file) # Use Path object project_path_obj = Path(project_file)
project_object = portal_instance.open_project( project_object = portal_instance.open_project(
project_file_path=str(project_path_obj) project_file_path=str(project_path_obj)
) )
if project_object is None: if project_object is None:
print("Project might already be open, attempting to get handle...") print("El proyecto podría estar ya abierto, intentando obtener el manejador...")
project_object = portal_instance.get_project() project_object = portal_instance.get_project()
if project_object is None: if project_object is None:
raise Exception("Failed to open or get the specified project.") raise Exception("No se pudo abrir u obtener el proyecto especificado.")
print("Project opened successfully.") print("Proyecto abierto exitosamente.")
# 5. Get PLCs # 6. Get PLCs
plcs = project_object.get_plcs() plcs = project_object.get_plcs()
if not plcs: if not plcs:
print("No PLC devices found in the project.") print("No se encontraron dispositivos PLC en el proyecto.")
else: else:
print( print(
f"Found {len(plcs)} PLC(s). Starting cross-reference export process..." f"Se encontraron {len(plcs)} PLC(s). Iniciando proceso de exportación de referencias cruzadas..."
) )
# 6. Iterate and Export Cross-References for each PLC # 7. Iterate and Export Cross-References for each PLC
for plc_device in plcs: for plc_device in plcs:
export_plc_cross_references( export_plc_cross_references(
plc=plc_device, plc=plc_device,
export_base_dir=export_base_dir, # Pass the base directory export_base_dir=export_base_dir,
) )
print("\nCross-reference export process completed.") print("\nProceso de exportación de referencias cruzadas completado.")
except RuntimeError as tia_ex: except RuntimeError as tia_ex:
print(f"\nTIA Portal Openness Error: {tia_ex}") print(f"\nError de TIA Portal Openness: {tia_ex}")
traceback.print_exc() traceback.print_exc()
except FileNotFoundError: except FileNotFoundError:
print(f"\nERROR: Project file not found at {project_file}") print(f"\nERROR: Archivo de proyecto no encontrado en {project_file}")
except Exception as e: except Exception as e:
print(f"\nAn unexpected error occurred: {e}") print(f"\nOcurrió un error inesperado: {e}")
traceback.print_exc() traceback.print_exc()
finally: finally:
# 7. Cleanup # 8. Cleanup
if portal_instance: if portal_instance:
try: try:
print("\nClosing TIA Portal...") print("\nCerrando TIA Portal...")
portal_instance.close_portal() portal_instance.close_portal()
print("TIA Portal closed.") print("TIA Portal cerrado.")
except Exception as close_ex: except Exception as close_ex:
print(f"Error during TIA Portal cleanup: {close_ex}") print(f"Error durante la limpieza de TIA Portal: {close_ex}")
print("\nScript finished.") print("\nScript finalizado.")

View File

@ -1,4 +1,4 @@
2025-06-12 20:02:24.046 - ======================================== LOG START ======================================== 2025-06-12 20:13:18.597 - ======================================== LOG START ========================================
2025-06-12 20:02:24.046 - Directorio de trabajo base configurado: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source' 2025-06-12 20:13:18.597 - Directorio de trabajo base configurado: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'
2025-06-12 20:02:24.046 - Buscando archivos XML recursivamente en el subdirectorio: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC' 2025-06-12 20:13:18.597 - Buscando archivos XML recursivamente en el subdirectorio: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'
2025-06-12 20:02:24.046 - Error: El subdirectorio 'PLC' no existe dentro de 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'. Se esperaba encontrar la estructura del proyecto TIA Portal en 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'. 2025-06-12 20:13:18.597 - Error: El subdirectorio 'PLC' no existe dentro de 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'. Se esperaba encontrar la estructura del proyecto TIA Portal en 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'.

View File

@ -1,9 +1,9 @@
--- Log de Ejecución: x0_main.py --- --- Log de Ejecución: x0_main.py ---
Grupo: XML Parser to SCL Grupo: XML Parser to SCL
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source
Inicio: 2025-06-12 20:02:23 Inicio: 2025-06-12 20:13:18
Fin: 2025-06-12 20:02:24 Fin: 2025-06-12 20:13:18
Duración: 0:00:00.882711 Duración: 0:00:00.611062
Estado: ERROR (Código de Salida: 1) Estado: ERROR (Código de Salida: 1)
--- SALIDA ESTÁNDAR (STDOUT) --- --- SALIDA ESTÁNDAR (STDOUT) ---

View File

@ -1,5 +1,10 @@
[20:03:36] Iniciando ejecución de x1.py en D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source... [20:13:18] Iniciando ejecución de x0_main.py en D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source...
[20:03:37] --- TIA Portal Data Exporter (Blocks, UDTs, Tags) --- [20:13:18] INFO: format_variable_name importado desde generators.generator_utils
[20:03:47] No project file selected. Exiting. [20:13:18] ======================================== LOG START ========================================
[20:03:47] Ejecución de x1.py finalizada (success). Duración: 0:00:10.497365. [20:13:18] Directorio de trabajo base configurado: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'
[20:03:47] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\log_x1.txt [20:13:18] Buscando archivos XML recursivamente en el subdirectorio: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'
[20:13:18] --- ERRORES ---
[20:13:18] Error: El subdirectorio 'PLC' no existe dentro de 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'. Asegúrese de que la ruta del directorio de trabajo apunte a la carpeta que *contiene* la carpeta 'PLC'.
[20:13:18] --- FIN ERRORES ---
[20:13:18] Ejecución de x0_main.py finalizada (error). Duración: 0:00:00.611062. Se detectaron errores (ver log).
[20:13:18] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\XML Parser to SCL\log_x0_main.txt