Actualización de logs y mejora en la gestión de excepciones en el script de exportación

- Se actualizaron los registros de ejecución en `log_x4.txt` para reflejar nuevas fechas y duraciones de los procesos.
- Se implementó una nueva clase `PortalDisposedException` para manejar excepciones relacionadas con el cierre inesperado de TIA Portal.
- Se mejoró la lógica de re-apertura del portal en `x4.py`, permitiendo múltiples intentos en caso de errores de acceso a bloques.
- Se normalizaron los nombres de bloques para evitar omisiones en la exportación de referencias cruzadas.
- Se actualizaron los logs de ejecución en `log_x0_main.txt` para reflejar el aumento en el número de archivos XML procesados.
This commit is contained in:
Miguel 2025-06-13 13:01:29 +02:00
parent 734e6637bc
commit bf30b2db52
4 changed files with 10387 additions and 221 deletions

View File

@ -1,9 +1,9 @@
--- Log de Ejecución: x4.py --- --- Log de Ejecución: x4.py ---
Grupo: ObtainIOFromProjectTia Grupo: ObtainIOFromProjectTia
Directorio de Trabajo: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports Directorio de Trabajo: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports
Inicio: 2025-06-13 11:14:30 Inicio: 2025-06-13 11:21:48
Fin: 2025-06-13 11:16:43 Fin: 2025-06-13 11:23:18
Duración: 0:02:13.165274 Duración: 0:01:29.910671
Estado: SUCCESS (Código de Salida: 0) Estado: SUCCESS (Código de Salida: 0)
--- SALIDA ESTÁNDAR (STDOUT) --- --- SALIDA ESTÁNDAR (STDOUT) ---
@ -14,16 +14,16 @@ Proyecto seleccionado: D:/Trabajo/VM/22 - 93841 - Sidel - Tilting/InLavoro/PLC/9
Usando directorio base de exportación: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports Usando directorio base de exportación: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports
Conectando a TIA Portal V19.0... Conectando a TIA Portal V19.0...
2025-06-13 11:14:34,713 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Global OpenPortal - Start TIA Portal, please acknowledge the security dialog. 2025-06-13 11:21:54,715 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Global OpenPortal - Start TIA Portal, please acknowledge the security dialog.
2025-06-13 11:14:34,731 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Global OpenPortal - With user interface 2025-06-13 11:21:54,726 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Global OpenPortal - With user interface
Conectado a TIA Portal. Conectado a TIA Portal.
2025-06-13 11:14:58,165 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal GetProcessId - Process id: 30140 2025-06-13 11:22:02,436 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal GetProcessId - Process id: 25644
ID del proceso del Portal: 30140 ID del proceso del Portal: 25644
Abriendo proyecto: 93841_PLC_28.ap19... Abriendo proyecto: 93841_PLC_28.ap19...
2025-06-13 11:14:58,500 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal OpenProject - Open project... D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\InLavoro\PLC\93841_PLC_28\93841_PLC_28.ap19 2025-06-13 11:22:02,613 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal OpenProject - Open project... D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\InLavoro\PLC\93841_PLC_28\93841_PLC_28.ap19
Proyecto abierto exitosamente. Proyecto abierto exitosamente.
2025-06-13 11:15:29,701 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Project GetPlcs - Found plc VM 1512 with parent name ET 200SP station_1 2025-06-13 11:22:12,777 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Project GetPlcs - Found plc VM 1512 with parent name ET 200SP station_1
2025-06-13 11:15:30,551 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Project GetPlcs - Found plc SIDEL Transport Example with parent name S71500/ET200MP station_1 2025-06-13 11:22:13,643 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Project GetPlcs - Found plc SIDEL Transport Example with parent name S71500/ET200MP station_1
Se encontraron 2 PLC(s). Iniciando proceso de exportación de referencias cruzadas... Se encontraron 2 PLC(s). Iniciando proceso de exportación de referencias cruzadas...
--- Procesando PLC: VM 1512 --- --- Procesando PLC: VM 1512 ---
@ -113,9 +113,9 @@ Se encontraron 2 PLC(s). Iniciando proceso de exportación de referencias cruzad
Exportando referencias cruzadas para FC Simple PID... Exportando referencias cruzadas para FC Simple PID...
Procesando bloque: FC Scale Real... Procesando bloque: FC Scale Real...
Exportando referencias cruzadas para FC Scale Real... Exportando referencias cruzadas para FC Scale Real...
Procesando bloque: FB Correct Speed F/Pulses... Procesando bloque: FB Correct Speed F_Pulses...
Exportando referencias cruzadas para FB Correct Speed F/Pulses... Exportando referencias cruzadas para FB Correct Speed F_Pulses...
ERROR GENERAL al exportar referencias cruzadas para el bloque FB Correct Speed F/Pulses: OpennessAccessException: Unexpected exception - no exception message available. ERROR GENERAL al exportar referencias cruzadas para el bloque FB Correct Speed F_Pulses: OpennessAccessException: Unexpected exception - no exception message available.
ERROR al acceder a los bloques de programa para exportar referencias cruzadas: OpennessAccessException: Access to a disposed object of type 'Siemens.Engineering.SW.Blocks.FB' is not possible. ERROR al acceder a los bloques de programa para exportar referencias cruzadas: OpennessAccessException: Access to a disposed object of type 'Siemens.Engineering.SW.Blocks.FB' is not possible.
TIA Portal has either been disposed or stopped running. TIA Portal has either been disposed or stopped running.
@ -143,19 +143,19 @@ Ocurrió un error inesperado: OpennessAccessException: Access to a disposed obje
TIA Portal has either been disposed or stopped running. TIA Portal has either been disposed or stopped running.
Cerrando TIA Portal... Cerrando TIA Portal...
2025-06-13 11:16:43,486 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal ClosePortal - Close TIA Portal 2025-06-13 11:23:18,643 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal ClosePortal - Close TIA Portal
TIA Portal cerrado. TIA Portal cerrado.
Script finalizado. Script finalizado.
--- ERRORES (STDERR) --- --- ERRORES (STDERR) ---
2025-06-13 11:16:43,458 [1] ERROR Siemens.TiaPortal.OpennessApi19.Implementations.ProgramBlock ExportCrossReferences - 2025-06-13 11:23:18,616 [1] ERROR Siemens.TiaPortal.OpennessApi19.Implementations.ProgramBlock ExportCrossReferences -
Siemens.TiaPortal.OpennessContracts.OpennessAccessException: Unexpected exception - no exception message available. Siemens.TiaPortal.OpennessContracts.OpennessAccessException: Unexpected exception - no exception message available.
Traceback (most recent call last): Traceback (most recent call last):
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 128, in export_plc_cross_references File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 128, in export_plc_cross_references
block.export_cross_references( block.export_cross_references(
ValueError: OpennessAccessException: Unexpected exception - no exception message available. ValueError: OpennessAccessException: Unexpected exception - no exception message available.
2025-06-13 11:16:43,462 [1] ERROR Siemens.TiaPortal.OpennessApi19.Implementations.ProgramBlock GetName - 2025-06-13 11:23:18,620 [1] ERROR Siemens.TiaPortal.OpennessApi19.Implementations.ProgramBlock GetName -
Siemens.TiaPortal.OpennessContracts.OpennessAccessException: Access to a disposed object of type 'Siemens.Engineering.SW.Blocks.FB' is not possible. Siemens.TiaPortal.OpennessContracts.OpennessAccessException: Access to a disposed object of type 'Siemens.Engineering.SW.Blocks.FB' is not possible.
TIA Portal has either been disposed or stopped running. TIA Portal has either been disposed or stopped running.

View File

@ -29,6 +29,28 @@ SUPPORTED_TIA_VERSIONS = {
# 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
MAX_REOPEN_ATTEMPTS = 5 # Número máximo de re-aperturas permitidas para evitar bucles infinitos
class PortalDisposedException(Exception):
"""Excepción lanzada cuando TIA Portal se ha cerrado inesperadamente o un objeto ha sido descartado."""
def __init__(self, original_exception, failed_block: str | None = None):
super().__init__(str(original_exception))
self.failed_block = failed_block
def _is_disposed_exception(exc: Exception) -> bool:
"""Devuelve True si la excepción proviene de un objeto/portal ya cerrado o sin mensaje útil."""
msg = str(exc).lower()
return any(
indicator in msg
for indicator in (
"disposed object",
"tia portal has either been disposed",
"unexpected exception - no exception message available",
)
)
# --- TIA Scripting Import Handling --- # --- TIA Scripting Import Handling ---
if os.getenv("TIA_SCRIPTING"): if os.getenv("TIA_SCRIPTING"):
sys.path.append(os.getenv("TIA_SCRIPTING")) sys.path.append(os.getenv("TIA_SCRIPTING"))
@ -100,8 +122,25 @@ def select_project_file():
sys.exit(0) sys.exit(0)
return file_path return file_path
def export_plc_cross_references(plc, export_base_dir): # Normalizar nombres de bloque/tabla/udt para comparaciones consistentes
"""Exports cross-references for various elements from a given PLC.""" def _normalize_name(name: str) -> str:
"""Normaliza un nombre quitando espacios laterales y convirtiendo a minúsculas."""
return name.strip().lower()
def export_plc_cross_references(plc, export_base_dir, exported_blocks=None, problematic_blocks=None):
"""Exports cross-references for various elements from a given PLC.
Parámetros
----------
plc : objeto PLC actual
export_base_dir : pathlib.Path directorio base para exportar
exported_blocks : set[str] bloques que ya se han exportado
problematic_blocks : set[str] bloques que se deben omitir tras fallos previos
"""
if exported_blocks is None:
exported_blocks = set()
if problematic_blocks is None:
problematic_blocks = set()
plc_name = plc.get_name() plc_name = plc.get_name()
print(f"\n--- Procesando PLC: {plc_name} ---") print(f"\n--- Procesando PLC: {plc_name} ---")
@ -122,6 +161,14 @@ def export_plc_cross_references(plc, export_base_dir):
print(f" Se encontraron {len(program_blocks)} bloques de programa.") 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()
norm_block = _normalize_name(block_name)
if norm_block in problematic_blocks:
print(f" Omitiendo bloque problemático previamente detectado: {block_name}")
blocks_cr_skipped += 1
continue
if norm_block in exported_blocks:
# Ya exportado en un intento anterior, no repetir
continue
print(f" Procesando bloque: {block_name}...") print(f" Procesando bloque: {block_name}...")
try: try:
print(f" Exportando referencias cruzadas para {block_name}...") print(f" Exportando referencias cruzadas para {block_name}...")
@ -130,10 +177,12 @@ def export_plc_cross_references(plc, export_base_dir):
filter=CROSS_REF_FILTER, filter=CROSS_REF_FILTER,
) )
blocks_cr_exported += 1 blocks_cr_exported += 1
exported_blocks.add(norm_block)
except RuntimeError as block_ex: except RuntimeError as block_ex:
print( print(
f" ERROR TIA al exportar referencias cruzadas para el bloque {block_name}: {block_ex}" f" ERROR TIA al exportar referencias cruzadas para el bloque {block_name}: {block_ex}"
) )
problematic_blocks.add(norm_block)
blocks_cr_skipped += 1 blocks_cr_skipped += 1
except Exception as block_ex: except Exception as block_ex:
print( print(
@ -141,6 +190,10 @@ def export_plc_cross_references(plc, export_base_dir):
) )
traceback.print_exc() traceback.print_exc()
blocks_cr_skipped += 1 blocks_cr_skipped += 1
if _is_disposed_exception(block_ex):
# Escalamos para que el script pueda re-abrir el Portal y omitir el bloque
problematic_blocks.add(norm_block)
raise PortalDisposedException(block_ex, failed_block=block_name)
print( print(
f" Resumen de exportación de referencias cruzadas de bloques: Exportados={blocks_cr_exported}, Omitidos/Errores={blocks_cr_skipped}" f" Resumen de exportación de referencias cruzadas de bloques: Exportados={blocks_cr_exported}, Omitidos/Errores={blocks_cr_skipped}"
) )
@ -151,6 +204,8 @@ def export_plc_cross_references(plc, export_base_dir):
except Exception as e: except Exception as e:
print(f" ERROR al acceder a los bloques de programa para exportar referencias cruzadas: {e}") print(f" ERROR al acceder a los bloques de programa para exportar referencias cruzadas: {e}")
traceback.print_exc() traceback.print_exc()
problematic_blocks.add(_normalize_name(e.__str__()))
raise PortalDisposedException(e)
# --- Export PLC Tag Table Cross-References --- # --- Export PLC Tag Table Cross-References ---
tags_cr_exported = 0 tags_cr_exported = 0
@ -345,6 +400,23 @@ def export_plc_cross_references(plc, export_base_dir):
print(f"\n--- Finalizado el procesamiento del PLC: {plc_name} ---") print(f"\n--- Finalizado el procesamiento del PLC: {plc_name} ---")
def open_portal_and_project(tia_version: str, project_file_path: str):
"""Abre TIA Portal y el proyecto indicado, devolviendo el portal y el objeto proyecto."""
print(f"\nConectando a TIA Portal V{tia_version}...")
portal = ts.open_portal(
version=tia_version,
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
)
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.")
return portal, project_obj
# --- Main Script --- # --- Main Script ---
if __name__ == "__main__": if __name__ == "__main__":
@ -380,28 +452,9 @@ if __name__ == "__main__":
try: try:
# 4. Connect to TIA Portal with detected version # 4. Connect to TIA Portal with detected version
print(f"\nConectando a TIA Portal V{tia_version}...") portal_instance, project_object = open_portal_and_project(tia_version, project_file)
portal_instance = ts.open_portal(
version=tia_version,
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
)
print("Conectado a TIA Portal.")
print(f"ID del proceso del Portal: {portal_instance.get_process_id()}")
# 5. Open Project # 5. Get PLCs
print(f"Abriendo proyecto: {os.path.basename(project_file)}...")
project_path_obj = Path(project_file)
project_object = portal_instance.open_project(
project_file_path=str(project_path_obj)
)
if project_object is None:
print("El proyecto podría estar ya abierto, intentando obtener el manejador...")
project_object = portal_instance.get_project()
if project_object is None:
raise Exception("No se pudo abrir u obtener el proyecto especificado.")
print("Proyecto abierto exitosamente.")
# 6. Get PLCs
plcs = project_object.get_plcs() plcs = project_object.get_plcs()
if not plcs: if not plcs:
print("No se encontraron dispositivos PLC en el proyecto.") print("No se encontraron dispositivos PLC en el proyecto.")
@ -410,12 +463,63 @@ if __name__ == "__main__":
f"Se encontraron {len(plcs)} PLC(s). Iniciando proceso de exportación de referencias cruzadas..." f"Se encontraron {len(plcs)} PLC(s). Iniciando proceso de exportación de referencias cruzadas..."
) )
# 7. Iterate and Export Cross-References for each PLC # 7. Iterate and Export Cross-References for each PLC con lógica de re-apertura
for plc_device in plcs: for plc_device in plcs:
export_plc_cross_references( plc_name = plc_device.get_name()
plc=plc_device, exported_blocks = set()
export_base_dir=export_base_dir, problematic_blocks = set()
) skipped_blocks_report = []
reopen_attempts = 0
while True:
try:
export_plc_cross_references(
plc=plc_device,
export_base_dir=export_base_dir,
exported_blocks=exported_blocks,
problematic_blocks=problematic_blocks,
)
break # Éxito
except PortalDisposedException as pd_ex:
reopen_attempts += 1
failed_block = pd_ex.failed_block
if failed_block:
problematic_blocks.add(_normalize_name(failed_block))
skipped_blocks_report.append(failed_block)
if reopen_attempts > MAX_REOPEN_ATTEMPTS:
print(
f"Se alcanzó el máximo de re-aperturas permitidas ({MAX_REOPEN_ATTEMPTS}) para el PLC '{plc_name}'. Abortando."
)
break
# Intentamos cerrar el portal actual (si existe)
try:
print("Cerrando instancia actual de TIA Portal...")
portal_instance.close_portal()
except Exception:
pass
# Re-abrir portal y proyecto
print(f"Re-abriendo TIA Portal (intento {reopen_attempts}/{MAX_REOPEN_ATTEMPTS})...")
portal_instance, project_object = open_portal_and_project(tia_version, project_file)
# Buscar de nuevo el PLC por nombre
plc_device = None
for _plc in project_object.get_plcs():
if _plc.get_name() == plc_name:
plc_device = _plc
break
if plc_device is None:
print(
f"No se encontró el PLC '{plc_name}' tras la re-apertura. Se aborta su procesamiento."
)
break
# Continuar con el while
continue
if skipped_blocks_report:
print(f"\nBloques problemáticos para el PLC '{plc_name}': {', '.join(set(skipped_blocks_report))}")
print("\nProceso de exportación de referencias cruzadas completado.") print("\nProceso de exportación de referencias cruzadas completado.")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff