Files
kkelomatic_home/scripts/parse-codesys-xml.py
nearxos bf7bd56fe7 Initial commit: Home automation docs and CODESYS project
- Reorganized project: codesys/, docs/codesys|redesign|integration|reference/, scripts/
- CODESYS project and exports in codesys/
- Documentation index in docs/README.md
- Redesign and light naming configuration
- Water boiler control and safety design

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-07 21:52:46 +02:00

138 lines
4.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
CODESYS XML Export Parser
This script parses exported CODESYS XML files (.export or .xml) to extract
useful information for documentation.
Usage:
python3 parse-codesys-xml.py <export_file.export>
python3 parse-codesys-xml.py <export_file.xml>
"""
import sys
import xml.etree.ElementTree as ET
from pathlib import Path
from typing import Dict, List, Optional
def parse_codesys_export(file_path: str) -> Dict:
"""Parse a CODESYS XML export file."""
try:
tree = ET.parse(file_path)
root = tree.getroot()
return extract_project_info(root)
except ET.ParseError as e:
print(f"Error parsing XML: {e}")
return {}
except Exception as e:
print(f"Error reading file: {e}")
return {}
def extract_project_info(root: ET.Element) -> Dict:
"""Extract project information from XML root."""
info = {
'project_name': '',
'network_variables': [],
'programs': [],
'function_blocks': [],
'io_config': [],
'variables': []
}
# Try to find project name
project_elem = root.find('.//Project')
if project is not None:
info['project_name'] = project_elem.get('Name', 'Unknown')
# Extract network variables
# (Structure depends on CODESYS version and export format)
for nv in root.findall('.//NetworkVariable'):
nv_info = {
'name': nv.get('Name', ''),
'type': nv.get('Type', ''),
'direction': nv.get('Direction', ''),
'initial_value': nv.get('InitialValue', '')
}
info['network_variables'].append(nv_info)
# Extract programs/POUs
for pou in root.findall('.//POU'):
pou_info = {
'name': pou.get('Name', ''),
'type': pou.get('POUType', ''),
'language': pou.get('Language', '')
}
info['programs'].append(pou_info)
# Extract function blocks
for fb in root.findall('.//FunctionBlock'):
fb_info = {
'name': fb.get('Name', ''),
'type': fb.get('Type', '')
}
info['function_blocks'].append(fb_info)
return info
def print_summary(info: Dict):
"""Print a summary of extracted information."""
print("=" * 60)
print("CODESYS Project Summary")
print("=" * 60)
if info.get('project_name'):
print(f"\nProject Name: {info['project_name']}")
if info.get('network_variables'):
print(f"\nNetwork Variables ({len(info['network_variables'])}):")
for nv in info['network_variables']:
print(f" - {nv['name']} ({nv['type']}) [{nv.get('direction', 'N/A')}]")
if info.get('programs'):
print(f"\nPrograms/POUs ({len(info['programs'])}):")
for prog in info['programs']:
print(f" - {prog['name']} ({prog['type']}) [{prog.get('language', 'N/A')}]")
if info.get('function_blocks'):
print(f"\nFunction Blocks ({len(info['function_blocks'])}):")
for fb in info['function_blocks']:
print(f" - {fb['name']} ({fb.get('type', 'N/A')})")
print("\n" + "=" * 60)
def main():
if len(sys.argv) < 2:
print("Usage: python3 parse-codesys-xml.py <export_file.export|.xml>")
sys.exit(1)
file_path = sys.argv[1]
if not Path(file_path).exists():
print(f"Error: File not found: {file_path}")
sys.exit(1)
print(f"Parsing: {file_path}")
info = parse_codesys_export(file_path)
if info:
print_summary(info)
# Optionally save to JSON
if len(sys.argv) > 2 and sys.argv[2] == '--json':
import json
output_file = Path(file_path).stem + '_parsed.json'
with open(output_file, 'w') as f:
json.dump(info, f, indent=2)
print(f"\nParsed data saved to: {output_file}")
else:
print("No information extracted. The XML structure may be different.")
print("Try opening the file in a text editor to inspect its structure.")
if __name__ == '__main__':
main()