scl_skeleton --eplan: E-Planung-Namen auch in den PinStore-Lagerlinien
Sensor und Stopper jeder Lagerlinie (und des Pin-Separators) kommen aus der E-Planung wie bei den Separatorbloecken (scl_context._sep_namen); die Zaehlung der eingesetzten Namen beruecksichtigt die Linien. Dazu die ID-Datei cfg/mubea_tro_ids.ini und .gitignore fuer lokale Claude-Code- Einstellungen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
77c5aac343
commit
7ec2b88b79
@@ -68,3 +68,8 @@ ipython_config.py
|
||||
/work
|
||||
/log
|
||||
/results
|
||||
|
||||
# Claude Code: persoenliche Einstellungen und TRO-Kriterien-Waechter
|
||||
.claude/settings.local.json
|
||||
.claude/hooks/
|
||||
.claude/tro_criteria_baseline
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
; ============================================================
|
||||
; TRO-IDs zu mubea.csv - erzeugt von lib/tro_flow.py am 2026-10-15
|
||||
;
|
||||
; Je TRO: ID = x, y (mm) seines Anker-Separators im CSV-Koordinatensystem.
|
||||
; Die IDs duerfen umbenannt werden (eindeutig, gueltiger SCL-Bezeichner);
|
||||
; tro_flow findet jeden TRO ueber die Lage wieder. Neue TROs werden
|
||||
; unten angehaengt, weggefallene bleiben stehen und werden gemeldet.
|
||||
; Alles neu nummerieren: tro_flow --renumber (ueberschreibt diese Datei).
|
||||
; Siehe doc/Konzept_Layout_Hardware_SCL.md, Abschnitt TRO-IDs.
|
||||
; ============================================================
|
||||
|
||||
[tro]
|
||||
TRO01 = 10310.0, -440.1 ; 1Sep | Separator 0042 auf Kreisel3 Bahn R | Sep 0042
|
||||
TRO02 = 10310.0, 159.9 ; 1Sep | Separator 0043 auf Kreisel3 Bahn R | Sep 0043
|
||||
TRO03 = 10310.0, -5013.1 ; 1Sep | Separator 0044 auf Kreisel3 Bahn R | Sep 0044
|
||||
TRO04 = 958.0, 12300.0 ; PinStore_Auto | Speicher (20 Schwerkraftlinien) | Sep 0066, 0069, 0072, 0075, 0078, 0081, 0084, 0087, 0090, 0093, 0096, 0099, 0102, 0105, 0108, 0111, 0114, 0117, 0120, 0123
|
||||
TRO05 = -400.0, -3554.9 ; 1Sep | Separator 0012 auf Kreisel2 Bahn L | Sep 0012
|
||||
TRO06 = 5355.1, -5878.0 ; 1Sep | Separator 0040 auf Kreisel1 Bahn R | Sep 0040
|
||||
TRO07 = -898.9, 1134.6 ; Vario | VF_3 | Sep 0062
|
||||
TRO08 = -703.0, 12296.5 ; 1Sep | VF_3 | Sep 0063
|
||||
TRO09 = -400.0, -562.0 ; 1Sep1Swi | Separator 0011 an Ausschleuselement 0061 (Strecke 0015, Anfang) | Sep 0011
|
||||
TRO10 = -1026.0, 10723.0 ; 1Sep | VF_3 | Sep 0037
|
||||
TRO11 = -1026.0, 5250.1 ; 1Sep | VF_3 | Sep 0038
|
||||
TRO12 = 3299.6, 13509.6 ; Vario | VF_1 | Sep 0054
|
||||
TRO13 = 8953.1, 13509.6 ; 1Sep | VF_1 | Sep 0055
|
||||
TRO14 = -400.0, 13920.0 ; 1Sep1Swi | Separator 0003 an Ausschleuselement 0053 (Strecke 0013, Anfang) | Sep 0003
|
||||
TRO15 = 9510.0, 14217.0 ; 1Sep | VF_1 | Sep 0045
|
||||
TRO16 = 3299.6, -4743.4 ; Vario | VF_2 | Sep 0058
|
||||
TRO17 = 8953.1, -4743.4 ; 1Sep | VF_2 | Sep 0059
|
||||
TRO18 = 400.0, -3978.1 ; 2Sep2Swi | Uebergabestelle Kreisel2: Ausschleuselement 0057 + ILS Weiche 0125 | Sep 0005, 0036
|
||||
+32
-14
@@ -432,17 +432,28 @@ def _jam(n: int, neighbour: str, jam_db: str, sensor: SclName | None = None,
|
||||
)
|
||||
|
||||
|
||||
def _store(tro: TroBase) -> SclStore:
|
||||
def _store(tro: TroBase, eplan: EplanDocument | None = None) -> SclStore:
|
||||
"""PinStore_Auto: eine Linie je Speicherbahn (Host) des Layouts.
|
||||
|
||||
tro_flow legt die Separatoren als [steuernde ..., Linien ...] ab; die
|
||||
Linien sind die letzten len(hosts). Fehlen Hosts (fremde JSON), zaehlt
|
||||
jeder Separator als Linie.
|
||||
jeder Separator als Linie. Sensor und Stopper jeder Linie (und des
|
||||
Pin-Separators, falls tro_flow einen gefunden hat) kommen aus der
|
||||
E-Planung wie bei den Separatorbloecken.
|
||||
"""
|
||||
hosts = list(getattr(tro, "hosts", []) or [])
|
||||
seps = list(tro.separators)
|
||||
anzahl = len(hosts) if 0 < len(hosts) <= len(seps) else len(seps)
|
||||
steuer, linien = seps[:len(seps) - anzahl], seps[len(seps) - anzahl:]
|
||||
pin_sensor, pin_stopper = _sep_namen(steuer[0], eplan) if steuer else (
|
||||
_offen("cInBG____"), _offen("MB____"))
|
||||
zeilen = []
|
||||
for n, sep in enumerate(linien, start=1):
|
||||
sensor, stopper = _sep_namen(sep, eplan)
|
||||
zeilen.append(SclStoreLine(n=n, layout=sep,
|
||||
jam_length=_offen('"cStorage____ExitJam"'),
|
||||
sensor=sensor, jam_sensor=_offen("cInBG____"),
|
||||
stopper=stopper))
|
||||
return SclStore(
|
||||
encoder=_offen("#fbEncoder____"),
|
||||
dest=_offen("cDest____"),
|
||||
@@ -460,27 +471,34 @@ def _store(tro: TroBase) -> SclStore:
|
||||
'arrudt_StorageRemovalHandshakeTROsLvl1[____]'),
|
||||
conv_db=_offen('"DB_ConveyorStations".stConveyorStations____'),
|
||||
pin_layout=", ".join(steuer) or "?",
|
||||
pin_sensor=_offen("cInBG____"),
|
||||
pin_stopper=_offen("MB____"),
|
||||
lines=[
|
||||
SclStoreLine(n=n, layout=sep, jam_length=_offen('"cStorage____ExitJam"'),
|
||||
sensor=_offen("cInBG____"), jam_sensor=_offen("cInBG____"),
|
||||
stopper=_offen("MB____"))
|
||||
for n, sep in enumerate(linien, start=1)
|
||||
],
|
||||
pin_sensor=pin_sensor,
|
||||
pin_stopper=pin_stopper,
|
||||
lines=zeilen,
|
||||
)
|
||||
|
||||
|
||||
def _separator(i: int, layout: str, eplan: EplanDocument | None) -> SclSeparator:
|
||||
def _sep_namen(layout: str, eplan: EplanDocument | None) -> tuple[SclName, SclName]:
|
||||
"""Sensor und Stopperventil eines Layout-Separators aus der E-Planung.
|
||||
|
||||
Gilt fuer die Separatorbloecke (stInSeparator<n>) und genauso fuer die
|
||||
Linien eines PinStore_Auto - beide sind Separatoren im Layout. Ohne
|
||||
Zuordnung bleiben beide offen.
|
||||
"""
|
||||
rollen = eplan.for_layout(layout) if eplan is not None and layout != "?" else {}
|
||||
sensor = rollen.get("sensor")
|
||||
stopper = rollen.get("stopper")
|
||||
return (_bekannt(_SENSOR.format(bmk=sensor.bmk)) if sensor else _offen("cInBG____"),
|
||||
_bekannt(_VENTIL.format(bmk=stopper.bmk)) if stopper else _offen("MB____"))
|
||||
|
||||
|
||||
def _separator(i: int, layout: str, eplan: EplanDocument | None) -> SclSeparator:
|
||||
sensor, stopper = _sep_namen(layout, eplan)
|
||||
return SclSeparator(
|
||||
n=i,
|
||||
layout=layout,
|
||||
no=_offen("cSep_____"),
|
||||
sensor=_bekannt(_SENSOR.format(bmk=sensor.bmk)) if sensor else _offen("cInBG____"),
|
||||
stopper=_bekannt(_VENTIL.format(bmk=stopper.bmk)) if stopper else _offen("MB____"),
|
||||
sensor=sensor,
|
||||
stopper=stopper,
|
||||
# Teilesensor kennt die E-Planung-Bruecke noch nicht - offen
|
||||
part_sensor=_offen("cInBG____"),
|
||||
)
|
||||
@@ -604,7 +622,7 @@ def _tro_context(tro: TroBase, alle: dict[str, TroBase],
|
||||
station_release=_offen('#"rTrig_Workstation ____".CLK'),
|
||||
loaded_error_sensor=_offen("cInBG____"))
|
||||
if items.get(TroItem.WORK_STATION) else None),
|
||||
store=_store(tro) if items.get(TroItem.STORAGE_LINE) else None,
|
||||
store=_store(tro, eplan) if items.get(TroItem.STORAGE_LINE) else None,
|
||||
)
|
||||
|
||||
|
||||
|
||||
+11
-4
@@ -485,10 +485,17 @@ def _in_results(name: str, results: Path) -> Path:
|
||||
|
||||
|
||||
def _eingesetzt(context: SclFile) -> int:
|
||||
"""Wie viele Separator-Namen aus der E-Planung kamen."""
|
||||
return sum(not name.todo
|
||||
for tro in context.tros for s in tro.separators
|
||||
for name in (s.sensor, s.stopper))
|
||||
"""Wie viele Separator-Namen aus der E-Planung kamen (auch Speicherlinien)."""
|
||||
namen = []
|
||||
for tro in context.tros:
|
||||
if tro.store is not None:
|
||||
# Speicher: Pin-Separator und Linien; der Separatorblock wiederholt
|
||||
# nur die erste Linie und wird im PinStore-Template nicht geschrieben
|
||||
namen += [tro.store.pin_sensor, tro.store.pin_stopper]
|
||||
namen += [n for linie in tro.store.lines for n in (linie.sensor, linie.stopper)]
|
||||
else:
|
||||
namen += [n for s in tro.separators for n in (s.sensor, s.stopper)]
|
||||
return sum(not name.todo for name in namen)
|
||||
|
||||
|
||||
def _schema_of(path: Path) -> str:
|
||||
|
||||
@@ -208,6 +208,35 @@ def test_kontext_setzt_namen_ein_und_loescht_den_merker():
|
||||
assert kontext.eplan_source.startswith("Mubea_positionsdraw.json")
|
||||
|
||||
|
||||
def test_kontext_setzt_namen_auch_in_speicherlinien_ein():
|
||||
"""PinStore_Auto: die Linien sind Separatoren im Layout - ihre E-Planung-Namen
|
||||
kommen in store.lines an (und damit ins PinStore-Template), nicht nur in den
|
||||
Separatorblock."""
|
||||
from model import Analysis, DerivedTro, TroDocument
|
||||
from scl_skeleton import TEMPLATE_DIR, SclTemplates
|
||||
|
||||
linien = ["0066", "0069"]
|
||||
store = DerivedTro(tro_id="TRO04", type_name="PinStore_Auto", label="Speicher",
|
||||
hosts=["0016", "0017"], separators=linien, scanners=[],
|
||||
reason="Test", predecessors=["TRO03"], successors=["TRO05"])
|
||||
punkte = [LayoutPoint("0066", "Separator", 0, 0), LayoutPoint("0069", "Separator", 1000, 0)]
|
||||
geraete = [_dev("BG0766", "IN SEP", 0, 0), _dev("MB0767", "SEP", 0, 300),
|
||||
_dev("BG0769", "IN SEP", 1000, 0), _dev("MB0770", "SEP", 1000, 300)]
|
||||
eplan = EplanDocument(csv_file="mubea.csv", eplan_file="Mubea_positionsdraw.json",
|
||||
assignments=assign(punkte, geraete, [SENSOR, STOPPER], IDENT))
|
||||
document = TroDocument.from_analysis(Analysis(tros=[store]), source="mubea.csv")
|
||||
kontext = build_context(document, "mubea_tro.json", eplan=eplan)
|
||||
|
||||
zeilen = kontext.tros[0].store.lines
|
||||
assert [(z.layout, z.sensor.value, z.stopper.value) for z in zeilen] == [
|
||||
("0066", "cInBG0766", "MB0767"), ("0069", "cInBG0769", "MB0770")]
|
||||
assert not any(n.todo for z in zeilen for n in (z.sensor, z.stopper))
|
||||
|
||||
text = SclTemplates(TEMPLATE_DIR).render(kontext.tros[0])
|
||||
assert '#TRO04.arInSep[#nActNo].stSenTrolley := "DB_Inputs".Sensors["cInBG0766"];\n' in text
|
||||
assert '"MB0770" := #TRO04.arOutSeparatorStore[2];\n' in text
|
||||
|
||||
|
||||
def _lauf(tmp_path, monkeypatch, eplan: EplanDocument,
|
||||
*weitere: str) -> tuple[int, Path]:
|
||||
shutil.copy(FIXTURES / "mubea_tro.json", tmp_path / "mubea_tro.json")
|
||||
|
||||
Reference in New Issue
Block a user