Add TRO type definition as a self-contained pydantic model
lib/tro_catalog.py is the single source for everything needed to create a TRO.
It reads no files at runtime; the origin of the data is recorded in comments
only, with CATALOG_AS_OF naming the revision it was taken from.
A TRO type is described by four things:
name short type as used in FB_Main and connect.ini ("1Sep")
fb_block the Siemens function block ("FB_ILS_MTRO_1Sep")
items which components sit inside it and how many
style colour group for drawings
TroDefinition is a pydantic v2 model with validate_assignment, so the get_*/set_*
methods cannot leave an object in an invalid state, and model_dump()/
model_validate() come for free for the planned JSON layout model.
Component lists for the four locally vendored FBs are verified against their VAR
declarations; the rest are .liblink references and follow the composition table
in TRO_Typen.md. Two findings from that comparison, recorded in the comments:
FB_ILS_MTRO_2Sep1Swi also declares two barcode readers, which the doc table
omits, and FB_EmptyCarrBuffer has no separator of its own - its base is a
separate 1Sep TRO (TRO101_IN next to TRO101 in the reference plant).
Colours follow the "Color legend" of the catalog: green means storage, the Vario
is purple. TroStyle renders both Graphviz attributes and Mermaid classDefs, so
the palette exists once and is ready for the BricsCAD symbol.
Enables pydantic in requirements.txt accordingly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,491 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Absichtlich ohne Shebang: der Windows-py-Launcher wuerde daraus "python3"
|
||||
# ableiten und scheitert, wenn keine PythonCore-Installation registriert ist.
|
||||
"""
|
||||
tro_catalog.py - Typdefinition der TROs (Transfer Route Objects).
|
||||
|
||||
Dieses Modul ist die **einzige** Quelle fuer alles, was zur Erzeugung eines TRO
|
||||
gebraucht wird. Es liest keine Dateien und braucht kein Markdown zur Laufzeit -
|
||||
die Herkunft der Daten steht nur noch in den Kommentaren.
|
||||
|
||||
Ein TRO-Typ wird durch vier Dinge beschrieben:
|
||||
|
||||
1. Name - Kurztyp, wie in FB_Main und connect.ini verwendet ("1Sep")
|
||||
2. FB-Baustein - der Siemens-Funktionsbaustein ("FB_ILS_MTRO_1Sep")
|
||||
3. Bauteile - welche Elemente in diesem TRO stecken und wie viele
|
||||
(1Sep = 1x Separator, 1Sep1Swi = 1x Separator + 1x Weiche)
|
||||
4. Darstellung - Farbe/Gruppe fuer Zeichnungen (Graphviz, Mermaid, spaeter
|
||||
das BricsCAD-Symbol)
|
||||
|
||||
Herkunft der Daten (Stand :data:`CATALOG_AS_OF`)
|
||||
-----------------------------------------------
|
||||
Einmalig uebernommen aus - danach hier gepflegt, nicht mehr nachgelesen:
|
||||
|
||||
doc/TRO_Katalog/TRO_Katalog.md
|
||||
"Overview of all TRO types" -> Typname und FB-Baustein
|
||||
"Color legend" -> Farbgruppen (siehe TroStyle)
|
||||
doc/TRO_Typen.md
|
||||
"Baukasten-Analyse" -> Bauteile je Typ (Sub-Bausteine/STRO)
|
||||
doc/HundM/Json_Layout-Konzept.md
|
||||
classDef-Farben -> die konkreten Farbwerte
|
||||
doc/TRO_Katalog/scl_templates/*.scl
|
||||
VAR-Deklarationen der lokal vorliegenden FBs - dort sind die Bauteile
|
||||
direkt nachweisbar
|
||||
|
||||
Belegbarkeit der Bauteillisten
|
||||
------------------------------
|
||||
Nur vier FBs liegen als Quelle im Repo; deren Bauteile sind aus den
|
||||
VAR-Deklarationen **verifiziert** (Kommentar "aus SCL belegt"). Die uebrigen
|
||||
Typen sind `.liblink`-Referenzen auf die externe ILSLib - ihre Bauteile stammen
|
||||
aus der Mapping-Tabelle in TRO_Typen.md (Kommentar "laut TRO_Typen.md").
|
||||
|
||||
Verwendung
|
||||
----------
|
||||
from tro_catalog import TroItem, get_tro, tro_names
|
||||
|
||||
tro = get_tro("1Sep1Swi")
|
||||
tro.get_fb_block() -> "FB_ILS_MTRO_1Sep1Swi"
|
||||
tro.get_item_count(TroItem.SWITCH) -> 1
|
||||
tro.get_items() -> {"Separator": 1, "Switch": 1}
|
||||
tro.describe_items() -> "1x Separator, 1x Switch"
|
||||
tro.get_style().fill -> "#ffe4a0"
|
||||
tro.get_dot_attrs() -> {"fillcolor": ..., "color": ...}
|
||||
tro.set_item(TroItem.SCANNER, 1) -> Bauteil ergaenzen/aendern
|
||||
|
||||
TroDefinition ist ein Pydantic-Modell (v2). Neben den get_*/set_*-Methoden gibt
|
||||
es damit Validierung bei jeder Zuweisung sowie model_dump()/model_dump_json()
|
||||
und model_validate() fuer das geplante JSON-Layoutmodell.
|
||||
Benoetigt `pydantic >= 2.0.0` (siehe requirements.txt, bin/install_py).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
__all__ = [
|
||||
"CATALOG_AS_OF",
|
||||
"TroItem",
|
||||
"TroStyle",
|
||||
"TroDefinition",
|
||||
"ITEM_FB",
|
||||
"STYLES",
|
||||
"TRO_CATALOG",
|
||||
"get_tro",
|
||||
"tro_names",
|
||||
"set_tro",
|
||||
"catalog",
|
||||
"mermaid_classdefs",
|
||||
]
|
||||
|
||||
# Stand der Dokumente, aus denen die Typdefinition uebernommen wurde
|
||||
CATALOG_AS_OF = "2026-07-20"
|
||||
|
||||
|
||||
class TroItem:
|
||||
"""
|
||||
Bauteilarten, aus denen ein TRO zusammengesetzt ist.
|
||||
|
||||
Konstanten statt freier Strings, damit Tippfehler auffallen.
|
||||
:data:`ITEM_FB` ordnet jeder Art ihren Sub-Funktionsbaustein zu.
|
||||
"""
|
||||
|
||||
SEPARATOR = "Separator"
|
||||
SWITCH = "Switch"
|
||||
SCANNER = "Scanner"
|
||||
VARIO_DRIVE = "VarioDrive"
|
||||
WORK_STATION = "WorkStation"
|
||||
STORAGE_LINE = "StorageLine"
|
||||
ACCUMULATE = "Accumulate"
|
||||
ENCODER = "Encoder"
|
||||
SSCC = "SSCC"
|
||||
BOOM = "Boom"
|
||||
FOOT = "Foot"
|
||||
TILT_SENSOR = "TiltSensor"
|
||||
|
||||
@classmethod
|
||||
def all(cls) -> tuple[str, ...]:
|
||||
"""Alle bekannten Bauteilarten."""
|
||||
return tuple(
|
||||
value
|
||||
for key, value in vars(cls).items()
|
||||
if key.isupper() and isinstance(value, str)
|
||||
)
|
||||
|
||||
|
||||
# Sub-Funktionsbaustein je Bauteilart. Leer = kein eigener FB (Hardware bzw.
|
||||
# im Rahmenwerk des TRO umgesetzt).
|
||||
ITEM_FB: dict[str, str] = {
|
||||
TroItem.SEPARATOR: "FB_ILS_STRO_Sep",
|
||||
TroItem.SWITCH: "FB_ILS_STRO_Switch",
|
||||
TroItem.SCANNER: "FB_BarcodeReaderCognex",
|
||||
TroItem.VARIO_DRIVE: "FB_ILS_STRO_Vario",
|
||||
TroItem.WORK_STATION: "FB_ILS_STRO_Vario_WorkStation",
|
||||
TroItem.STORAGE_LINE: "FB_ILS_STRO_Sep", # als Array[1..N]
|
||||
TroItem.ACCUMULATE: "FB_CarrAccumulate1Sep",
|
||||
TroItem.ENCODER: "",
|
||||
TroItem.SSCC: "",
|
||||
TroItem.BOOM: "FB_BoomWorkStation",
|
||||
TroItem.FOOT: "FB_DistanceFoot",
|
||||
TroItem.TILT_SENSOR: "FB_Tilt_TEST",
|
||||
}
|
||||
|
||||
|
||||
class TroStyle(BaseModel):
|
||||
"""
|
||||
Darstellung einer TRO-Typgruppe.
|
||||
|
||||
Farbwerte uebernommen aus der "Color legend" in TRO_Katalog.md bzw. den
|
||||
classDef-Zeilen in Json_Layout-Konzept.md:
|
||||
|
||||
sep blau Separator (1Sep)
|
||||
swi orange Weiche (1Sep1Swi, 1Sep2Swi, 2Sep1Swi)
|
||||
sscc rot Scanner-Sonderfall (1Sep_SSCC)
|
||||
vario violett Kettenfoerderer (Vario, Vario_workStation)
|
||||
store gruen Speicher/Puffer (PinStore_Auto, EmptyCarrBuffer)
|
||||
ext grau Systemgrenze, extern, Loading Boom
|
||||
|
||||
Wichtig: gruen bedeutet **Speicher**, nicht Foerderer. Der Vario ist
|
||||
violett.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(validate_assignment=True, extra="forbid",
|
||||
str_strip_whitespace=True)
|
||||
|
||||
group: str = Field(min_length=1, description="Kurzname der Farbgruppe, z. B. 'vario'")
|
||||
label: str = Field(min_length=1, description="Klartext, z. B. 'Kettenfoerderer'")
|
||||
fill: str = Field(min_length=4, description="Fuellfarbe als Hex, z. B. '#e8d4f0'")
|
||||
stroke: str = Field(min_length=4, description="Randfarbe als Hex")
|
||||
font: str = Field(default="#111111", min_length=4, description="Schriftfarbe")
|
||||
|
||||
def get_group(self) -> str:
|
||||
return self.group
|
||||
|
||||
def get_fill(self) -> str:
|
||||
return self.fill
|
||||
|
||||
def get_stroke(self) -> str:
|
||||
return self.stroke
|
||||
|
||||
def get_font(self) -> str:
|
||||
return self.font
|
||||
|
||||
def dot_attrs(self) -> dict[str, str]:
|
||||
"""Graphviz-Knotenattribute."""
|
||||
return {"fillcolor": self.fill, "color": self.stroke, "fontcolor": self.font}
|
||||
|
||||
def mermaid_classdef(self) -> str:
|
||||
"""Mermaid-classDef-Zeile fuer diese Gruppe."""
|
||||
return (
|
||||
f"classDef {self.group} fill:{self.fill},"
|
||||
f"stroke:{self.stroke},color:{self.font}"
|
||||
)
|
||||
|
||||
|
||||
# Farbgruppen - eine Instanz je Gruppe, von den Typen unten referenziert.
|
||||
STYLE_SEP = TroStyle(group="sep", label="Separator",
|
||||
fill="#d4e8ff", stroke="#3388cc")
|
||||
STYLE_SWI = TroStyle(group="swi", label="Weiche",
|
||||
fill="#ffe4a0", stroke="#cc8800")
|
||||
STYLE_SSCC = TroStyle(group="sscc", label="Scanner (SSCC)",
|
||||
fill="#ffd4d4", stroke="#cc3333")
|
||||
STYLE_VARIO = TroStyle(group="vario", label="Kettenfoerderer",
|
||||
fill="#e8d4f0", stroke="#883388")
|
||||
STYLE_STORE = TroStyle(group="store", label="Speicher / Puffer",
|
||||
fill="#d4f0d4", stroke="#338833")
|
||||
STYLE_EXT = TroStyle(group="ext", label="Systemgrenze / extern",
|
||||
fill="#f0f0f0", stroke="#888888", font="#404040")
|
||||
|
||||
STYLES: tuple[TroStyle, ...] = (
|
||||
STYLE_SEP, STYLE_SWI, STYLE_SSCC, STYLE_VARIO, STYLE_STORE, STYLE_EXT,
|
||||
)
|
||||
|
||||
|
||||
class TroDefinition(BaseModel):
|
||||
"""
|
||||
Ein TRO-Typ: Name, FB-Baustein, Bauteile und Darstellung.
|
||||
|
||||
Pydantic-Modell - die Felder werden bei Erzeugung *und* bei jeder Zuweisung
|
||||
geprueft (`validate_assignment`). Damit ist ein TroDefinition-Objekt nie in
|
||||
einem ungueltigen Zustand:
|
||||
|
||||
name nicht leer
|
||||
fb_block nicht leer
|
||||
items {Bauteilart: Anzahl}, Anzahl >= 1, Art nicht leer;
|
||||
Eintraege mit Anzahl <= 0 werden verworfen
|
||||
|
||||
Positionsargumente sind weiter moeglich (`TroDefinition("1Sep", "FB_...")`),
|
||||
ebenso benannte (`TroDefinition(name="1Sep", fb_block="FB_...")`).
|
||||
|
||||
Weil es ein BaseModel ist, gibt es Serialisierung gratis - nuetzlich fuer
|
||||
das geplante JSON-Layoutmodell:
|
||||
|
||||
tro.model_dump() -> dict
|
||||
tro.model_dump_json(indent=2) -> JSON
|
||||
TroDefinition.model_validate(d) -> aus dict
|
||||
TroDefinition.model_json_schema() -> JSON-Schema
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(
|
||||
validate_assignment=True, # set_* darf nichts Ungueltiges hinterlassen
|
||||
extra="forbid", # Tippfehler in Feldnamen fallen auf
|
||||
str_strip_whitespace=True,
|
||||
)
|
||||
|
||||
name: str = Field(
|
||||
min_length=1,
|
||||
description="Kurztyp, wie in FB_Main und connect.ini verwendet, z. B. '1Sep'",
|
||||
)
|
||||
fb_block: str = Field(
|
||||
min_length=1,
|
||||
description="Name des Siemens-Funktionsbausteins, z. B. 'FB_ILS_MTRO_1Sep'",
|
||||
)
|
||||
items: dict[str, int] = Field(
|
||||
default_factory=dict,
|
||||
description="Bauteilart -> Anzahl, z. B. {'Separator': 1, 'Switch': 1}",
|
||||
)
|
||||
style: TroStyle = Field(
|
||||
default=STYLE_EXT,
|
||||
description="Farbgruppe fuer Zeichnungen (Graphviz, Mermaid, CAD-Symbol)",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str | None = None,
|
||||
fb_block: str | None = None,
|
||||
items: dict[str, int] | None = None,
|
||||
style: TroStyle | None = None,
|
||||
**data,
|
||||
) -> None:
|
||||
# Positionsargumente auf Feldnamen abbilden, damit die bisherige
|
||||
# Aufrufform TroDefinition("1Sep", "FB_...", {...}) erhalten bleibt.
|
||||
if name is not None:
|
||||
data["name"] = name
|
||||
if fb_block is not None:
|
||||
data["fb_block"] = fb_block
|
||||
if items is not None:
|
||||
data["items"] = items
|
||||
if style is not None:
|
||||
data["style"] = style
|
||||
super().__init__(**data)
|
||||
|
||||
@field_validator("items", mode="after")
|
||||
@classmethod
|
||||
def _clean_items(cls, value: dict[str, int]) -> dict[str, int]:
|
||||
"""Leere Bauteilarten ablehnen, Anzahlen <= 0 verwerfen."""
|
||||
cleaned: dict[str, int] = {}
|
||||
for item, count in value.items():
|
||||
key = str(item).strip()
|
||||
if not key:
|
||||
raise ValueError("Bauteilart darf nicht leer sein")
|
||||
if int(count) > 0:
|
||||
cleaned[key] = int(count)
|
||||
return cleaned
|
||||
|
||||
# -- get ---------------------------------------------------------------
|
||||
|
||||
def get_name(self) -> str:
|
||||
"""Kurztyp, z. B. '1Sep1Swi'."""
|
||||
return self.name
|
||||
|
||||
def get_fb_block(self) -> str:
|
||||
"""Name des Siemens-Funktionsbausteins."""
|
||||
return self.fb_block
|
||||
|
||||
def get_items(self) -> dict[str, int]:
|
||||
"""Alle Bauteile als {Art: Anzahl} (Kopie - Aenderungen wirken nicht)."""
|
||||
return dict(self.items)
|
||||
|
||||
def get_item_names(self) -> list[str]:
|
||||
"""Enthaltene Bauteilarten, alphabetisch."""
|
||||
return sorted(self.items)
|
||||
|
||||
def get_item_count(self, item: str) -> int:
|
||||
"""Anzahl einer Bauteilart; 0 wenn nicht enthalten."""
|
||||
return self.items.get(item, 0)
|
||||
|
||||
def has_item(self, item: str) -> bool:
|
||||
"""Ist die Bauteilart enthalten?"""
|
||||
return self.get_item_count(item) > 0
|
||||
|
||||
def get_item_fb(self, item: str) -> str:
|
||||
"""Sub-Funktionsbaustein einer Bauteilart ('' wenn keiner)."""
|
||||
return ITEM_FB.get(item, "")
|
||||
|
||||
def get_total_items(self) -> int:
|
||||
"""Summe aller Bauteile."""
|
||||
return sum(self.items.values())
|
||||
|
||||
def get_style(self) -> TroStyle:
|
||||
"""Darstellung (Farbgruppe) dieses Typs."""
|
||||
return self.style
|
||||
|
||||
def get_group(self) -> str:
|
||||
"""Kurzname der Farbgruppe, z. B. 'vario'."""
|
||||
return self.style.group
|
||||
|
||||
def get_dot_attrs(self) -> dict[str, str]:
|
||||
"""Graphviz-Knotenattribute dieses Typs."""
|
||||
return self.style.dot_attrs()
|
||||
|
||||
# -- set ---------------------------------------------------------------
|
||||
#
|
||||
# Jede Zuweisung laeuft durch die Pydantic-Validierung, weil
|
||||
# validate_assignment aktiv ist.
|
||||
|
||||
def set_name(self, name: str) -> None:
|
||||
"""Kurztyp setzen."""
|
||||
self.name = name
|
||||
|
||||
def set_fb_block(self, fb_block: str) -> None:
|
||||
"""FB-Baustein setzen."""
|
||||
self.fb_block = fb_block
|
||||
|
||||
def set_items(self, items: dict[str, int]) -> None:
|
||||
"""Bauteilliste vollstaendig ersetzen."""
|
||||
self.items = dict(items)
|
||||
|
||||
def set_style(self, style: TroStyle) -> None:
|
||||
"""Darstellung (Farbgruppe) setzen."""
|
||||
self.style = style
|
||||
|
||||
def set_item(self, item: str, count: int) -> None:
|
||||
"""
|
||||
Anzahl einer Bauteilart setzen.
|
||||
|
||||
count <= 0 entfernt das Bauteil. Unbekannte Arten sind erlaubt, damit
|
||||
neue Bauteile ohne Aenderung an TroItem ergaenzt werden koennen.
|
||||
"""
|
||||
updated = dict(self.items)
|
||||
key = str(item).strip()
|
||||
if not key:
|
||||
raise ValueError(f"{self.name}: Bauteilart darf nicht leer sein")
|
||||
if int(count) <= 0:
|
||||
updated.pop(key, None)
|
||||
else:
|
||||
updated[key] = int(count)
|
||||
self.items = updated
|
||||
|
||||
def add_item(self, item: str, count: int = 1) -> None:
|
||||
"""Anzahl einer Bauteilart erhoehen (oder Bauteil neu aufnehmen)."""
|
||||
self.set_item(item, self.get_item_count(item) + int(count))
|
||||
|
||||
def remove_item(self, item: str) -> None:
|
||||
"""Bauteilart entfernen."""
|
||||
self.set_item(item, 0)
|
||||
|
||||
# -- Darstellung -------------------------------------------------------
|
||||
|
||||
def describe_items(self) -> str:
|
||||
"""Bauteile als Text, z. B. '1x Separator, 1x Switch'."""
|
||||
if not self.items:
|
||||
return "-"
|
||||
return ", ".join(f"{self.items[i]}x {i}" for i in self.get_item_names())
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Statische Typdefinition
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
# Quellen: doc/TRO_Typen.md (Baukasten-Analyse, Mapping-Tabelle) und
|
||||
# doc/TRO_Katalog/scl_templates/*.scl (VAR-Deklarationen)
|
||||
|
||||
TRO_CATALOG: tuple[TroDefinition, ...] = (
|
||||
# Basistyp: 1x Separator plus das Rahmenwerk, das jeder Typ besitzt
|
||||
# (PriorityManager, JamArea Entry/Exit, HMI, Safety, MachineState).
|
||||
TroDefinition("1Sep", "FB_ILS_MTRO_1Sep", {
|
||||
TroItem.SEPARATOR: 1,
|
||||
}, STYLE_SEP),
|
||||
# laut TRO_Typen.md: Basis + 1x Switch-Modul
|
||||
TroDefinition("1Sep1Swi", "FB_ILS_MTRO_1Sep1Swi", {
|
||||
TroItem.SEPARATOR: 1,
|
||||
TroItem.SWITCH: 1,
|
||||
}, STYLE_SWI),
|
||||
# laut TRO_Typen.md: Basis + 2x Switch-Modul + Scanner-Modul
|
||||
TroDefinition("1Sep2Swi", "FB_ILS_MTRO_1Sep2Swi", {
|
||||
TroItem.SEPARATOR: 1,
|
||||
TroItem.SWITCH: 2,
|
||||
TroItem.SCANNER: 1,
|
||||
}, STYLE_SWI),
|
||||
# laut TRO_Typen.md: Basis + Scanner-Modul + SSCC-Modul (Messsensor + WCS)
|
||||
TroDefinition("1Sep_SSCC", "FB_ILS_MTRO_1Sep_SSCC", {
|
||||
TroItem.SEPARATOR: 1,
|
||||
TroItem.SCANNER: 1,
|
||||
TroItem.SSCC: 1,
|
||||
}, STYLE_SSCC),
|
||||
# laut TRO_Typen.md: Basis + Vario-Antriebsmodul
|
||||
TroDefinition("Vario", "FB_ILS_MTRO_Vario", {
|
||||
TroItem.SEPARATOR: 1,
|
||||
TroItem.VARIO_DRIVE: 1,
|
||||
}, STYLE_VARIO),
|
||||
# laut TRO_Typen.md: Basis (Pin-Separator) + 19x Storage-Line + Scanner
|
||||
# + Encoder + StorageRemoval-Schnittstelle
|
||||
TroDefinition("PinStore_Auto", "FB_ILS_MTRO_PinStore_Auto", {
|
||||
TroItem.SEPARATOR: 1,
|
||||
TroItem.STORAGE_LINE: 19,
|
||||
TroItem.SCANNER: 1,
|
||||
TroItem.ENCODER: 1,
|
||||
}, STYLE_STORE),
|
||||
# aus SCL belegt (FB_ILS_MTRO_Vario_workStation.scl, VAR ab Zeile 77):
|
||||
# fbSeparator1, fbConvVario, fbSepWait, fbBarcodeReader.
|
||||
# Der Vario-Antrieb ist hier die WorkStation-Variante des STRO-Bausteins.
|
||||
TroDefinition("Vario_workStation", "FB_ILS_MTRO_Vario_workStation", {
|
||||
TroItem.SEPARATOR: 1,
|
||||
TroItem.VARIO_DRIVE: 1,
|
||||
TroItem.WORK_STATION: 1,
|
||||
TroItem.ACCUMULATE: 1,
|
||||
TroItem.SCANNER: 1,
|
||||
}, STYLE_VARIO),
|
||||
# aus SCL belegt (FB_EmptyCarrBuffer.scl): arfbSeparatorStorage als
|
||||
# Array[1..5] of FB_ILS_STRO_Sep + 5x fbCarrierWaitStore.
|
||||
# Kein eigener Eingangs-Separator - der "inTro" ist ein separater 1Sep-TRO
|
||||
# (in der Referenzanlage z. B. TRO101_IN neben TRO101).
|
||||
TroDefinition("EmptyCarrBuffer", "FB_EmptyCarrBuffer", {
|
||||
TroItem.STORAGE_LINE: 5,
|
||||
TroItem.ACCUMULATE: 5,
|
||||
}, STYLE_STORE),
|
||||
# aus SCL belegt (FB_LoadingBoom_INBOUND.scl): fbTiltSensor,
|
||||
# fbDistanceFoot, fbWorkSation. Bewusst KEIN Separator und KEINE Weiche -
|
||||
# der einzige nicht additive Typ.
|
||||
TroDefinition("LoadingBoom", "FB_LoadingBoom_INBOUND", {
|
||||
TroItem.BOOM: 1,
|
||||
TroItem.FOOT: 1,
|
||||
TroItem.TILT_SENSOR: 1,
|
||||
}, STYLE_EXT),
|
||||
# aus SCL belegt (FB_ILS_MTRO_2Sep1Swi.scl, VAR ab Zeile 115):
|
||||
# fbSeparator1, fbSeparator2, fbSwitch1, fbBarcodeReader1, fbBarcodeReader2.
|
||||
# Die Mapping-Tabelle in TRO_Typen.md nennt die beiden Scanner nicht -
|
||||
# hier gilt der Code.
|
||||
TroDefinition("2Sep1Swi", "FB_ILS_MTRO_2Sep1Swi", {
|
||||
TroItem.SEPARATOR: 2,
|
||||
TroItem.SWITCH: 1,
|
||||
TroItem.SCANNER: 2,
|
||||
}, STYLE_SWI),
|
||||
)
|
||||
|
||||
_BY_NAME: dict[str, TroDefinition] = {t.get_name(): t for t in TRO_CATALOG}
|
||||
|
||||
|
||||
def get_tro(name: str) -> TroDefinition | None:
|
||||
"""Typdefinition nach Namen; None wenn unbekannt."""
|
||||
return _BY_NAME.get(name)
|
||||
|
||||
|
||||
def tro_names() -> list[str]:
|
||||
"""Alle Typnamen in Katalogreihenfolge."""
|
||||
return [t.get_name() for t in TRO_CATALOG]
|
||||
|
||||
|
||||
def set_tro(definition: TroDefinition) -> None:
|
||||
"""Typdefinition ergaenzen oder ersetzen (nur zur Laufzeit)."""
|
||||
_BY_NAME[definition.get_name()] = definition
|
||||
|
||||
|
||||
|
||||
def catalog() -> dict[str, TroDefinition]:
|
||||
"""Alle Typdefinitionen als {Name: TroDefinition} (Kopie der Zuordnung)."""
|
||||
return dict(_BY_NAME)
|
||||
|
||||
|
||||
def mermaid_classdefs() -> list[str]:
|
||||
"""classDef-Zeilen fuer ein Mermaid-Diagramm, eine je Farbgruppe."""
|
||||
return [style.mermaid_classdef() for style in STYLES]
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
# Python-Abhaengigkeiten
|
||||
# Installieren mit: pip install -r requirements.txt
|
||||
|
||||
# Beispiel-Abhaengigkeiten - anpassen nach Bedarf:
|
||||
# pydantic >= 2.0.0
|
||||
pydantic >= 2.0.0
|
||||
|
||||
# Noch nicht benoetigt:
|
||||
# pytest >= 9.0.0
|
||||
|
||||
Reference in New Issue
Block a user