Adaptacion de los scripts de ObtainIOFromProjectTia a la logica de los directorios de trabajo
This commit is contained in:
parent
239126bb96
commit
b018e82848
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"level1": {
|
||||||
|
"api_key": "your-api-key-here",
|
||||||
|
"model": "gpt-3.5-turbo"
|
||||||
|
},
|
||||||
|
"level2": {},
|
||||||
|
"level3": {},
|
||||||
|
"working_directory": "C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\IOExport"
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"path": "C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\IOExport",
|
||||||
|
"history": [
|
||||||
|
"C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\IOExport"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
"""
|
"""
|
||||||
export_logic_from_tia :
|
export_logic_from_tia :
|
||||||
Script para exportar el software de un PLC desde TIA Portal en archivos XML y SCL.
|
Script para exportar el software de un PLC desde TIA Portal en archivos XML y SCL.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import filedialog
|
from tkinter import filedialog
|
||||||
import os
|
import os
|
||||||
|
@ -15,31 +16,42 @@ 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")
|
TIA_PORTAL_VERSION = "18.0" # Target TIA Portal version (e.g., "18.0")
|
||||||
EXPORT_OPTIONS = None # Use default export options
|
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 ---
|
# --- TIA Scripting Import Handling ---
|
||||||
# Check if the TIA_SCRIPTING environment variable is set
|
# Check if the TIA_SCRIPTING environment variable is set
|
||||||
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:
|
||||||
# Optional: Define a fallback path if the environment variable isn't set
|
# Optional: Define a fallback path if the environment variable isn't set
|
||||||
# fallback_path = "C:\\path\\to\\your\\TIA_Scripting_binaries"
|
# fallback_path = "C:\\path\\to\\your\\TIA_Scripting_binaries"
|
||||||
# if os.path.exists(fallback_path):
|
# if os.path.exists(fallback_path):
|
||||||
# sys.path.append(fallback_path)
|
# sys.path.append(fallback_path)
|
||||||
pass # Allow import to fail if not found
|
pass # Allow import to fail if not found
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import siemens_tia_scripting as ts
|
import siemens_tia_scripting as ts
|
||||||
EXPORT_OPTIONS = ts.Enums.ExportOptions.WithDefaults # Set default options now that 'ts' is imported
|
|
||||||
|
EXPORT_OPTIONS = (
|
||||||
|
ts.Enums.ExportOptions.WithDefaults
|
||||||
|
) # Set default options now that 'ts' is imported
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print("ERROR: Failed to import 'siemens_tia_scripting'.")
|
print("ERROR: Failed to import 'siemens_tia_scripting'.")
|
||||||
print("Ensure:")
|
print("Ensure:")
|
||||||
print(f"1. TIA Portal Openness for V{TIA_PORTAL_VERSION} is installed.")
|
print(f"1. TIA Portal Openness for V{TIA_PORTAL_VERSION} is installed.")
|
||||||
print("2. The 'siemens_tia_scripting' Python module is installed (pip install ...) or")
|
print(
|
||||||
print(" the path to its binaries is set in the 'TIA_SCRIPTING' environment variable.")
|
"2. The 'siemens_tia_scripting' Python module is installed (pip install ...) or"
|
||||||
print("3. You are using a compatible Python version (e.g., 3.12.X as per documentation).")
|
)
|
||||||
|
print(
|
||||||
|
" the path to its binaries is set in the 'TIA_SCRIPTING' environment variable."
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"3. You are using a compatible Python version (e.g., 3.12.X as per documentation)."
|
||||||
|
)
|
||||||
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"An unexpected error occurred during import: {e}")
|
||||||
|
@ -48,13 +60,19 @@ except Exception as e:
|
||||||
|
|
||||||
# --- Functions ---
|
# --- Functions ---
|
||||||
|
|
||||||
|
|
||||||
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() # 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=[(f"TIA Portal V{TIA_PORTAL_VERSION} Projects", f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}")] # e.g. *.ap18
|
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:
|
||||||
|
@ -62,19 +80,19 @@ def select_project_file():
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
def select_export_directory():
|
def select_export_directory():
|
||||||
"""Opens a dialog to select the export directory."""
|
"""Opens a dialog to select the export directory."""
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.withdraw() # Hide the main tkinter window
|
root.withdraw() # Hide the main tkinter window
|
||||||
dir_path = filedialog.askdirectory(
|
dir_path = filedialog.askdirectory(title="Select Export Directory")
|
||||||
title="Select Export Directory"
|
|
||||||
)
|
|
||||||
root.destroy()
|
root.destroy()
|
||||||
if not dir_path:
|
if not dir_path:
|
||||||
print("No export directory selected. Exiting.")
|
print("No export directory selected. Exiting.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return dir_path
|
return dir_path
|
||||||
|
|
||||||
|
|
||||||
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()
|
||||||
|
@ -96,42 +114,52 @@ def export_plc_data(plc, export_base_dir):
|
||||||
print(f" SCL Target: {scl_blocks_path}")
|
print(f" SCL Target: {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" Found {len(program_blocks)} program blocks.")
|
||||||
for block in program_blocks:
|
for block in program_blocks:
|
||||||
block_name = block.get_name() # Assuming get_name() exists
|
block_name = block.get_name() # Assuming get_name() exists
|
||||||
print(f" Processing block: {block_name}...")
|
print(f" Processing block: {block_name}...")
|
||||||
try:
|
try:
|
||||||
if not block.is_consistent(): #
|
if not block.is_consistent(): #
|
||||||
print(f" Compiling block {block_name}...")
|
print(f" Compiling block {block_name}...")
|
||||||
block.compile() #
|
block.compile() #
|
||||||
if not block.is_consistent():
|
if not block.is_consistent():
|
||||||
print(f" WARNING: Block {block_name} inconsistent after compile. Skipping.")
|
print(
|
||||||
blocks_skipped += 1
|
f" WARNING: Block {block_name} inconsistent after compile. Skipping."
|
||||||
continue
|
)
|
||||||
|
blocks_skipped += 1
|
||||||
|
continue
|
||||||
|
|
||||||
print(f" Exporting {block_name} as XML...")
|
print(f" Exporting {block_name} as XML...")
|
||||||
block.export(target_directory_path=xml_blocks_path, #
|
block.export(
|
||||||
export_options=EXPORT_OPTIONS, #
|
target_directory_path=xml_blocks_path, #
|
||||||
export_format=ts.Enums.ExportFormats.SimaticML, #
|
export_options=EXPORT_OPTIONS, #
|
||||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE) #
|
export_format=ts.Enums.ExportFormats.SimaticML, #
|
||||||
|
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" Exporting {block_name} as SCL...")
|
||||||
block.export(target_directory_path=scl_blocks_path,
|
block.export(
|
||||||
export_options=EXPORT_OPTIONS,
|
target_directory_path=scl_blocks_path,
|
||||||
export_format=ts.Enums.ExportFormats.ExternalSource, #
|
export_options=EXPORT_OPTIONS,
|
||||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE)
|
export_format=ts.Enums.ExportFormats.ExternalSource, #
|
||||||
|
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||||
|
)
|
||||||
except Exception as prop_ex:
|
except Exception as prop_ex:
|
||||||
print(f" Could not get ProgrammingLanguage for {block_name}. Skipping SCL. Error: {prop_ex}")
|
print(
|
||||||
|
f" Could not get ProgrammingLanguage for {block_name}. Skipping 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 exporting block {block_name}: {block_ex}")
|
||||||
blocks_skipped += 1
|
blocks_skipped += 1
|
||||||
print(f" Program Blocks Export Summary: Exported={blocks_exported}, Skipped/Errors={blocks_skipped}")
|
print(
|
||||||
|
f" Program Blocks Export Summary: Exported={blocks_exported}, Skipped/Errors={blocks_skipped}"
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR processing Program Blocks: {e}")
|
print(f" ERROR processing Program Blocks: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -145,30 +173,36 @@ def export_plc_data(plc, export_base_dir):
|
||||||
print(f" Target: {udt_export_path}")
|
print(f" Target: {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" Found {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" Processing UDT: {udt_name}...")
|
||||||
try:
|
try:
|
||||||
if not udt.is_consistent(): #
|
if not udt.is_consistent(): #
|
||||||
print(f" Compiling UDT {udt_name}...")
|
print(f" Compiling UDT {udt_name}...")
|
||||||
udt.compile() #
|
udt.compile() #
|
||||||
if not udt.is_consistent():
|
if not udt.is_consistent():
|
||||||
print(f" WARNING: UDT {udt_name} inconsistent after compile. Skipping.")
|
print(
|
||||||
|
f" WARNING: UDT {udt_name} inconsistent after compile. Skipping."
|
||||||
|
)
|
||||||
udts_skipped += 1
|
udts_skipped += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f" Exporting {udt_name}...")
|
print(f" Exporting {udt_name}...")
|
||||||
udt.export(target_directory_path=udt_export_path, #
|
udt.export(
|
||||||
export_options=EXPORT_OPTIONS, #
|
target_directory_path=udt_export_path, #
|
||||||
# export_format defaults to SimaticML for UDTs
|
export_options=EXPORT_OPTIONS, #
|
||||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE) #
|
# export_format defaults to SimaticML for UDTs
|
||||||
|
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 exporting UDT {udt_name}: {udt_ex}")
|
||||||
udts_skipped += 1
|
udts_skipped += 1
|
||||||
print(f" UDT Export Summary: Exported={udts_exported}, Skipped/Errors={udts_skipped}")
|
print(
|
||||||
|
f" UDT Export Summary: Exported={udts_exported}, Skipped/Errors={udts_skipped}"
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR processing UDTs: {e}")
|
print(f" ERROR processing UDTs: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -182,23 +216,27 @@ def export_plc_data(plc, export_base_dir):
|
||||||
print(f" Target: {tags_export_path}")
|
print(f" Target: {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" Found {len(tag_tables)} Tag Tables.")
|
||||||
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" Processing Tag Table: {table_name}...")
|
||||||
try:
|
try:
|
||||||
# Note: Consistency check might not be available/needed for tag tables like blocks/UDTs
|
# Note: Consistency check might not be available/needed for tag tables like blocks/UDTs
|
||||||
print(f" Exporting {table_name}...")
|
print(f" Exporting {table_name}...")
|
||||||
table.export(target_directory_path=tags_export_path, #
|
table.export(
|
||||||
export_options=EXPORT_OPTIONS, #
|
target_directory_path=tags_export_path, #
|
||||||
# export_format defaults to SimaticML for Tag Tables
|
export_options=EXPORT_OPTIONS, #
|
||||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE) #
|
# export_format defaults to SimaticML for Tag Tables
|
||||||
|
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 exporting Tag Table {table_name}: {table_ex}")
|
||||||
tags_skipped += 1
|
tags_skipped += 1
|
||||||
print(f" Tag Table Export Summary: Exported={tags_exported}, Skipped/Errors={tags_skipped}")
|
print(
|
||||||
|
f" Tag Table Export Summary: Exported={tags_exported}, Skipped/Errors={tags_skipped}"
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ERROR processing Tag Tables: {e}")
|
print(f" ERROR processing Tag Tables: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -208,17 +246,25 @@ def export_plc_data(plc, export_base_dir):
|
||||||
|
|
||||||
# --- Main Script ---
|
# --- Main Script ---
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
configs = load_configuration()
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
print("--- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---")
|
print("--- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---")
|
||||||
|
|
||||||
# 1. Select Files/Folders
|
# Validate working directory
|
||||||
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
|
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()
|
project_file = select_project_file()
|
||||||
export_dir = select_export_directory()
|
export_dir = working_directory # Use working directory from config
|
||||||
|
|
||||||
print(f"\nSelected Project: {project_file}")
|
print(f"\nSelected Project: {project_file}")
|
||||||
print(f"Selected Export Directory: {export_dir}")
|
print(f"Using Export Directory (Working Directory): {export_dir}")
|
||||||
|
|
||||||
portal_instance = None
|
portal_instance = None
|
||||||
project_object = None
|
project_object = None
|
||||||
|
@ -228,31 +274,33 @@ if __name__ == "__main__":
|
||||||
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...")
|
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...")
|
||||||
portal_instance = ts.open_portal(
|
portal_instance = ts.open_portal(
|
||||||
version=TIA_PORTAL_VERSION,
|
version=TIA_PORTAL_VERSION,
|
||||||
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface
|
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
|
||||||
)
|
)
|
||||||
print("Connected to TIA Portal.")
|
print("Connected to TIA Portal.")
|
||||||
print(f"Portal Process ID: {portal_instance.get_process_id()}") #
|
print(f"Portal Process ID: {portal_instance.get_process_id()}") #
|
||||||
|
|
||||||
# 3. Open Project
|
# 3. Open Project
|
||||||
print(f"Opening project: {os.path.basename(project_file)}...")
|
print(f"Opening project: {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("Project might already be open, attempting to get handle...")
|
||||||
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("Failed to open or get the specified project.")
|
||||||
print("Project opened successfully.")
|
print("Project opened successfully.")
|
||||||
|
|
||||||
# 4. Get PLCs
|
# 4. 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 PLC devices found in the project.")
|
||||||
else:
|
else:
|
||||||
print(f"Found {len(plcs)} PLC(s). Starting export process...")
|
print(f"Found {len(plcs)} PLC(s). Starting export process...")
|
||||||
|
|
||||||
# 5. Iterate and Export Data for each PLC
|
# 5. Iterate and Export Data for each PLC
|
||||||
for plc_device in plcs:
|
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("\nExport process completed.")
|
print("\nExport process completed.")
|
||||||
|
|
||||||
|
@ -269,9 +317,9 @@ if __name__ == "__main__":
|
||||||
if portal_instance:
|
if portal_instance:
|
||||||
try:
|
try:
|
||||||
print("\nClosing TIA Portal...")
|
print("\nClosing TIA Portal...")
|
||||||
portal_instance.close_portal() #
|
portal_instance.close_portal() #
|
||||||
print("TIA Portal closed.")
|
print("TIA Portal closed.")
|
||||||
except Exception as close_ex:
|
except Exception as close_ex:
|
||||||
print(f"Error during TIA Portal cleanup: {close_ex}")
|
print(f"Error during TIA Portal cleanup: {close_ex}")
|
||||||
|
|
||||||
print("\nScript finished.")
|
print("\nScript finished.")
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
"""
|
"""
|
||||||
export_CAx_from_tia :
|
export_CAx_from_tia :
|
||||||
Script que exporta los datos CAx de un proyecto de TIA Portal y genera un resumen en Markdown.
|
Script que exporta los datos CAx de un proyecto de TIA Portal y genera un resumen en Markdown.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import filedialog
|
from tkinter import filedialog
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import xml.etree.ElementTree as ET # Library to parse XML (AML)
|
import xml.etree.ElementTree as ET # Library to parse XML (AML)
|
||||||
|
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__)))
|
||||||
|
@ -16,12 +18,12 @@ 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
|
TIA_PORTAL_VERSION = "18.0" # Target TIA Portal version
|
||||||
|
|
||||||
# --- TIA Scripting Import Handling ---
|
# --- TIA Scripting Import Handling ---
|
||||||
# (Same import handling as the previous script)
|
# (Same import handling as the previous script)
|
||||||
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:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -38,13 +40,19 @@ except Exception as e:
|
||||||
|
|
||||||
# --- Functions ---
|
# --- Functions ---
|
||||||
|
|
||||||
|
|
||||||
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()
|
root.withdraw()
|
||||||
file_path = filedialog.askopenfilename(
|
file_path = filedialog.askopenfilename(
|
||||||
title="Select TIA Portal Project File",
|
title="Select TIA Portal Project File",
|
||||||
filetypes=[(f"TIA Portal V{TIA_PORTAL_VERSION} Projects", f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}")]
|
filetypes=[
|
||||||
|
(
|
||||||
|
f"TIA Portal V{TIA_PORTAL_VERSION} Projects",
|
||||||
|
f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}",
|
||||||
|
)
|
||||||
|
],
|
||||||
)
|
)
|
||||||
root.destroy()
|
root.destroy()
|
||||||
if not file_path:
|
if not file_path:
|
||||||
|
@ -52,6 +60,7 @@ def select_project_file():
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
def select_output_directory():
|
def select_output_directory():
|
||||||
"""Opens a dialog to select the output directory."""
|
"""Opens a dialog to select the output directory."""
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
|
@ -65,35 +74,42 @@ def select_output_directory():
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return dir_path
|
return dir_path
|
||||||
|
|
||||||
|
|
||||||
def find_elements(element, path):
|
def find_elements(element, path):
|
||||||
"""Helper to find elements using namespaces commonly found in AML."""
|
"""Helper to find elements using namespaces commonly found in AML."""
|
||||||
# AutomationML namespaces often vary slightly or might be default
|
# AutomationML namespaces often vary slightly or might be default
|
||||||
# This basic approach tries common prefixes or no prefix
|
# This basic approach tries common prefixes or no prefix
|
||||||
namespaces = {
|
namespaces = {
|
||||||
'': element.tag.split('}')[0][1:] if '}' in element.tag else '', # Default namespace if present
|
"": (
|
||||||
'caex': 'http://www.dke.de/CAEX', # Common CAEX namespace
|
element.tag.split("}")[0][1:] if "}" in element.tag else ""
|
||||||
|
), # Default namespace if present
|
||||||
|
"caex": "http://www.dke.de/CAEX", # Common CAEX namespace
|
||||||
# Add other potential namespaces if needed based on file inspection
|
# Add other potential namespaces if needed based on file inspection
|
||||||
}
|
}
|
||||||
# Try finding with common prefixes or the default namespace
|
# Try finding with common prefixes or the default namespace
|
||||||
for prefix, uri in namespaces.items():
|
for prefix, uri in namespaces.items():
|
||||||
# Construct path with namespace URI if prefix is defined
|
# Construct path with namespace URI if prefix is defined
|
||||||
namespaced_path = path
|
namespaced_path = path
|
||||||
if prefix:
|
if prefix:
|
||||||
parts = path.split('/')
|
parts = path.split("/")
|
||||||
namespaced_parts = [f"{{{uri}}}{part}" if part != '.' else part for part in parts]
|
namespaced_parts = [
|
||||||
namespaced_path = '/'.join(namespaced_parts)
|
f"{{{uri}}}{part}" if part != "." else part for part in parts
|
||||||
|
]
|
||||||
# Try findall with the constructed path
|
namespaced_path = "/".join(namespaced_parts)
|
||||||
found = element.findall(namespaced_path)
|
|
||||||
if found:
|
# Try findall with the constructed path
|
||||||
return found # Return first successful find
|
found = element.findall(namespaced_path)
|
||||||
|
if found:
|
||||||
|
return found # Return first successful find
|
||||||
|
|
||||||
# Fallback: try finding without explicit namespace (might work if default ns is used throughout)
|
# Fallback: try finding without explicit namespace (might work if default ns is used throughout)
|
||||||
# This might require adjusting the path string itself depending on the XML structure
|
# This might require adjusting the path string itself depending on the XML structure
|
||||||
try:
|
try:
|
||||||
# Simple attempt without namespace handling if the above fails
|
# Simple attempt without namespace handling if the above fails
|
||||||
return element.findall(path)
|
return element.findall(path)
|
||||||
except SyntaxError: # Handle potential errors if path isn't valid without namespaces
|
except (
|
||||||
|
SyntaxError
|
||||||
|
): # Handle potential errors if path isn't valid without namespaces
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,96 +125,137 @@ def parse_aml_to_markdown(aml_file_path, md_file_path):
|
||||||
# Find InstanceHierarchy - usually contains the project structure
|
# Find InstanceHierarchy - usually contains the project structure
|
||||||
# Note: Namespace handling in ElementTree can be tricky. Adjust '{...}' part if needed.
|
# Note: Namespace handling in ElementTree can be tricky. Adjust '{...}' part if needed.
|
||||||
# We will use a helper function 'find_elements' to try common patterns
|
# We will use a helper function 'find_elements' to try common patterns
|
||||||
instance_hierarchies = find_elements(root, './/InstanceHierarchy') # Common CAEX tag
|
instance_hierarchies = find_elements(
|
||||||
|
root, ".//InstanceHierarchy"
|
||||||
|
) # Common CAEX tag
|
||||||
|
|
||||||
if not instance_hierarchies:
|
if not instance_hierarchies:
|
||||||
markdown_lines.append("Could not find InstanceHierarchy in the AML file.")
|
markdown_lines.append("Could not find InstanceHierarchy in the AML file.")
|
||||||
print("Warning: Could not find InstanceHierarchy element.")
|
print("Warning: Could not find InstanceHierarchy element.")
|
||||||
else:
|
else:
|
||||||
# Assuming the first InstanceHierarchy is the main one
|
# Assuming the first InstanceHierarchy is the main one
|
||||||
ih = instance_hierarchies[0]
|
ih = instance_hierarchies[0]
|
||||||
markdown_lines.append(f"## Instance Hierarchy: {ih.get('Name', 'N/A')}")
|
markdown_lines.append(f"## Instance Hierarchy: {ih.get('Name', 'N/A')}")
|
||||||
markdown_lines.append("")
|
markdown_lines.append("")
|
||||||
|
|
||||||
# Look for InternalElements which represent devices/components
|
# Look for InternalElements which represent devices/components
|
||||||
internal_elements = find_elements(ih, './/InternalElement') # Common CAEX tag
|
internal_elements = find_elements(
|
||||||
|
ih, ".//InternalElement"
|
||||||
|
) # Common CAEX tag
|
||||||
|
|
||||||
if not internal_elements:
|
if not internal_elements:
|
||||||
markdown_lines.append("No devices (InternalElement) found in InstanceHierarchy.")
|
markdown_lines.append(
|
||||||
print("Info: No InternalElement tags found under InstanceHierarchy.")
|
"No devices (InternalElement) found in InstanceHierarchy."
|
||||||
|
)
|
||||||
|
print("Info: No InternalElement tags found under InstanceHierarchy.")
|
||||||
else:
|
else:
|
||||||
markdown_lines.append(f"Found {len(internal_elements)} device(s)/component(s):")
|
markdown_lines.append(
|
||||||
|
f"Found {len(internal_elements)} device(s)/component(s):"
|
||||||
|
)
|
||||||
markdown_lines.append("")
|
markdown_lines.append("")
|
||||||
markdown_lines.append("| Name | SystemUnitClass | RefBaseSystemUnitPath | Attributes |")
|
markdown_lines.append(
|
||||||
|
"| Name | SystemUnitClass | RefBaseSystemUnitPath | Attributes |"
|
||||||
|
)
|
||||||
markdown_lines.append("|---|---|---|---|")
|
markdown_lines.append("|---|---|---|---|")
|
||||||
|
|
||||||
for elem in internal_elements:
|
for elem in internal_elements:
|
||||||
name = elem.get('Name', 'N/A')
|
name = elem.get("Name", "N/A")
|
||||||
ref_path = elem.get('RefBaseSystemUnitPath', 'N/A') # Path to class definition
|
ref_path = elem.get(
|
||||||
|
"RefBaseSystemUnitPath", "N/A"
|
||||||
|
) # Path to class definition
|
||||||
|
|
||||||
# Try to get the class name from the RefBaseSystemUnitPath or SystemUnitClassLib
|
# Try to get the class name from the RefBaseSystemUnitPath or SystemUnitClassLib
|
||||||
su_class_path = find_elements(elem, './/SystemUnitClass') # Check direct child first
|
su_class_path = find_elements(
|
||||||
su_class = su_class_path[0].get('Path', 'N/A') if su_class_path else ref_path.split('/')[-1] # Fallback to last part of path
|
elem, ".//SystemUnitClass"
|
||||||
|
) # Check direct child first
|
||||||
|
su_class = (
|
||||||
|
su_class_path[0].get("Path", "N/A")
|
||||||
|
if su_class_path
|
||||||
|
else ref_path.split("/")[-1]
|
||||||
|
) # Fallback to last part of path
|
||||||
|
|
||||||
attributes_md = ""
|
attributes_md = ""
|
||||||
attributes = find_elements(elem, './/Attribute') # Find attributes
|
attributes = find_elements(elem, ".//Attribute") # Find attributes
|
||||||
attr_list = []
|
attr_list = []
|
||||||
for attr in attributes:
|
for attr in attributes:
|
||||||
attr_name = attr.get('Name', '')
|
attr_name = attr.get("Name", "")
|
||||||
attr_value_elem = find_elements(attr, './/Value') # Get Value element
|
attr_value_elem = find_elements(
|
||||||
attr_value = attr_value_elem[0].text if attr_value_elem and attr_value_elem[0].text else 'N/A'
|
attr, ".//Value"
|
||||||
|
) # Get Value element
|
||||||
|
attr_value = (
|
||||||
|
attr_value_elem[0].text
|
||||||
|
if attr_value_elem and attr_value_elem[0].text
|
||||||
|
else "N/A"
|
||||||
|
)
|
||||||
|
|
||||||
# Look for potential IP addresses (common attribute names)
|
# Look for potential IP addresses (common attribute names)
|
||||||
if "Address" in attr_name or "IP" in attr_name:
|
if "Address" in attr_name or "IP" in attr_name:
|
||||||
attr_list.append(f"**{attr_name}**: {attr_value}")
|
attr_list.append(f"**{attr_name}**: {attr_value}")
|
||||||
else:
|
else:
|
||||||
attr_list.append(f"{attr_name}: {attr_value}")
|
attr_list.append(f"{attr_name}: {attr_value}")
|
||||||
|
|
||||||
attributes_md = "<br>".join(attr_list) if attr_list else "None"
|
attributes_md = "<br>".join(attr_list) if attr_list else "None"
|
||||||
|
|
||||||
|
markdown_lines.append(
|
||||||
markdown_lines.append(f"| {name} | {su_class} | `{ref_path}` | {attributes_md} |")
|
f"| {name} | {su_class} | `{ref_path}` | {attributes_md} |"
|
||||||
|
)
|
||||||
|
|
||||||
# Write to Markdown file
|
# Write to Markdown file
|
||||||
with open(md_file_path, 'w', encoding='utf-8') as f:
|
with open(md_file_path, "w", encoding="utf-8") as f:
|
||||||
f.write("\n".join(markdown_lines))
|
f.write("\n".join(markdown_lines))
|
||||||
print(f"Markdown summary written to: {md_file_path}")
|
print(f"Markdown summary written to: {md_file_path}")
|
||||||
|
|
||||||
except ET.ParseError as xml_err:
|
except ET.ParseError as xml_err:
|
||||||
print(f"ERROR parsing XML file {aml_file_path}: {xml_err}")
|
print(f"ERROR parsing XML file {aml_file_path}: {xml_err}")
|
||||||
with open(md_file_path, 'w', encoding='utf-8') as f:
|
with open(md_file_path, "w", encoding="utf-8") as f:
|
||||||
f.write(f"# Error\n\nFailed to parse AML file: {os.path.basename(aml_file_path)}\n\nError: {xml_err}")
|
f.write(
|
||||||
|
f"# Error\n\nFailed to parse AML file: {os.path.basename(aml_file_path)}\n\nError: {xml_err}"
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERROR processing AML file {aml_file_path}: {e}")
|
print(f"ERROR processing AML file {aml_file_path}: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
with open(md_file_path, 'w', encoding='utf-8') as f:
|
with open(md_file_path, "w", encoding="utf-8") as f:
|
||||||
f.write(f"# Error\n\nAn unexpected error occurred while processing AML file: {os.path.basename(aml_file_path)}\n\nError: {e}")
|
f.write(
|
||||||
|
f"# Error\n\nAn unexpected error occurred while processing AML file: {os.path.basename(aml_file_path)}\n\nError: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- Main Script ---
|
# --- Main Script ---
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
configs = load_configuration()
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
print("--- TIA Portal Project CAx Exporter and Analyzer ---")
|
print("--- TIA Portal Project CAx Exporter and Analyzer ---")
|
||||||
|
|
||||||
# 1. Select Files/Folders
|
# Validate working directory
|
||||||
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
|
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, Output Directory comes from config
|
||||||
project_file = select_project_file()
|
project_file = select_project_file()
|
||||||
output_dir = select_output_directory()
|
output_dir = Path(
|
||||||
|
working_directory
|
||||||
|
) # Use working directory from config, ensure it's a Path object
|
||||||
|
|
||||||
print(f"\nSelected Project: {project_file}")
|
print(f"\nSelected Project: {project_file}")
|
||||||
print(f"Selected Output Directory: {output_dir}")
|
print(f"Using Output Directory (Working Directory): {output_dir}")
|
||||||
|
|
||||||
# Define output file names
|
# Define output file names using Path object
|
||||||
project_base_name = os.path.splitext(os.path.basename(project_file))[0]
|
project_path = Path(project_file)
|
||||||
aml_file = os.path.join(output_dir, f"{project_base_name}_CAx_Export.aml")
|
project_base_name = project_path.stem # Get filename without extension
|
||||||
md_file = os.path.join(output_dir, f"{project_base_name}_CAx_Summary.md")
|
aml_file = output_dir / f"{project_base_name}_CAx_Export.aml"
|
||||||
log_file = os.path.join(output_dir, f"{project_base_name}_CAx_Export.log") # Log file for the export process
|
md_file = output_dir / f"{project_base_name}_CAx_Summary.md"
|
||||||
|
log_file = (
|
||||||
|
output_dir / f"{project_base_name}_CAx_Export.log"
|
||||||
|
) # Log file for the export process
|
||||||
|
|
||||||
print(f"Will export CAx data to: {aml_file}")
|
print(f"Will export CAx data to: {aml_file}")
|
||||||
print(f"Will generate summary to: {md_file}")
|
print(f"Will generate summary to: {md_file}")
|
||||||
print(f"Export log file: {log_file}")
|
print(f"Export log file: {log_file}")
|
||||||
|
|
||||||
|
|
||||||
portal_instance = None
|
portal_instance = None
|
||||||
project_object = None
|
project_object = None
|
||||||
cax_export_successful = False
|
cax_export_successful = False
|
||||||
|
@ -208,25 +265,33 @@ if __name__ == "__main__":
|
||||||
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...")
|
print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...")
|
||||||
portal_instance = ts.open_portal(
|
portal_instance = ts.open_portal(
|
||||||
version=TIA_PORTAL_VERSION,
|
version=TIA_PORTAL_VERSION,
|
||||||
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface
|
portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
|
||||||
)
|
)
|
||||||
print("Connected.")
|
print("Connected.")
|
||||||
|
|
||||||
# 3. Open Project
|
# 3. Open Project
|
||||||
print(f"Opening project: {os.path.basename(project_file)}...")
|
print(
|
||||||
project_object = portal_instance.open_project(project_file_path=project_file)
|
f"Opening project: {project_path.name}..."
|
||||||
|
) # Use Path object's name attribute
|
||||||
|
project_object = portal_instance.open_project(
|
||||||
|
project_file_path=str(project_path)
|
||||||
|
) # Pass path as string
|
||||||
if project_object is None:
|
if project_object is None:
|
||||||
project_object = portal_instance.get_project()
|
print("Project might already be open, attempting to get handle...")
|
||||||
if project_object is None:
|
project_object = portal_instance.get_project()
|
||||||
raise Exception("Failed to open or get the specified project.")
|
if project_object is None:
|
||||||
|
raise Exception("Failed to open or get the specified project.")
|
||||||
print("Project opened.")
|
print("Project opened.")
|
||||||
|
|
||||||
# 4. Export CAx Data (Project Level)
|
# 4. Export CAx Data (Project Level)
|
||||||
print(f"Exporting CAx data for the project to {aml_file}...")
|
print(f"Exporting CAx data for the project to {aml_file}...")
|
||||||
# Ensure output directory exists for the log file as well
|
# Ensure output directory exists (Path.mkdir handles this implicitly if needed later, but good practice)
|
||||||
os.makedirs(os.path.dirname(log_file), exist_ok=True)
|
output_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
export_result = project_object.export_cax_data(export_file_path=aml_file, log_file_path=log_file) # [cite: 361]
|
# Pass paths as strings to the TIA function
|
||||||
|
export_result = project_object.export_cax_data(
|
||||||
|
export_file_path=str(aml_file), log_file_path=str(log_file)
|
||||||
|
)
|
||||||
|
|
||||||
if export_result:
|
if export_result:
|
||||||
print("CAx data exported successfully.")
|
print("CAx data exported successfully.")
|
||||||
|
@ -235,9 +300,10 @@ if __name__ == "__main__":
|
||||||
print("CAx data export failed. Check the log file for details:")
|
print("CAx data export failed. Check the log file for details:")
|
||||||
print(f" Log file: {log_file}")
|
print(f" Log file: {log_file}")
|
||||||
# Write basic error message to MD file if export fails
|
# Write basic error message to MD file if export fails
|
||||||
with open(md_file, 'w', encoding='utf-8') as f:
|
with open(md_file, "w", encoding="utf-8") as f:
|
||||||
f.write(f"# Error\n\nCAx data export failed. Check log file: {log_file}")
|
f.write(
|
||||||
|
f"# Error\n\nCAx data export failed. Check log file: {log_file}"
|
||||||
|
)
|
||||||
|
|
||||||
except ts.TiaException as tia_ex:
|
except ts.TiaException as tia_ex:
|
||||||
print(f"\nTIA Portal Openness Error: {tia_ex}")
|
print(f"\nTIA Portal Openness Error: {tia_ex}")
|
||||||
|
@ -259,11 +325,15 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# 5. Parse AML and Generate Markdown (only if export was successful)
|
# 5. Parse AML and Generate Markdown (only if export was successful)
|
||||||
if cax_export_successful:
|
if cax_export_successful:
|
||||||
if os.path.exists(aml_file):
|
if aml_file.exists(): # Use Path object's exists() method
|
||||||
parse_aml_to_markdown(aml_file, md_file)
|
parse_aml_to_markdown(aml_file, md_file)
|
||||||
else:
|
else:
|
||||||
print(f"ERROR: Export was reported successful, but AML file not found at {aml_file}")
|
print(
|
||||||
with open(md_file, 'w', encoding='utf-8') as f:
|
f"ERROR: Export was reported successful, but AML file not found at {aml_file}"
|
||||||
f.write(f"# Error\n\nExport was reported successful, but AML file not found:\n{aml_file}")
|
)
|
||||||
|
with open(md_file, "w", encoding="utf-8") as f:
|
||||||
|
f.write(
|
||||||
|
f"# Error\n\nExport was reported successful, but AML file not found:\n{aml_file}"
|
||||||
|
)
|
||||||
|
|
||||||
print("\nScript finished.")
|
print("\nScript finished.")
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
"""
|
"""
|
||||||
export_io_from_CAx :
|
export_io_from_CAx :
|
||||||
Script que sirve para exraer los IOs de un proyecto de TIA Portal y
|
Script que sirve para exraer los IOs de un proyecto de TIA Portal y
|
||||||
generar un archivo Markdown con la información.
|
generar un archivo Markdown con la información.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from tkinter import filedialog
|
from tkinter import filedialog
|
||||||
|
@ -19,6 +20,7 @@ script_root = os.path.dirname(
|
||||||
sys.path.append(script_root)
|
sys.path.append(script_root)
|
||||||
from backend.script_utils import load_configuration
|
from backend.script_utils import load_configuration
|
||||||
|
|
||||||
|
|
||||||
# --- extract_aml_data function (Unchanged from v15) ---
|
# --- extract_aml_data function (Unchanged from v15) ---
|
||||||
def extract_aml_data(root):
|
def extract_aml_data(root):
|
||||||
"""(v15 logic - Unchanged) Extracts data, correcting PLC network association lookup."""
|
"""(v15 logic - Unchanged) Extracts data, correcting PLC network association lookup."""
|
||||||
|
@ -955,13 +957,15 @@ def process_aml_file(
|
||||||
print(f"ERROR processing AML file {aml_file_path}: {e}")
|
print(f"ERROR processing AML file {aml_file_path}: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
def select_cax_file():
|
|
||||||
"""Opens a dialog to select a CAx (XML) export file."""
|
def select_cax_file(initial_dir=None): # Add initial_dir parameter
|
||||||
|
"""Opens a dialog to select a CAx (XML) export file, starting in the specified directory."""
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.withdraw()
|
root.withdraw()
|
||||||
file_path = filedialog.askopenfilename(
|
file_path = filedialog.askopenfilename(
|
||||||
title="Select CAx Export File (XML)",
|
title="Select CAx Export File (XML)",
|
||||||
filetypes=[("XML Files", "*.xml"), ("All Files", "*.*")] # Changed filetypes
|
filetypes=[("XML Files", "*.xml"), ("AML Files", "*.aml"), ("All Files", "*.*")], # Added AML
|
||||||
|
initialdir=initial_dir # Set the initial directory
|
||||||
)
|
)
|
||||||
root.destroy()
|
root.destroy()
|
||||||
if not file_path:
|
if not file_path:
|
||||||
|
@ -969,12 +973,13 @@ def select_cax_file():
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
def select_output_directory():
|
def select_output_directory():
|
||||||
"""Opens a dialog to select the output directory."""
|
"""Opens a dialog to select the output directory."""
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.withdraw()
|
root.withdraw()
|
||||||
dir_path = filedialog.askdirectory(
|
dir_path = filedialog.askdirectory(
|
||||||
title="Select Output Directory for JSON and MD files" # Updated title slightly
|
title="Select Output Directory for JSON and MD files" # Updated title slightly
|
||||||
)
|
)
|
||||||
root.destroy()
|
root.destroy()
|
||||||
if not dir_path:
|
if not dir_path:
|
||||||
|
@ -982,35 +987,53 @@ def select_output_directory():
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return dir_path
|
return dir_path
|
||||||
|
|
||||||
|
|
||||||
# --- Main Execution ---
|
# --- Main Execution ---
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# configs = load_configuration() # Keep if needed, otherwise remove
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
script_version = "v27 - User Input/Output Paths" # Updated version
|
script_version = "v28 - Working Directory Integration" # Updated version
|
||||||
print(
|
print(
|
||||||
f"--- AML (CAx Export) to Hierarchical JSON and Obsidian MD Converter ({script_version}) ---"
|
f"--- AML (CAx Export) to Hierarchical JSON and Obsidian MD Converter ({script_version}) ---"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 1. Select Input CAx File and Output Directory
|
# Validate working directory
|
||||||
cax_file_path = select_cax_file()
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
output_dir = select_output_directory()
|
print("ERROR: Working directory not set or invalid in configuration.")
|
||||||
|
print("Attempting to use script's directory as fallback.")
|
||||||
|
# Fallback to script's directory or current directory if needed
|
||||||
|
working_directory = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
if not os.path.isdir(working_directory):
|
||||||
|
working_directory = os.getcwd()
|
||||||
|
print(f"Using fallback directory: {working_directory}")
|
||||||
|
# Optionally, prompt user to select a working directory here if critical
|
||||||
|
# output_dir = select_output_directory() # Keep this if you want user selection on failure
|
||||||
|
|
||||||
|
# Use working_directory as the output directory
|
||||||
|
output_dir = working_directory
|
||||||
|
print(f"Using Working Directory for Output: {output_dir}")
|
||||||
|
|
||||||
|
# 1. Select Input CAx File, starting in the working directory
|
||||||
|
# Pass working_directory to the selection function
|
||||||
|
cax_file_path = select_cax_file(initial_dir=working_directory)
|
||||||
|
|
||||||
# Convert paths to Path objects
|
# Convert paths to Path objects
|
||||||
input_path = Path(cax_file_path)
|
input_path = Path(cax_file_path)
|
||||||
output_path = Path(output_dir)
|
output_path = Path(output_dir) # Output path is the working directory
|
||||||
|
|
||||||
# Check if input file exists
|
# Check if input file exists
|
||||||
if not input_path.is_file():
|
if not input_path.is_file():
|
||||||
print(f"ERROR: Input file '{input_path}' not found or is not a file.")
|
print(f"ERROR: Input file '{input_path}' not found or is not a file.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Ensure output directory exists
|
# Ensure output directory exists (redundant if working_directory is valid, but safe)
|
||||||
output_path.mkdir(parents=True, exist_ok=True)
|
output_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# Construct output file paths within the selected output directory
|
# Construct output file paths within the selected output directory (working_directory)
|
||||||
output_json_file = output_path / input_path.with_suffix(".hierarchical.json").name
|
output_json_file = output_path / input_path.with_suffix(".hierarchical.json").name
|
||||||
output_md_file = output_path / input_path.with_name(f"{input_path.stem}_Hardware_Tree.md").name
|
output_md_file = output_path / input_path.with_name(f"{input_path.stem}_Hardware_Tree.md") # Simplified name
|
||||||
output_md_upward_file = output_path / input_path.with_name(f"{input_path.stem}_IO_Upward_Debug.md").name
|
output_md_upward_file = output_path / input_path.with_name(f"{input_path.stem}_IO_Upward_Debug.md") # Simplified name
|
||||||
|
|
||||||
print(f"Input AML: {input_path.resolve()}")
|
print(f"Input AML: {input_path.resolve()}")
|
||||||
print(f"Output Directory: {output_path.resolve()}")
|
print(f"Output Directory: {output_path.resolve()}")
|
||||||
|
|
1936
data/log.txt
1936
data/log.txt
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
||||||
|
flask
|
||||||
|
flask-sock
|
||||||
|
lxml
|
||||||
|
pandas
|
||||||
|
google-cloud-translate
|
||||||
|
openai
|
||||||
|
ollama
|
||||||
|
langid
|
||||||
|
openpyxl
|
||||||
|
beautifulsoup4
|
||||||
|
requests
|
||||||
|
mammoth
|
||||||
|
html2text
|
||||||
|
pypandoc
|
||||||
|
# siemens-tia-scripting # Requiere instalación especial de TIA Portal Openness
|
Loading…
Reference in New Issue