166 lines
6.0 KiB
Python
166 lines
6.0 KiB
Python
"""
|
|
IB16S Safety Digital Input Module L5X Generator (Boilerplate-based)
|
|
==================================================================
|
|
|
|
This module provides functionality to generate IB16S safety module L5X files by
|
|
loading a boilerplate template and modifying specific fields.
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Optional, Dict
|
|
import xml.etree.ElementTree as ET
|
|
from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
|
|
|
|
|
|
@dataclass
|
|
class IB16SModuleConfig(BaseModuleConfig):
|
|
"""Configuration for an IB16S safety module."""
|
|
name: str
|
|
boilerplate_path: str = "boilerplate/SLOT7_IB16S_Module.L5X"
|
|
slot_address: str = "7"
|
|
parent_module: str = "Local"
|
|
parent_port_id: str = "1"
|
|
safety_network: str = "16#0000_4c33_031d_8f1b"
|
|
safety_input_device_names: Optional[Dict[int, str]] = None # Names for 16 safety input devices (0-15)
|
|
|
|
def get_updates(self):
|
|
"""Get dictionary of updates to apply."""
|
|
return {
|
|
"name": self.name,
|
|
"slot_address": self.slot_address,
|
|
"parent_module": self.parent_module,
|
|
"parent_port_id": self.parent_port_id,
|
|
"safety_network": self.safety_network,
|
|
"safety_input_device_names": self.safety_input_device_names
|
|
}
|
|
|
|
|
|
class IB16SModuleGenerator(BaseBoilerplateGenerator):
|
|
"""Generator for IB16S safety module L5X files using boilerplate template."""
|
|
|
|
def apply_updates(self):
|
|
"""Apply IB16S-specific updates to the boilerplate."""
|
|
# Update TargetName in root element
|
|
self.root.set("TargetName", self.config.name)
|
|
|
|
# Update Module name and parent info
|
|
module = self.root.find(".//Module[@Use='Target']")
|
|
if module is not None:
|
|
module.set("Name", self.config.name)
|
|
module.set("ParentModule", self.config.parent_module)
|
|
module.set("ParentModPortId", self.config.parent_port_id)
|
|
module.set("SafetyNetwork", self.config.safety_network)
|
|
|
|
# Update slot address (ICP port)
|
|
icp_port = self.root.find(".//Module[@Use='Target']/Ports/Port[@Type='ICP']")
|
|
if icp_port is not None:
|
|
icp_port.set("Address", self.config.slot_address)
|
|
|
|
# Update safety input device comments
|
|
self.update_comments()
|
|
|
|
def update_comments(self):
|
|
"""Update comments for safety input devices."""
|
|
safety_input_comments = self.root.find(".//Connection[@Name='SafetyInput']/InputTag/Comments")
|
|
if safety_input_comments is None:
|
|
return
|
|
|
|
safety_input_comments.clear()
|
|
|
|
if not self.config.safety_input_device_names:
|
|
return
|
|
|
|
for index, text in self.config.safety_input_device_names.items():
|
|
comment = ET.SubElement(safety_input_comments, "Comment")
|
|
comment.set("Operand", f".PT{index:02d}.DATA")
|
|
comment.text = text
|
|
|
|
@classmethod
|
|
def from_mapping(cls, mapping: Dict[str, str], comments: Optional[Dict[int, str]] = None) -> "IB16SModuleGenerator":
|
|
"""Create and fully configure an IB16S generator from the Excel-derived
|
|
`modules` entry (a plain dict). The structure expected is the one
|
|
produced in EnhancedMCMGenerator._organize_modules_by_type().
|
|
|
|
:param comments: Optional dict of input index (0-15) to comment text.
|
|
"""
|
|
|
|
cfg = IB16SModuleConfig(
|
|
name=mapping["name"],
|
|
slot_address=mapping["slot_address"],
|
|
parent_module="Local",
|
|
parent_port_id="1",
|
|
safety_network=mapping.get("safety_network", "16#0000_4c33_031d_8f1b"),
|
|
safety_input_device_names=comments,
|
|
)
|
|
|
|
gen = cls(cfg)
|
|
gen.load_boilerplate()
|
|
gen.apply_updates()
|
|
return gen
|
|
|
|
|
|
# Factory function
|
|
def create_ib16s_module(
|
|
name: str,
|
|
slot_address: str = "7",
|
|
parent_module: str = "Local",
|
|
parent_port_id: str = "1",
|
|
safety_network: str = "16#0000_4c33_031d_8f1b",
|
|
safety_input_device_names: Optional[Dict[int, str]] = None
|
|
) -> IB16SModuleConfig:
|
|
"""
|
|
Create an IB16S safety module configuration.
|
|
|
|
Args:
|
|
name: Module name
|
|
slot_address: Slot number in the chassis
|
|
parent_module: Parent module name
|
|
parent_port_id: Parent module port ID
|
|
safety_network: Safety network ID
|
|
safety_input_device_names: Dictionary mapping safety input index (0-15) to device names
|
|
|
|
Returns:
|
|
IB16SModuleConfig object
|
|
"""
|
|
return IB16SModuleConfig(
|
|
name=name,
|
|
slot_address=slot_address,
|
|
parent_module=parent_module,
|
|
parent_port_id=parent_port_id,
|
|
safety_network=safety_network,
|
|
safety_input_device_names=safety_input_device_names
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Example usage
|
|
config = create_ib16s_module(
|
|
name="SLOT8_IB16S",
|
|
slot_address="8",
|
|
parent_module="Local",
|
|
parent_port_id="1",
|
|
safety_network="16#0000_4c33_031d_8f1b",
|
|
safety_input_device_names={
|
|
0: "Emergency Stop Circuit 1",
|
|
1: "Emergency Stop Circuit 2",
|
|
2: "Safety Door 1 Closed",
|
|
3: "Safety Door 2 Closed",
|
|
4: "Light Curtain Area 1",
|
|
5: "Light Curtain Area 2",
|
|
6: "Safety Mat Zone 1",
|
|
7: "Safety Mat Zone 2",
|
|
8: "Two Hand Control Left",
|
|
9: "Two Hand Control Right",
|
|
10: "Pull Cord Switch 1",
|
|
11: "Pull Cord Switch 2",
|
|
12: "Safety Interlock 1",
|
|
13: "Safety Interlock 2",
|
|
14: "Guard Door Position",
|
|
15: "Safety Reset Button"
|
|
}
|
|
)
|
|
|
|
# Generate the module
|
|
generator = IB16SModuleGenerator(config)
|
|
generator.save_to_file("generated/SLOT8_IB16S.L5X")
|
|
print(f"Generated IB16S safety module configuration saved to generated/SLOT8_IB16S.L5X") |