2025-08-05 14:38:54 +04:00

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