123 lines
4.2 KiB
Python
123 lines
4.2 KiB
Python
"""
|
|
ZZZ_BeltTracking routine generator.
|
|
|
|
Generates belt tracking AOI calls for every VFD in network:
|
|
zzz_BeltTracking(zzz_UL1_3Tracking,UL1_3_VFD1:I,UL1_3_VFD1:O);
|
|
"""
|
|
|
|
import xml.etree.ElementTree as ET
|
|
from typing import List
|
|
from ..utils.common import format_xml_to_match_original, natural_sort_key
|
|
from ..plugin_system import RoutinePlugin, register_plugin
|
|
|
|
|
|
def generate_belt_tracking_routine(data_loader) -> ET.Element:
|
|
"""Generate the ZZZ_BeltTracking routine XML element."""
|
|
# Get all VFDs from network data
|
|
network = data_loader.network
|
|
|
|
# Config-driven routine name
|
|
try:
|
|
from ..config import get_config
|
|
routine_name = get_config().routines.name_map.get('belt_tracking', 'ZZZ_BeltTracking')
|
|
except Exception:
|
|
routine_name = 'ZZZ_BeltTracking'
|
|
|
|
# Create routine XML structure
|
|
routine = ET.Element("Routine")
|
|
routine.set("Name", routine_name)
|
|
routine.set("Type", "RLL")
|
|
|
|
rll_content = ET.SubElement(routine, "RLLContent")
|
|
|
|
# Get VFDs from network sheet (filter by Name ending with _VFD1)
|
|
if network.empty or 'Name' not in network.columns:
|
|
return routine
|
|
|
|
vfd_entries = network[network['Name'].astype(str).str.endswith('_VFD1', na=False)]
|
|
|
|
if vfd_entries.empty:
|
|
return routine
|
|
|
|
# Sort VFDs by name for deterministic output
|
|
vfd_entries = vfd_entries.sort_values('Name', key=lambda x: [natural_sort_key(name) for name in x])
|
|
|
|
# Rung 0: Comment rung
|
|
rung0 = ET.SubElement(rll_content, "Rung")
|
|
rung0.set("Number", "0")
|
|
rung0.set("Type", "N")
|
|
|
|
comment = ET.SubElement(rung0, "Comment")
|
|
comment.text = """Belt Tracking AOI Calls
|
|
|
|
Generates zzz_BeltTracking AOI calls for each VFD in the network.
|
|
Each VFD gets its own tracking tag and AOI instantiation."""
|
|
|
|
text0 = ET.SubElement(rung0, "Text")
|
|
text0.text = "NOP();"
|
|
|
|
rung_number = 1
|
|
|
|
# Generate AOI call for each VFD
|
|
for _, vfd_row in vfd_entries.iterrows():
|
|
vfd_name = str(vfd_row['Name']).strip()
|
|
if not vfd_name:
|
|
continue
|
|
|
|
# Extract base name from VFD name (e.g., UL1_3 from UL1_3_VFD1)
|
|
if vfd_name.endswith('_VFD1'):
|
|
base_name = vfd_name[:-5] # Remove '_VFD1'
|
|
else:
|
|
# Fallback - shouldn't happen with our filter
|
|
base_name = vfd_name.replace('_VFD', '')
|
|
|
|
# Create tracking tag name (zzz_UL1_3Tracking)
|
|
tracking_tag = f"zzz_{base_name}Tracking"
|
|
|
|
# Create rung for this VFD
|
|
rung = ET.SubElement(rll_content, "Rung")
|
|
rung.set("Number", str(rung_number))
|
|
rung.set("Type", "N")
|
|
|
|
text = ET.SubElement(rung, "Text")
|
|
|
|
# Generate AOI call: zzz_BeltTracking(zzz_UL1_3Tracking,UL1_3_VFD1:I,UL1_3_VFD1:O);
|
|
aoi_call = f"zzz_BeltTracking({tracking_tag},{vfd_name}:I,{vfd_name}:O);"
|
|
text.text = aoi_call
|
|
|
|
print(f" Belt tracking for {vfd_name} -> {tracking_tag}")
|
|
|
|
rung_number += 1
|
|
|
|
print(f" - Added {rung_number - 1} belt tracking AOI calls")
|
|
|
|
return routine
|
|
|
|
|
|
def append_belt_tracking_routine(routines_element: ET.Element, data_loader):
|
|
"""Append belt tracking routine to routines element."""
|
|
routine_element = generate_belt_tracking_routine(data_loader)
|
|
routines_element.append(routine_element)
|
|
|
|
|
|
class BeltTrackingRoutinePlugin(RoutinePlugin):
|
|
name = "belt_tracking"
|
|
description = "Generates the ZZZ_BeltTracking routine"
|
|
category = "device"
|
|
|
|
def can_generate(self) -> bool:
|
|
# Check if there are any VFDs in the network data
|
|
network = self.context.data_loader.network
|
|
if network.empty or 'Name' not in network.columns:
|
|
return False
|
|
vfd_entries = network[network['Name'].astype(str).str.endswith('_VFD1', na=False)]
|
|
return not vfd_entries.empty
|
|
|
|
def generate(self) -> bool:
|
|
routine_element = generate_belt_tracking_routine(self.context.data_loader)
|
|
self.context.routines_element.append(routine_element)
|
|
return True
|
|
|
|
|
|
register_plugin(BeltTrackingRoutinePlugin)
|