Add test script for verifying SIMATIC SD compatibility detection
- Implemented a new test script `test_simatic_sd_compatibility.py` to check the availability of SIMATIC SD format in TIA Scripting. - Included detailed analysis of SIMATIC SD requirements based on official Siemens documentation. - Provided feedback on supported and unsupported programming languages and block types. - Added error handling for TIA Scripting import and environment variable checks.
This commit is contained in:
parent
affab8a646
commit
586e3cc9b3
|
@ -5,22 +5,22 @@
|
|||
"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
|
||||
},
|
||||
"x4.py": {
|
||||
"display_name": "2: Exportar Referencias Cruzadas desde Tia Portal",
|
||||
"short_description": "Script para exportar las referencias cruzadas",
|
||||
"long_description": "",
|
||||
"hidden": false
|
||||
},
|
||||
"x2.py": {
|
||||
"display_name": "2: Exportar Lógica desde TIA Portal V20 en SIMATIC SD format",
|
||||
"short_description": "export_logic_from_tia_v20_simatic_sd : Script para exportar el software de un PLC desde TIA Portal V20",
|
||||
"long_description": "",
|
||||
"short_description": "Script para exportar el software de un PLC desde TIA Portal V20 en el nuevo formato SIMATIC SD",
|
||||
"long_description": "Script especializado para exportar bloques de PLC desde TIA Portal V20 utilizando el nuevo formato SIMATIC SD (Structured Data). Este formato proporciona una representación más estructurada y moderna de los datos del PLC.\n***\n**Características principales:**\n\n1. **Formato SIMATIC SD:** Utiliza el nuevo formato de exportación disponible en TIA Portal V20+\n2. **Detección automática:** Verifica compatibilidad con el formato SIMATIC SD antes de la exportación\n3. **Comparación dual:** Exporta tanto en formato SIMATIC SD como en XML tradicional para comparación\n4. **Estructura organizada:** Crea carpetas separadas para bloques, UDTs y tablas de variables\n5. **Timestamp único:** Evita conflictos con exports anteriores usando timestamp en nombres de carpetas\n\n**Estructura de exportación:**\n- `01_ProgramBlocks_SD/` - Bloques en formato SIMATIC SD\n- `02_ProgramBlocks_XML_Compare/` - Bloques en XML para comparación\n- `03_PlcDataTypes_SD/` - UDTs en formato SIMATIC SD\n- `04_PlcDataTypes_XML_Compare/` - UDTs en XML para comparación\n- `05_PlcTags_SD/` - Tablas de variables en formato SIMATIC SD\n- `06_PlcTags_XML_Compare/` - Tablas de variables en XML para comparación\n\n**Compatibilidad:** Requiere TIA Portal V20 o superior. Puede ejecutarse después de x1.py sin conflictos.",
|
||||
"hidden": false
|
||||
},
|
||||
"x4.py": {
|
||||
"display_name": "3: Exportar Referencias Cruzadas desde TIA Portal",
|
||||
"short_description": "Script para exportar las referencias cruzadas de un proyecto TIA Portal",
|
||||
"long_description": "Este script exporta las referencias cruzadas (cross-references) de un proyecto TIA Portal, proporcionando información detallada sobre las interconexiones entre variables, bloques y componentes del sistema.\n***\n**Funcionalidad:**\n\n1. **Referencias cruzadas:** Extrae información sobre dónde se utilizan las variables y bloques\n2. **Análisis de dependencias:** Identifica relaciones entre componentes del proyecto\n3. **Documentación:** Genera reportes útiles para mantenimiento y debugging\n4. **Formato estructurado:** Exporta en formato legible para análisis posterior\n\n**Casos de uso:**\n- Documentación de proyecto\n- Análisis de impacto de cambios\n- Debugging y mantenimiento\n- Auditorías de código",
|
||||
"hidden": false
|
||||
},
|
||||
"xTest.py": {
|
||||
"display_name": "xTest",
|
||||
"display_name": "xTest - Pruebas SIMATIC SD ExportAsDocuments",
|
||||
"short_description": "Test específico para exportación SIMATIC SD usando ExportAsDocuments()",
|
||||
"long_description": "",
|
||||
"long_description": "Script de prueba experimental para validar la funcionalidad de exportación SIMATIC SD utilizando el método ExportAsDocuments() de la API de TIA Portal Openness.\n***\n**Propósito:**\n\n1. **Validación de API:** Prueba diferentes métodos de exportación SIMATIC SD\n2. **Comparación de métodos:** Evalúa ExportAsDocuments() vs Export() estándar\n3. **Debugging:** Identifica problemas y limitaciones en la exportación SD\n4. **Desarrollo:** Base para mejoras en scripts de producción\n\n**Estado:** Script experimental - usar solo para pruebas y desarrollo\n\n**Nota:** Este script es parte del proceso de desarrollo y optimización de los métodos de exportación SIMATIC SD.",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
"""
|
||||
Test script to verify SIMATIC SD compatibility detection
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# --- TIA Scripting Import Handling ---
|
||||
if os.getenv("TIA_SCRIPTING"):
|
||||
sys.path.append(os.getenv("TIA_SCRIPTING"))
|
||||
|
||||
try:
|
||||
import siemens_tia_scripting as ts
|
||||
|
||||
print("✓ TIA Scripting import successful")
|
||||
print(
|
||||
f"Available programming languages: {[lang for lang in dir(ts.Enums.ProgrammingLanguage) if not lang.startswith('_')]}"
|
||||
)
|
||||
print(
|
||||
f"Available export formats: {[fmt for fmt in dir(ts.Enums.ExportFormats) if not fmt.startswith('_')]}"
|
||||
)
|
||||
print(
|
||||
f"Available block types: {[bt for bt in dir(ts.Enums.BlockType) if not bt.startswith('_')]}"
|
||||
)
|
||||
|
||||
# Check if SIMATIC SD is available
|
||||
try:
|
||||
simatic_sd_format = ts.Enums.ExportFormats.SimaticSD
|
||||
print(f"✓ SIMATIC SD format available: {simatic_sd_format}")
|
||||
except AttributeError:
|
||||
print("✗ SIMATIC SD format NOT available in this TIA Scripting version")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"✗ Failed to import TIA Scripting: {e}")
|
||||
print(
|
||||
"This is expected if TIA Portal is not installed or TIA_SCRIPTING env var not set"
|
||||
)
|
||||
|
||||
|
||||
def analyze_simatic_sd_requirements():
|
||||
"""Analyze and display SIMATIC SD requirements"""
|
||||
print("\n=== SIMATIC SD FORMAT REQUIREMENTS ===")
|
||||
print("Based on official Siemens documentation:")
|
||||
print()
|
||||
print("✓ SUPPORTED:")
|
||||
print(" • Programming Language: LAD (Ladder) ONLY")
|
||||
print(
|
||||
" • Block Types: FB (Function Block), FC (Function), OB (Organization Block)"
|
||||
)
|
||||
print(" • TIA Portal Version: V20 or later")
|
||||
print(" • Target PLCs: S7-1200, S7-1500")
|
||||
print()
|
||||
print("✗ NOT SUPPORTED:")
|
||||
print(" • SCL (Structured Control Language)")
|
||||
print(" • STL (Statement List)")
|
||||
print(" • FBD (Function Block Diagram)")
|
||||
print(" • Graph programming")
|
||||
print(" • CFC (Continuous Function Chart)")
|
||||
print(" • Complex LAD elements (some advanced functions)")
|
||||
print()
|
||||
print("📋 COMMON CAUSES FOR XML-ONLY EXPORT:")
|
||||
print(" 1. Block programmed in SCL/STL/FBD instead of LAD")
|
||||
print(" 2. Block contains unsupported LAD elements")
|
||||
print(" 3. Block is not compiled/consistent")
|
||||
print(" 4. TIA Portal version < V20")
|
||||
print(" 5. Wrong block type (not FB/FC/OB)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
analyze_simatic_sd_requirements()
|
|
@ -61,6 +61,154 @@ except Exception as e:
|
|||
# --- Functions ---
|
||||
|
||||
|
||||
def verify_export_format(export_path, expected_format="SIMATIC_SD"):
|
||||
"""
|
||||
Verifies what format was actually exported by examining file extensions.
|
||||
Returns (actual_format, file_extensions, file_count)
|
||||
"""
|
||||
if not os.path.exists(export_path):
|
||||
return "NO_FILES", [], 0
|
||||
|
||||
files = [
|
||||
f
|
||||
for f in os.listdir(export_path)
|
||||
if os.path.isfile(os.path.join(export_path, f))
|
||||
]
|
||||
if not files:
|
||||
return "EMPTY_FOLDER", [], 0
|
||||
|
||||
extensions = [os.path.splitext(f)[1].lower() for f in files]
|
||||
extension_counts = {}
|
||||
for ext in extensions:
|
||||
extension_counts[ext] = extension_counts.get(ext, 0) + 1
|
||||
|
||||
# Determine actual format based on file extensions
|
||||
if all(ext == ".xml" for ext in extensions):
|
||||
actual_format = "XML_ONLY"
|
||||
elif any(ext in [".sd", ".simatic"] for ext in extensions):
|
||||
actual_format = "SIMATIC_SD"
|
||||
elif ".xml" in extensions and len(set(extensions)) > 1:
|
||||
actual_format = "MIXED"
|
||||
else:
|
||||
actual_format = "UNKNOWN"
|
||||
|
||||
return actual_format, extension_counts, len(files)
|
||||
|
||||
|
||||
def check_simatic_sd_block_compatibility(block):
|
||||
"""
|
||||
Checks if a block is compatible with SIMATIC SD export format.
|
||||
Returns (is_compatible, reason)
|
||||
"""
|
||||
try:
|
||||
# Check if block is consistent
|
||||
if not block.is_consistent():
|
||||
return False, "Block is not consistent/compiled"
|
||||
|
||||
# Check programming language - SIMATIC SD only supports LAD
|
||||
try:
|
||||
prog_lang = block.get_programming_language()
|
||||
if prog_lang != ts.Enums.ProgrammingLanguage.LAD:
|
||||
return (
|
||||
False,
|
||||
f"Language {prog_lang} not supported (SIMATIC SD requires LAD)",
|
||||
)
|
||||
except Exception:
|
||||
return False, "Could not determine programming language"
|
||||
|
||||
# Check block type - SIMATIC SD typically supports FB, FC, OB
|
||||
try:
|
||||
block_type = block.get_block_type()
|
||||
supported_types = [
|
||||
ts.Enums.BlockType.FB, # Function Block
|
||||
ts.Enums.BlockType.FC, # Function
|
||||
ts.Enums.BlockType.OB, # Organization Block
|
||||
]
|
||||
if block_type not in supported_types:
|
||||
return False, f"Block type {block_type} may not be supported"
|
||||
except Exception:
|
||||
# If we can't determine type, assume it might work
|
||||
pass
|
||||
|
||||
return True, "Block appears compatible with SIMATIC SD"
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Error checking compatibility: {e}"
|
||||
|
||||
|
||||
def verify_export_format(export_path, expected_format="SimaticSD"):
|
||||
"""
|
||||
Verifies if the exported files are actually in the expected format.
|
||||
For SIMATIC SD, looks for specific keywords like RUNG, END_RUNG, wire#
|
||||
Returns (is_correct_format, file_count, sample_files, format_details)
|
||||
"""
|
||||
if not os.path.exists(export_path):
|
||||
return False, 0, [], "Directory does not exist"
|
||||
|
||||
files = [
|
||||
f
|
||||
for f in os.listdir(export_path)
|
||||
if os.path.isfile(os.path.join(export_path, f))
|
||||
]
|
||||
if not files:
|
||||
return False, 0, [], "No files found"
|
||||
|
||||
# Check first few files for format
|
||||
sample_files = files[:3]
|
||||
format_details = []
|
||||
|
||||
for file_name in sample_files:
|
||||
file_path = os.path.join(export_path, file_name)
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
||||
content = f.read(2000) # Read first 2KB
|
||||
|
||||
file_info = {"file": file_name, "size": len(content)}
|
||||
|
||||
if expected_format == "SimaticSD":
|
||||
# SIMATIC SD specific keywords and structure
|
||||
sd_keywords = ["RUNG", "END_RUNG", "wire#", "NETWORK", "TITLE", "LAD"]
|
||||
xml_indicators = ["<?xml", "<Document", "<SW.Blocks"]
|
||||
|
||||
found_sd_keywords = [kw for kw in sd_keywords if kw in content]
|
||||
found_xml_indicators = [xi for xi in xml_indicators if xi in content]
|
||||
|
||||
file_info["sd_keywords"] = found_sd_keywords
|
||||
file_info["xml_indicators"] = found_xml_indicators
|
||||
file_info["is_xml"] = len(found_xml_indicators) > 0
|
||||
file_info["is_simatic_sd"] = (
|
||||
len(found_sd_keywords) > 0 and not file_info["is_xml"]
|
||||
)
|
||||
file_info["first_100_chars"] = (
|
||||
content[:100].replace("\n", " ").replace("\r", "")
|
||||
)
|
||||
|
||||
else: # XML format
|
||||
file_info["is_xml"] = (
|
||||
content.strip().startswith("<?xml") or "<Document" in content
|
||||
)
|
||||
file_info["first_100_chars"] = (
|
||||
content[:100].replace("\n", " ").replace("\r", "")
|
||||
)
|
||||
|
||||
format_details.append(file_info)
|
||||
|
||||
except Exception as e:
|
||||
format_details.append({"file": file_name, "error": str(e)})
|
||||
|
||||
# Determine overall result for SIMATIC SD
|
||||
if expected_format == "SimaticSD":
|
||||
is_correct_format = any(
|
||||
f.get("is_simatic_sd", False) for f in format_details if "error" not in f
|
||||
)
|
||||
else:
|
||||
is_correct_format = any(
|
||||
f.get("is_xml", False) for f in format_details if "error" not in f
|
||||
)
|
||||
|
||||
return is_correct_format, len(files), sample_files, format_details
|
||||
|
||||
|
||||
def select_project_file():
|
||||
"""Opens a dialog to select a TIA Portal project file."""
|
||||
root = tk.Tk()
|
||||
|
@ -98,11 +246,35 @@ def check_simatic_sd_support():
|
|||
try:
|
||||
# Check if SimaticSD is available in ExportFormats enum
|
||||
simatic_sd_format = ts.Enums.ExportFormats.SimaticSD
|
||||
print(f"✓ SIMATIC SD format supported (enum value: {simatic_sd_format})")
|
||||
print(f"✓ SIMATIC SD format enum found (value: {simatic_sd_format})")
|
||||
|
||||
# Try to get more information about available formats
|
||||
try:
|
||||
all_formats = [
|
||||
attr for attr in dir(ts.Enums.ExportFormats) if not attr.startswith("_")
|
||||
]
|
||||
print(f" Available export formats: {all_formats}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return True
|
||||
except AttributeError:
|
||||
print("✗ ERROR: SIMATIC SD format not available in this TIA Scripting version.")
|
||||
print("Please ensure you are using TIA Portal V20 or later with compatible TIA Scripting.")
|
||||
print(
|
||||
"Please ensure you are using TIA Portal V20 or later with compatible TIA Scripting."
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def check_tia_portal_version():
|
||||
"""Check TIA Portal version and compatibility."""
|
||||
print("\n=== TIA PORTAL VERSION CHECK ===")
|
||||
try:
|
||||
# This will be filled when we connect to TIA Portal
|
||||
print("TIA Portal version check will be performed after connection...")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Could not check TIA Portal version: {e}")
|
||||
return False
|
||||
|
||||
|
||||
|
@ -113,18 +285,22 @@ def export_plc_data_simatic_sd(plc, export_base_dir):
|
|||
|
||||
# Define base export path for this PLC with timestamp to avoid conflicts
|
||||
import datetime
|
||||
|
||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
plc_export_dir = os.path.join(export_base_dir, f"{plc_name}_SimaticSD_{timestamp}")
|
||||
os.makedirs(plc_export_dir, exist_ok=True)
|
||||
|
||||
# --- Export Program Blocks in SIMATIC SD Format ---
|
||||
blocks_exported = 0
|
||||
blocks_exported_sd = 0
|
||||
blocks_exported_xml = 0
|
||||
blocks_skipped = 0
|
||||
blocks_not_lad = 0
|
||||
print(f"\n[PLC: {plc_name}] Exporting Program Blocks (SIMATIC SD)...")
|
||||
print(" NOTE: SIMATIC SD format only supports LAD (Ladder) programming language!")
|
||||
sd_blocks_path = os.path.join(plc_export_dir, "01_ProgramBlocks_SD")
|
||||
os.makedirs(sd_blocks_path, exist_ok=True)
|
||||
print(f" SIMATIC SD Target: {sd_blocks_path}")
|
||||
|
||||
|
||||
# Also create a separate SimaticML export for comparison
|
||||
xml_blocks_path = os.path.join(plc_export_dir, "02_ProgramBlocks_XML_Compare")
|
||||
os.makedirs(xml_blocks_path, exist_ok=True)
|
||||
|
@ -146,17 +322,86 @@ def export_plc_data_simatic_sd(plc, export_base_dir):
|
|||
blocks_skipped += 1
|
||||
continue
|
||||
|
||||
print(f" Exporting {block_name} as SIMATIC SD...")
|
||||
# Check programming language - CRITICAL for SIMATIC SD
|
||||
is_compatible, compatibility_reason = (
|
||||
check_simatic_sd_block_compatibility(block)
|
||||
)
|
||||
print(f" Compatibility check: {compatibility_reason}")
|
||||
|
||||
if not is_compatible:
|
||||
print(f" Block {block_name} not compatible with SIMATIC SD.")
|
||||
print(f" Exporting XML only: {compatibility_reason}")
|
||||
blocks_not_lad += 1
|
||||
|
||||
# Export only in XML for incompatible blocks
|
||||
block.export(
|
||||
target_directory_path=xml_blocks_path,
|
||||
export_options=EXPORT_OPTIONS,
|
||||
export_format=ts.Enums.ExportFormats.SimaticML,
|
||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||
)
|
||||
blocks_exported_xml += 1
|
||||
print(
|
||||
f" ✓ Exported {block_name} in XML (incompatible with SIMATIC SD)"
|
||||
)
|
||||
continue
|
||||
|
||||
# Try SIMATIC SD export for LAD blocks
|
||||
print(f" Exporting LAD block {block_name} as SIMATIC SD...")
|
||||
try:
|
||||
block.export(
|
||||
target_directory_path=sd_blocks_path,
|
||||
export_options=EXPORT_OPTIONS,
|
||||
export_format=ts.Enums.ExportFormats.SimaticSD, # New SIMATIC SD format
|
||||
export_format=ts.Enums.ExportFormats.SimaticSD, # SIMATIC SD format
|
||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||
)
|
||||
blocks_exported += 1
|
||||
print(f" ✓ Successfully exported {block_name} in SIMATIC SD")
|
||||
|
||||
|
||||
# Verify if the export was actually in SIMATIC SD format
|
||||
print(f" Verifying SIMATIC SD format for {block_name}...")
|
||||
is_sd, file_count, sample_files, format_details = (
|
||||
verify_export_format(sd_blocks_path, "SimaticSD")
|
||||
)
|
||||
|
||||
if is_sd:
|
||||
blocks_exported_sd += 1
|
||||
print(
|
||||
f" ✓ Successfully exported {block_name} in REAL SIMATIC SD format"
|
||||
)
|
||||
# Show sample of SD content
|
||||
for detail in format_details:
|
||||
if detail.get("is_simatic_sd") and detail.get(
|
||||
"sd_keywords"
|
||||
):
|
||||
print(
|
||||
f" 🎯 SD Keywords found: {', '.join(detail['sd_keywords'])}"
|
||||
)
|
||||
break
|
||||
else:
|
||||
print(
|
||||
f" ❌ FAILED: Export claimed SD but files are actually XML!"
|
||||
)
|
||||
print(f" 📋 Format analysis:")
|
||||
for detail in format_details:
|
||||
if "error" not in detail:
|
||||
print(f" File: {detail['file']}")
|
||||
print(
|
||||
f" SIMATIC SD: {detail.get('is_simatic_sd', False)}"
|
||||
)
|
||||
print(
|
||||
f" XML format: {detail.get('is_xml', False)}"
|
||||
)
|
||||
if detail.get("sd_keywords"):
|
||||
print(
|
||||
f" SD keywords: {detail['sd_keywords']}"
|
||||
)
|
||||
if detail.get("xml_indicators"):
|
||||
print(
|
||||
f" XML indicators: {detail['xml_indicators']}"
|
||||
)
|
||||
print(
|
||||
f" Content start: {detail.get('first_100_chars', '')[:50]}..."
|
||||
)
|
||||
|
||||
# Also export same block in XML for comparison
|
||||
print(f" Exporting {block_name} as XML for comparison...")
|
||||
block.export(
|
||||
|
@ -165,31 +410,45 @@ def export_plc_data_simatic_sd(plc, export_base_dir):
|
|||
export_format=ts.Enums.ExportFormats.SimaticML, # Traditional XML format
|
||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||
)
|
||||
blocks_exported_xml += 1
|
||||
print(f" + Also exported {block_name} in XML for comparison")
|
||||
|
||||
|
||||
except Exception as export_ex:
|
||||
print(f" ERROR during export: {export_ex}")
|
||||
print(f" ERROR during SIMATIC SD export: {export_ex}")
|
||||
print(
|
||||
f" This is likely because SIMATIC SD has specific requirements:"
|
||||
)
|
||||
print(f" - Block must be in LAD (Ladder) format")
|
||||
print(
|
||||
f" - Block must be compatible with SIMATIC SD specification"
|
||||
)
|
||||
# Try to export only in XML if SD fails
|
||||
try:
|
||||
print(f" Attempting fallback XML export for {block_name}...")
|
||||
print(
|
||||
f" Attempting fallback XML export for {block_name}..."
|
||||
)
|
||||
block.export(
|
||||
target_directory_path=xml_blocks_path,
|
||||
export_options=EXPORT_OPTIONS,
|
||||
export_format=ts.Enums.ExportFormats.SimaticML,
|
||||
keep_folder_structure=KEEP_FOLDER_STRUCTURE,
|
||||
)
|
||||
print(f" ✓ Fallback XML export successful for {block_name}")
|
||||
blocks_exported += 1
|
||||
print(
|
||||
f" ✓ Fallback XML export successful for {block_name}"
|
||||
)
|
||||
blocks_exported_xml += 1
|
||||
except Exception as fallback_ex:
|
||||
print(f" ERROR: Both SD and XML export failed: {fallback_ex}")
|
||||
print(
|
||||
f" ERROR: Both SD and XML export failed: {fallback_ex}"
|
||||
)
|
||||
blocks_skipped += 1
|
||||
|
||||
|
||||
except Exception as block_ex:
|
||||
print(f" ERROR exporting block {block_name}: {block_ex}")
|
||||
blocks_skipped += 1
|
||||
|
||||
|
||||
print(
|
||||
f" Program Blocks Export Summary: Exported={blocks_exported}, Skipped/Errors={blocks_skipped}"
|
||||
f" Program Blocks Export Summary: SIMATIC SD={blocks_exported_sd}, XML={blocks_exported_xml}, Non-LAD={blocks_not_lad}, Skipped/Errors={blocks_skipped}"
|
||||
)
|
||||
except Exception as e:
|
||||
print(f" ERROR processing Program Blocks: {e}")
|
||||
|
@ -243,11 +502,11 @@ def export_plc_data_simatic_sd(plc, export_base_dir):
|
|||
except Exception as udt_export_ex:
|
||||
print(f" ERROR during UDT export: {udt_export_ex}")
|
||||
udts_skipped += 1
|
||||
|
||||
|
||||
except Exception as udt_ex:
|
||||
print(f" ERROR exporting UDT {udt_name}: {udt_ex}")
|
||||
udts_skipped += 1
|
||||
|
||||
|
||||
print(
|
||||
f" UDT Export Summary: Exported={udts_exported}, Skipped/Errors={udts_skipped}"
|
||||
)
|
||||
|
@ -293,11 +552,11 @@ def export_plc_data_simatic_sd(plc, export_base_dir):
|
|||
except Exception as tag_export_ex:
|
||||
print(f" ERROR during Tag Table export: {tag_export_ex}")
|
||||
tags_skipped += 1
|
||||
|
||||
|
||||
except Exception as table_ex:
|
||||
print(f" ERROR exporting Tag Table {table_name}: {table_ex}")
|
||||
tags_skipped += 1
|
||||
|
||||
|
||||
print(
|
||||
f" Tag Table Export Summary: Exported={tags_exported}, Skipped/Errors={tags_skipped}"
|
||||
)
|
||||
|
@ -311,16 +570,18 @@ def export_plc_data_simatic_sd(plc, export_base_dir):
|
|||
def export_additional_formats(plc, export_base_dir):
|
||||
"""Optional: Export in traditional formats alongside SIMATIC SD for comparison."""
|
||||
plc_name = plc.get_name()
|
||||
print(f"\n[Optional] Exporting traditional formats for comparison - PLC: {plc_name}")
|
||||
|
||||
print(
|
||||
f"\n[Optional] Exporting traditional formats for comparison - PLC: {plc_name}"
|
||||
)
|
||||
|
||||
# Create comparison directory
|
||||
comparison_dir = os.path.join(export_base_dir, plc_name, "Comparison_Formats")
|
||||
os.makedirs(comparison_dir, exist_ok=True)
|
||||
|
||||
|
||||
# Export a few blocks in SimaticML for comparison
|
||||
xml_comparison_path = os.path.join(comparison_dir, "SimaticML_Sample")
|
||||
os.makedirs(xml_comparison_path, exist_ok=True)
|
||||
|
||||
|
||||
try:
|
||||
program_blocks = plc.get_program_blocks()
|
||||
# Export first 3 blocks in SimaticML for comparison
|
||||
|
@ -347,7 +608,7 @@ if __name__ == "__main__":
|
|||
|
||||
print("--- TIA Portal 20 SIMATIC SD Exporter ---")
|
||||
print("Exporting Blocks, UDTs, and Tags in SIMATIC SD Format")
|
||||
|
||||
|
||||
# Check SIMATIC SD support first
|
||||
if not check_simatic_sd_support():
|
||||
sys.exit(1)
|
||||
|
@ -378,6 +639,24 @@ if __name__ == "__main__":
|
|||
print("Connected to TIA Portal V20.")
|
||||
print(f"Portal Process ID: {portal_instance.get_process_id()}")
|
||||
|
||||
# Get TIA Portal version information
|
||||
try:
|
||||
portal_version = portal_instance.get_version()
|
||||
print(f"TIA Portal Version: {portal_version}")
|
||||
|
||||
# Check if this version really supports SIMATIC SD
|
||||
version_parts = portal_version.split(".")
|
||||
major_version = int(version_parts[0]) if version_parts else 0
|
||||
if major_version < 20:
|
||||
print(
|
||||
f"⚠️ WARNING: TIA Portal V{major_version} may not fully support SIMATIC SD (requires V20+)"
|
||||
)
|
||||
else:
|
||||
print(f"✓ TIA Portal V{major_version} should support SIMATIC SD")
|
||||
|
||||
except Exception as ver_ex:
|
||||
print(f"Could not get TIA Portal version: {ver_ex}")
|
||||
|
||||
# 3. Open Project
|
||||
print(f"Opening project: {os.path.basename(project_file)}...")
|
||||
project_object = portal_instance.open_project(project_file_path=project_file)
|
||||
|
@ -397,29 +676,41 @@ if __name__ == "__main__":
|
|||
|
||||
# 5. Iterate and Export Data for each PLC in SIMATIC SD format
|
||||
import datetime # Add this import for timestamp
|
||||
|
||||
for plc_device in plcs:
|
||||
export_plc_data_simatic_sd(
|
||||
plc=plc_device, export_base_dir=export_dir
|
||||
)
|
||||
export_plc_data_simatic_sd(plc=plc_device, export_base_dir=export_dir)
|
||||
|
||||
print("\n🎉 SIMATIC SD Export process completed successfully!")
|
||||
print("\nExported files structure:")
|
||||
print("├── [PLC_Name]_SimaticSD_[timestamp]/")
|
||||
print("│ ├── 01_ProgramBlocks_SD/ # SIMATIC SD format")
|
||||
print(
|
||||
"│ ├── 01_ProgramBlocks_SD/ # SIMATIC SD format (LAD blocks only)"
|
||||
)
|
||||
print("│ ├── 02_ProgramBlocks_XML_Compare/ # Traditional XML for comparison")
|
||||
print("│ ├── 03_PlcDataTypes_SD/")
|
||||
print("│ ├── 04_PlcDataTypes_XML_Compare/")
|
||||
print("│ ├── 05_PlcTags_SD/")
|
||||
print("│ └── 06_PlcTags_XML_Compare/")
|
||||
print("\nNow you can compare the differences between SIMATIC SD and traditional XML formats!")
|
||||
|
||||
print("\n📋 IMPORTANT SIMATIC SD LIMITATIONS:")
|
||||
print(" • SIMATIC SD format ONLY supports LAD (Ladder) programming language")
|
||||
print(" • SCL, STL, FBD blocks are exported as XML only")
|
||||
print(" • Only FB, FC, OB block types are typically supported")
|
||||
print(" • Complex LAD elements may still fall back to XML")
|
||||
print(
|
||||
"\nNow you can compare the differences between SIMATIC SD and traditional XML formats!"
|
||||
)
|
||||
|
||||
# Add file analysis
|
||||
print("\n=== FILE ANALYSIS ===")
|
||||
print("\n=== FILE FORMAT ANALYSIS ===")
|
||||
for plc_device in plcs:
|
||||
plc_name = plc_device.get_name()
|
||||
import datetime
|
||||
|
||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
plc_export_dir = os.path.join(export_dir, f"{plc_name}_SimaticSD_{timestamp}")
|
||||
|
||||
plc_export_dir = os.path.join(
|
||||
export_dir, f"{plc_name}_SimaticSD_{timestamp}"
|
||||
)
|
||||
|
||||
print(f"\nAnalyzing exported files for PLC: {plc_name}")
|
||||
folders_to_check = [
|
||||
("01_ProgramBlocks_SD", "SIMATIC SD Blocks"),
|
||||
|
@ -427,20 +718,56 @@ if __name__ == "__main__":
|
|||
("03_PlcDataTypes_SD", "SIMATIC SD UDTs"),
|
||||
("04_PlcDataTypes_XML_Compare", "XML UDTs"),
|
||||
("05_PlcTags_SD", "SIMATIC SD Tags"),
|
||||
("06_PlcTags_XML_Compare", "XML Tags")
|
||||
("06_PlcTags_XML_Compare", "XML Tags"),
|
||||
]
|
||||
|
||||
|
||||
simatic_sd_working = False
|
||||
total_sd_files = 0
|
||||
total_xml_fallbacks = 0
|
||||
|
||||
for folder_name, description in folders_to_check:
|
||||
folder_path = os.path.join(plc_export_dir, folder_name)
|
||||
if os.path.exists(folder_path):
|
||||
files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]
|
||||
print(f" {description}: {len(files)} files")
|
||||
if files:
|
||||
extensions = set(os.path.splitext(f)[1].lower() for f in files)
|
||||
print(f" File extensions: {', '.join(extensions) if extensions else 'No extensions'}")
|
||||
actual_format, extensions, file_count = verify_export_format(
|
||||
folder_path
|
||||
)
|
||||
print(f" {description}: {file_count} files")
|
||||
print(f" Format detected: {actual_format}")
|
||||
print(f" File extensions: {extensions}")
|
||||
|
||||
if "SD" in folder_name: # This should be SIMATIC SD folder
|
||||
if actual_format == "XML_ONLY":
|
||||
print(
|
||||
f" ⚠️ WARNING: Expected SIMATIC SD but got XML only!"
|
||||
)
|
||||
total_xml_fallbacks += file_count
|
||||
elif actual_format == "SIMATIC_SD":
|
||||
simatic_sd_working = True
|
||||
total_sd_files += file_count
|
||||
elif actual_format == "UNKNOWN" and file_count > 0:
|
||||
print(f" 🔍 UNKNOWN format - needs manual inspection")
|
||||
|
||||
else:
|
||||
print(f" {description}: Folder not found")
|
||||
|
||||
print(f"\n🔍 SIMATIC SD DIAGNOSIS FOR {plc_name}:")
|
||||
if simatic_sd_working:
|
||||
print(
|
||||
f" ✅ SIMATIC SD is working: {total_sd_files} files in true SD format"
|
||||
)
|
||||
else:
|
||||
print(f" ❌ SIMATIC SD NOT working: All 'SD' exports are actually XML")
|
||||
print(f" 📊 Total XML fallbacks: {total_xml_fallbacks}")
|
||||
|
||||
if total_xml_fallbacks > 0:
|
||||
print(f"\n 💡 POSSIBLE CAUSES:")
|
||||
print(f" • TIA Portal version doesn't fully support SIMATIC SD")
|
||||
print(f" • TIA Scripting version incompatible with SIMATIC SD")
|
||||
print(f" • Project blocks contain unsupported LAD elements")
|
||||
print(
|
||||
f" • SIMATIC SD enum exists but falls back to XML silently"
|
||||
)
|
||||
|
||||
except ts.TiaException as tia_ex:
|
||||
print(f"\nTIA Portal Openness Error: {tia_ex}")
|
||||
traceback.print_exc()
|
||||
|
@ -459,4 +786,4 @@ if __name__ == "__main__":
|
|||
except Exception as close_ex:
|
||||
print(f"Error during TIA Portal cleanup: {close_ex}")
|
||||
|
||||
print("\nScript finished.")
|
||||
print("\nScript finished.")
|
||||
|
|
2889
data/log.txt
2889
data/log.txt
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue