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 ---
Grupo: ObtainIOFromProjectTia
Directorio de Trabajo: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports
Inicio: 2025-06-13 11:14:30
Fin: 2025-06-13 11:16:43
Duración: 0:02:13.165274
Inicio: 2025-06-13 11:21:48
Fin: 2025-06-13 11:23:18
Duración: 0:01:29.910671
Estado: SUCCESS (Código de Salida: 0)
--- 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
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:14:34,731 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Global OpenPortal - With user interface
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:21:54,726 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Global OpenPortal - With user interface
Conectado a TIA Portal.
2025-06-13 11:14:58,165 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal GetProcessId - Process id: 30140
ID del proceso del Portal: 30140
2025-06-13 11:22:02,436 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal GetProcessId - Process id: 25644
ID del proceso del Portal: 25644
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.
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: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: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: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...
--- 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...
Procesando bloque: FC Scale Real...
Exportando referencias cruzadas para FC Scale Real...
Procesando bloque: 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.
Procesando bloque: 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 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.
@ -143,19 +143,19 @@ Ocurrió un error inesperado: OpennessAccessException: Access to a disposed obje
TIA Portal has either been disposed or stopped running.
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.
Script finalizado.
--- 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.
Traceback (most recent call last):
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 128, in export_plc_cross_references
block.export_cross_references(
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.
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.
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 ---
if os.getenv("TIA_SCRIPTING"):
sys.path.append(os.getenv("TIA_SCRIPTING"))
@ -100,8 +122,25 @@ def select_project_file():
sys.exit(0)
return file_path
def export_plc_cross_references(plc, export_base_dir):
"""Exports cross-references for various elements from a given PLC."""
# Normalizar nombres de bloque/tabla/udt para comparaciones consistentes
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()
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.")
for block in program_blocks:
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}...")
try:
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,
)
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}"
)
problematic_blocks.add(norm_block)
blocks_cr_skipped += 1
except Exception as block_ex:
print(
@ -141,6 +190,10 @@ def export_plc_cross_references(plc, export_base_dir):
)
traceback.print_exc()
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(
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:
print(f" ERROR al acceder a los bloques de programa para exportar referencias cruzadas: {e}")
traceback.print_exc()
problematic_blocks.add(_normalize_name(e.__str__()))
raise PortalDisposedException(e)
# --- Export PLC Tag Table Cross-References ---
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} ---")
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 ---
if __name__ == "__main__":
@ -380,28 +452,9 @@ if __name__ == "__main__":
try:
# 4. Connect to TIA Portal with detected version
print(f"\nConectando a TIA Portal V{tia_version}...")
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()}")
portal_instance, project_object = open_portal_and_project(tia_version, project_file)
# 5. Open Project
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
# 5. Get PLCs
plcs = project_object.get_plcs()
if not plcs:
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..."
)
# 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:
plc_name = plc_device.get_name()
exported_blocks = set()
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.")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff