120 lines
4.1 KiB
Python
120 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
LPE Module Boilerplate Model
|
|
====================================
|
|
|
|
Model for LPE modules.
|
|
Supports configuring module name and parent module.
|
|
"""
|
|
|
|
from typing import Dict, Optional
|
|
import xml.etree.ElementTree as ET
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
import os
|
|
|
|
@dataclass
|
|
class LPEModuleConfig:
|
|
"""Configuration for an LPE module."""
|
|
name: str
|
|
parent_module: str
|
|
port_address: str = "0"
|
|
|
|
class LPEBoilerplateGenerator:
|
|
"""Generator for LPE module XML."""
|
|
|
|
def __init__(self, name: str, parent_module: str, port_address: str = "0"):
|
|
self.name = name
|
|
self.parent_module = parent_module
|
|
self.port_address = port_address
|
|
self.boilerplate_path = os.path.join("boilerplate", "LPE_Module.L5X")
|
|
self.tree = None
|
|
self.root = None
|
|
|
|
def load_boilerplate(self):
|
|
"""Load the LPE boilerplate template."""
|
|
if not os.path.exists(self.boilerplate_path):
|
|
raise FileNotFoundError(f"Boilerplate file not found: {self.boilerplate_path}")
|
|
|
|
self.tree = ET.parse(self.boilerplate_path)
|
|
self.root = self.tree.getroot()
|
|
|
|
def update_module_name(self):
|
|
"""Update the module name throughout the XML."""
|
|
self.root.set("TargetName", self.name)
|
|
|
|
module = self.root.find(".//Module[@Use='Target']")
|
|
if module is not None:
|
|
module.set("Name", self.name)
|
|
|
|
def update_parent_module(self):
|
|
"""Update parent module references."""
|
|
module = self.root.find(".//Module[@Use='Target']")
|
|
if module is not None:
|
|
module.set("ParentModule", self.parent_module)
|
|
# All LPE modules are children of IOLM, so ParentModPortId is always 4 (IO-Link Port)
|
|
module.set("ParentModPortId", "4")
|
|
|
|
def update_port_address(self):
|
|
"""Update the IO-Link port address."""
|
|
port = self.root.find(".//Port[@Type='IO-Link']")
|
|
if port is not None:
|
|
port.set("Address", self.port_address)
|
|
|
|
def update_export_date(self):
|
|
"""Update the export date to current time."""
|
|
export_date = datetime.now().strftime("%a %b %d %H:%M:%S %Y")
|
|
self.root.set("ExportDate", export_date)
|
|
|
|
def apply_updates(self):
|
|
"""Apply all updates to the boilerplate."""
|
|
self.update_module_name()
|
|
self.update_parent_module()
|
|
self.update_port_address()
|
|
self.update_export_date()
|
|
|
|
def save(self, output_path: str):
|
|
"""Save the updated module to file."""
|
|
if self.tree is None:
|
|
raise RuntimeError("No boilerplate loaded. Call load_boilerplate() first.")
|
|
|
|
self.tree.write(output_path, encoding='UTF-8', xml_declaration=True)
|
|
|
|
def get_xml_string(self) -> str:
|
|
"""Get the XML as a string."""
|
|
if self.tree is None:
|
|
raise RuntimeError("No boilerplate loaded. Call load_boilerplate() first.")
|
|
|
|
return ET.tostring(self.root, encoding='unicode')
|
|
|
|
@classmethod
|
|
def from_mapping(cls, mapping: Dict[str, str]) -> "LPEBoilerplateGenerator":
|
|
"""Create, configure, and return a generator from an entry in
|
|
`EnhancedMCMGenerator.lpe_modules`."""
|
|
|
|
gen = cls(
|
|
name=mapping["name"],
|
|
parent_module=mapping["parent_module"],
|
|
port_address=mapping["port_address"],
|
|
)
|
|
gen.load_boilerplate()
|
|
gen.apply_updates()
|
|
return gen
|
|
|
|
def create_lpe_module(config: LPEModuleConfig) -> LPEBoilerplateGenerator:
|
|
"""Factory function to create and configure an LPE module generator.
|
|
|
|
Args:
|
|
config: Configuration for the LPE module
|
|
|
|
Returns:
|
|
Configured LPE module generator
|
|
"""
|
|
generator = LPEBoilerplateGenerator(
|
|
name=config.name,
|
|
parent_module=config.parent_module,
|
|
port_address=config.port_address
|
|
)
|
|
generator.load_boilerplate()
|
|
generator.apply_updates()
|
|
return generator |