Compare commits

..

No commits in common. "734e6637bc4be7105cedd4100e33a6a7610fd1ac" and "be3b3334918c05ff6b90ddbaa070eb1d1801631b" have entirely different histories.

37 changed files with 562 additions and 30513 deletions

3
.gitignore vendored
View File

@ -25,9 +25,6 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
*.txt
*.json
# PyInstaller
# Usually these files are written by a python script from a template

69
app.py
View File

@ -33,37 +33,6 @@ websocket_connections = set()
# --- Globals for Tray Icon ---
tray_icon = None
# --- Parámetros para envío por lotes de logs ---
BATCH_FLUSH_INTERVAL = 0.5 # segundos
broadcast_buffer = [] # Almacena líneas formateadas pendientes de envío
buffer_lock = threading.Lock() # Sincroniza acceso al buffer
def _broadcast_flush_loop():
"""Hilo que vacía el buffer de logs cada BATCH_FLUSH_INTERVAL segundos."""
while True:
time.sleep(BATCH_FLUSH_INTERVAL)
with buffer_lock:
if not broadcast_buffer:
continue
batch = "\n".join(broadcast_buffer)
broadcast_buffer.clear()
_send_batch_to_clients(batch)
def _send_batch_to_clients(batch_message: str):
"""Envía un bloque de texto a todas las conexiones WebSocket activas."""
dead_connections = set()
for ws in list(websocket_connections):
try:
if ws.connected:
ws.send(batch_message + "\n")
except Exception:
dead_connections.add(ws)
websocket_connections.difference_update(dead_connections)
# Iniciar hilo de vaciado en segundo plano (ahora que las dependencias están definidas)
flusher_thread = threading.Thread(target=_broadcast_flush_loop, daemon=True)
flusher_thread.start()
@sock.route("/ws")
def handle_websocket(ws):
@ -80,34 +49,49 @@ def handle_websocket(ws):
def broadcast_message(message):
"""Acumula mensajes en un buffer y los envía por lotes cada 500 ms."""
"""Envía un mensaje a todas las conexiones WebSocket activas y guarda en log."""
dead_connections = set()
timestamp = datetime.now().strftime("[%H:%M:%S] ")
# Normalizar entrada a lista de mensajes
# Normalize input to a list of messages
if isinstance(message, list):
messages = message
else:
# Si es un solo mensaje, dividirlo en líneas
messages = [line.strip() for line in message.splitlines() if line.strip()]
# Procesar cada mensaje
for raw_msg in messages:
# Limpiar timestamps duplicados al inicio del mensaje
while raw_msg.startswith("[") and "]" in raw_msg:
try:
closing_bracket = raw_msg.index("]") + 1
if raw_msg[1:closing_bracket - 1].replace(":", "").isdigit():
raw_msg = raw_msg[closing_bracket:].strip()
if raw_msg[1 : closing_bracket - 1].replace(":", "").isdigit():
raw_msg = raw_msg[closing_bracket:].strip() # Update raw_msg itself
else:
break
except ValueError:
except:
break
# Registrar en archivo (la clase Logger añade timestamp propio)
# Log the raw message using the config_manager's logger
# The logger will handle its own timestamping for the file.
config_manager.append_log(raw_msg)
# Formatear para el WebSocket y añadir al buffer
# Format message with timestamp *for WebSocket broadcast*
formatted_msg_for_ws = f"{timestamp}{raw_msg}"
with buffer_lock:
broadcast_buffer.append(formatted_msg_for_ws)
# Enviar a todos los clientes WebSocket
for ws in list(websocket_connections):
try:
if ws.connected: # Check if ws is still connected before sending
ws.send(
f"{formatted_msg_for_ws}\n"
) # Use the correct variable name here
except Exception:
dead_connections.add(ws) # Collect dead connections
# Limpiar conexiones muertas
websocket_connections.difference_update(dead_connections)
@app.route("/api/execute_script", methods=["POST"])
@ -1069,8 +1053,3 @@ if __name__ == "__main__":
print(f"Error al iniciar el icono de notificación: {e}", file=sys.stderr)
print("Aplicación finalizada.")
# --- Iniciar hilo de vaciado en segundo plano (única vez) ---
# flusher_thread = threading.Thread(target=_broadcast_flush_loop, daemon=True)
# flusher_thread.start()
# ------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -1,199 +1,251 @@
--- 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
Directorio de Trabajo: C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\Reporte\SourceDoc\SourceXML
Inicio: 2025-05-20 12:12:51
Fin: 2025-05-20 12:20:01
Duración: 0:07:09.648304
Estado: SUCCESS (Código de Salida: 0)
--- SALIDA ESTÁNDAR (STDOUT) ---
--- Exportador de Referencias Cruzadas de TIA Portal ---
Versión de TIA Portal detectada: 19.0 (de la extensión .ap19)
--- TIA Portal Cross-Reference Exporter ---
Proyecto seleccionado: D:/Trabajo/VM/22 - 93841 - Sidel - Tilting/InLavoro/PLC/93841_PLC_28/93841_PLC_28.ap19
Usando directorio base de exportación: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports
Selected Project: C:/Trabajo/SIDEL/09 - SAE452 - Diet as Regular - San Giovanni in Bosco/Reporte/SourceDoc/Migration/SAE452/SAE452.ap18
Using Base Export Directory: C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\Reporte\SourceDoc\SourceXML
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
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
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
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
Se encontraron 2 PLC(s). Iniciando proceso de exportación de referencias cruzadas...
Connecting to TIA Portal V18.0...
2025-05-20 12:12:56,780 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Global OpenPortal - Start TIA Portal, please acknowledge the security dialog.
2025-05-20 12:12:56,804 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Global OpenPortal - With user interface
Connected to TIA Portal.
2025-05-20 12:13:30,582 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Portal GetProcessId - Process id: 21952
Portal Process ID: 21952
Opening project: SAE452.ap18...
2025-05-20 12:13:31,077 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Portal OpenProject - Open project... C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\Reporte\SourceDoc\Migration\SAE452\SAE452.ap18
Project opened successfully.
2025-05-20 12:14:15,234 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Project GetPlcs - Found plc CPU 315F-2 PN/DP with parent name _SSAE0452
Found 1 PLC(s). Starting cross-reference export process...
--- Procesando PLC: VM 1512 ---
--- Processing PLC: CPU 315F-2 PN/DP ---
[PLC: VM 1512] Exportando referencias cruzadas de bloques de programa...
Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\ProgramBlocks_CR
Se encontraron 201 bloques de programa.
Procesando bloque: FC General COM...
Exportando referencias cruzadas para FC General COM...
Procesando bloque: From_SIDEL...
Exportando referencias cruzadas para From_SIDEL...
Procesando bloque: To_SIDEL...
Exportando referencias cruzadas para To_SIDEL...
Procesando bloque: DB Early Restart Blower...
Exportando referencias cruzadas para DB Early Restart Blower...
Procesando bloque: DB Early Restart Filler...
Exportando referencias cruzadas para DB Early Restart Filler...
Procesando bloque: DB Early Restart SynchroBlock...
Exportando referencias cruzadas para DB Early Restart SynchroBlock...
Procesando bloque: FB Early Restart...
Exportando referencias cruzadas para FB Early Restart...
Procesando bloque: DB Signal Transport...
Exportando referencias cruzadas para DB Signal Transport...
Procesando bloque: FC Signal Transport...
Exportando referencias cruzadas para FC Signal Transport...
Procesando bloque: DB Lube - Dry Ecolab...
Exportando referencias cruzadas para DB Lube - Dry Ecolab...
Procesando bloque: FB Lube - Water/Dry...
Exportando referencias cruzadas para FB Lube - Water/Dry...
Procesando bloque: FB Lube - Dry Ecolab...
Exportando referencias cruzadas para FB Lube - Dry Ecolab...
Procesando bloque: FB Lube - EcoLab VM...
Exportando referencias cruzadas para FB Lube - EcoLab VM...
Procesando bloque: FB Lube - Ecolab...
Exportando referencias cruzadas para FB Lube - Ecolab...
Procesando bloque: DB LUBE - Ecolab...
Exportando referencias cruzadas para DB LUBE - Ecolab...
Procesando bloque: FC Ttop Configuration...
Exportando referencias cruzadas para FC Ttop Configuration...
Procesando bloque: FC Ttop Run...
Exportando referencias cruzadas para FC Ttop Run...
Procesando bloque: FC Ttop Alarms...
Exportando referencias cruzadas para FC Ttop Alarms...
Procesando bloque: DB Ttop Run...
Exportando referencias cruzadas para DB Ttop Run...
Procesando bloque: DB Ttop Motor CFG...
Exportando referencias cruzadas para DB Ttop Motor CFG...
Procesando bloque: DB Ttop Alarm...
Exportando referencias cruzadas para DB Ttop Alarm...
Procesando bloque: FC Ttop Motor 31...
Exportando referencias cruzadas para FC Ttop Motor 31...
Procesando bloque: FC Ttop Motor 32...
Exportando referencias cruzadas para FC Ttop Motor 32...
Procesando bloque: FC Ttop Motor 34...
Exportando referencias cruzadas para FC Ttop Motor 34...
Procesando bloque: FC Ttop Motor 35...
Exportando referencias cruzadas para FC Ttop Motor 35...
Procesando bloque: FC Ttop Motor 36...
Exportando referencias cruzadas para FC Ttop Motor 36...
Procesando bloque: DB Ttop Motor 31...
Exportando referencias cruzadas para DB Ttop Motor 31...
Procesando bloque: DB Ttop Motor 32...
Exportando referencias cruzadas para DB Ttop Motor 32...
Procesando bloque: DB Ttop Motor 34...
Exportando referencias cruzadas para DB Ttop Motor 34...
Procesando bloque: DB Ttop Motor 35...
Exportando referencias cruzadas para DB Ttop Motor 35...
Procesando bloque: DB Ttop Minimotor Cfg 32...
Exportando referencias cruzadas para DB Ttop Minimotor Cfg 32...
Procesando bloque: DB Ttop Minimotor Data 32...
Exportando referencias cruzadas para DB Ttop Minimotor Data 32...
Procesando bloque: DB Ttop Motor 36...
Exportando referencias cruzadas para DB Ttop Motor 36...
Procesando bloque: FB Ttop Dryer...
Exportando referencias cruzadas para FB Ttop Dryer...
Procesando bloque: FB Ttop Energy Saving...
Exportando referencias cruzadas para FB Ttop Energy Saving...
Procesando bloque: FB SKID...
Exportando referencias cruzadas para FB SKID...
Procesando bloque: FC Analog Sensor Process...
Exportando referencias cruzadas para FC Analog Sensor Process...
Procesando bloque: FC Valve...
Exportando referencias cruzadas para FC Valve...
Procesando bloque: FB SpeedRegulation...
Exportando referencias cruzadas para FB SpeedRegulation...
Procesando bloque: FC Simple PID...
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.
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.
[PLC: CPU 315F-2 PN/DP] Exporting Program Block Cross-References...
Target: C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\Reporte\SourceDoc\SourceXML\CPU 315F-2 PN\DP\ProgramBlocks_CR
Found 410 program blocks.
Processing block: ISOonTCP_or_TCP_Protocol...
Exporting cross-references for ISOonTCP_or_TCP_Protocol...
Processing block: PIDControl...
Exporting cross-references for PIDControl...
Processing block: DETAIL_DP_DIAG...
Exporting cross-references for DETAIL_DP_DIAG...
Processing block: Net Dosing Sys Prof...
Exporting cross-references for Net Dosing Sys Prof...
Processing block: ICS Profibus Comm...
Exporting cross-references for ICS Profibus Comm...
Processing block: GNS DriveDiag...
Exporting cross-references for GNS DriveDiag...
Processing block: HMI_Blender_Parameters...
Exporting cross-references for HMI_Blender_Parameters...
Processing block: HMI Drive...
Exporting cross-references for HMI Drive...
Processing block: GNS DriveDiagMain...
Exporting cross-references for GNS DriveDiagMain...
Processing block: Integral...
Exporting cross-references for Integral...
Processing block: LowPassFilter...
Exporting cross-references for LowPassFilter...
Processing block: SlewLimit...
Exporting cross-references for SlewLimit...
Processing block: MSE Slope...
Exporting cross-references for MSE Slope...
Processing block: Statistical_Analisys...
Exporting cross-references for Statistical_Analisys...
Processing block: Blender_Variables...
Exporting cross-references for Blender_Variables...
Processing block: BrixTracking_ProdSamples...
Exporting cross-references for BrixTracking_ProdSamples...
Processing block: Procedure_Variables...
Exporting cross-references for Procedure_Variables...
Processing block: Blender_Constants...
Exporting cross-references for Blender_Constants...
Processing block: BrixTracking_SampleTime...
Exporting cross-references for BrixTracking_SampleTime...
Processing block: Delay...
Exporting cross-references for Delay...
Processing block: CO2Tracking_ProdSamples...
Exporting cross-references for CO2Tracking_ProdSamples...
Processing block: CO2Tracking_SampleTime...
Exporting cross-references for CO2Tracking_SampleTime...
Processing block: Interlocking_Variables...
Exporting cross-references for Interlocking_Variables...
Processing block: System_RunOut_Variables...
Exporting cross-references for System_RunOut_Variables...
Processing block: CIP_Program_Variables...
Exporting cross-references for CIP_Program_Variables...
Processing block: Filler_Head_Variables...
Exporting cross-references for Filler_Head_Variables...
Processing block: Filling_Time_Tranfer_DB...
Exporting cross-references for Filling_Time_Tranfer_DB...
Processing block: Blender_Variables_Pers...
Exporting cross-references for Blender_Variables_Pers...
Processing block: HMI_Alarms...
Exporting cross-references for HMI_Alarms...
Processing block: HMI_Local_CIP_Variables...
Exporting cross-references for HMI_Local_CIP_Variables...
Processing block: HMI_Service...
Exporting cross-references for HMI_Service...
Processing block: HMI_Variables_Cmd...
Exporting cross-references for HMI_Variables_Cmd...
Processing block: HMI_Variables_Status...
Exporting cross-references for HMI_Variables_Status...
Processing block: HMI_Device...
Exporting cross-references for HMI_Device...
Processing block: HMI_Instrument...
Exporting cross-references for HMI_Instrument...
Processing block: HMI_Digital...
Exporting cross-references for HMI_Digital...
Processing block: HMI_PID...
Exporting cross-references for HMI_PID...
Processing block: HMI_ICS...
Exporting cross-references for HMI_ICS...
Processing block: HMI_Device_AVS...
Exporting cross-references for HMI_Device_AVS...
Processing block: Profibus_Variables...
Exporting cross-references for Profibus_Variables...
Processing block: Input_CheckFlowMetersSta...
Exporting cross-references for Input_CheckFlowMetersSta...
Processing block: Input_DigitalScanner...
Exporting cross-references for Input_DigitalScanner...
Processing block: ProductLiterInTank...
Exporting cross-references for ProductLiterInTank...
Processing block: ProductAvailable...
Exporting cross-references for ProductAvailable...
Processing block: T_Timer...
Exporting cross-references for T_Timer...
Processing block: SEL_I...
Exporting cross-references for SEL_I...
Processing block: _StepMove...
Exporting cross-references for _StepMove...
Processing block: ProductPipeDrain_Seq...
Exporting cross-references for ProductPipeDrain_Seq...
Processing block: ProductPipeDrain...
Exporting cross-references for ProductPipeDrain...
Processing block: ProductPipeRunOut_Seq...
Exporting cross-references for ProductPipeRunOut_Seq...
Processing block: SEL_R...
Exporting cross-references for SEL_R...
Processing block: ProductPipeRunOut...
Exporting cross-references for ProductPipeRunOut...
Processing block: LIMIT_I...
Exporting cross-references for LIMIT_I...
Processing block: System_Run_Out...
Exporting cross-references for System_Run_Out...
Processing block: System_Run_Out_Data...
Exporting cross-references for System_Run_Out_Data...
ERROR accessing Program Blocks for cross-reference export: RemotingException: El objeto '/bd68de4c_3307_463d_b3ce_57a1378b3bde/lnycb9uriadrpgmom_mjdspm_249.rem' se desconectó o no existe en el servidor.
TIA Portal has either been disposed or stopped running.
[PLC: CPU 315F-2 PN/DP] Exporting PLC Tag Table Cross-References...
Target: C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\Reporte\SourceDoc\SourceXML\CPU 315F-2 PN\DP\PlcTags_CR
Found 2 Tag Tables.
Processing Tag Table: Default tag table...
Exporting cross-references for Default tag table...
Processing Tag Table: STEP7 classic symbols...
Exporting cross-references for STEP7 classic symbols...
Tag Table CR Export Summary: Exported=2, Skipped/Errors=0
[PLC: VM 1512] Exportando referencias cruzadas de tablas de variables...
Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\PlcTags_CR
ERROR al acceder a las tablas de variables para exportar referencias cruzadas: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
[PLC: CPU 315F-2 PN/DP] Exporting PLC Data Type (UDT) Cross-References...
Target: C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\Reporte\SourceDoc\SourceXML\CPU 315F-2 PN\DP\PlcDataTypes_CR
Found 21 UDTs.
Processing UDT: AnyPoint...
Exporting cross-references for AnyPoint...
Processing UDT: FunctionButton...
Exporting cross-references for FunctionButton...
Processing UDT: TADDR_PAR...
Exporting cross-references for TADDR_PAR...
Processing UDT: Device...
Exporting cross-references for Device...
Processing UDT: AnalogInstrument...
Exporting cross-references for AnalogInstrument...
Processing UDT: DigitalInstrument...
Exporting cross-references for DigitalInstrument...
Processing UDT: PID...
Exporting cross-references for PID...
Processing UDT: EHS16...
Exporting cross-references for EHS16...
Processing UDT: Danfoss Diag...
Exporting cross-references for Danfoss Diag...
Processing UDT: QCO Timer...
Exporting cross-references for QCO Timer...
Processing UDT: QCO Phase...
Exporting cross-references for QCO Phase...
Processing UDT: ReportCIPSimpleData...
Exporting cross-references for ReportCIPSimpleData...
Processing UDT: CIP_WaitEvent_Type...
Exporting cross-references for CIP_WaitEvent_Type...
Processing UDT: CIP_Step_Type_New...
Exporting cross-references for CIP_Step_Type_New...
Processing UDT: CIP_Simple_Type...
Exporting cross-references for CIP_Simple_Type...
Processing UDT: CIP_Link_Type...
Exporting cross-references for CIP_Link_Type...
Processing UDT: CIP_Step_Type...
Exporting cross-references for CIP_Step_Type...
Processing UDT: Recipe_Prod...
Exporting cross-references for Recipe_Prod...
Processing UDT: ICS Hndsk receive signal...
Exporting cross-references for ICS Hndsk receive signal...
Processing UDT: ICS Hndsk send signal...
Exporting cross-references for ICS Hndsk send signal...
Processing UDT: TCON_PAR...
Exporting cross-references for TCON_PAR...
UDT CR Export Summary: Exported=21, Skipped/Errors=0
[PLC: VM 1512] Exportando referencias cruzadas de tipos de datos PLC (UDTs)...
Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\PlcDataTypes_CR
ERROR al acceder a los UDTs para exportar referencias cruzadas: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
[PLC: CPU 315F-2 PN/DP] Attempting to Export System Block Cross-References...
Target: C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\Reporte\SourceDoc\SourceXML\CPU 315F-2 PN\DP\SystemBlocks_CR
Found 12 system blocks (using get_system_blocks).
Processing System Block: TIM_S5TI...
Exporting cross-references for TIM_S5TI...
Processing System Block: REPLACE...
Exporting cross-references for REPLACE...
Processing System Block: LIMIT...
Exporting cross-references for LIMIT...
Processing System Block: NE_STRNG...
Exporting cross-references for NE_STRNG...
Processing System Block: TURCV...
Exporting cross-references for TURCV...
Processing System Block: TUSEND...
Exporting cross-references for TUSEND...
Processing System Block: PID_Continuos...
Exporting cross-references for PID_Continuos...
Processing System Block: TDISCON...
Exporting cross-references for TDISCON...
Processing System Block: TCON...
Exporting cross-references for TCON...
Processing System Block: TRCV...
Exporting cross-references for TRCV...
Processing System Block: TSEND...
Exporting cross-references for TSEND...
Processing System Block: DT_DATE...
Exporting cross-references for DT_DATE...
System Block CR Export Summary: Exported=12, Skipped/Errors=0
[PLC: VM 1512] Intentando exportar referencias cruzadas de bloques de sistema...
Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\SystemBlocks_CR
ERROR al acceder/procesar bloques de sistema para exportar referencias cruzadas: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
[PLC: CPU 315F-2 PN/DP] Attempting to Export Software Unit Cross-References...
Target: C:\Trabajo\SIDEL\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\Reporte\SourceDoc\SourceXML\CPU 315F-2 PN\DP\SoftwareUnits_CR
Found 0 Software Units.
Software Unit CR Export Summary: Exported=0, Skipped/Errors=0
[PLC: VM 1512] Intentando exportar referencias cruzadas de unidades de software...
Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\SoftwareUnits_CR
ERROR al acceder/procesar unidades de software para exportar referencias cruzadas: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
--- Finished processing PLC: CPU 315F-2 PN/DP ---
--- Finalizado el procesamiento del PLC: VM 1512 ---
Cross-reference export process completed.
Ocurrió un error inesperado: OpennessAccessException: Access to a disposed object of type 'Siemens.Engineering.HW.DeviceItemImpl' is not possible.
Closing TIA Portal...
2025-05-20 12:19:54,187 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Portal ClosePortal - Close TIA Portal
TIA Portal closed.
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
TIA Portal cerrado.
Script finalizado.
Script finished.
--- ERRORES (STDERR) ---
2025-06-13 11:16:43,458 [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 -
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.
Traceback (most recent call last):
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 124, in export_plc_cross_references
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 99, in export_plc_cross_references
block_name = block.get_name()
^^^^^^^^^^^^^^^^
ValueError: 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.
Traceback (most recent call last):
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 164, in export_plc_cross_references
tag_tables = plc.get_plc_tag_tables()
^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
Traceback (most recent call last):
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 207, in export_plc_cross_references
udts = plc.get_user_data_types()
^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
Traceback (most recent call last):
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 251, in export_plc_cross_references
system_blocks = plc.get_system_blocks()
^^^^^^^^^^^^^^^^^^^^^^^
ValueError: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
Traceback (most recent call last):
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 305, in export_plc_cross_references
software_units = plc.get_software_units()
^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
Traceback (most recent call last):
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 415, in <module>
export_plc_cross_references(
File "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x4.py", line 105, in export_plc_cross_references
plc_name = plc.get_name()
^^^^^^^^^^^^^^
ValueError: OpennessAccessException: Access to a disposed object of type 'Siemens.Engineering.HW.DeviceItemImpl' is not possible.
TIA Portal has either been disposed or stopped running.
ValueError: RemotingException: El objeto '/bd68de4c_3307_463d_b3ce_57a1378b3bde/lnycb9uriadrpgmom_mjdspm_249.rem' se desconectó o no existe en el servidor.
--- FIN DEL LOG ---

View File

@ -5,5 +5,5 @@
},
"level2": {},
"level3": {},
"working_directory": "D:\\Trabajo\\VM\\22 - 93841 - Sidel - Tilting\\Reporte\\TiaExports"
"working_directory": "D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source"
}

View File

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

View File

@ -1,7 +1,6 @@
{
"path": "D:\\Trabajo\\VM\\22 - 93841 - Sidel - Tilting\\Reporte\\TiaExports",
"path": "D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
"history": [
"D:\\Trabajo\\VM\\22 - 93841 - Sidel - Tilting\\Reporte\\TiaExports",
"D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourcdSD",
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML"

View File

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

View File

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

View File

@ -1,81 +0,0 @@
{
"block_name": "FC General Lamp",
"block_number": 172,
"language": "LAD",
"block_type": "FC",
"block_comment": "",
"interface": {
"Return": [
{
"name": "Ret_Val",
"datatype": "Void",
"remanence": "NonRetain",
"accessibility": "Public",
"start_value": null,
"comment": null,
"children": [],
"array_elements": {}
}
]
},
"networks": [
{
"id": "4",
"title": "Lamp Alarm - Q.E. - Light Green",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "B",
"title": "Lamp Alarm - Q.E. - Light Red",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "12",
"title": "Lamp Alarm - Q.E. - Buzzer",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "19",
"title": "Lamp Alarm - Q.E. - Light Blue",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "20",
"title": "Lamp - Alarm Presence",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "27",
"title": "Light Signal Phased Stop Machine",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "2E",
"title": "",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
}
],
"source_xml_mod_time": 1749751920.2702959,
"source_xml_size": 39346
}

View File

@ -1,81 +0,0 @@
{
"block_name": "FC General Lamp",
"block_number": 172,
"language": "LAD",
"block_type": "FC",
"block_comment": "",
"interface": {
"Return": [
{
"name": "Ret_Val",
"datatype": "Void",
"remanence": "NonRetain",
"accessibility": "Public",
"start_value": null,
"comment": null,
"children": [],
"array_elements": {}
}
]
},
"networks": [
{
"id": "4",
"title": "Lamp Alarm - Q.E. - Light Green",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "B",
"title": "Lamp Alarm - Q.E. - Light Red",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "12",
"title": "Lamp Alarm - Q.E. - Buzzer",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "19",
"title": "Lamp Alarm - Q.E. - Light Blue",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "20",
"title": "Lamp - Alarm Presence",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "27",
"title": "Light Signal Phased Stop Machine",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
},
{
"id": "2E",
"title": "",
"comment": "",
"language": "LAD",
"logic": [],
"error": "FlgNet not found inside NetworkSource or CompileUnit"
}
],
"source_xml_mod_time": 1749751920.2702959,
"source_xml_size": 39346
}

View File

@ -1,455 +0,0 @@
// Block Type: FC
// Block Name (Original): FC Ttop Motor M31010
// Block Number: 327
// Original Network Languages: LAD, SCL
FUNCTION "FC_Ttop_Motor_M31010" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INOUT
Motor : STRUCT
RCP_Speed_Fix_01 : Int;
RCP_Speed_Fix_02 : Int;
RCP_Speed_Fix_03 : Int;
RCP_Speed_Fix_04 : Int;
RCP_Speed_Fix_05 : Int;
RCP_Speed_Sync_01 : Int;
RCP_Speed_Sync_02 : Int;
RCP_Speed_Sync_03 : Int;
RCP_Speed_Sync_04 : Int;
RCP_Speed_Sync_05 : Int;
RCP_Timer_01 : Int;
RCP_Timer_02 : Int;
RCP_Timer_03 : Int;
RCP_Timer_04 : Int;
RCP_Timer_05 : Int;
RCP_Speed_Fix_01_mBar : Int;
RCP_Speed_Fix_02_mBar : Int;
RCP_Speed_Fix_03_mBar : Int;
RCP_Speed_Fix_04_mBar : Int;
RCP_Speed_Fix_05_mBar : Int;
RCP_ACC_Ramp : Int;
RCP_DEC_Ramp : Int;
RCP_W044 : Int;
RCP_W046 : Int;
RCP_W048 : Int;
CFG_VFD : Bool;
CFG_DP : Bool;
CFG_Analog_Speed : Bool;
CFG_EN_BWD : Bool;
CFG_Reverse : Bool;
CFG_Motor_N_Sel : Bool;
CFG_PN : Bool;
CFG_X050_7 : Bool;
CFG_TH_CTR_Single : Bool;
CFG_SW_CTR_Single : Bool;
CFG_TRIP_CTR_Single : Bool;
CFG_Speed_User : Bool;
CFG_mBar : Bool;
CFG_SW_CTR_OnOff : Bool;
CFG_Plug_CTR_Single : Bool;
CFG_X051_7 : Bool;
CFG_Min_Speed_Hz : Int;
CFG_Max_Speed_Hz : Int;
CFG_mBar_Type : Byte;
CFG_B57 : Byte;
CFG_Max_mBar : Int;
CFG_EOLO_Zone : Bool;
CFG_TableTop_Zone : Bool;
CFG_Pack_Zone : Bool;
CFG_VIS_Sp_User_Step200 : Bool;
CFG_X060_4 : Bool;
CFG_X060_5 : Bool;
CFG_X060_6 : Bool;
CFG_X060_7 : Bool;
CFG_MPrew : Int;
CFG_MNext : Int;
CFG_DBExternal1 : Int;
CFG_DBExternal2 : Int;
CFG_Vis_Fix_00 : Bool;
CFG_VIS_Fix_01 : Bool;
CFG_VIS_Fix_02 : Bool;
CFG_VIS_Fix_03 : Bool;
CFG_VIS_Fix_04 : Bool;
CFG_VIS_Fix_05 : Bool;
CFG_VIS_Fix_06 : Bool;
CFG_VIS_Fix_07 : Bool;
CFG_VIS_Sync_00 : Bool;
CFG_VIS_Sync_01 : Bool;
CFG_VIS_Sync_02 : Bool;
CFG_VIS_Sync_03 : Bool;
CFG_VIS_Sync_04 : Bool;
CFG_VIS_Sync_05 : Bool;
CFG_VIS_Sync_06 : Bool;
CFG_VIS_Sync_07 : Bool;
CFG_VIS_Timer_00 : Bool;
CFG_VIS_Timer_01 : Bool;
CFG_VIS_Timer_02 : Bool;
CFG_VIS_Timer_03 : Bool;
CFG_VIS_Timer_04 : Bool;
CFG_VIS_Timer_05 : Bool;
CFG_VIS_Timer_06 : Bool;
CFG_VIS_Timer_07 : Bool;
CFG_VIS_SA : Bool;
CFG_VIS_SB : Bool;
CFG_VIS_SC : Bool;
CFG_VIS_SD : Bool;
CFG_VIS_BA : Bool;
CFG_VIS_BB : Bool;
CFG_VIS_EXTA : Bool;
CFG_VIS_EXTB : Bool;
CFG_VIS_SW : Bool;
CFG_VIS_TH : Bool;
CFG_VIS_TRIP : Bool;
CFG_VIS_PAW : Bool;
CFG_VIS_RUN_FWD : Bool;
CFG_VIS_RUN_BWD : Bool;
CFG_VIS_Kspeed : Bool;
CFG_VIS_PLUG : Bool;
CFG_VIS_PB_Auto : Bool;
CFG_VIS_PB_Man : Bool;
CFG_VIS_PB_Jog : Bool;
CFG_VIS_PB_Stop : Bool;
CFG_VIS_PB_Reverse : Bool;
CFG_VIS_PB_sp_05 : Bool;
CFG_VIS_PB_sp_06 : Bool;
CFG_VIS_ManSpeed : Bool;
CFG_VIS_ACT_Torque : Bool;
CFG_VIS_ACC_Ramp : Bool;
CFG_VIS_DEC_Ramp : Bool;
CFG_VIS_X76_3 : Bool;
CFG_VIS_X76_4 : Bool;
CFG_VIS_X76_5 : Bool;
CFG_VIS_X76_6 : Bool;
CFG_VIS_X76 : Bool;
CFG_B77 : Byte;
CFG_W078 : Int;
CFG_Add_Signal_SA : UInt;
CFG_Add_Signal_SB : UInt;
CFG_Add_Signal_SC : UInt;
CFG_Add_Signal_SD : UInt;
CFG_Add_Signal_BA : UInt;
CFG_Add_Signal_BB : UInt;
CFG_Add_Signal_EXTA : UInt;
CFG_Add_Signal_EXTB : UInt;
CFG_Add_Signal_SW : UInt;
CFG_Add_Signal_TH : UInt;
CFG_Add_Signal_TRIP : UInt;
CFG_Add_Signal_PAW : Int;
CFG_Add_Signal_RUN_FWD : UInt;
CFG_Add_Signal_RUN_BWD : UInt;
CFG_Add_Signal_mBar : Int;
CFG_Add_Signal_PLUG : Int;
CFG_Add_Signal_SP02 : Int;
CFG_DB_Machine : Int;
CFG_DB_NextMotor : Int;
CFG_W118 : Int;
CFG_Stop_Empty : Bool;
CFG_Stop_Full : Bool;
CFG_Stop_STBY : Bool;
CFG_Pressurization : Bool;
CFG_EOLO_Press_Speed : Int;
Spare_124 : Array[124..145] of Byte;
CFG_Motor_N : DInt;
CFG_Phylosopy_N : Int;
CFG_Motor_HW_IO : "HW_IO";
CFG_Node_N : Int;
CFG_Inverter_Type : Int;
CFG_W158 : Int;
CFG_Kspeed_User50Hz : Int;
CFG_Min_Speed_User : Int;
CFG_Max_Speed_User : Int;
CFG_W166 : Int;
CFG_W168 : Int;
CFG_EN_mBar_FCT : Bool;
CFG_EN_mBar_FilterALM : Bool;
CFG_Isteresi_mBar : Int;
CFG_Gain_Mbar : Int;
CFG_Max_Speed_FilterALM : Int;
CFG_W178 : Int;
CFG_T_Gain : STRUCT
S : Bool;
Q : Bool;
TW : Int;
ST : Int;
ACT : Int;
W008 : Int;
END_STRUCT;
CFG_T_FilterALM : STRUCT
S : Bool;
Q : Bool;
TW : Int;
ST : Int;
ACT : Int;
W008 : Int;
END_STRUCT;
IN_PB_Start : Bool;
IN_PB_Stop : Bool;
IN_PB_Reset : Bool;
IN_PB_Silence : Bool;
IN_X200_4 : Bool;
IN_X200_5 : Bool;
IN_X200_6 : Bool;
IN_X200_7 : Bool;
IN_KG_PowerON : Bool;
IN_SW_ManAuto : Bool;
IN_Cycle_ON : Bool;
IN_X201_3 : Bool;
IN_X201_4 : Bool;
IN_X201_5 : Bool;
IN_X201_6 : Bool;
IN_X201_7 : Bool;
IN_SW_HMI_Auto : Bool;
IN_SW_HMI_Man : Bool;
IN_SW_HMI_Jog : Bool;
IN_SW_HMI_Stop : Bool;
IN_SW_HMI_Reverse : Bool;
IN_SW_HMI_sp_05 : Bool;
IN_SW_HMI_sp_06 : Bool;
IN_SW_HMI_ManSpeed : Bool;
IN_SW_HMI_sp_08 : Bool;
IN_SW_HMI_VVFix1 : Bool;
IN_SW_HMI_VVFix2 : Bool;
IN_SW_HMI_VVFix3 : Bool;
IN_SW_HMI_VVFix4 : Bool;
IN_SW_HMI_VVFix5 : Bool;
IN_SW_HMI_sp_14 : Bool;
IN_SW_HMI_sp_15 : Bool;
IN_HMI_ManSpeed : Int;
IN_Signal_SA : Bool;
IN_Signal_SB : Bool;
IN_Signal_SC : Bool;
IN_Signal_SD : Bool;
IN_Signal_BA : Bool;
IN_Signal_BB : Bool;
IN_Signal_EXTA : Bool;
IN_Signal_EXTB : Bool;
IN_Signal_SW : Bool;
IN_Signal_TH : Bool;
IN_Signal_TRIP : Bool;
IN_Signal_RUN_FWD : Bool;
IN_Signal_RUN_BWD : Bool;
IN_Signal_sp_05 : Bool;
IN_Signal_sp_06 : Bool;
IN_Signal_PLUG : Bool;
IN_Signal_sp_08 : Int;
IN_Signal_PEW_mBar : Int;
IN_Signal_mBar : Int;
IN_Motor_DI : "Struct";
IN_W216 : Int;
IN_W218 : Int;
IN_Line_Empty : Bool;
IN_Line_Full : Bool;
IN_Line_StandBy : Bool;
Spare_222 : Array[222..249] of Byte;
OUT_VFD_Run_FWD : Bool;
OUT_VFD_Run_BWD : Bool;
OUT_VFD_Reverse : Bool;
OUT_VFD_Qstop : Bool;
OUT_VFD_Reset : Bool;
OUT_X250_5 : Bool;
OUT_X250_6 : Bool;
OUT_EnergySavingON : Bool;
OUT_VFD_REQ_Speed_Hz : Int;
OUT_VFD_REQ_Speed_User : Int;
OUT_VFD_ACT_Sync_Speed : Int;
OUT_VFD_REQ_Speed_mBar : Int;
OUT_Motor_DO : "Struct";
OUT_W262 : Int;
OUT_W264 : Int;
OUT_W266 : Int;
OUT_W268 : Int;
STATUS_VFD_Run_FWD : Bool;
STATUS_VFD_Run_BWD : Bool;
STATUS_VFD_Trip : Bool;
STATUS_VFD_Warning : Bool;
STATUS_Ready : Bool;
STATUS_VFD_Ready : Bool;
STATUS_VFD_Coasting : Bool;
STATUS_X270_7 : Bool;
STATUS_VFD_ACT_Speed_Hz : Int;
STATUS_VFD_ACT_Speed_Use : Int;
STATUS_VFD_ACT_Torque : Int;
STATUS_MainFault_MovigearADV : Byte;
STATUS_Subfault_MovigearADV : Byte;
STATUS_W280 : Int;
STATUS_W282 : Int;
STATUS_PWR_OFF : Bool;
STATUS_CYCLE_OFF : Bool;
STATUS_ALARM : Bool;
STATUS_AUTO : Bool;
STATUS_MAN : Bool;
STATUS_JOG : Bool;
STATUS_STOP : Bool;
STATUS_X284_7 : Bool;
STATUS_X285_0 : Bool;
STATUS_X285_1 : Bool;
STATUS_X285_2 : Bool;
STATUS_X285_3 : Bool;
STATUS_X285_4 : Bool;
STATUS_X285_5 : Bool;
STATUS_X285_6 : Bool;
STATUS_X285_7 : Bool;
STATUS_NOTRUN : Bool;
STATUS_RUN : Bool;
STATUS_X286_2 : Bool;
STATUS_X286_3 : Bool;
STATUS_X286_4 : Bool;
STATUS_X286_5 : Bool;
STATUS_X286_6 : Bool;
STATUS_X286_7 : Bool;
Spare_288 : Array[288..289] of Byte;
Alarm_09 : Bool;
Alarm_10 : Bool;
Alarm_11 : Bool;
Alarm_12 : Bool;
Alarm_13 : Bool;
Alarm_14 : Bool;
Alarm_15 : Bool;
Alarm_16 : Bool;
Alarm_01 : Bool;
Alarm_02 : Bool;
Alarm_03 : Bool;
Alarm_04 : Bool;
Alarm_05 : Bool;
Alarm_06 : Bool;
Alarm_07 : Bool;
Alarm_08 : Bool;
Spare_292 : Array[292..299] of Byte;
M_Power_ON : Bool;
M_Cycle_ON_AUTO : Bool;
M_Cycle_ON_MAN : Bool;
M_W302 : Int;
M_W304 : Int;
M_W306 : Int;
M_W308 : Int;
M_Delay_Cycle_ON_Auto : STRUCT
S : Bool;
Q : Bool;
TW : Int;
ST : Int;
ACT : Int;
W008 : Int;
END_STRUCT;
Spare_320 : Array[320..349] of Byte;
REQ_EN_Run : Bool;
REQ_Start_FWD : Bool;
REQ_Start_BWD : Bool;
REQ_QStop : Bool;
REQ_X350_4 : Bool;
REQ_X350_5 : Bool;
REQ_X350_6 : Bool;
REQ_X350_7 : Bool;
REQ_X351_0 : Bool;
REQ_X351_1 : Bool;
REQ_X351_2 : Bool;
REQ_X351_3 : Bool;
REQ_X351_4 : Bool;
REQ_X351_5 : Bool;
REQ_X351_6 : Bool;
REQ_X351_7 : Bool;
REQ_W352 : Int;
REQ_Master_Speed_Sync : Int;
REQ_W356 : Int;
REQ_Speed_Fix_00_NU : Bool;
REQ_Speed_Fix_01 : Bool;
REQ_Speed_Fix_02 : Bool;
REQ_Speed_Fix_03 : Bool;
REQ_Speed_Fix_04 : Bool;
REQ_Speed_Fix_05 : Bool;
REQ_Speed_Fix_06_NU : Bool;
REQ_Speed_Fix_07_NU : Bool;
REQ_Speed_Sync_00_NU : Bool;
REQ_Speed_Sync_01 : Bool;
REQ_Speed_Sync_02 : Bool;
REQ_Speed_Sync_03 : Bool;
REQ_Speed_Sync_04 : Bool;
REQ_Speed_Sync_05 : Bool;
REQ_Speed_Sync_06_NU : Bool;
REQ_Speed_Sync_07_NU : Bool;
REQ_T01 : STRUCT
S : Bool;
Q : Bool;
TW : Int;
ST : Int;
ACT : Int;
W008 : Int;
END_STRUCT;
REQ_T02 : STRUCT
S : Bool;
Q : Bool;
TW : Int;
ST : Int;
ACT : Int;
W008 : Int;
END_STRUCT;
REQ_T03 : STRUCT
S : Bool;
Q : Bool;
TW : Int;
ST : Int;
ACT : Int;
W008 : Int;
END_STRUCT;
REQ_T04 : STRUCT
S : Bool;
Q : Bool;
TW : Int;
ST : Int;
ACT : Int;
W008 : Int;
END_STRUCT;
REQ_T05 : STRUCT
S : Bool;
Q : Bool;
TW : Int;
ST : Int;
ACT : Int;
W008 : Int;
END_STRUCT;
END_STRUCT;
END_VAR
VAR_TEMP
RetVal : Int;
MotorNumber : Int;
DBNumber : Int;
END_VAR
BEGIN
// Network 1: INIT Configuration (Original Language: SCL)
// SCL extraction failed: StructuredText node not found.
// Network 2: (Original Language: LAD)
// Network 2 has no logic elements.
// Network 3: EN run (Original Language: LAD)
"Motor"."REQ_EN_Run" := "M0.1";
// Network 4: REQ Auto RUN (Original Language: LAD)
"Motor"."REQ_Start_FWD" := TRUE;
// Network 5: Request Speed Fix 01 (Original Language: LAD)
"Motor"."REQ_Speed_Fix_01" := "M0.1";
// Network 6: INIT Configuration (Original Language: SCL)
// SCL extraction failed: StructuredText node not found.
END_FUNCTION

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +0,0 @@
--- Log de Ejecución: x7_clear.py ---
Grupo: XML Parser to SCL
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source
Inicio: 2025-06-13 01:01:10
Fin: 2025-06-13 01:01:11
Duración: 0:00:00.701052
Estado: SUCCESS (Código de Salida: 0)
--- SALIDA ESTÁNDAR (STDOUT) ---
INFO: format_variable_name importado desde generators.generator_utils
=== Limpiando PLC: 98050_PLC ===
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\CONVEYORS\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\CONVEYORS\MiniMotor\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\CONVEYORS\MiniMotor\DBS55_PN_Extend-A\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\CONVEYORS\SICK AG\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\CONVEYORS\TRANSFER\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\ConveyorsBase\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\Library\Motion\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\Library\Motion\Siemens\LCamHdl_Types\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\Library\Motion\Technology\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\Library\SeamlessDivider\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\Library\SeamlessDivider\Technology\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\Machine\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcDataTypes\Machine\Cycle\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcTags\parsing
- Eliminado directorio de parsing: 98050_PLC\PlcTags\Library\Motion\Siemens\LCamHdl_Tags\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\DB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FC\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FC\1-AIR Philosophy\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FC\2-TTOP Philosophy\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FC\3-Motors Manage\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FC\3-Motors Manage\MiniMotor_PN\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FC\3-Motors Manage\MiniMotor_PN\MiniMotor_PN\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FC\HMI\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\FC\MACHINE SIGNALS\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!! SYS !!!\OB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\!!!TRANSFER\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\0 - MAIN\DB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\0 - MAIN\FC\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\0 - MAIN\OB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\Device\DB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\Device\FB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\Device\FC\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\General\DB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\General\FC\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\Motor\DB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\Motor\DB\Minimotor\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\Motor\FC\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\2 - TTOP\Motor\FC\Minimotor\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\4 - LUBE\DB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\4 - LUBE\FB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\1 - CONVEYORS\4 - LUBE\FB\OLD\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\2 - MACHINE\DB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\2 - MACHINE\FB\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\! ConveyorsSTD\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\! ConveyorsSTD\Hmi\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\! ConveyorsSTD\System\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\! ConveyorsSTD\TimeZone\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\AAA_Debug\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\AAA_VirtualMaster\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\ExchangeSignals\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\ExchangeSignals\Loop\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\HMI\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Instances\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Libraries\Generic\Alarms\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Libraries\Motion\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Libraries\Motion\Siemens\LCamHdl_Blocks\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Libraries\Motion\Technology\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Libraries\Motion\Utilities\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Libraries\SeamlessDivider\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Libraries\SeamlessDivider\Technology\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Machine\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Machine\Instances\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\Setup\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\TimingBelt (downstream divider)\parsing
- Eliminado directorio de parsing: 98050_PLC\ProgramBlocks_XML\Divider\TimingBelt (downstream divider)\Instances\parsing
- Eliminado directorio 'scl_output': 98050_PLC\scl_output
- Eliminado directorio 'xref_output': 98050_PLC\xref_output
- Eliminado archivo agregado: 98050_PLC\full_project_representation.md
- Eliminado log: log_98050_PLC.txt
--- Resumen de limpieza ---
Directorios eliminados: 70
Archivos eliminados: 2
Limpieza completada.
--- ERRORES (STDERR) ---
Ninguno
--- FIN DEL LOG ---

View File

@ -61,19 +61,15 @@ def parse_lad_fbd_network(network_element):
network_lang = lang_node_net[0].strip()
# --- Buscar FlgNet ---
# Paso 1: localizar el nodo <NetworkSource> (sin importar namespace)
network_source_node = network_element.xpath(".//*[local-name()='NetworkSource']")
# Buscar NetworkSource y luego FlgNet (ambos usan namespace flg)
network_source_node = network_element.xpath(".//flg:NetworkSource", namespaces=ns)
flgnet = None
if network_source_node:
# Buscar FlgNet dentro del NetworkSource
flgnet_list = network_source_node[0].xpath(".//*[local-name()='FlgNet']")
flgnet_list = network_source_node[0].xpath("./flg:FlgNet", namespaces=ns)
if flgnet_list:
flgnet = flgnet_list[0]
# Paso 2: si no se encontró, intentar buscar FlgNet directamente en el CompileUnit
if flgnet is None:
flgnet_list = network_element.xpath(".//*[local-name()='FlgNet']")
else: # Intentar buscar FlgNet directamente si no hay NetworkSource
flgnet_list = network_element.xpath(".//flg:FlgNet", namespaces=ns)
if flgnet_list:
flgnet = flgnet_list[0]

View File

@ -215,43 +215,32 @@ def parse_scl_network(network_element):
Devuelve un diccionario representando la red para el JSON.
"""
network_id = network_element.get("ID", "UnknownSCL_ID")
network_lang = "SCL" # Sabemos que es SCL
network_lang = "SCL" # Sabemos que es SCL
# --- Obtener título y comentario para coherencia con otros parsers ---
title_elem = network_element.xpath(
"./ObjectList/MultilingualText[@CompositionName='Title']", namespaces=ns
)
network_title = get_multilingual_text(title_elem[0]) if title_elem else f"Network {network_id}"
comment_elem = network_element.xpath(
"./ObjectList/MultilingualText[@CompositionName='Comment']", namespaces=ns
)
network_comment = get_multilingual_text(comment_elem[0]) if comment_elem else ""
# --- Buscar NetworkSource y StructuredText sin depender del namespace ---
network_source_node = network_element.xpath(".//*[local-name()='NetworkSource']")
# Buscar NetworkSource y luego StructuredText
network_source_node = network_element.xpath(".//flg:NetworkSource", namespaces=ns)
structured_text_node = None
if network_source_node:
st_nodes = network_source_node[0].xpath(".//*[local-name()='StructuredText']")
if st_nodes:
structured_text_node = st_nodes[0]
structured_text_node_list = network_source_node[0].xpath("./st:StructuredText", namespaces=ns)
if structured_text_node_list:
structured_text_node = structured_text_node_list[0]
reconstructed_scl = "// SCL extraction failed: StructuredText node not found.\n"
if structured_text_node is not None:
reconstructed_scl = reconstruct_scl_from_tokens(structured_text_node)
# Crear la estructura de datos para la red
parsed_network_data = {
"id": network_id,
"title": network_title,
"comment": network_comment,
"language": network_lang,
"logic": [
"logic": [ # SCL se guarda como un único bloque lógico
{
"instruction_uid": f"SCL_{network_id}",
"type": "RAW_SCL_CHUNK",
"scl": reconstructed_scl,
"instruction_uid": f"SCL_{network_id}", # UID sintético
"type": "RAW_SCL_CHUNK", # Tipo especial para SCL crudo
"scl": reconstructed_scl, # El código SCL reconstruido
}
],
# No añadimos error aquí, reconstruct_scl_from_tokens ya incluye comentarios de error
}
return parsed_network_data

View File

@ -478,74 +478,3 @@ def parse_interface_members(member_elements):
} # Guardar como dict simple si no hay comment
members_data.append(member_info)
return members_data
# --- NUEVA FUNCIÓN: Adaptación dinámica de namespaces ---
def adapt_namespaces(root):
"""Actualiza dinámicamente los valores en el diccionario global `ns` para que
coincidan con los namespaces reales presentes en el XML exportado por TIA.
Debe llamarse después de obtener la raíz (`root = tree.getroot()`). Si en el
XML aparecen nuevas versiones (p.ej. v6) de los URIs, esta función las
detectará y sobreescribirá las entradas correspondientes en `ns`.
"""
if root is None:
return # nada que hacer
detected = {}
# 1) Examinar los namespaces declarados en la raíz (cuando existan)
if hasattr(root, "nsmap") and root.nsmap:
for uri in root.nsmap.values():
if not uri or "siemens.com/automation" not in str(uri):
continue
_assign_uri_to_prefix(str(uri), detected)
# 2) Escaneo rápido por elementos clave si aún no hemos encontrado URIs
# Utilizamos búsquedas sin namespace (local-name) para localizar el primer
# elemento relevante y extraer su URI real.
# helper interno
def find_uri_by_localname(tag_local):
elem = root.xpath(f'//*[local-name()="{tag_local}"]')
if elem:
return etree.QName(elem[0]).namespace
return None
if "flg" not in detected or not detected.get("flg"):
flg_uri = find_uri_by_localname("FlgNet")
if flg_uri:
detected["flg"] = flg_uri
if "st" not in detected or not detected.get("st"):
st_uri = find_uri_by_localname("StructuredText")
if st_uri:
detected["st"] = st_uri
if "stl" not in detected or not detected.get("stl"):
stl_uri = find_uri_by_localname("StatementList")
if stl_uri:
detected["stl"] = stl_uri
if "iface" not in detected or not detected.get("iface"):
iface_uri = find_uri_by_localname("Sections")
if iface_uri and "/Interface/" in iface_uri:
detected["iface"] = iface_uri
if detected:
ns.update(detected)
# --- función auxiliar privada para adapt_namespaces ---
def _assign_uri_to_prefix(uri_str: str, out_dict: dict):
"""Asigna un URI concreto al prefijo adecuado en `out_dict`."""
if "/Interface/" in uri_str:
out_dict["iface"] = uri_str
elif "/NetworkSource/FlgNet/" in uri_str:
out_dict["flg"] = uri_str
elif "/NetworkSource/StructuredText/" in uri_str:
out_dict["st"] = uri_str
elif "/NetworkSource/StatementList/" in uri_str:
out_dict["stl"] = uri_str

View File

@ -15,5 +15,5 @@
"xref_source_subdir": "source"
},
"level3": {},
"working_directory": "D:\\Trabajo\\VM\\22 - 93841 - Sidel - Tilting\\Reporte\\TiaExports"
"working_directory": "D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source"
}

View File

@ -1,6 +1,6 @@
{
"x0_main.py": {
"display_name": "1: Procesar Exportación XML de un proyecto a SCL",
"display_name": "1: Procesar Exportación XML",
"short_description": "LadderToSCL - Conversor de Siemens LAD/FUP XML a SCL",
"long_description": "Este script es el punto de entrada y orquestador principal para el proceso de conversión de archivos XML de Siemens TIA Portal (LAD/FUP) a código SCL y la generación de documentación relacionada.\n\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, nombres de carpetas de salida, etc.).\n2. **Logging:** Inicia un archivo `log.txt` para registrar detalladamente el progreso y los errores.\n3. **Descubrimiento:** Busca recursivamente todos los archivos `.xml` dentro del subdirectorio `PLC` del directorio de trabajo configurado.\n4. **Procesamiento Individual (Pasos x1-x3):**\n * Itera sobre cada archivo XML encontrado.\n * Implementa lógica para **saltar** pasos si el XML no ha cambiado y las salidas ya existen y están actualizadas.\n * Llama a funciones de `x1_to_json.py`, `x2_process.py`, y `x3_generate_scl.py` para convertir XML -> JSON intermedio -> JSON procesado -> archivo SCL/Markdown final.\n5. **Referencias Cruzadas (Paso x4):** Llama a una función de `x4_cross_reference.py` para generar análisis de llamadas, uso de DBs, etc., basándose en los archivos procesados.\n6. **Agregación (Paso x5):** Llama a una función de `x5_aggregate.py` para combinar las salidas SCL/Markdown y las referencias cruzadas en un único archivo Markdown resumen.\n7. **Resumen y Salida:** Registra un resumen final del proceso (éxitos, saltos, fallos) y finaliza con un código de estado (0 para éxito, 1 si hubo errores).\n",
"hidden": false
@ -34,11 +34,5 @@
"short_description": "LadderToSCL - Conversor de Siemens LAD/FUP XML a SCL",
"long_description": "",
"hidden": true
},
"x7_clear.py": {
"display_name": "3: Limpiar archivos json y md",
"short_description": "3: Limpiar archivos json y md generados por (1)",
"long_description": "",
"hidden": false
}
}

View File

@ -1,7 +1,6 @@
{
"path": "D:\\Trabajo\\VM\\22 - 93841 - Sidel - Tilting\\Reporte\\TiaExports",
"path": "D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
"history": [
"D:\\Trabajo\\VM\\22 - 93841 - Sidel - Tilting\\Reporte\\TiaExports",
"D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML",
"C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\IOExport"

View File

@ -158,225 +158,76 @@ def check_skip_status(
return status
# --- FUNCIÓN DE LIMPIEZA (x7) ---------------------------------------------------------------------------
def clear_generated_outputs(plc_dir: str = None) -> bool:
"""Elimina todos los artefactos (JSON, SCL, MD, logs) generados por este script.
Si *plc_dir* es None, se comporta de forma análoga al modo orquestador,
localizando todos los PLCs bajo el *working_directory* configurado y
limpiándolos uno a uno. Devuelve *True* si la operación terminó sin
errores críticos, *False* en caso contrario.
"""
errors_found = False
try:
configs = load_configuration()
working_directory = configs.get("working_directory")
if not working_directory or not os.path.isdir(working_directory):
print("Error: 'working_directory' inválido en la configuración.", file=sys.stderr)
return False
xml_parser_config = configs.get("level2", {})
cfg_scl_output_dirname = xml_parser_config.get("scl_output_dir", "scl_output")
cfg_xref_output_dirname = xml_parser_config.get("xref_output_dir", "xref_output")
cfg_aggregated_filename = xml_parser_config.get("aggregated_filename", "full_project_representation.md")
# Determinar la lista de PLCs a limpiar
if plc_dir is not None:
plc_dirs = [os.path.abspath(plc_dir)]
if not os.path.isdir(plc_dirs[0]):
print(f"Advertencia: El directorio PLC especificado no existe: {plc_dirs[0]}")
return False
else:
plc_dirs = []
for entry in os.listdir(working_directory):
cand_path = os.path.join(working_directory, entry)
if os.path.isdir(cand_path) and glob.glob(os.path.join(cand_path, "**", "*.xml"), recursive=True):
plc_dirs.append(cand_path)
if not plc_dirs:
plc_dirs = [working_directory]
total_dirs_removed = 0
total_files_removed = 0
for plc_path in plc_dirs:
plc_path = os.path.abspath(plc_path)
plc_name_safe = os.path.basename(plc_path.strip(os.sep))
print(f"\n=== Limpiando PLC: {plc_name_safe} ===")
# 1) Eliminar carpetas 'parsing' (y su contenido JSON)
for parsing_dir in glob.glob(os.path.join(plc_path, "**", "parsing"), recursive=True):
if os.path.isdir(parsing_dir):
try:
shutil.rmtree(parsing_dir)
print(f" - Eliminado directorio de parsing: {os.path.relpath(parsing_dir, working_directory)}")
total_dirs_removed += 1
except Exception as e:
print(f" - ERROR al eliminar {parsing_dir}: {e}")
errors_found = True
# 2) Eliminar directorios de salida SCL y XRef
for dirname in [cfg_scl_output_dirname, cfg_xref_output_dirname]:
target_dir = os.path.join(plc_path, dirname)
if os.path.isdir(target_dir):
try:
shutil.rmtree(target_dir)
print(f" - Eliminado directorio '{dirname}': {os.path.relpath(target_dir, working_directory)}")
total_dirs_removed += 1
except Exception as e:
print(f" - ERROR al eliminar {target_dir}: {e}")
errors_found = True
# 3) Eliminar archivo agregado principal
agg_file = os.path.join(plc_path, cfg_aggregated_filename)
if os.path.isfile(agg_file):
try:
os.remove(agg_file)
print(f" - Eliminado archivo agregado: {os.path.relpath(agg_file, working_directory)}")
total_files_removed += 1
except Exception as e:
print(f" - ERROR al eliminar {agg_file}: {e}")
errors_found = True
# 4) Eliminar logs específicos del PLC
script_dir = os.path.dirname(os.path.abspath(__file__))
log_path = os.path.join(script_dir, f"log_{plc_name_safe}.txt")
if os.path.isfile(log_path):
try:
os.remove(log_path)
print(f" - Eliminado log: {os.path.basename(log_path)}")
total_files_removed += 1
except Exception as e:
print(f" - ERROR al eliminar {log_path}: {e}")
errors_found = True
print("\n--- Resumen de limpieza ---")
print(f" Directorios eliminados: {total_dirs_removed}")
print(f" Archivos eliminados: {total_files_removed}")
print(" Limpieza completada." if not errors_found else " Limpieza completada con errores.")
return not errors_found
except Exception as e:
print(f"ERROR inesperado durante la limpieza: {e}", file=sys.stderr)
traceback.print_exc()
return False
# --- FIN FUNCIÓN DE LIMPIEZA -----------------------------------------------------------------------------
# --- Bloque Principal ---
if __name__ == "__main__":
# -------------------------------------------------------------------------
# 1. Analizar argumentos de línea de comandos
# --plc-dir : ruta al PLC a procesar directamente (modo interno)
# Si NO se pasa el flag, el script actuará como "orquestador" detectando
# todos los PLCs bajo el working_directory y lanzándose a sí mismo para
# cada uno de ellos.
# -------------------------------------------------------------------------
arg_parser = argparse.ArgumentParser(description="Convertidor XML→SCL (multi-PLC)")
arg_parser.add_argument("--plc-dir", dest="plc_dir", help="Ruta del PLC a procesar (uso interno).", default=None)
cli_args, _ = arg_parser.parse_known_args()
# Cargar configuración
configs = load_configuration()
working_directory = configs.get("working_directory")
# -------------------------------------------------------------------------
# 2. Si NO se indicó --plc-dir ⇒ modo ORQUESTADOR
# Detecta todos los PLC (subdirectorios con al menos un .xml) y lanza
# este mismo script para cada uno con el flag --plc-dir.
# -------------------------------------------------------------------------
if cli_args.plc_dir is None:
if not working_directory or not os.path.isdir(working_directory):
print("Error: 'working_directory' inválido en la configuración.", file=sys.stderr)
sys.exit(1)
# Detectar PLCs como subdirectorios que contengan al menos un XML
detected_plc_dirs = []
for entry in os.listdir(working_directory):
cand_path = os.path.join(working_directory, entry)
if os.path.isdir(cand_path):
if glob.glob(os.path.join(cand_path, "**", "*.xml"), recursive=True):
detected_plc_dirs.append(cand_path)
# Si no se encontró ningún PLC (quizás el working_directory ya ES el PLC)
if not detected_plc_dirs:
detected_plc_dirs = [working_directory]
# Ejecutar secuencialmente el script para cada PLC
overall_exit_code = 0
for plc_dir in detected_plc_dirs:
print(f"\n=== Lanzando procesamiento para PLC: {os.path.basename(plc_dir)} ===")
ret = subprocess.call([sys.executable, os.path.abspath(__file__), "--plc-dir", plc_dir])
if ret != 0:
overall_exit_code = 1 # Registrar fallo global si algún PLC falla
sys.exit(overall_exit_code)
# -------------------------------------------------------------------------
# 3. Modo INTERNO (se recibió --plc-dir) ⇒ procesar sólo ese PLC
# -------------------------------------------------------------------------
xml_project_dir = os.path.abspath(cli_args.plc_dir)
if not os.path.isdir(xml_project_dir):
print(f"Error: El directorio PLC especificado no existe: {xml_project_dir}", file=sys.stderr)
sys.exit(1)
# Usaremos el nombre del PLC para diferenciar los logs
plc_name_safe = os.path.basename(xml_project_dir.strip(os.sep))
# ---------------------------------------------------------------------
# 3.1 Leer parámetros específicos del grupo para reutilizarlos más abajo
# ---------------------------------------------------------------------
xml_parser_config = configs.get("level2", {})
# <-- NUEVO: Leer parámetros de configuración para x3, x4, x5 -->
# xml_parser_config = configs.get("XML Parser to SCL", {})
cfg_scl_output_dirname = xml_parser_config.get("scl_output_dir", "scl_output")
cfg_xref_output_dirname = xml_parser_config.get("xref_output_dir", "xref_output")
cfg_xref_source_subdir = xml_parser_config.get("xref_source_subdir", "source")
cfg_call_xref_filename = xml_parser_config.get("call_xref_filename", "xref_calls_tree.md")
cfg_db_usage_xref_filename = xml_parser_config.get("db_usage_xref_filename", "xref_db_usage_summary.md")
cfg_plc_tag_xref_filename = xml_parser_config.get("plc_tag_xref_filename", "xref_plc_tags_summary.md")
# Conversión de enteros con control de errores
# Ensure max_call_depth is an integer
try:
cfg_max_call_depth = int(xml_parser_config.get("max_call_depth", 5))
except (ValueError, TypeError):
print("Advertencia: Valor inválido para 'max_call_depth' en la configuración. Usando valor por defecto 5.", file=sys.stderr)
cfg_max_call_depth = 5
# Ensure max_users_list is an integer
try:
cfg_max_users_list = int(xml_parser_config.get("max_users_list", 20))
except (ValueError, TypeError):
print("Advertencia: Valor inválido para 'max_users_list' en la configuración. Usando valor por defecto 20.", file=sys.stderr)
cfg_max_users_list = 20
cfg_aggregated_filename = xml_parser_config.get("aggregated_filename", "full_project_representation.md")
# Generar un nombre de log específico por PLC
log_filename_dynamic = f"log_{plc_name_safe}.txt"
log_filepath = os.path.join(
os.path.dirname(os.path.abspath(__file__)), log_filename_dynamic
)
# <-- FIN NUEVO -->
# Directorio donde se encuentra este script (x0_main.py)
script_dir = os.path.dirname(os.path.abspath(__file__))
# <-- MODIFICADO: Abrir archivo log -->
log_filepath = os.path.join(
os.path.dirname(os.path.abspath(__file__)), LOG_FILENAME
)
with open(
log_filepath, "w", encoding="utf-8"
) as log_f: # Usar 'a' para añadir al log
log_message("=" * 40 + " LOG START " + "=" * 40, log_f)
# --- PARTE 1: BUSCAR ARCHIVOS ---
# Se trabaja exclusivamente dentro del PLC indicado.
# <-- MODIFICADO: Apuntar al subdirectorio 'PLC' dentro del working_directory -->
plc_subdir_name = "PLC" # Nombre estándar del subdirectorio de TIA Portal
xml_project_dir = os.path.join(working_directory, plc_subdir_name)
log_message(
f"Directorio de trabajo base configurado: '{working_directory}'", log_f
)
log_message(
f"Buscando archivos XML recursivamente en: '{xml_project_dir}'", log_f
f"Buscando archivos XML recursivamente en el subdirectorio: '{xml_project_dir}'", log_f
)
# Patrón de búsqueda global para todos los PLC
# Verificar si el directorio PLC existe
if not os.path.isdir(xml_project_dir):
log_message(
f"Error: El subdirectorio '{plc_subdir_name}' no existe dentro de '{working_directory}'. "
f"Se esperaba encontrar la estructura del proyecto TIA Portal en '{xml_project_dir}'.",
log_f,
also_print=False,
)
print(
f"Error: El subdirectorio '{plc_subdir_name}' no existe dentro de '{working_directory}'. "
f"Asegúrese de que la ruta del directorio de trabajo apunte a la carpeta que *contiene* la carpeta '{plc_subdir_name}'.", file=sys.stderr
)
sys.exit(1)
search_pattern = os.path.join(xml_project_dir, "**", "*.xml")
xml_files_found = glob.glob(search_pattern, recursive=True)
if not xml_files_found:
@ -572,7 +423,7 @@ if __name__ == "__main__":
log_message(f"Se encontraron {len(filtered_scl_files)} archivos .scl existentes para copiar:", log_f)
for src_scl_path in filtered_scl_files:
relative_scl_path = os.path.relpath(src_scl_path, xml_project_dir)
dest_scl_path = os.path.join(scl_output_dir, os.path.basename(src_scl_path)) # Copia directa al scl_output del PLC
dest_scl_path = os.path.join(scl_output_dir, os.path.basename(src_scl_path)) # Copy directly into scl_output_dir
# Check if a file with the same name was already generated from XML
if os.path.exists(dest_scl_path):
@ -662,8 +513,7 @@ if __name__ == "__main__":
run_x5 = False
if run_x5:
# El archivo agregado se guarda dentro del PLC para mantener salidas separadas
output_agg_file = os.path.join(xml_project_dir, cfg_aggregated_filename)
output_agg_file = os.path.join(working_directory, cfg_aggregated_filename) # Usar valor de config
log_message(
f"Ejecutando x5 (aggregate_outputs) sobre: {xml_project_dir}, salida agregada en: {output_agg_file}",
log_f
@ -740,7 +590,7 @@ if __name__ == "__main__":
log_message(final_console_message, log_f) # Loguear mensaje final
print(
f"\n{final_console_message} Consulta '{log_filename_dynamic}' para detalles."
f"\n{final_console_message} Consulta '{LOG_FILENAME}' para detalles."
) # Mostrar mensaje en consola
log_message("="*41 + " LOG END " + "="*42, log_f)

View File

@ -25,7 +25,7 @@ from backend.script_utils import load_configuration
# Importar funciones comunes y namespaces desde el nuevo módulo de utils
try:
from parsers.parser_utils import ns, get_multilingual_text, parse_interface_members, adapt_namespaces
from parsers.parser_utils import ns, get_multilingual_text, parse_interface_members
except ImportError as e:
print(
f"Error crítico: No se pudieron importar funciones desde parsers.parser_utils: {e}"
@ -253,11 +253,6 @@ def convert_xml_to_json(xml_filepath, json_filepath):
parser = etree.XMLParser(remove_blank_text=True, recover=True)
tree = etree.parse(xml_filepath, parser)
root = tree.getroot()
# Ajustar namespaces dinámicamente para soportar distintas versiones de TIA
try:
adapt_namespaces(root)
except Exception as e_ns:
print(f"Advertencia: No se pudo adaptar namespaces dinámicamente: {e_ns}")
print("Paso 1: Parseo XML completado.")
result = None

View File

@ -366,18 +366,6 @@ def generate_call_tree_output(call_graph, block_data, base_xref_dir, max_call_de
"""
output_lines = ["# Árbol de Referencias Cruzadas de Llamadas\n"]
output_lines.append(f"(Profundidad máxima: {max_call_depth})\n") # <-- Usar el parámetro
# ------------------------------------------------------------
# Aviso cuando NO se han detectado llamadas entre bloques
# ------------------------------------------------------------
has_any_call = any(len(callees) > 0 for callees in call_graph.values())
if not has_any_call:
output_lines.append(
"\n> ⚠️ Nota: No se detectaron referencias cruzadas de llamadas. "
"Es posible que no existan los archivos '*_XRef.xml' o que aún no "
"se haya ejecutado el análisis de fallback sobre los bloques SCL.\n"
)
root_nodes = sorted( # Encontrar OBs
[
name
@ -658,8 +646,7 @@ def generate_cross_references(
# 2. Construir Grafo de Llamadas desde XML XRef
print("Construyendo grafo de llamadas desde archivos XML XRef...")
call_graph = defaultdict(list) # Usamos lista, no necesitamos contar llamadas múltiples aquí
# Buscar recursivamente en todas las subcarpetas (algunos proyectos guardan los XML en estructuras anidadas)
xref_xml_files = glob.glob(os.path.join(xref_xml_dir, "**", "*_XRef.xml"), recursive=True)
xref_xml_files = glob.glob(os.path.join(xref_xml_dir, "*_XRef.xml"))
if not xref_xml_files:
print(f"ADVERTENCIA: No se encontraron archivos '*_XRef.xml' en {xref_xml_dir}. El árbol de llamadas estará vacío.", file=sys.stderr)
else:

View File

@ -1,39 +0,0 @@
"""x7_clear.py
Script de limpieza para eliminar todos los artefactos generados por x0_main.py.
Este script actúa como envoltorio del método `clear_generated_outputs` definido
en `x0_main.py`. De esta forma, la lógica de eliminación se mantiene en un solo
lugar y se adapta automáticamente a futuros cambios en la estructura de
salidas de x0.
"""
import argparse
import sys
# Importar la función de limpieza desde x0_main.py
from x0_main import clear_generated_outputs # noqa: E402 import absoluto intencional
def main() -> None:
parser = argparse.ArgumentParser(
description="Elimina los archivos generados por x0_main.py (JSON, SCL, MD, logs)."
)
parser.add_argument(
"--plc-dir",
dest="plc_dir",
default=None,
help=(
"Ruta de un PLC específico a limpiar. Si se omite, se limpiarán "
"todos los PLCs detectados bajo el working_directory definido en la configuración."
),
)
args = parser.parse_args()
success = clear_generated_outputs(args.plc_dir)
# Salir con 0 si todo fue bien, 1 en caso de errores
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()

View File

@ -1,18 +1,5 @@
{
"history": [
{
"id": "15176a5f",
"group_id": "1",
"script_name": "calc.py",
"executed_date": "2025-06-13T10:53:37.648203Z",
"arguments": [],
"working_directory": "D:/Proyectos/Scripts/Calcv2",
"python_env": "tia_scripting",
"executable_type": "pythonw.exe",
"status": "running",
"pid": 21072,
"execution_time": null
},
{
"id": "a599effd",
"group_id": "4",

View File

@ -1,129 +1,5 @@
[11:14:30] Iniciando ejecución de x4.py en D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports...
[11:14:30] --- Exportador de Referencias Cruzadas de TIA Portal ---
[11:14:34] Versión de TIA Portal detectada: 19.0 (de la extensión .ap19)
[11:14:34] Proyecto seleccionado: D:/Trabajo/VM/22 - 93841 - Sidel - Tilting/InLavoro/PLC/93841_PLC_28/93841_PLC_28.ap19
[11:14:34] Usando directorio base de exportación: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports
[11:14:34] Conectando a TIA Portal V19.0...
[11:14:34] 2025-06-13 11:14:34,713 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Global OpenPortal - Start TIA Portal, please acknowledge the security dialog.
[11:14:34] 2025-06-13 11:14:34,731 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Global OpenPortal - With user interface
[11:14:58] Conectado a TIA Portal.
[11:14:58] 2025-06-13 11:14:58,165 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal GetProcessId - Process id: 30140
[11:14:58] ID del proceso del Portal: 30140
[11:14:58] Abriendo proyecto: 93841_PLC_28.ap19...
[11:14:58] 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
[11:15:25] Proyecto abierto exitosamente.
[11:15:29] 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
[11:15:30] 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
[11:15:34] Se encontraron 2 PLC(s). Iniciando proceso de exportación de referencias cruzadas...
[11:15:34] --- Procesando PLC: VM 1512 ---
[11:15:34] [PLC: VM 1512] Exportando referencias cruzadas de bloques de programa...
[11:15:34] Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\ProgramBlocks_CR
[11:15:34] Se encontraron 201 bloques de programa.
[11:15:34] Procesando bloque: FC General COM...
[11:15:34] Exportando referencias cruzadas para FC General COM...
[11:15:38] Procesando bloque: From_SIDEL...
[11:15:38] Exportando referencias cruzadas para From_SIDEL...
[11:15:38] Procesando bloque: To_SIDEL...
[11:15:38] Exportando referencias cruzadas para To_SIDEL...
[11:15:38] Procesando bloque: DB Early Restart Blower...
[11:15:38] Exportando referencias cruzadas para DB Early Restart Blower...
[11:15:39] Procesando bloque: DB Early Restart Filler...
[11:15:39] Exportando referencias cruzadas para DB Early Restart Filler...
[11:15:39] Procesando bloque: DB Early Restart SynchroBlock...
[11:15:39] Exportando referencias cruzadas para DB Early Restart SynchroBlock...
[11:15:40] Procesando bloque: FB Early Restart...
[11:15:40] Exportando referencias cruzadas para FB Early Restart...
[11:15:40] Procesando bloque: DB Signal Transport...
[11:15:40] Exportando referencias cruzadas para DB Signal Transport...
[11:15:42] Procesando bloque: FC Signal Transport...
[11:15:42] Exportando referencias cruzadas para FC Signal Transport...
[11:15:43] Procesando bloque: DB Lube - Dry Ecolab...
[11:15:43] Exportando referencias cruzadas para DB Lube - Dry Ecolab...
[11:15:46] Procesando bloque: FB Lube - Water/Dry...
[11:15:46] Exportando referencias cruzadas para FB Lube - Water/Dry...
[11:15:46] Procesando bloque: FB Lube - Dry Ecolab...
[11:15:46] Exportando referencias cruzadas para FB Lube - Dry Ecolab...
[11:15:47] Procesando bloque: FB Lube - EcoLab VM...
[11:15:47] Exportando referencias cruzadas para FB Lube - EcoLab VM...
[11:15:48] Procesando bloque: FB Lube - Ecolab...
[11:15:48] Exportando referencias cruzadas para FB Lube - Ecolab...
[11:15:49] Procesando bloque: DB LUBE - Ecolab...
[11:15:49] Exportando referencias cruzadas para DB LUBE - Ecolab...
[11:15:57] Procesando bloque: FC Ttop Configuration...
[11:15:57] Exportando referencias cruzadas para FC Ttop Configuration...
[11:15:57] Procesando bloque: FC Ttop Run...
[11:15:57] Exportando referencias cruzadas para FC Ttop Run...
[11:15:58] Procesando bloque: FC Ttop Alarms...
[11:15:58] Exportando referencias cruzadas para FC Ttop Alarms...
[11:15:58] Procesando bloque: DB Ttop Run...
[11:15:58] Exportando referencias cruzadas para DB Ttop Run...
[11:15:59] Procesando bloque: DB Ttop Motor CFG...
[11:15:59] Exportando referencias cruzadas para DB Ttop Motor CFG...
[11:16:02] Procesando bloque: DB Ttop Alarm...
[11:16:02] Exportando referencias cruzadas para DB Ttop Alarm...
[11:16:07] Procesando bloque: FC Ttop Motor 31...
[11:16:07] Exportando referencias cruzadas para FC Ttop Motor 31...
[11:16:07] Procesando bloque: FC Ttop Motor 32...
[11:16:07] Exportando referencias cruzadas para FC Ttop Motor 32...
[11:16:07] Procesando bloque: FC Ttop Motor 34...
[11:16:07] Exportando referencias cruzadas para FC Ttop Motor 34...
[11:16:08] Procesando bloque: FC Ttop Motor 35...
[11:16:08] Exportando referencias cruzadas para FC Ttop Motor 35...
[11:16:08] Procesando bloque: FC Ttop Motor 36...
[11:16:08] Exportando referencias cruzadas para FC Ttop Motor 36...
[11:16:08] Procesando bloque: DB Ttop Motor 31...
[11:16:08] Exportando referencias cruzadas para DB Ttop Motor 31...
[11:16:13] Procesando bloque: DB Ttop Motor 32...
[11:16:13] Exportando referencias cruzadas para DB Ttop Motor 32...
[11:16:18] Procesando bloque: DB Ttop Motor 34...
[11:16:18] Exportando referencias cruzadas para DB Ttop Motor 34...
[11:16:23] Procesando bloque: DB Ttop Motor 35...
[11:16:23] Exportando referencias cruzadas para DB Ttop Motor 35...
[11:16:27] Procesando bloque: DB Ttop Minimotor Cfg 32...
[11:16:27] Exportando referencias cruzadas para DB Ttop Minimotor Cfg 32...
[11:16:29] Procesando bloque: DB Ttop Minimotor Data 32...
[11:16:29] Exportando referencias cruzadas para DB Ttop Minimotor Data 32...
[11:16:31] Procesando bloque: DB Ttop Motor 36...
[11:16:31] Exportando referencias cruzadas para DB Ttop Motor 36...
[11:16:35] Procesando bloque: FB Ttop Dryer...
[11:16:35] Exportando referencias cruzadas para FB Ttop Dryer...
[11:16:36] Procesando bloque: FB Ttop Energy Saving...
[11:16:36] Exportando referencias cruzadas para FB Ttop Energy Saving...
[11:16:36] Procesando bloque: FB SKID...
[11:16:36] Exportando referencias cruzadas para FB SKID...
[11:16:36] Procesando bloque: FC Analog Sensor Process...
[11:16:36] Exportando referencias cruzadas para FC Analog Sensor Process...
[11:16:37] Procesando bloque: FC Valve...
[11:16:37] Exportando referencias cruzadas para FC Valve...
[11:16:37] Procesando bloque: FB SpeedRegulation...
[11:16:37] Exportando referencias cruzadas para FB SpeedRegulation...
[11:16:37] Procesando bloque: FC Simple PID...
[11:16:37] Exportando referencias cruzadas para FC Simple PID...
[11:16:38] Procesando bloque: FC Scale Real...
[11:16:38] Exportando referencias cruzadas para FC Scale Real...
[11:16:38] Procesando bloque: FB Correct Speed F/Pulses...
[11:16:38] Exportando referencias cruzadas para FB Correct Speed F/Pulses...
[11:16:43] ERROR GENERAL al exportar referencias cruzadas para el bloque FB Correct Speed F/Pulses: OpennessAccessException: Unexpected exception - no exception message available.
[11:16:43] 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.
[11:16:43] TIA Portal has either been disposed or stopped running.
[11:16:43] [PLC: VM 1512] Exportando referencias cruzadas de tablas de variables...
[11:16:43] Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\PlcTags_CR
[11:16:43] ERROR al acceder a las tablas de variables para exportar referencias cruzadas: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
[11:16:43] [PLC: VM 1512] Exportando referencias cruzadas de tipos de datos PLC (UDTs)...
[11:16:43] Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\PlcDataTypes_CR
[11:16:43] ERROR al acceder a los UDTs para exportar referencias cruzadas: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
[11:16:43] [PLC: VM 1512] Intentando exportar referencias cruzadas de bloques de sistema...
[11:16:43] Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\SystemBlocks_CR
[11:16:43] ERROR al acceder/procesar bloques de sistema para exportar referencias cruzadas: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
[11:16:43] [PLC: VM 1512] Intentando exportar referencias cruzadas de unidades de software...
[11:16:43] Destino: D:\Trabajo\VM\22 - 93841 - Sidel - Tilting\Reporte\TiaExports\VM 1512\SoftwareUnits_CR
[11:16:43] ERROR al acceder/procesar unidades de software para exportar referencias cruzadas: SerializationException: No se puede encontrar el ensamblado 'Siemens.Engineering, Version=19.0.0.0, Culture=neutral, PublicKeyToken=d29ec89bac048f84'.
[11:16:43] --- Finalizado el procesamiento del PLC: VM 1512 ---
[11:16:43] Ocurrió un error inesperado: OpennessAccessException: Access to a disposed object of type 'Siemens.Engineering.HW.DeviceItemImpl' is not possible.
[11:16:43] TIA Portal has either been disposed or stopped running.
[11:16:43] Cerrando TIA Portal...
[11:16:43] 2025-06-13 11:16:43,486 [1] INFO Siemens.TiaPortal.OpennessApi19.Implementations.Portal ClosePortal - Close TIA Portal
[11:16:43] TIA Portal cerrado.
[11:16:43] Script finalizado.
[11:16:43] Ejecución de x4.py finalizada (success). Duración: 0:02:13.165274. Se detectaron errores (ver log).
[11:16:43] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\log_x4.txt
[20:03:36] Iniciando ejecución de x1.py en D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source...
[20:03:37] --- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---
[20:03:47] No project file selected. Exiting.
[20:03:47] Ejecución de x1.py finalizada (success). Duración: 0:00:10.497365.
[20:03:47] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\log_x1.txt

View File

@ -181,17 +181,17 @@
<div class="flex-1 flex gap-2">
<input type="text" id="working-directory" class="flex-1 p-2 border rounded bg-green-50">
<button class="bg-gray-500 text-white px-4 py-2 rounded" onclick="browseDirectory()">
Buscar
Explorar
</button>
<button id="open-in-explorer-btn"
class="bg-indigo-500 hover:bg-indigo-600 text-white px-4 py-2 rounded"
title="Abrir directorio actual en el explorador de archivos">
Abrir Carpeta
</button>
<button class="bg-blue-500 text-white px-4 py-2 rounded" onclick="setWorkingDirectory()">
Salvar
</button>
</div>
</div>
<button class="bg-blue-500 text-white px-4 py-2 rounded" onclick="setWorkingDirectory()">
Confirmar
</button>
</div>
<!-- Add directory history dropdown -->
<div class="mt-2">