Actualización de scripts de exportación y mejora en la gestión de versiones de TIA Portal
- Se modificó el script x1.py para soportar múltiples versiones de TIA Portal (18, 19 y 20) y se mejoró la detección de la versión a partir de la extensión del archivo del proyecto. - Se actualizó la descripción del script en scripts_description.json para reflejar las nuevas versiones soportadas. - Se realizaron ajustes en los logs de ejecución para reflejar las nuevas fechas y duraciones en el script x1. - Se mejoró la gestión de directorios de exportación y se añadieron mensajes en español para una mejor comprensión del proceso de exportación.
This commit is contained in:
parent
be3b333491
commit
04084e7289
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"x1.py": {
|
"x1.py": {
|
||||||
"display_name": "1: Exportar Lógica desde TIA Portal v18 en XML",
|
"display_name": "1: Exportar Lógica desde TIA Portal v18,v19,v20 en XML",
|
||||||
"short_description": "Exporta la lógica del PLC desde TIA Portal en archivos XML y SCL.",
|
"short_description": "Exporta la lógica del PLC desde TIA Portal en archivos XML y SCL.",
|
||||||
"long_description": "Este script utiliza TIA Portal Openness para exportar la lógica de un PLC en formato XML y SCL. Permite seleccionar un proyecto de TIA Portal y genera los archivos de exportación en el directorio configurado.\n***\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, versión de TIA Portal).\n2. **Selección de Proyecto:** Abre un cuadro de diálogo para seleccionar el archivo del proyecto de TIA Portal.\n3. **Conexión a TIA Portal:** Utiliza la API de TIA Openness para conectarse al portal y abrir el proyecto seleccionado.\n4. **Exportación:** Exporta la lógica del PLC en archivos XML y SCL al directorio configurado.\n5. **Cierre:** Cierra la conexión con TIA Portal al finalizar.",
|
"long_description": "Este script utiliza TIA Portal Openness para exportar la lógica de un PLC en formato XML y SCL. Permite seleccionar un proyecto de TIA Portal y genera los archivos de exportación en el directorio configurado.\n***\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, versión de TIA Portal).\n2. **Selección de Proyecto:** Abre un cuadro de diálogo para seleccionar el archivo del proyecto de TIA Portal.\n3. **Conexión a TIA Portal:** Utiliza la API de TIA Openness para conectarse al portal y abrir el proyecto seleccionado.\n4. **Exportación:** Exporta la lógica del PLC en archivos XML y SCL al directorio configurado.\n5. **Cierre:** Cierra la conexión con TIA Portal al finalizar.",
|
||||||
"hidden": false
|
"hidden": false
|
||||||
|
|
|
@ -7,6 +7,7 @@ from tkinter import filedialog
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
from pathlib import Path # Import Path
|
||||||
|
|
||||||
script_root = os.path.dirname(
|
script_root = os.path.dirname(
|
||||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
@ -15,11 +16,15 @@ sys.path.append(script_root)
|
||||||
from backend.script_utils import load_configuration
|
from backend.script_utils import load_configuration
|
||||||
|
|
||||||
# --- Configuration ---
|
# --- Configuration ---
|
||||||
TIA_PORTAL_VERSION = "18.0" # Target TIA Portal version (e.g., "18.0")
|
# Supported TIA Portal versions mapping (extension -> version)
|
||||||
|
SUPPORTED_TIA_VERSIONS = {
|
||||||
|
".ap18": "18.0",
|
||||||
|
".ap19": "19.0",
|
||||||
|
".ap20": "20.0"
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT_OPTIONS = None # Use default export options
|
EXPORT_OPTIONS = None # Use default export options
|
||||||
KEEP_FOLDER_STRUCTURE = (
|
KEEP_FOLDER_STRUCTURE = True # Replicate TIA project folder structure in export directory
|
||||||
True # Replicate TIA project folder structure in export directory
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- TIA Scripting Import Handling ---
|
# --- TIA Scripting Import Handling ---
|
||||||
# Check if the TIA_SCRIPTING environment variable is set
|
# Check if the TIA_SCRIPTING environment variable is set
|
||||||
|
@ -59,6 +64,33 @@ except Exception as e:
|
||||||
|
|
||||||
# --- Functions ---
|
# --- Functions ---
|
||||||
|
|
||||||
|
def get_supported_filetypes():
|
||||||
|
"""Returns the supported file types for TIA Portal projects."""
|
||||||
|
filetypes = []
|
||||||
|
for ext, version in SUPPORTED_TIA_VERSIONS.items():
|
||||||
|
version_major = version.split('.')[0]
|
||||||
|
filetypes.append((f"TIA Portal V{version_major} Projects", f"*{ext}"))
|
||||||
|
|
||||||
|
# Add option to show all supported files
|
||||||
|
all_extensions = " ".join([f"*{ext}" for ext in SUPPORTED_TIA_VERSIONS.keys()])
|
||||||
|
filetypes.insert(0, ("All TIA Portal Projects", all_extensions))
|
||||||
|
|
||||||
|
return filetypes
|
||||||
|
|
||||||
|
def detect_tia_version(project_file_path):
|
||||||
|
"""Detects TIA Portal version based on file extension."""
|
||||||
|
file_path = Path(project_file_path)
|
||||||
|
file_extension = file_path.suffix.lower()
|
||||||
|
|
||||||
|
if file_extension in SUPPORTED_TIA_VERSIONS:
|
||||||
|
detected_version = SUPPORTED_TIA_VERSIONS[file_extension]
|
||||||
|
print(f"Versión de TIA Portal detectada: {detected_version} (de la extensión {file_extension})")
|
||||||
|
return detected_version
|
||||||
|
else:
|
||||||
|
print(f"ADVERTENCIA: Extensión de archivo no reconocida '{file_extension}'. Extensiones soportadas: {list(SUPPORTED_TIA_VERSIONS.keys())}")
|
||||||
|
# Default to version 18.0 for backward compatibility
|
||||||
|
print("Usando por defecto TIA Portal V18.0")
|
||||||
|
return "18.0"
|
||||||
|
|
||||||
def select_project_file():
|
def select_project_file():
|
||||||
"""Opens a dialog to select a TIA Portal project file."""
|
"""Opens a dialog to select a TIA Portal project file."""
|
||||||
|
@ -66,16 +98,11 @@ def select_project_file():
|
||||||
root.withdraw() # Hide the main tkinter window
|
root.withdraw() # Hide the main tkinter window
|
||||||
file_path = filedialog.askopenfilename(
|
file_path = filedialog.askopenfilename(
|
||||||
title="Select TIA Portal Project File",
|
title="Select TIA Portal Project File",
|
||||||
filetypes=[
|
filetypes=get_supported_filetypes()
|
||||||
(
|
|
||||||
f"TIA Portal V{TIA_PORTAL_VERSION} Projects",
|
|
||||||
f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}",
|
|
||||||
)
|
|
||||||
], # e.g. *.ap18
|
|
||||||
)
|
)
|
||||||
root.destroy()
|
root.destroy()
|
||||||
if not file_path:
|
if not file_path:
|
||||||
print("No project file selected. Exiting.")
|
print("No se seleccionó ningún archivo de proyecto. Saliendo.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
@ -95,7 +122,7 @@ def select_export_directory():
|
||||||
def export_plc_data(plc, export_base_dir):
|
def export_plc_data(plc, export_base_dir):
|
||||||
"""Exports Blocks, UDTs, and Tag Tables from a given PLC."""
|
"""Exports Blocks, UDTs, and Tag Tables from a given PLC."""
|
||||||
plc_name = plc.get_name()
|
plc_name = plc.get_name()
|
||||||
print(f"\n--- Processing PLC: {plc_name} ---")
|
print(f"\n--- Procesando PLC: {plc_name} ---")
|
||||||
|
|
||||||
# Define base export path for this PLC
|
# Define base export path for this PLC
|
||||||
plc_export_dir = os.path.join(export_base_dir, plc_name)
|
plc_export_dir = os.path.join(export_base_dir, plc_name)
|
||||||
|
@ -104,143 +131,140 @@ def export_plc_data(plc, export_base_dir):
|
||||||
# --- Export Program Blocks ---
|
# --- Export Program Blocks ---
|
||||||
blocks_exported = 0
|
blocks_exported = 0
|
||||||
blocks_skipped = 0
|
blocks_skipped = 0
|
||||||
print(f"\n[PLC: {plc_name}] Exporting Program Blocks...")
|
print(f"\n[PLC: {plc_name}] Exportando bloques de programa...")
|
||||||
xml_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_XML")
|
xml_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_XML")
|
||||||
scl_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_SCL")
|
scl_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_SCL")
|
||||||
os.makedirs(xml_blocks_path, exist_ok=True)
|
os.makedirs(xml_blocks_path, exist_ok=True)
|
||||||
os.makedirs(scl_blocks_path, exist_ok=True)
|
os.makedirs(scl_blocks_path, exist_ok=True)
|
||||||
print(f" XML Target: {xml_blocks_path}")
|
print(f" Destino XML: {xml_blocks_path}")
|
||||||
print(f" SCL Target: {scl_blocks_path}")
|
print(f" Destino SCL: {scl_blocks_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
program_blocks = plc.get_program_blocks() #
|
program_blocks = plc.get_program_blocks()
|
||||||
print(f" Found {len(program_blocks)} program blocks.")
|
print(f" Se encontraron {len(program_blocks)} bloques de programa.")
|
||||||
for block in program_blocks:
|
for block in program_blocks:
|
||||||
block_name = block.get_name() # Assuming get_name() exists
|
block_name = block.get_name()
|
||||||
print(f" Processing block: {block_name}...")
|
print(f" Procesando bloque: {block_name}...")
|
||||||
try:
|
try:
|
||||||
if not block.is_consistent(): #
|
if not block.is_consistent():
|
||||||
print(f" Compiling block {block_name}...")
|
print(f" Compilando bloque {block_name}...")
|
||||||
block.compile() #
|
block.compile()
|
||||||
if not block.is_consistent():
|
if not block.is_consistent():
|
||||||
print(
|
print(
|
||||||
f" WARNING: Block {block_name} inconsistent after compile. Skipping."
|
f" ADVERTENCIA: Bloque {block_name} inconsistente después de compilar. Omitiendo."
|
||||||
)
|
)
|
||||||
blocks_skipped += 1
|
blocks_skipped += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f" Exporting {block_name} as XML...")
|
print(f" Exportando {block_name} como XML...")
|
||||||
block.export(
|
block.export(
|
||||||
target_directory_path=xml_blocks_path, #
|
target_directory_path=xml_blocks_path,
|
||||||
export_options=EXPORT_OPTIONS, #
|
export_options=EXPORT_OPTIONS,
|
||||||
export_format=ts.Enums.ExportFormats.SimaticML, #
|
export_format=ts.Enums.ExportFormats.SimaticML,
|
||||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
) #
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
prog_language = block.get_property(name="ProgrammingLanguage")
|
prog_language = block.get_property(name="ProgrammingLanguage")
|
||||||
if prog_language == "SCL":
|
if prog_language == "SCL":
|
||||||
print(f" Exporting {block_name} as SCL...")
|
print(f" Exportando {block_name} como SCL...")
|
||||||
block.export(
|
block.export(
|
||||||
target_directory_path=scl_blocks_path,
|
target_directory_path=scl_blocks_path,
|
||||||
export_options=EXPORT_OPTIONS,
|
export_options=EXPORT_OPTIONS,
|
||||||
export_format=ts.Enums.ExportFormats.ExternalSource, #
|
export_format=ts.Enums.ExportFormats.ExternalSource,
|
||||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
)
|
)
|
||||||
except Exception as prop_ex:
|
except Exception as prop_ex:
|
||||||
print(
|
print(
|
||||||
f" Could not get ProgrammingLanguage for {block_name}. Skipping SCL. Error: {prop_ex}"
|
f" No se pudo obtener el lenguaje de programación para {block_name}. Omitiendo SCL. Error: {prop_ex}"
|
||||||
)
|
)
|
||||||
|
|
||||||
blocks_exported += 1
|
blocks_exported += 1
|
||||||
except Exception as block_ex:
|
except Exception as block_ex:
|
||||||
print(f" ERROR exporting block {block_name}: {block_ex}")
|
print(f" ERROR exportando bloque {block_name}: {block_ex}")
|
||||||
blocks_skipped += 1
|
blocks_skipped += 1
|
||||||
print(
|
print(
|
||||||
f" Program Blocks Export Summary: Exported={blocks_exported}, Skipped/Errors={blocks_skipped}"
|
f" Resumen de exportación de bloques: Exportados={blocks_exported}, Omitidos/Errores={blocks_skipped}"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR processing Program Blocks: {e}")
|
print(f" ERROR procesando bloques de programa: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
# --- Export PLC Data Types (UDTs) ---
|
# --- Export PLC Data Types (UDTs) ---
|
||||||
udts_exported = 0
|
udts_exported = 0
|
||||||
udts_skipped = 0
|
udts_skipped = 0
|
||||||
print(f"\n[PLC: {plc_name}] Exporting PLC Data Types (UDTs)...")
|
print(f"\n[PLC: {plc_name}] Exportando tipos de datos PLC (UDTs)...")
|
||||||
udt_export_path = os.path.join(plc_export_dir, "PlcDataTypes")
|
udt_export_path = os.path.join(plc_export_dir, "PlcDataTypes")
|
||||||
os.makedirs(udt_export_path, exist_ok=True)
|
os.makedirs(udt_export_path, exist_ok=True)
|
||||||
print(f" Target: {udt_export_path}")
|
print(f" Destino: {udt_export_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
udts = plc.get_user_data_types() #
|
udts = plc.get_user_data_types()
|
||||||
print(f" Found {len(udts)} UDTs.")
|
print(f" Se encontraron {len(udts)} UDTs.")
|
||||||
for udt in udts:
|
for udt in udts:
|
||||||
udt_name = udt.get_name() #
|
udt_name = udt.get_name()
|
||||||
print(f" Processing UDT: {udt_name}...")
|
print(f" Procesando UDT: {udt_name}...")
|
||||||
try:
|
try:
|
||||||
if not udt.is_consistent(): #
|
if not udt.is_consistent():
|
||||||
print(f" Compiling UDT {udt_name}...")
|
print(f" Compilando UDT {udt_name}...")
|
||||||
udt.compile() #
|
udt.compile()
|
||||||
if not udt.is_consistent():
|
if not udt.is_consistent():
|
||||||
print(
|
print(
|
||||||
f" WARNING: UDT {udt_name} inconsistent after compile. Skipping."
|
f" ADVERTENCIA: UDT {udt_name} inconsistente después de compilar. Omitiendo."
|
||||||
)
|
)
|
||||||
udts_skipped += 1
|
udts_skipped += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f" Exporting {udt_name}...")
|
print(f" Exportando {udt_name}...")
|
||||||
udt.export(
|
udt.export(
|
||||||
target_directory_path=udt_export_path, #
|
target_directory_path=udt_export_path,
|
||||||
export_options=EXPORT_OPTIONS, #
|
export_options=EXPORT_OPTIONS,
|
||||||
# export_format defaults to SimaticML for UDTs
|
|
||||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
) #
|
)
|
||||||
udts_exported += 1
|
udts_exported += 1
|
||||||
except Exception as udt_ex:
|
except Exception as udt_ex:
|
||||||
print(f" ERROR exporting UDT {udt_name}: {udt_ex}")
|
print(f" ERROR exportando UDT {udt_name}: {udt_ex}")
|
||||||
udts_skipped += 1
|
udts_skipped += 1
|
||||||
print(
|
print(
|
||||||
f" UDT Export Summary: Exported={udts_exported}, Skipped/Errors={udts_skipped}"
|
f" Resumen de exportación de UDTs: Exportados={udts_exported}, Omitidos/Errores={udts_skipped}"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR processing UDTs: {e}")
|
print(f" ERROR procesando UDTs: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
# --- Export PLC Tag Tables ---
|
# --- Export PLC Tag Tables ---
|
||||||
tags_exported = 0
|
tags_exported = 0
|
||||||
tags_skipped = 0
|
tags_skipped = 0
|
||||||
print(f"\n[PLC: {plc_name}] Exporting PLC Tag Tables...")
|
print(f"\n[PLC: {plc_name}] Exportando tablas de variables PLC...")
|
||||||
tags_export_path = os.path.join(plc_export_dir, "PlcTags")
|
tags_export_path = os.path.join(plc_export_dir, "PlcTags")
|
||||||
os.makedirs(tags_export_path, exist_ok=True)
|
os.makedirs(tags_export_path, exist_ok=True)
|
||||||
print(f" Target: {tags_export_path}")
|
print(f" Destino: {tags_export_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tag_tables = plc.get_plc_tag_tables() #
|
tag_tables = plc.get_plc_tag_tables()
|
||||||
print(f" Found {len(tag_tables)} Tag Tables.")
|
print(f" Se encontraron {len(tag_tables)} tablas de variables.")
|
||||||
for table in tag_tables:
|
for table in tag_tables:
|
||||||
table_name = table.get_name() #
|
table_name = table.get_name()
|
||||||
print(f" Processing Tag Table: {table_name}...")
|
print(f" Procesando tabla de variables: {table_name}...")
|
||||||
try:
|
try:
|
||||||
# Note: Consistency check might not be available/needed for tag tables like blocks/UDTs
|
print(f" Exportando {table_name}...")
|
||||||
print(f" Exporting {table_name}...")
|
|
||||||
table.export(
|
table.export(
|
||||||
target_directory_path=tags_export_path, #
|
target_directory_path=tags_export_path,
|
||||||
export_options=EXPORT_OPTIONS, #
|
export_options=EXPORT_OPTIONS,
|
||||||
# export_format defaults to SimaticML for Tag Tables
|
|
||||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
) #
|
)
|
||||||
tags_exported += 1
|
tags_exported += 1
|
||||||
except Exception as table_ex:
|
except Exception as table_ex:
|
||||||
print(f" ERROR exporting Tag Table {table_name}: {table_ex}")
|
print(f" ERROR exportando tabla de variables {table_name}: {table_ex}")
|
||||||
tags_skipped += 1
|
tags_skipped += 1
|
||||||
print(
|
print(
|
||||||
f" Tag Table Export Summary: Exported={tags_exported}, Skipped/Errors={tags_skipped}"
|
f" Resumen de exportación de tablas de variables: Exportados={tags_exported}, Omitidos/Errores={tags_skipped}"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR processing Tag Tables: {e}")
|
print(f" ERROR procesando tablas de variables: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
print(f"\n--- Finished processing PLC: {plc_name} ---")
|
print(f"\n--- Finalizado el procesamiento del PLC: {plc_name} ---")
|
||||||
|
|
||||||
|
|
||||||
# --- Main Script ---
|
# --- Main Script ---
|
||||||
|
@ -250,75 +274,76 @@ if __name__ == "__main__":
|
||||||
configs = load_configuration()
|
configs = load_configuration()
|
||||||
working_directory = configs.get("working_directory")
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
print("--- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---")
|
print("--- Exportador de datos TIA Portal (Bloques, UDTs, Variables) ---")
|
||||||
|
|
||||||
# Validate working directory
|
# Validate working directory
|
||||||
if not working_directory or not os.path.isdir(working_directory):
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
print("ERROR: Working directory not set or invalid in configuration.")
|
print("ERROR: Directorio de trabajo no configurado o inválido.")
|
||||||
print("Please configure the working directory using the main application.")
|
print("Por favor configure el directorio de trabajo usando la aplicación principal.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# 1. Select Project File, Export Directory comes from config
|
# 1. Select Project File, Export Directory comes from config
|
||||||
project_file = select_project_file()
|
project_file = select_project_file()
|
||||||
export_dir = working_directory # Use working directory from config
|
export_dir = working_directory # Use working directory from config
|
||||||
|
|
||||||
print(f"\nSelected Project: {project_file}")
|
# 2. Detect TIA Portal version from project file
|
||||||
print(f"Using Export Directory (Working Directory): {export_dir}")
|
tia_version = detect_tia_version(project_file)
|
||||||
|
|
||||||
|
print(f"\nProyecto seleccionado: {project_file}")
|
||||||
|
print(f"Usando directorio de exportación (Directorio de trabajo): {export_dir}")
|
||||||
|
|
||||||
portal_instance = None
|
portal_instance = None
|
||||||
project_object = None
|
project_object = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 2. Connect to TIA Portal
|
# 3. Connect to TIA Portal with detected version
|
||||||
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...")
|
print(f"\nConectando a TIA Portal V{tia_version}...")
|
||||||
portal_instance = ts.open_portal(
|
portal_instance = ts.open_portal(
|
||||||
version=TIA_PORTAL_VERSION,
|
version=tia_version,
|
||||||
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
|
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
|
||||||
)
|
)
|
||||||
print("Connected to TIA Portal.")
|
print("Conectado a TIA Portal.")
|
||||||
print(f"Portal Process ID: {portal_instance.get_process_id()}") #
|
print(f"ID del proceso del Portal: {portal_instance.get_process_id()}")
|
||||||
|
|
||||||
# 3. Open Project
|
# 4. Open Project
|
||||||
print(f"Opening project: {os.path.basename(project_file)}...")
|
print(f"Abriendo proyecto: {os.path.basename(project_file)}...")
|
||||||
project_object = portal_instance.open_project(project_file_path=project_file) #
|
project_object = portal_instance.open_project(project_file_path=project_file)
|
||||||
if project_object is None:
|
if project_object is None:
|
||||||
print("Project might already be open, attempting to get handle...")
|
print("El proyecto podría estar ya abierto, intentando obtener el manejador...")
|
||||||
project_object = portal_instance.get_project() #
|
project_object = portal_instance.get_project()
|
||||||
if project_object is None:
|
if project_object is None:
|
||||||
raise Exception("Failed to open or get the specified project.")
|
raise Exception("No se pudo abrir u obtener el proyecto especificado.")
|
||||||
print("Project opened successfully.")
|
print("Proyecto abierto exitosamente.")
|
||||||
|
|
||||||
# 4. Get PLCs
|
# 5. Get PLCs
|
||||||
plcs = project_object.get_plcs() #
|
plcs = project_object.get_plcs()
|
||||||
if not plcs:
|
if not plcs:
|
||||||
print("No PLC devices found in the project.")
|
print("No se encontraron dispositivos PLC en el proyecto.")
|
||||||
else:
|
else:
|
||||||
print(f"Found {len(plcs)} PLC(s). Starting export process...")
|
print(f"Se encontraron {len(plcs)} PLC(s). Iniciando proceso de exportación...")
|
||||||
|
|
||||||
# 5. Iterate and Export Data for each PLC
|
# 6. Iterate and Export Data for each PLC
|
||||||
for plc_device in plcs:
|
for plc_device in plcs:
|
||||||
export_plc_data(
|
export_plc_data(plc=plc_device, export_base_dir=export_dir)
|
||||||
plc=plc_device, export_base_dir=export_dir
|
|
||||||
) # Pass export_dir
|
|
||||||
|
|
||||||
print("\nExport process completed.")
|
print("\nProceso de exportación completado.")
|
||||||
|
|
||||||
except ts.TiaException as tia_ex:
|
except ts.TiaException as tia_ex:
|
||||||
print(f"\nTIA Portal Openness Error: {tia_ex}")
|
print(f"\nError de TIA Portal Openness: {tia_ex}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f"\nERROR: Project file not found at {project_file}")
|
print(f"\nERROR: Archivo de proyecto no encontrado en {project_file}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\nAn unexpected error occurred: {e}")
|
print(f"\nOcurrió un error inesperado: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
# 6. Cleanup
|
# 7. Cleanup
|
||||||
if portal_instance:
|
if portal_instance:
|
||||||
try:
|
try:
|
||||||
print("\nClosing TIA Portal...")
|
print("\nCerrando TIA Portal...")
|
||||||
portal_instance.close_portal() #
|
portal_instance.close_portal()
|
||||||
print("TIA Portal closed.")
|
print("TIA Portal cerrado.")
|
||||||
except Exception as close_ex:
|
except Exception as close_ex:
|
||||||
print(f"Error during TIA Portal cleanup: {close_ex}")
|
print(f"Error durante la limpieza de TIA Portal: {close_ex}")
|
||||||
|
|
||||||
print("\nScript finished.")
|
print("\nScript finalizado.")
|
||||||
|
|
|
@ -8,7 +8,7 @@ from tkinter import filedialog
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from pathlib import Path # Import Path for easier path manipulation
|
from pathlib import Path
|
||||||
|
|
||||||
script_root = os.path.dirname(
|
script_root = os.path.dirname(
|
||||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
@ -17,14 +17,19 @@ sys.path.append(script_root)
|
||||||
from backend.script_utils import load_configuration
|
from backend.script_utils import load_configuration
|
||||||
|
|
||||||
# --- Configuration ---
|
# --- Configuration ---
|
||||||
TIA_PORTAL_VERSION = "18.0" # Target TIA Portal version (e.g., "18.0")
|
# Supported TIA Portal versions mapping (extension -> version)
|
||||||
|
SUPPORTED_TIA_VERSIONS = {
|
||||||
|
".ap18": "18.0",
|
||||||
|
".ap19": "19.0",
|
||||||
|
".ap20": "20.0"
|
||||||
|
}
|
||||||
|
|
||||||
# Filter for cross-references. Based on documentation:
|
# Filter for cross-references. Based on documentation:
|
||||||
# 1: 'AllObjects', 2: 'ObjectsWithReferences', 3: 'ObjectsWithoutReferences', 4: 'UnusedObjects'
|
# 1: 'AllObjects', 2: 'ObjectsWithReferences', 3: 'ObjectsWithoutReferences', 4: 'UnusedObjects'
|
||||||
# Using 1 to export all. 0 might also work as a default in some API versions.
|
# Using 1 to export all. 0 might also work as a default in some API versions.
|
||||||
CROSS_REF_FILTER = 1
|
CROSS_REF_FILTER = 1
|
||||||
|
|
||||||
# --- TIA Scripting Import Handling ---
|
# --- TIA Scripting Import Handling ---
|
||||||
# (Same import handling as x1.py)
|
|
||||||
if os.getenv("TIA_SCRIPTING"):
|
if os.getenv("TIA_SCRIPTING"):
|
||||||
sys.path.append(os.getenv("TIA_SCRIPTING"))
|
sys.path.append(os.getenv("TIA_SCRIPTING"))
|
||||||
else:
|
else:
|
||||||
|
@ -33,209 +38,225 @@ else:
|
||||||
try:
|
try:
|
||||||
import siemens_tia_scripting as ts
|
import siemens_tia_scripting as ts
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print("ERROR: Failed to import 'siemens_tia_scripting'.")
|
print("ERROR: Error al importar 'siemens_tia_scripting'.")
|
||||||
print("Ensure:")
|
print("Asegúrese de que:")
|
||||||
print(f"1. TIA Portal Openness for V{TIA_PORTAL_VERSION} is installed.")
|
print("1. TIA Portal Openness está instalado.")
|
||||||
print(
|
print(
|
||||||
"2. The 'siemens_tia_scripting' Python module is installed (pip install ...) or"
|
"2. El módulo 'siemens_tia_scripting' de Python está instalado (pip install ...) o"
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
" the path to its binaries is set in the 'TIA_SCRIPTING' environment variable."
|
" la ruta a sus binarios está configurada en la variable de entorno 'TIA_SCRIPTING'."
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
"3. You are using a compatible Python version (e.g., 3.12.X as per documentation)."
|
"3. Está usando una versión compatible de Python (ej. 3.12.X según la documentación)."
|
||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"An unexpected error occurred during import: {e}")
|
print(f"Ocurrió un error inesperado durante la importación: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# --- Functions ---
|
# --- Functions ---
|
||||||
|
|
||||||
|
def get_supported_filetypes():
|
||||||
|
"""Returns the supported file types for TIA Portal projects."""
|
||||||
|
filetypes = []
|
||||||
|
for ext, version in SUPPORTED_TIA_VERSIONS.items():
|
||||||
|
version_major = version.split('.')[0]
|
||||||
|
filetypes.append((f"TIA Portal V{version_major} Projects", f"*{ext}"))
|
||||||
|
|
||||||
|
# Add option to show all supported files
|
||||||
|
all_extensions = " ".join([f"*{ext}" for ext in SUPPORTED_TIA_VERSIONS.keys()])
|
||||||
|
filetypes.insert(0, ("All TIA Portal Projects", all_extensions))
|
||||||
|
|
||||||
|
return filetypes
|
||||||
|
|
||||||
|
def detect_tia_version(project_file_path):
|
||||||
|
"""Detects TIA Portal version based on file extension."""
|
||||||
|
file_path = Path(project_file_path)
|
||||||
|
file_extension = file_path.suffix.lower()
|
||||||
|
|
||||||
|
if file_extension in SUPPORTED_TIA_VERSIONS:
|
||||||
|
detected_version = SUPPORTED_TIA_VERSIONS[file_extension]
|
||||||
|
print(f"Versión de TIA Portal detectada: {detected_version} (de la extensión {file_extension})")
|
||||||
|
return detected_version
|
||||||
|
else:
|
||||||
|
print(f"ADVERTENCIA: Extensión de archivo no reconocida '{file_extension}'. Extensiones soportadas: {list(SUPPORTED_TIA_VERSIONS.keys())}")
|
||||||
|
# Default to version 18.0 for backward compatibility
|
||||||
|
print("Usando por defecto TIA Portal V18.0")
|
||||||
|
return "18.0"
|
||||||
|
|
||||||
def select_project_file():
|
def select_project_file():
|
||||||
"""Opens a dialog to select a TIA Portal project file."""
|
"""Opens a dialog to select a TIA Portal project file."""
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.withdraw() # Hide the main tkinter window
|
root.withdraw()
|
||||||
file_path = filedialog.askopenfilename(
|
file_path = filedialog.askopenfilename(
|
||||||
title="Select TIA Portal Project File",
|
title="Seleccionar archivo de proyecto TIA Portal",
|
||||||
filetypes=[
|
filetypes=get_supported_filetypes()
|
||||||
(
|
|
||||||
f"TIA Portal V{TIA_PORTAL_VERSION} Projects",
|
|
||||||
f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}",
|
|
||||||
)
|
|
||||||
], # e.g. *.ap18
|
|
||||||
)
|
)
|
||||||
root.destroy()
|
root.destroy()
|
||||||
if not file_path:
|
if not file_path:
|
||||||
print("No project file selected. Exiting.")
|
print("No se seleccionó ningún archivo de proyecto. Saliendo.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
def export_plc_cross_references(plc, export_base_dir):
|
def export_plc_cross_references(plc, export_base_dir):
|
||||||
"""Exports cross-references for various elements from a given PLC."""
|
"""Exports cross-references for various elements from a given PLC."""
|
||||||
plc_name = plc.get_name()
|
plc_name = plc.get_name()
|
||||||
print(f"\n--- Processing PLC: {plc_name} ---")
|
print(f"\n--- Procesando PLC: {plc_name} ---")
|
||||||
|
|
||||||
# Define base export path for this PLC's cross-references
|
# Define base export path for this PLC's cross-references
|
||||||
plc_export_dir = export_base_dir / plc_name
|
plc_export_dir = export_base_dir / plc_name
|
||||||
plc_export_dir.mkdir(parents=True, exist_ok=True) # Use pathlib's mkdir
|
plc_export_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# --- Export Program Block Cross-References ---
|
# --- Export Program Block Cross-References ---
|
||||||
blocks_cr_exported = 0
|
blocks_cr_exported = 0
|
||||||
blocks_cr_skipped = 0
|
blocks_cr_skipped = 0
|
||||||
print(f"\n[PLC: {plc_name}] Exporting Program Block Cross-References...")
|
print(f"\n[PLC: {plc_name}] Exportando referencias cruzadas de bloques de programa...")
|
||||||
blocks_cr_path = plc_export_dir / "ProgramBlocks_CR"
|
blocks_cr_path = plc_export_dir / "ProgramBlocks_CR"
|
||||||
blocks_cr_path.mkdir(exist_ok=True)
|
blocks_cr_path.mkdir(exist_ok=True)
|
||||||
print(f" Target: {blocks_cr_path}")
|
print(f" Destino: {blocks_cr_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Assuming get_program_blocks() doesn't need folder_path to get all blocks
|
|
||||||
program_blocks = plc.get_program_blocks()
|
program_blocks = plc.get_program_blocks()
|
||||||
print(f" Found {len(program_blocks)} program blocks.")
|
print(f" Se encontraron {len(program_blocks)} bloques de programa.")
|
||||||
for block in program_blocks:
|
for block in program_blocks:
|
||||||
block_name = block.get_name()
|
block_name = block.get_name()
|
||||||
print(f" Processing block: {block_name}...")
|
print(f" Procesando bloque: {block_name}...")
|
||||||
try:
|
try:
|
||||||
# Note: Consistency check might not be needed/available before cross-ref export
|
print(f" Exportando referencias cruzadas para {block_name}...")
|
||||||
print(f" Exporting cross-references for {block_name}...")
|
|
||||||
block.export_cross_references(
|
block.export_cross_references(
|
||||||
target_directorypath=str(
|
target_directorypath=str(blocks_cr_path),
|
||||||
blocks_cr_path
|
|
||||||
), # API likely needs string path
|
|
||||||
filter=CROSS_REF_FILTER,
|
filter=CROSS_REF_FILTER,
|
||||||
)
|
)
|
||||||
blocks_cr_exported += 1
|
blocks_cr_exported += 1
|
||||||
except RuntimeError as block_ex:
|
except RuntimeError as block_ex:
|
||||||
print(
|
print(
|
||||||
f" TIA ERROR exporting cross-references for block {block_name}: {block_ex}"
|
f" ERROR TIA al exportar referencias cruzadas para el bloque {block_name}: {block_ex}"
|
||||||
)
|
)
|
||||||
blocks_cr_skipped += 1
|
blocks_cr_skipped += 1
|
||||||
except Exception as block_ex:
|
except Exception as block_ex:
|
||||||
print(
|
print(
|
||||||
f" GENERAL ERROR exporting cross-references for block {block_name}: {block_ex}"
|
f" ERROR GENERAL al exportar referencias cruzadas para el bloque {block_name}: {block_ex}"
|
||||||
)
|
)
|
||||||
traceback.print_exc() # Print stack trace for general errors
|
traceback.print_exc()
|
||||||
blocks_cr_skipped += 1
|
blocks_cr_skipped += 1
|
||||||
print(
|
print(
|
||||||
f" Program Block CR Export Summary: Exported={blocks_cr_exported}, Skipped/Errors={blocks_cr_skipped}"
|
f" Resumen de exportación de referencias cruzadas de bloques: Exportados={blocks_cr_exported}, Omitidos/Errores={blocks_cr_skipped}"
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print(
|
print(
|
||||||
" AttributeError: Could not find 'get_program_blocks' on PLC object. Skipping Program Blocks."
|
" Error de atributo: No se pudo encontrar 'get_program_blocks' en el objeto PLC. Omitiendo bloques de programa."
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR accessing Program Blocks for cross-reference export: {e}")
|
print(f" ERROR al acceder a los bloques de programa para exportar referencias cruzadas: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
# --- Export PLC Tag Table Cross-References ---
|
# --- Export PLC Tag Table Cross-References ---
|
||||||
tags_cr_exported = 0
|
tags_cr_exported = 0
|
||||||
tags_cr_skipped = 0
|
tags_cr_skipped = 0
|
||||||
print(f"\n[PLC: {plc_name}] Exporting PLC Tag Table Cross-References...")
|
print(f"\n[PLC: {plc_name}] Exportando referencias cruzadas de tablas de variables...")
|
||||||
tags_cr_path = plc_export_dir / "PlcTags_CR"
|
tags_cr_path = plc_export_dir / "PlcTags_CR"
|
||||||
tags_cr_path.mkdir(exist_ok=True)
|
tags_cr_path.mkdir(exist_ok=True)
|
||||||
print(f" Target: {tags_cr_path}")
|
print(f" Destino: {tags_cr_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Assuming get_plc_tag_tables() doesn't need folder_path to get all tables
|
|
||||||
tag_tables = plc.get_plc_tag_tables()
|
tag_tables = plc.get_plc_tag_tables()
|
||||||
print(f" Found {len(tag_tables)} Tag Tables.")
|
print(f" Se encontraron {len(tag_tables)} tablas de variables.")
|
||||||
for table in tag_tables:
|
for table in tag_tables:
|
||||||
table_name = table.get_name()
|
table_name = table.get_name()
|
||||||
print(f" Processing Tag Table: {table_name}...")
|
print(f" Procesando tabla de variables: {table_name}...")
|
||||||
try:
|
try:
|
||||||
print(f" Exporting cross-references for {table_name}...")
|
print(f" Exportando referencias cruzadas para {table_name}...")
|
||||||
table.export_cross_references(
|
table.export_cross_references(
|
||||||
target_directorypath=str(tags_cr_path), filter=CROSS_REF_FILTER
|
target_directorypath=str(tags_cr_path),
|
||||||
|
filter=CROSS_REF_FILTER
|
||||||
)
|
)
|
||||||
tags_cr_exported += 1
|
tags_cr_exported += 1
|
||||||
except RuntimeError as table_ex:
|
except RuntimeError as table_ex:
|
||||||
print(
|
print(
|
||||||
f" TIA ERROR exporting cross-references for Tag Table {table_name}: {table_ex}"
|
f" ERROR TIA al exportar referencias cruzadas para la tabla {table_name}: {table_ex}"
|
||||||
)
|
)
|
||||||
tags_cr_skipped += 1
|
tags_cr_skipped += 1
|
||||||
except Exception as table_ex:
|
except Exception as table_ex:
|
||||||
print(
|
print(
|
||||||
f" GENERAL ERROR exporting cross-references for Tag Table {table_name}: {table_ex}"
|
f" ERROR GENERAL al exportar referencias cruzadas para la tabla {table_name}: {table_ex}"
|
||||||
)
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
tags_cr_skipped += 1
|
tags_cr_skipped += 1
|
||||||
print(
|
print(
|
||||||
f" Tag Table CR Export Summary: Exported={tags_cr_exported}, Skipped/Errors={tags_cr_skipped}"
|
f" Resumen de exportación de referencias cruzadas de tablas: Exportados={tags_cr_exported}, Omitidos/Errores={tags_cr_skipped}"
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print(
|
print(
|
||||||
" AttributeError: Could not find 'get_plc_tag_tables' on PLC object. Skipping Tag Tables."
|
" Error de atributo: No se pudo encontrar 'get_plc_tag_tables' en el objeto PLC. Omitiendo tablas de variables."
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR accessing Tag Tables for cross-reference export: {e}")
|
print(f" ERROR al acceder a las tablas de variables para exportar referencias cruzadas: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
# --- Export PLC Data Type (UDT) Cross-References ---
|
# --- Export PLC Data Type (UDT) Cross-References ---
|
||||||
udts_cr_exported = 0
|
udts_cr_exported = 0
|
||||||
udts_cr_skipped = 0
|
udts_cr_skipped = 0
|
||||||
print(f"\n[PLC: {plc_name}] Exporting PLC Data Type (UDT) Cross-References...")
|
print(f"\n[PLC: {plc_name}] Exportando referencias cruzadas de tipos de datos PLC (UDTs)...")
|
||||||
udts_cr_path = plc_export_dir / "PlcDataTypes_CR"
|
udts_cr_path = plc_export_dir / "PlcDataTypes_CR"
|
||||||
udts_cr_path.mkdir(exist_ok=True)
|
udts_cr_path.mkdir(exist_ok=True)
|
||||||
print(f" Target: {udts_cr_path}")
|
print(f" Destino: {udts_cr_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Assuming get_user_data_types() doesn't need folder_path to get all UDTs
|
|
||||||
udts = plc.get_user_data_types()
|
udts = plc.get_user_data_types()
|
||||||
print(f" Found {len(udts)} UDTs.")
|
print(f" Se encontraron {len(udts)} UDTs.")
|
||||||
for udt in udts:
|
for udt in udts:
|
||||||
udt_name = udt.get_name()
|
udt_name = udt.get_name()
|
||||||
print(f" Processing UDT: {udt_name}...")
|
print(f" Procesando UDT: {udt_name}...")
|
||||||
try:
|
try:
|
||||||
print(f" Exporting cross-references for {udt_name}...")
|
print(f" Exportando referencias cruzadas para {udt_name}...")
|
||||||
udt.export_cross_references(
|
udt.export_cross_references(
|
||||||
target_directorypath=str(udts_cr_path), filter=CROSS_REF_FILTER
|
target_directorypath=str(udts_cr_path),
|
||||||
|
filter=CROSS_REF_FILTER
|
||||||
)
|
)
|
||||||
udts_cr_exported += 1
|
udts_cr_exported += 1
|
||||||
except RuntimeError as udt_ex:
|
except RuntimeError as udt_ex:
|
||||||
print(
|
print(
|
||||||
f" TIA ERROR exporting cross-references for UDT {udt_name}: {udt_ex}"
|
f" ERROR TIA al exportar referencias cruzadas para el UDT {udt_name}: {udt_ex}"
|
||||||
)
|
)
|
||||||
udts_cr_skipped += 1
|
udts_cr_skipped += 1
|
||||||
except Exception as udt_ex:
|
except Exception as udt_ex:
|
||||||
print(
|
print(
|
||||||
f" GENERAL ERROR exporting cross-references for UDT {udt_name}: {udt_ex}"
|
f" ERROR GENERAL al exportar referencias cruzadas para el UDT {udt_name}: {udt_ex}"
|
||||||
)
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
udts_cr_skipped += 1
|
udts_cr_skipped += 1
|
||||||
print(
|
print(
|
||||||
f" UDT CR Export Summary: Exported={udts_cr_exported}, Skipped/Errors={udts_cr_skipped}"
|
f" Resumen de exportación de referencias cruzadas de UDTs: Exportados={udts_cr_exported}, Omitidos/Errores={udts_cr_skipped}"
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print(
|
print(
|
||||||
" AttributeError: Could not find 'get_user_data_types' on PLC object. Skipping UDTs."
|
" Error de atributo: No se pudo encontrar 'get_user_data_types' en el objeto PLC. Omitiendo UDTs."
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR accessing UDTs for cross-reference export: {e}")
|
print(f" ERROR al acceder a los UDTs para exportar referencias cruzadas: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
# --- Export System Block Cross-References ---
|
# --- Export System Block Cross-References ---
|
||||||
sys_blocks_cr_exported = 0
|
sys_blocks_cr_exported = 0
|
||||||
sys_blocks_cr_skipped = 0
|
sys_blocks_cr_skipped = 0
|
||||||
print(f"\n[PLC: {plc_name}] Attempting to Export System Block Cross-References...")
|
print(f"\n[PLC: {plc_name}] Intentando exportar referencias cruzadas de bloques de sistema...")
|
||||||
sys_blocks_cr_path = plc_export_dir / "SystemBlocks_CR"
|
sys_blocks_cr_path = plc_export_dir / "SystemBlocks_CR"
|
||||||
sys_blocks_cr_path.mkdir(exist_ok=True)
|
sys_blocks_cr_path.mkdir(exist_ok=True)
|
||||||
print(f" Target: {sys_blocks_cr_path}")
|
print(f" Destino: {sys_blocks_cr_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Check if method exists before calling
|
|
||||||
if hasattr(plc, "get_system_blocks"):
|
if hasattr(plc, "get_system_blocks"):
|
||||||
system_blocks = plc.get_system_blocks()
|
system_blocks = plc.get_system_blocks()
|
||||||
print(
|
print(
|
||||||
f" Found {len(system_blocks)} system blocks (using get_system_blocks)."
|
f" Se encontraron {len(system_blocks)} bloques de sistema."
|
||||||
)
|
)
|
||||||
for sys_block in system_blocks:
|
for sys_block in system_blocks:
|
||||||
sys_block_name = sys_block.get_name()
|
sys_block_name = sys_block.get_name()
|
||||||
print(f" Processing System Block: {sys_block_name}...")
|
print(f" Procesando bloque de sistema: {sys_block_name}...")
|
||||||
try:
|
try:
|
||||||
print(f" Exporting cross-references for {sys_block_name}...")
|
print(f" Exportando referencias cruzadas para {sys_block_name}...")
|
||||||
sys_block.export_cross_references(
|
sys_block.export_cross_references(
|
||||||
target_directorypath=str(sys_blocks_cr_path),
|
target_directorypath=str(sys_blocks_cr_path),
|
||||||
filter=CROSS_REF_FILTER,
|
filter=CROSS_REF_FILTER,
|
||||||
|
@ -243,53 +264,51 @@ def export_plc_cross_references(plc, export_base_dir):
|
||||||
sys_blocks_cr_exported += 1
|
sys_blocks_cr_exported += 1
|
||||||
except RuntimeError as sys_ex:
|
except RuntimeError as sys_ex:
|
||||||
print(
|
print(
|
||||||
f" TIA ERROR exporting cross-references for System Block {sys_block_name}: {sys_ex}"
|
f" ERROR TIA al exportar referencias cruzadas para el bloque de sistema {sys_block_name}: {sys_ex}"
|
||||||
)
|
)
|
||||||
sys_blocks_cr_skipped += 1
|
sys_blocks_cr_skipped += 1
|
||||||
except Exception as sys_ex:
|
except Exception as sys_ex:
|
||||||
print(
|
print(
|
||||||
f" GENERAL ERROR exporting cross-references for System Block {sys_block_name}: {sys_ex}"
|
f" ERROR GENERAL al exportar referencias cruzadas para el bloque de sistema {sys_block_name}: {sys_ex}"
|
||||||
)
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys_blocks_cr_skipped += 1
|
sys_blocks_cr_skipped += 1
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
" Method 'get_system_blocks' not found on PLC object. Skipping System Blocks."
|
" Método 'get_system_blocks' no encontrado en el objeto PLC. Omitiendo bloques de sistema."
|
||||||
)
|
)
|
||||||
# Alternative: Try navigating DeviceItems if needed, but that's more complex.
|
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f" System Block CR Export Summary: Exported={sys_blocks_cr_exported}, Skipped/Errors={sys_blocks_cr_skipped}"
|
f" Resumen de exportación de referencias cruzadas de bloques de sistema: Exportados={sys_blocks_cr_exported}, Omitidos/Errores={sys_blocks_cr_skipped}"
|
||||||
)
|
)
|
||||||
except AttributeError: # Catch if get_name() or other methods fail on sys_block
|
except AttributeError:
|
||||||
print(
|
print(
|
||||||
" AttributeError during System Block processing. Skipping remaining System Blocks."
|
" Error de atributo durante el procesamiento de bloques de sistema. Omitiendo bloques de sistema restantes."
|
||||||
)
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(
|
print(
|
||||||
f" ERROR accessing/processing System Blocks for cross-reference export: {e}"
|
f" ERROR al acceder/procesar bloques de sistema para exportar referencias cruzadas: {e}"
|
||||||
)
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
# --- Export Software Unit Cross-References ---
|
# --- Export Software Unit Cross-References ---
|
||||||
sw_units_cr_exported = 0
|
sw_units_cr_exported = 0
|
||||||
sw_units_cr_skipped = 0
|
sw_units_cr_skipped = 0
|
||||||
print(f"\n[PLC: {plc_name}] Attempting to Export Software Unit Cross-References...")
|
print(f"\n[PLC: {plc_name}] Intentando exportar referencias cruzadas de unidades de software...")
|
||||||
sw_units_cr_path = plc_export_dir / "SoftwareUnits_CR"
|
sw_units_cr_path = plc_export_dir / "SoftwareUnits_CR"
|
||||||
sw_units_cr_path.mkdir(exist_ok=True)
|
sw_units_cr_path.mkdir(exist_ok=True)
|
||||||
print(f" Target: {sw_units_cr_path}")
|
print(f" Destino: {sw_units_cr_path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Check if method exists before calling
|
|
||||||
if hasattr(plc, "get_software_units"):
|
if hasattr(plc, "get_software_units"):
|
||||||
software_units = plc.get_software_units()
|
software_units = plc.get_software_units()
|
||||||
print(f" Found {len(software_units)} Software Units.")
|
print(f" Se encontraron {len(software_units)} unidades de software.")
|
||||||
for unit in software_units:
|
for unit in software_units:
|
||||||
unit_name = unit.get_name()
|
unit_name = unit.get_name()
|
||||||
print(f" Processing Software Unit: {unit_name}...")
|
print(f" Procesando unidad de software: {unit_name}...")
|
||||||
try:
|
try:
|
||||||
print(f" Exporting cross-references for {unit_name}...")
|
print(f" Exportando referencias cruzadas para {unit_name}...")
|
||||||
unit.export_cross_references(
|
unit.export_cross_references(
|
||||||
target_directorypath=str(sw_units_cr_path),
|
target_directorypath=str(sw_units_cr_path),
|
||||||
filter=CROSS_REF_FILTER,
|
filter=CROSS_REF_FILTER,
|
||||||
|
@ -297,35 +316,34 @@ def export_plc_cross_references(plc, export_base_dir):
|
||||||
sw_units_cr_exported += 1
|
sw_units_cr_exported += 1
|
||||||
except RuntimeError as unit_ex:
|
except RuntimeError as unit_ex:
|
||||||
print(
|
print(
|
||||||
f" TIA ERROR exporting cross-references for Software Unit {unit_name}: {unit_ex}"
|
f" ERROR TIA al exportar referencias cruzadas para la unidad de software {unit_name}: {unit_ex}"
|
||||||
)
|
)
|
||||||
sw_units_cr_skipped += 1
|
sw_units_cr_skipped += 1
|
||||||
except Exception as unit_ex:
|
except Exception as unit_ex:
|
||||||
print(
|
print(
|
||||||
f" GENERAL ERROR exporting cross-references for Software Unit {unit_name}: {unit_ex}"
|
f" ERROR GENERAL al exportar referencias cruzadas para la unidad de software {unit_name}: {unit_ex}"
|
||||||
)
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sw_units_cr_skipped += 1
|
sw_units_cr_skipped += 1
|
||||||
print(
|
print(
|
||||||
f" Software Unit CR Export Summary: Exported={sw_units_cr_exported}, Skipped/Errors={sw_units_cr_skipped}"
|
f" Resumen de exportación de referencias cruzadas de unidades de software: Exportados={sw_units_cr_exported}, Omitidos/Errores={sw_units_cr_skipped}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
" Method 'get_software_units' not found on PLC object. Skipping Software Units."
|
" Método 'get_software_units' no encontrado en el objeto PLC. Omitiendo unidades de software."
|
||||||
)
|
)
|
||||||
except AttributeError: # Catch if get_name() or other methods fail on unit
|
except AttributeError:
|
||||||
print(
|
print(
|
||||||
" AttributeError during Software Unit processing. Skipping remaining Software Units."
|
" Error de atributo durante el procesamiento de unidades de software. Omitiendo unidades restantes."
|
||||||
)
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(
|
print(
|
||||||
f" ERROR accessing/processing Software Units for cross-reference export: {e}"
|
f" ERROR al acceder/procesar unidades de software para exportar referencias cruzadas: {e}"
|
||||||
)
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
print(f"\n--- Finished processing PLC: {plc_name} ---")
|
print(f"\n--- Finalizado el procesamiento del PLC: {plc_name} ---")
|
||||||
|
|
||||||
|
|
||||||
# --- Main Script ---
|
# --- Main Script ---
|
||||||
|
|
||||||
|
@ -333,90 +351,90 @@ if __name__ == "__main__":
|
||||||
configs = load_configuration()
|
configs = load_configuration()
|
||||||
working_directory = configs.get("working_directory")
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
print("--- TIA Portal Cross-Reference Exporter ---")
|
print("--- Exportador de Referencias Cruzadas de TIA Portal ---")
|
||||||
|
|
||||||
# Validate working directory
|
# Validate working directory
|
||||||
if not working_directory or not os.path.isdir(working_directory):
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
print("ERROR: Working directory not set or invalid in configuration.")
|
print("ERROR: Directorio de trabajo no configurado o inválido.")
|
||||||
print("Please configure the working directory using the main application.")
|
print("Por favor configure el directorio de trabajo usando la aplicación principal.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# 1. Select Project File
|
# 1. Select Project File
|
||||||
project_file = select_project_file()
|
project_file = select_project_file()
|
||||||
|
|
||||||
# 2. Define Export Directory using working_directory and subfolder
|
# 2. Detect TIA Portal version from project file
|
||||||
# The export base directory is the working directory. PLC-specific folders will be created inside.
|
tia_version = detect_tia_version(project_file)
|
||||||
|
|
||||||
|
# 3. Define Export Directory using working_directory and subfolder
|
||||||
export_base_dir = Path(working_directory)
|
export_base_dir = Path(working_directory)
|
||||||
try:
|
try:
|
||||||
# Ensure the base working directory exists (it should, but check doesn't hurt)
|
|
||||||
export_base_dir.mkdir(parents=True, exist_ok=True)
|
export_base_dir.mkdir(parents=True, exist_ok=True)
|
||||||
print(f"\nSelected Project: {project_file}")
|
print(f"\nProyecto seleccionado: {project_file}")
|
||||||
print(f"Using Base Export Directory: {export_base_dir.resolve()}")
|
print(f"Usando directorio base de exportación: {export_base_dir.resolve()}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERROR: Could not create export directory '{export_dir}'. Error: {e}")
|
print(f"ERROR: No se pudo crear el directorio de exportación '{export_base_dir}'. Error: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
portal_instance = None
|
portal_instance = None
|
||||||
project_object = None
|
project_object = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 3. Connect to TIA Portal
|
# 4. Connect to TIA Portal with detected version
|
||||||
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...")
|
print(f"\nConectando a TIA Portal V{tia_version}...")
|
||||||
# Connect using WithGraphicalUserInterface mode for visibility
|
|
||||||
portal_instance = ts.open_portal(
|
portal_instance = ts.open_portal(
|
||||||
version=TIA_PORTAL_VERSION,
|
version=tia_version,
|
||||||
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
|
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
|
||||||
)
|
)
|
||||||
print("Connected to TIA Portal.")
|
print("Conectado a TIA Portal.")
|
||||||
print(f"Portal Process ID: {portal_instance.get_process_id()}")
|
print(f"ID del proceso del Portal: {portal_instance.get_process_id()}")
|
||||||
|
|
||||||
# 4. Open Project
|
# 5. Open Project
|
||||||
print(f"Opening project: {os.path.basename(project_file)}...")
|
print(f"Abriendo proyecto: {os.path.basename(project_file)}...")
|
||||||
project_path_obj = Path(project_file) # Use Path object
|
project_path_obj = Path(project_file)
|
||||||
project_object = portal_instance.open_project(
|
project_object = portal_instance.open_project(
|
||||||
project_file_path=str(project_path_obj)
|
project_file_path=str(project_path_obj)
|
||||||
)
|
)
|
||||||
if project_object is None:
|
if project_object is None:
|
||||||
print("Project might already be open, attempting to get handle...")
|
print("El proyecto podría estar ya abierto, intentando obtener el manejador...")
|
||||||
project_object = portal_instance.get_project()
|
project_object = portal_instance.get_project()
|
||||||
if project_object is None:
|
if project_object is None:
|
||||||
raise Exception("Failed to open or get the specified project.")
|
raise Exception("No se pudo abrir u obtener el proyecto especificado.")
|
||||||
print("Project opened successfully.")
|
print("Proyecto abierto exitosamente.")
|
||||||
|
|
||||||
# 5. Get PLCs
|
# 6. Get PLCs
|
||||||
plcs = project_object.get_plcs()
|
plcs = project_object.get_plcs()
|
||||||
if not plcs:
|
if not plcs:
|
||||||
print("No PLC devices found in the project.")
|
print("No se encontraron dispositivos PLC en el proyecto.")
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f"Found {len(plcs)} PLC(s). Starting cross-reference export process..."
|
f"Se encontraron {len(plcs)} PLC(s). Iniciando proceso de exportación de referencias cruzadas..."
|
||||||
)
|
)
|
||||||
|
|
||||||
# 6. Iterate and Export Cross-References for each PLC
|
# 7. Iterate and Export Cross-References for each PLC
|
||||||
for plc_device in plcs:
|
for plc_device in plcs:
|
||||||
export_plc_cross_references(
|
export_plc_cross_references(
|
||||||
plc=plc_device,
|
plc=plc_device,
|
||||||
export_base_dir=export_base_dir, # Pass the base directory
|
export_base_dir=export_base_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
print("\nCross-reference export process completed.")
|
print("\nProceso de exportación de referencias cruzadas completado.")
|
||||||
|
|
||||||
except RuntimeError as tia_ex:
|
except RuntimeError as tia_ex:
|
||||||
print(f"\nTIA Portal Openness Error: {tia_ex}")
|
print(f"\nError de TIA Portal Openness: {tia_ex}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f"\nERROR: Project file not found at {project_file}")
|
print(f"\nERROR: Archivo de proyecto no encontrado en {project_file}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\nAn unexpected error occurred: {e}")
|
print(f"\nOcurrió un error inesperado: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
# 7. Cleanup
|
# 8. Cleanup
|
||||||
if portal_instance:
|
if portal_instance:
|
||||||
try:
|
try:
|
||||||
print("\nClosing TIA Portal...")
|
print("\nCerrando TIA Portal...")
|
||||||
portal_instance.close_portal()
|
portal_instance.close_portal()
|
||||||
print("TIA Portal closed.")
|
print("TIA Portal cerrado.")
|
||||||
except Exception as close_ex:
|
except Exception as close_ex:
|
||||||
print(f"Error during TIA Portal cleanup: {close_ex}")
|
print(f"Error durante la limpieza de TIA Portal: {close_ex}")
|
||||||
|
|
||||||
print("\nScript finished.")
|
print("\nScript finalizado.")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
2025-06-12 20:02:24.046 - ======================================== LOG START ========================================
|
2025-06-12 20:13:18.597 - ======================================== LOG START ========================================
|
||||||
2025-06-12 20:02:24.046 - Directorio de trabajo base configurado: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'
|
2025-06-12 20:13:18.597 - Directorio de trabajo base configurado: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'
|
||||||
2025-06-12 20:02:24.046 - Buscando archivos XML recursivamente en el subdirectorio: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'
|
2025-06-12 20:13:18.597 - Buscando archivos XML recursivamente en el subdirectorio: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'
|
||||||
2025-06-12 20:02:24.046 - Error: El subdirectorio 'PLC' no existe dentro de 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'. Se esperaba encontrar la estructura del proyecto TIA Portal en 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'.
|
2025-06-12 20:13:18.597 - Error: El subdirectorio 'PLC' no existe dentro de 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'. Se esperaba encontrar la estructura del proyecto TIA Portal en 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
--- Log de Ejecución: x0_main.py ---
|
--- Log de Ejecución: x0_main.py ---
|
||||||
Grupo: XML Parser to SCL
|
Grupo: XML Parser to SCL
|
||||||
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source
|
Directorio de Trabajo: D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source
|
||||||
Inicio: 2025-06-12 20:02:23
|
Inicio: 2025-06-12 20:13:18
|
||||||
Fin: 2025-06-12 20:02:24
|
Fin: 2025-06-12 20:13:18
|
||||||
Duración: 0:00:00.882711
|
Duración: 0:00:00.611062
|
||||||
Estado: ERROR (Código de Salida: 1)
|
Estado: ERROR (Código de Salida: 1)
|
||||||
|
|
||||||
--- SALIDA ESTÁNDAR (STDOUT) ---
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
|
15
data/log.txt
15
data/log.txt
|
@ -1,5 +1,10 @@
|
||||||
[20:03:36] Iniciando ejecución de x1.py en D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source...
|
[20:13:18] Iniciando ejecución de x0_main.py en D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source...
|
||||||
[20:03:37] --- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---
|
[20:13:18] INFO: format_variable_name importado desde generators.generator_utils
|
||||||
[20:03:47] No project file selected. Exiting.
|
[20:13:18] ======================================== LOG START ========================================
|
||||||
[20:03:47] Ejecución de x1.py finalizada (success). Duración: 0:00:10.497365.
|
[20:13:18] Directorio de trabajo base configurado: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'
|
||||||
[20:03:47] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\log_x1.txt
|
[20:13:18] Buscando archivos XML recursivamente en el subdirectorio: 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source\PLC'
|
||||||
|
[20:13:18] --- ERRORES ---
|
||||||
|
[20:13:18] Error: El subdirectorio 'PLC' no existe dentro de 'D:\Trabajo\VM\44 - 98050 - Fiera\Reporte\ExportsTia\Source'. Asegúrese de que la ruta del directorio de trabajo apunte a la carpeta que *contiene* la carpeta 'PLC'.
|
||||||
|
[20:13:18] --- FIN ERRORES ---
|
||||||
|
[20:13:18] Ejecución de x0_main.py finalizada (error). Duración: 0:00:00.611062. Se detectaron errores (ver log).
|
||||||
|
[20:13:18] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\XML Parser to SCL\log_x0_main.txt
|
||||||
|
|
Loading…
Reference in New Issue